diff --git a/DESIGN.md b/DESIGN.md index c2bcf23..b9a6485 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -72,4 +72,4 @@ Probably some `metadata.yml` that is *not* in the template. # 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/ +* Local docker registry for images? See https://www.docker.com/blog/how-to-use-your-own-registry-2/ (maybe later) diff --git a/examples/hello_cr/function.cr b/examples/hello_cr/function.cr index 8625475..88ae85f 100644 --- a/examples/hello_cr/function.cr +++ b/examples/hello_cr/function.cr @@ -1,3 +1,3 @@ get "/" do - "Hello World from Crystal!" + "Hello World Crystal!" end diff --git a/shard.lock b/shard.lock index 3e68c9c..63b4f90 100644 --- a/shard.lock +++ b/shard.lock @@ -12,3 +12,7 @@ shards: git: https://github.com/ralsina/docr.git version: 0.1.1+git.commit.18f15cc7111b1d0c63347c7cca07aee9ec87a7a8 + kiwi: + git: https://github.com/ralsina/kiwi.git + version: 0.1.0+git.commit.65059b87771238593a28b2b8b9fdf77d8e2b9e89 + diff --git a/shard.yml b/shard.yml index f426b0b..14c8e97 100644 --- a/shard.yml +++ b/shard.yml @@ -19,3 +19,6 @@ dependencies: branch: add_exposed_ports commander: github: mrrooijen/commander + kiwi: + github: ralsina/kiwi + branch: master \ No newline at end of file diff --git a/src/faaso.cr b/src/faaso.cr index 5c42514..a659229 100644 --- a/src/faaso.cr +++ b/src/faaso.cr @@ -1,9 +1,10 @@ +require "./funko.cr" require "commander" require "docr" require "docr/utils.cr" require "file_utils" +require "kiwi/file_store" require "uuid" -require "./funko.cr" # FIXME make it configurable REPO = "localhost:5000" @@ -12,6 +13,9 @@ REPO = "localhost:5000" module Faaso VERSION = "0.1.0" + # A simple persistent k/v store + store = Kiwi::FileStore.new(".kiwi") + module Commands class Build @arguments : Array(String) = [] of String @@ -56,17 +60,11 @@ module Faaso # FIXME: this should be configurable repo = REPO - tag = "#{repo}/#{funko.name}:latest" docker_api = Docr::API.new(Docr::Client.new) docker_api.images.build( context: tmp_dir.to_s, - tags: [tag, "#{funko.name}:latest"]) { } - - puts "Pushing to repo as #{tag}" - docker_api.images.tag(repo: repo, name: slug, tag: "latest") - # FIXME: pushing is broken because my test registry has no auth - # docker_api.images.push(name: slug, tag: "latest", auth: "") + tags: ["#{funko.name}:latest"]) { } end end end @@ -84,23 +82,51 @@ module Faaso funkos = Funko.from_paths(@arguments) funkos.each do |funko| repo = REPO - tag = "#{repo}/#{funko.name}:latest" + container_name = "faaso-#{funko.name}" docker_api = Docr::API.new(Docr::Client.new) # Pull image from registry - docker_api.images.create(image: tag) + # docker_api.images.create(image: tag) - containers = docker_api.containers.list(all: true) - # If it's running, do nothing + # FIXME: When reusing a paused/exited container, check that + # the version of the image is the correct one, otherwise purge them. + + # Get image history, sorted newer image first + begin + images = docker_api.images.history( + name: funko.name + ).sort { |a, b| b.@created <=> a.@created }.map(&.@id) + rescue ex : Docr::Errors::DockerAPIError + puts "Error: no images available for #{funko.name}:latest" + puts ex + next + end + + latest_image = images[0] + + # Filter by name so only faaso-thisfunko are affected from now on + # sorted newer image first + containers = docker_api.containers.list( + all: true, + filters: {"name" => [container_name]} + ).sort { |a, b| (images.index(b.@image_id) || 9999) <=> (images.index(a.@image_id) || 9999) } + pp! images + pp! containers.map { |c| images.index(c.@image_id) } + + # If it's already up, do nothing if containers.any? { |container| - container.@image == tag && container.@state == "running" + is_running = container.@state == "running" + is_old = container.@image_id != latest_image + p! container.@image_id + puts "Warning: running outdated version" if is_running && is_old + is_running } - puts "#{funko.name} is already running" + puts "#{funko.name} is already up" next end # If it is paused, unpause it paused = containers.select { |container| - container.@image == tag && container.@state == "paused" + container.@state == "paused" } if paused.size > 0 puts "Resuming existing paused container" @@ -110,7 +136,7 @@ module Faaso # If it is exited, start it existing = containers.select { |container| - container.@image == tag && container.@state == "exited" + container.@state == "exited" } puts "Starting function #{funko.name}" @@ -123,7 +149,7 @@ module Faaso # Creating from scratch puts "Creating new container" conf = Docr::Types::CreateContainerConfig.new( - image: tag, + image: "#{funko.name}:latest", hostname: funko.name, # Port in the container side exposed_ports: {"#{funko.port}/tcp" => {} of String => String}, @@ -135,10 +161,9 @@ module Faaso ) ) - # FIXME: name should be unique - response = docker_api.containers.create(name: "fungus", config: conf) + response = docker_api.containers.create(name: container_name, config: conf) response.@warnings.each { |msg| puts "Warning: #{msg}" } - container_id = response.@id + # container_id = response.@id docker_api.containers.start(response.@id) # TODO: wait until container is running before next end @@ -167,5 +192,22 @@ module Faaso end end end + + class Deploy + @arguments : Array(String) = [] of String + @options : Commander::Options + + def initialize(options, arguments) + @options = options + @arguments = arguments + end + + def run + @arguments.each do |arg| + puts "Stopping function... #{arg}" + # TODO: Everything + end + end + end end end diff --git a/src/main.cr b/src/main.cr index 55cb8f6..42886bd 100644 --- a/src/main.cr +++ b/src/main.cr @@ -7,8 +7,8 @@ cli = Commander::Command.new do |cmd| cmd.commands.add do |command| command.use = "build" - command.short = "Build a function" - command.long = "Build a function's Docker image and optionally upload it to registry" + command.short = "Build a funko" + command.long = "Build a funko's Docker image and upload it to registry" command.run do |options, arguments| Faaso::Commands::Build.new(options, arguments).run end @@ -16,13 +16,22 @@ cli = Commander::Command.new do |cmd| cmd.commands.add do |command| command.use = "up" - command.short = "Start a function" - command.long = "Start a function in a container" + command.short = "Ensure funkos are running" + command.long = "Start/unpause/create containers for requested funkos and ensure they are up." command.run do |options, arguments| Faaso::Commands::Up.new(options, arguments).run end end + cmd.commands.add do |command| + command.use = "deploy" + command.short = "Deploy latest images" + command.long = "Update containers for all funkos to latest image." + command.run do |options, arguments| + Faaso::Commands::Deploy.new(options, arguments).run + end + end + cmd.commands.add do |command| command.use = "down" command.short = "Stop a function"