diff --git a/DESIGN.md b/DESIGN.md index c7edf97..7c41b49 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -32,11 +32,11 @@ It should: * Start/reload/configure the proxy as needed * Periodically check the functions are still running -Intentionally: No HA yet, no multiple instances of functions, no +Intentionally: No HA yet, no multiple instances of functions, no up/downscaling, no multiple versions routed by header. # Implementation Ideas * caddy for proxy? It's simple, fast, API-configurable. * Local docker registry for images? See https://www.docker.com/blog/how-to-use-your-own-registry-2/ -* Maybe grip for crystal template? Maybe kemal? \ No newline at end of file +* Maybe grip for crystal template? Maybe kemal? diff --git a/examples/hello_cr/function.cr b/examples/hello_cr/function.cr new file mode 100644 index 0000000..1ebbbf9 --- /dev/null +++ b/examples/hello_cr/function.cr @@ -0,0 +1,3 @@ +get "/" do + "Hello World!" +end \ No newline at end of file diff --git a/src/faaso.cr b/src/faaso.cr index 93bac94..7e3b789 100644 --- a/src/faaso.cr +++ b/src/faaso.cr @@ -1,4 +1,6 @@ require "commander" +require "file_utils" +require "uuid" # TODO: Write documentation for `Faaso` module Faaso @@ -19,7 +21,15 @@ module Faaso puts "Building function... #{arg}" # A function is a folder with stuff in it # TODO: decide template based on file extensions or other metadata + template = "templates/crystal" # TODO: copy template and add function files to it + tmp_dir = "tmp/#{UUID.random}" + Dir.mkdir_p("tmp") unless File.exists? "tmp" + FileUtils.cp_r(template, tmp_dir) + Dir.glob(arg + "/**/*").each do |file| + FileUtils.cp(file, tmp_dir) + end + # TODO: build Docker image # TODO: push Docker image to registry # TODO: return image name for testing diff --git a/templates/crystal-http/function/handler.cr b/templates/crystal-http/function/handler.cr deleted file mode 100644 index 4ebe178..0000000 --- a/templates/crystal-http/function/handler.cr +++ /dev/null @@ -1,12 +0,0 @@ -require "http/request" -require "http/headers" - -class Handler - def run(request : HTTP::Request) - { - body: "Hello, Crystal. You said: #{request.body.try(&.gets_to_end)}", - status_code: 200, - headers: HTTP::Headers{"Content-Type" => "text/plain"}, - } - end -end diff --git a/templates/crystal-http/function/shard.yml b/templates/crystal-http/function/shard.yml deleted file mode 100644 index b65c156..0000000 --- a/templates/crystal-http/function/shard.yml +++ /dev/null @@ -1,2 +0,0 @@ -name: crystal-http-template -version: 0.1.0 diff --git a/templates/crystal-http/main.cr b/templates/crystal-http/main.cr deleted file mode 100644 index 90acc5f..0000000 --- a/templates/crystal-http/main.cr +++ /dev/null @@ -1,41 +0,0 @@ -require "http/server" -require "./function/handler" - -server = HTTP::Server.new do |context| - response_triple : NamedTuple(body: String, headers: HTTP::Headers, status_code: Int32) | - NamedTuple(body: String, headers: HTTP::Headers) | - NamedTuple(body: String, status_code: Int32) | - NamedTuple(body: String) | - NamedTuple(headers: HTTP::Headers, status_code: Int32) | - NamedTuple(headers: HTTP::Headers) | - NamedTuple(status_code: Int32) - - handler = Handler.new - response_triple = handler.run(context.request) - - if response_triple.is_a?(NamedTuple(body: String, headers: HTTP::Headers, status_code: Int32) | - NamedTuple(body: String, status_code: Int32) | - NamedTuple(headers: HTTP::Headers, status_code: Int32) | - NamedTuple(status_code: Int32)) - context.response.status_code = response_triple[:status_code] - end - - if response_triple.is_a?(NamedTuple(body: String, headers: HTTP::Headers, status_code: Int32) | - NamedTuple(body: String, headers: HTTP::Headers) | - NamedTuple(headers: HTTP::Headers, status_code: Int32) | - NamedTuple(headers: HTTP::Headers)) - response_triple[:headers].each do |key, value| - context.response.headers[key] = value - end - end - - if response_triple.is_a?(NamedTuple(body: String, headers: HTTP::Headers, status_code: Int32) | - NamedTuple(body: String, headers: HTTP::Headers) | - NamedTuple(body: String, status_code: Int32) | - NamedTuple(body: String)) - context.response.print(response_triple[:body]) - end -end - -server.bind_tcp "0.0.0.0", 5000 -server.listen diff --git a/templates/crystal-http/template.yml b/templates/crystal-http/template.yml deleted file mode 100644 index 66d437b..0000000 --- a/templates/crystal-http/template.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: crystal -fprocess: ./handler -welcome_message: | - You have created a new function which uses crystal 1.0.0. - To include third-party dependencies, use a vendoring tool like shards: - shards documentation: https://github.com/crystal-lang/shards diff --git a/templates/crystal-http/Dockerfile b/templates/crystal/Dockerfile similarity index 81% rename from templates/crystal-http/Dockerfile rename to templates/crystal/Dockerfile index d2357bc..b51c87a 100644 --- a/templates/crystal-http/Dockerfile +++ b/templates/crystal/Dockerfile @@ -1,10 +1,6 @@ -FROM --platform=${TARGETPLATFORM:-linux/amd64} ghcr.io/openfaas/of-watchdog:0.9.10 as watchdog FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine as build -ARG ADDITIONAL_PACKAGE -COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog - -RUN apk update && apk upgrade && apk add crystal shards openssl-dev ${ADDITIONAL_PACKAGE} && apk cache clean +RUN apk update && apk upgrade && apk add crystal shards openssl-dev && apk cache clean WORKDIR /home/app diff --git a/templates/crystal/main.cr b/templates/crystal/main.cr new file mode 100644 index 0000000..0294940 --- /dev/null +++ b/templates/crystal/main.cr @@ -0,0 +1,4 @@ +require "kemal" +require "./function.cr" + +Kemal.run diff --git a/templates/crystal/shard.yml b/templates/crystal/shard.yml new file mode 100644 index 0000000..474d079 --- /dev/null +++ b/templates/crystal/shard.yml @@ -0,0 +1,15 @@ +name: function +version: 0.1.0 + +targets: + function: + main: main.cr + +dependencies: + kemal: + github: kemalcr/kemal + +# development_dependencies: +# webmock: +# github: manastech/webmock.cr +