General rewrite to support scales different than 1
This commit is contained in:
parent
11d7cf1f9f
commit
cec745039b
@ -1,19 +1,17 @@
|
||||
# This configuration file was generated by `ameba --gen-config`
|
||||
# on 2024-07-02 22:36:34 UTC using Ameba version 1.6.1.
|
||||
# on 2024-07-03 14:31:04 UTC using Ameba version 1.6.1.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the reported problems are removed from the code base.
|
||||
|
||||
# Problems found: 12
|
||||
# Problems found: 5
|
||||
# Run `ameba --only Documentation/DocumentationAdmonition` for details
|
||||
Documentation/DocumentationAdmonition:
|
||||
Description: Reports documentation admonitions
|
||||
Timezone: UTC
|
||||
Excluded:
|
||||
- src/faaso.cr
|
||||
- src/secrets.cr
|
||||
- src/daemon/main.cr
|
||||
- src/daemon/secrets.cr
|
||||
- src/funko.cr
|
||||
- spec/faaso_spec.cr
|
||||
Admonitions:
|
||||
- TODO
|
||||
@ -29,8 +27,8 @@ Naming/BlockParameterName:
|
||||
MinNameLength: 3
|
||||
AllowNamesEndingInNumbers: true
|
||||
Excluded:
|
||||
- src/faaso.cr
|
||||
- src/daemon/funko.cr
|
||||
- src/commands/build.cr
|
||||
AllowedNames:
|
||||
- _
|
||||
- e
|
||||
|
68
src/commands/build.cr
Normal file
68
src/commands/build.cr
Normal file
@ -0,0 +1,68 @@
|
||||
module Faaso
|
||||
module Commands
|
||||
# Build images for one or more funkos from source
|
||||
struct Build
|
||||
def run(options, folders : Array(String))
|
||||
funkos = Funko::Funko.from_paths(folders)
|
||||
|
||||
if options["--local"]
|
||||
funkos.each do |funko|
|
||||
# Create temporary build location
|
||||
tmp_dir = Path.new("tmp", UUID.random.to_s)
|
||||
Dir.mkdir_p(tmp_dir) unless File.exists? tmp_dir
|
||||
funko.prepare_build tmp_dir
|
||||
|
||||
Log.info { "Building function... #{funko.name} in #{tmp_dir}" }
|
||||
funko.build tmp_dir
|
||||
end
|
||||
else # Running against a server
|
||||
funkos.each do |funko|
|
||||
# Create a tarball for the funko
|
||||
buf = IO::Memory.new
|
||||
Compress::Gzip::Writer.open(buf) do |gzip|
|
||||
Crystar::Writer.open(gzip) do |tw|
|
||||
Dir.glob("#{funko.path}/**/*").each do |path|
|
||||
next unless File.file? path
|
||||
rel_path = Path[path].relative_to funko.path
|
||||
file_info = File.info(path)
|
||||
hdr = Crystar::Header.new(
|
||||
name: rel_path.to_s,
|
||||
mode: file_info.permissions.to_u32,
|
||||
size: file_info.size,
|
||||
)
|
||||
tw.write_header(hdr)
|
||||
tw.write(File.read(path).to_slice)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tmp = File.tempname
|
||||
File.open(tmp, "w") do |outf|
|
||||
outf << buf
|
||||
end
|
||||
|
||||
url = "#{FAASO_SERVER}funkos/build/"
|
||||
|
||||
begin
|
||||
Log.info { "Uploading funko to #{FAASO_SERVER}" }
|
||||
response = Crest.post(
|
||||
url,
|
||||
{"funko.tgz" => File.open(tmp), "name" => "funko.tgz"},
|
||||
user: "admin", password: "admin"
|
||||
)
|
||||
Log.info { "Build finished successfully." }
|
||||
body = JSON.parse(response.body)
|
||||
Log.info { body["stdout"] }
|
||||
rescue ex : Crest::InternalServerError
|
||||
Log.error { "Error building funko #{funko.name} from #{funko.path}" }
|
||||
body = JSON.parse(ex.response.body)
|
||||
Log.info { body["stdout"] }
|
||||
Log.error { body["stderr"] }
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
src/commands/export.cr
Normal file
18
src/commands/export.cr
Normal file
@ -0,0 +1,18 @@
|
||||
module Faaso
|
||||
module Commands
|
||||
struct Export
|
||||
def run(options, source : String, destination : String)
|
||||
funko = Funko::Funko.from_paths([source])[0]
|
||||
# Create temporary build location
|
||||
dst_path = destination
|
||||
if File.exists? dst_path
|
||||
Log.error { "#{dst_path} already exists, not exporting #{funko.path}" }
|
||||
return 1
|
||||
end
|
||||
Log.info { "Exporting #{funko.path} to #{dst_path}" }
|
||||
Dir.mkdir_p(dst_path)
|
||||
funko.prepare_build Path[dst_path]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
85
src/commands/scale.cr
Normal file
85
src/commands/scale.cr
Normal file
@ -0,0 +1,85 @@
|
||||
module Faaso
|
||||
module Commands
|
||||
# Bring up one or more funkos by name.
|
||||
#
|
||||
# This doesn't guarantee that they will be running the latest
|
||||
# version, and it will try to recicle paused and exited containers.
|
||||
#
|
||||
# If there is no other way, it will create a brand new container with
|
||||
# the latest known image and start it.
|
||||
#
|
||||
# If there are no images for the funko, it will fail to bring it up.
|
||||
struct Scale
|
||||
def local(options, name, scale)
|
||||
funko = Funko::Funko.from_names([name])[0]
|
||||
# Asked about scale
|
||||
if !scale
|
||||
Log.info { "Funko #{name} has a scale of #{funko.scale}" }
|
||||
return 0
|
||||
end
|
||||
# Asked to set scale
|
||||
if funko.image_history.empty?
|
||||
Log.error { "Error: no images available for #{funko.name}:latest" }
|
||||
exit 1
|
||||
end
|
||||
funko.scale(scale.as(String).to_i)
|
||||
end
|
||||
|
||||
def remote(options, name, scale)
|
||||
if !scale
|
||||
response = Crest.get(
|
||||
"#{FAASO_SERVER}funkos/#{name}/scale/", \
|
||||
user: "admin", password: "admin")
|
||||
else
|
||||
response = Crest.post(
|
||||
"#{FAASO_SERVER}funkos/#{name}/scale/",
|
||||
{"scale" => scale}, user: "admin", password: "admin")
|
||||
end
|
||||
body = JSON.parse(response.body)
|
||||
Log.info { body["output"] }
|
||||
rescue ex : Crest::InternalServerError
|
||||
Log.error { "Error scaling funko #{name}" }
|
||||
body = JSON.parse(ex.response.body)
|
||||
Log.info { body["output"] }
|
||||
exit 1
|
||||
end
|
||||
|
||||
def run(options, name, scale)
|
||||
if options["--local"]
|
||||
return local(options, name, scale)
|
||||
end
|
||||
remote(options, name, scale)
|
||||
|
||||
# case self
|
||||
# when .running?
|
||||
# # If it's already up, do nothing
|
||||
# # FIXME: bring back out-of-date warning
|
||||
# Log.info { "#{funko.name} is already up" }
|
||||
# when .paused?
|
||||
# # If it is paused, unpause it
|
||||
# Log.info { "Resuming existing paused container" }
|
||||
# funko.unpause
|
||||
# when .exited?
|
||||
# Log.info { "Starting function #{funko.name}" }
|
||||
# Log.info { "Restarting existing exited container" }
|
||||
# funko.start
|
||||
# else
|
||||
# # Only have an image, deploy from scratch
|
||||
# Faaso.setup_network # We need it
|
||||
# Log.info { "Creating and starting new container" }
|
||||
# funko.create_container(autostart: true)
|
||||
|
||||
# (1..5).each { |_|
|
||||
# break if funko.running?
|
||||
# sleep 0.1.seconds
|
||||
# }
|
||||
# if !funko.running?
|
||||
# Log.warn { "Container for #{funko.name} is not running yet" }
|
||||
# next
|
||||
# end
|
||||
# Log.info { "Container for #{funko.name} is running" }
|
||||
# end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
31
src/commands/status.cr
Normal file
31
src/commands/status.cr
Normal file
@ -0,0 +1,31 @@
|
||||
module Faaso
|
||||
module Commands
|
||||
struct Status
|
||||
def local(options, name)
|
||||
funko = Funko::Funko.from_names([name])[0]
|
||||
Log.info { "Name: #{funko.name}" }
|
||||
Log.info { "Scale: #{funko.scale}" }
|
||||
containers = funko.containers
|
||||
Log.info { "Containers: #{funko.containers.size}" }
|
||||
containers.each do |container|
|
||||
Log.info { " #{container.@names[0]} #{container.status}" }
|
||||
end
|
||||
images = funko.images
|
||||
Log.info { "Images: #{images.size}" }
|
||||
images.each do |image|
|
||||
Log.info { " #{image.repo_tags} #{image.created}" }
|
||||
end
|
||||
end
|
||||
|
||||
def remote(options, name)
|
||||
end
|
||||
|
||||
def run(options, name)
|
||||
if options["--local"]
|
||||
return local(options, name)
|
||||
end
|
||||
remote(options, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -5,6 +5,32 @@ require "../funko.cr"
|
||||
module Funko
|
||||
extend self
|
||||
|
||||
# Get the funko's scale
|
||||
get "/funkos/:name/scale/" do |env|
|
||||
name = env.params.url["name"]
|
||||
response = run_faaso(["scale", name])
|
||||
|
||||
if response["exit_code"] != 0
|
||||
halt env, status_code: 500, response: response.to_json
|
||||
else
|
||||
response.to_json
|
||||
end
|
||||
end
|
||||
|
||||
# Set the funko's scale
|
||||
post "/funkos/:name/scale/" do |env|
|
||||
name = env.params.url["name"]
|
||||
scale = env.params.body["scale"].as(String)
|
||||
response = run_faaso(["scale", name, scale])
|
||||
if response["exit_code"] != 0
|
||||
Log.error { response }
|
||||
halt env, status_code: 500, response: response.to_json
|
||||
else
|
||||
Log.info { response }
|
||||
response.to_json
|
||||
end
|
||||
end
|
||||
|
||||
get "/funkos/:name/pause/" do |env|
|
||||
funko = Funko.from_names([env.params.url["name"]])[0]
|
||||
funko.pause
|
||||
@ -33,6 +59,36 @@ module Funko
|
||||
end
|
||||
end
|
||||
|
||||
# Build image for funko received as "funko.tgz"
|
||||
# TODO: This may take a while, consider using something like
|
||||
# mosquito-cr/mosquito to make it a job queue
|
||||
post "/funkos/build/" do |env|
|
||||
# Create place to build funko
|
||||
tmp_dir = Path.new("tmp", UUID.random.to_s)
|
||||
Dir.mkdir_p(tmp_dir) unless File.exists? tmp_dir
|
||||
|
||||
# Expand tarball in there
|
||||
file = env.params.files["funko.tgz"].tempfile
|
||||
Compress::Gzip::Reader.open(file) do |gzip|
|
||||
Crystar::Reader.open(gzip) do |tar|
|
||||
tar.each_entry do |entry|
|
||||
File.open(Path.new(tmp_dir, entry.name), "w") do |dst|
|
||||
IO.copy entry.io, dst
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Build the thing
|
||||
response = run_faaso(["build", tmp_dir.to_s])
|
||||
|
||||
if response["exit_code"] != 0
|
||||
halt env, status_code: 500, response: response.to_json
|
||||
else
|
||||
response.to_json
|
||||
end
|
||||
end
|
||||
|
||||
get "/funkos/" do |env|
|
||||
funkos = Funko.from_docker
|
||||
funkos.sort! { |a, b| a.name <=> b.name }
|
||||
@ -62,4 +118,20 @@ module Funko
|
||||
result.to_json
|
||||
end
|
||||
end
|
||||
|
||||
def run_faaso(args : Array(String))
|
||||
Log.info { "Running faaso [#{args.join(", ")}, -l]" }
|
||||
output = IO::Memory.new
|
||||
status = Process.run(
|
||||
command: "faaso",
|
||||
args: args + ["-l"], # Always local in the server
|
||||
output: output,
|
||||
error: output,
|
||||
)
|
||||
result = {
|
||||
"exit_code" => status.exit_code,
|
||||
"output" => output.to_s,
|
||||
}
|
||||
result
|
||||
end
|
||||
end
|
||||
|
@ -11,62 +11,4 @@ require "uuid"
|
||||
# FIXME: make configurable
|
||||
basic_auth "admin", "admin"
|
||||
|
||||
# Bring up the funko
|
||||
get "/funko/:name/up/" do |env|
|
||||
name = env.params.url["name"]
|
||||
response = run_faaso(["up", name])
|
||||
|
||||
if response["exit_code"] != 0
|
||||
halt env, status_code: 500, response: response.to_json
|
||||
else
|
||||
response.to_json
|
||||
end
|
||||
end
|
||||
|
||||
# Build image for funko received as "funko.tgz"
|
||||
# TODO: This may take a while, consider using something like
|
||||
# mosquito-cr/mosquito to make it a job queue
|
||||
post "/funko/build/" do |env|
|
||||
# Create place to build funko
|
||||
tmp_dir = Path.new("tmp", UUID.random.to_s)
|
||||
Dir.mkdir_p(tmp_dir) unless File.exists? tmp_dir
|
||||
|
||||
# Expand tarball in there
|
||||
file = env.params.files["funko.tgz"].tempfile
|
||||
Compress::Gzip::Reader.open(file) do |gzip|
|
||||
Crystar::Reader.open(gzip) do |tar|
|
||||
tar.each_entry do |entry|
|
||||
File.open(Path.new(tmp_dir, entry.name), "w") do |dst|
|
||||
IO.copy entry.io, dst
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Build the thing
|
||||
response = run_faaso(["build", tmp_dir.to_s])
|
||||
|
||||
if response["exit_code"] != 0
|
||||
halt env, status_code: 500, response: response.to_json
|
||||
else
|
||||
response.to_json
|
||||
end
|
||||
end
|
||||
|
||||
def run_faaso(args : Array(String))
|
||||
stderr = IO::Memory.new
|
||||
stdout = IO::Memory.new
|
||||
status = Process.run(
|
||||
command: "faaso",
|
||||
args: args + ["-l"], # Always local in the server
|
||||
output: stdout,
|
||||
error: stderr,
|
||||
)
|
||||
{
|
||||
"exit_code" => status.exit_code,
|
||||
"stdout" => stdout.to_s,
|
||||
"stderr" => stderr.to_s,
|
||||
}
|
||||
end
|
||||
|
||||
Kemal.run
|
||||
|
160
src/faaso.cr
160
src/faaso.cr
@ -1,3 +1,7 @@
|
||||
require "./commands/build.cr"
|
||||
require "./commands/export.cr"
|
||||
require "./commands/scale.cr"
|
||||
require "./commands/status.cr"
|
||||
require "./funko.cr"
|
||||
require "crest"
|
||||
require "docr"
|
||||
@ -26,161 +30,5 @@ module Faaso
|
||||
end
|
||||
|
||||
module Commands
|
||||
# Build images for one or more funkos
|
||||
class Build
|
||||
def run(options, folders : Array(String))
|
||||
funkos = Funko::Funko.from_paths(folders)
|
||||
|
||||
if options["--local"]
|
||||
funkos.each do |funko|
|
||||
# Create temporary build location
|
||||
tmp_dir = Path.new("tmp", UUID.random.to_s)
|
||||
Dir.mkdir_p(tmp_dir) unless File.exists? tmp_dir
|
||||
funko.prepare_build tmp_dir
|
||||
|
||||
Log.info { "Building function... #{funko.name} in #{tmp_dir}" }
|
||||
funko.build tmp_dir
|
||||
end
|
||||
else # Running against a server
|
||||
funkos.each do |funko|
|
||||
# Create a tarball for the funko
|
||||
buf = IO::Memory.new
|
||||
Compress::Gzip::Writer.open(buf) do |gzip|
|
||||
Crystar::Writer.open(gzip) do |tw|
|
||||
Dir.glob("#{funko.path}/**/*").each do |path|
|
||||
next unless File.file? path
|
||||
rel_path = Path[path].relative_to funko.path
|
||||
file_info = File.info(path)
|
||||
hdr = Crystar::Header.new(
|
||||
name: rel_path.to_s,
|
||||
mode: file_info.permissions.to_u32,
|
||||
size: file_info.size,
|
||||
)
|
||||
tw.write_header(hdr)
|
||||
tw.write(File.read(path).to_slice)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tmp = File.tempname
|
||||
File.open(tmp, "w") do |outf|
|
||||
outf << buf
|
||||
end
|
||||
|
||||
url = "#{FAASO_SERVER}funko/build/"
|
||||
|
||||
begin
|
||||
Log.info { "Uploading funko to #{FAASO_SERVER}" }
|
||||
response = Crest.post(
|
||||
url,
|
||||
{"funko.tgz" => File.open(tmp), "name" => "funko.tgz"},
|
||||
user: "admin", password: "admin"
|
||||
)
|
||||
Log.info { "Build finished successfully." }
|
||||
body = JSON.parse(response.body)
|
||||
Log.info { body["stdout"] }
|
||||
rescue ex : Crest::InternalServerError
|
||||
Log.error { "Error building funko #{funko.name} from #{funko.path}" }
|
||||
body = JSON.parse(ex.response.body)
|
||||
Log.info { body["stdout"] }
|
||||
Log.error { body["stderr"] }
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Bring up one or more funkos by name.
|
||||
#
|
||||
# This doesn't guarantee that they will be running the latest
|
||||
# version, and it will try to recicle paused and exited containers.
|
||||
#
|
||||
# If there is no other way, it will create a brand new container with
|
||||
# the latest known image and start it.
|
||||
#
|
||||
# If there are no images for the funko, it will fail to bring it up.
|
||||
class Up
|
||||
@arguments : Array(String) = [] of String
|
||||
@options : Hash(String, Bool)
|
||||
|
||||
def initialize(options, arguments)
|
||||
@options = options
|
||||
@arguments = arguments
|
||||
end
|
||||
|
||||
def run
|
||||
funkos = Funko::Funko.from_names(@arguments)
|
||||
funkos.each do |funko|
|
||||
local = @options.@bool["local"]
|
||||
|
||||
if !local
|
||||
begin
|
||||
response = Crest.get("#{FAASO_SERVER}funko/#{funko.name}/up/",
|
||||
user: "admin", password: "admin")
|
||||
body = JSON.parse(response.body)
|
||||
Log.info { body["stdout"] }
|
||||
next
|
||||
rescue ex : Crest::InternalServerError
|
||||
Log.error { "Error bringing up #{funko.name}" }
|
||||
body = JSON.parse(ex.response.body)
|
||||
Log.info { body["stdout"] }
|
||||
Log.error { body["stderr"] }
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
if funko.image_history.empty?
|
||||
Log.error { "Error: no images available for #{funko.name}:latest" }
|
||||
exit 1
|
||||
end
|
||||
|
||||
case funko
|
||||
when .running?
|
||||
# If it's already up, do nothing
|
||||
# FIXME: bring back out-of-date warning
|
||||
Log.info { "#{funko.name} is already up" }
|
||||
when .paused?
|
||||
# If it is paused, unpause it
|
||||
Log.info { "Resuming existing paused container" }
|
||||
funko.unpause
|
||||
when .exited?
|
||||
Log.info { "Starting function #{funko.name}" }
|
||||
Log.info { "Restarting existing exited container" }
|
||||
funko.start
|
||||
else
|
||||
# Only have an image, deploy from scratch
|
||||
Faaso.setup_network # We need it
|
||||
Log.info { "Creating and starting new container" }
|
||||
funko.create_container(autostart: true)
|
||||
|
||||
(1..5).each { |_|
|
||||
break if funko.running?
|
||||
sleep 0.1.seconds
|
||||
}
|
||||
if !funko.running?
|
||||
Log.warn { "Container for #{funko.name} is not running yet" }
|
||||
next
|
||||
end
|
||||
Log.info { "Container for #{funko.name} is running" }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Export
|
||||
def run(options, source : String, destination : String)
|
||||
funko = Funko::Funko.from_paths([source])[0]
|
||||
# Create temporary build location
|
||||
dst_path = destination
|
||||
if File.exists? dst_path
|
||||
Log.error { "#{dst_path} already exists, not exporting #{funko.path}" }
|
||||
return 1
|
||||
end
|
||||
Log.info { "Exporting #{funko.path} to #{dst_path}" }
|
||||
Dir.mkdir_p(dst_path)
|
||||
funko.prepare_build Path[dst_path]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
51
src/funko.cr
51
src/funko.cr
@ -67,8 +67,10 @@ module Funko
|
||||
# Get the number of running instances of this funko
|
||||
def scale
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
docker_api.containers.list.count { |container|
|
||||
container.@name.starts_with? "faaso-#{name}-" && container.@state == "running"
|
||||
docker_api.containers.list.select { |container|
|
||||
container.@state == "running"
|
||||
}.count { |container|
|
||||
container.@names.any?(&.starts_with?("/faaso-#{name}-"))
|
||||
}
|
||||
end
|
||||
|
||||
@ -78,12 +80,19 @@ module Funko
|
||||
current_scale = self.scale
|
||||
return if current_scale == new_scale
|
||||
|
||||
Log.info { "Scaling #{name} from #{current_scale} to #{new_scale}" }
|
||||
if new_scale > current_scale
|
||||
(current_scale...new_scale).each { start(create_container) }
|
||||
Log.info { "Adding instance" }
|
||||
(current_scale...new_scale).each {
|
||||
id = create_container
|
||||
sleep 0.2.seconds
|
||||
start(id)
|
||||
}
|
||||
else
|
||||
containers.select { |contatiner| container.@state == "running" }.sort! { |i, j|
|
||||
containers.select { |container| container.@state == "running" }.sort! { |i, j|
|
||||
i.@created <=> j.@created
|
||||
}.each { |container|
|
||||
Log.info { "Removing instance" }
|
||||
docker_api.containers.stop(container.@id)
|
||||
current_scale -= 1
|
||||
break if current_scale == new_scale
|
||||
@ -127,6 +136,14 @@ module Funko
|
||||
tags: ["faaso-#{name}:latest"]) { |x| Log.info { x } }
|
||||
end
|
||||
|
||||
def images
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
docker_api.images.list.select { |image|
|
||||
false if image.@repo_tags.nil?
|
||||
true if image.@repo_tags.as(Array(String)).any?(&.starts_with?("faaso-#{name}:"))
|
||||
}
|
||||
end
|
||||
|
||||
# Return a list of image IDs for this funko, most recent first
|
||||
def image_history
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
@ -143,10 +160,9 @@ module Funko
|
||||
# Get all containers related to this funko
|
||||
def containers
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
docker_api.containers.list(
|
||||
all: true,
|
||||
filters: {"name" => ["faaso-#{name}"]}
|
||||
)
|
||||
docker_api.containers.list(all: true).select { |container|
|
||||
container.@names.any?(&.starts_with?("/faaso-#{name}-"))
|
||||
}
|
||||
end
|
||||
|
||||
# Descriptive status for the funko
|
||||
@ -202,6 +218,16 @@ module Funko
|
||||
}
|
||||
end
|
||||
|
||||
# Start container with given id
|
||||
def start(id : String)
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
begin
|
||||
docker_api.containers.start(id)
|
||||
rescue ex : Docr::Errors::DockerAPIError
|
||||
Log.error { "#{ex}" } unless ex.status_code == 304 # This just happens
|
||||
end
|
||||
end
|
||||
|
||||
# Start exited container with the newer image
|
||||
# or unpause paused container
|
||||
def start
|
||||
@ -258,7 +284,7 @@ module Funko
|
||||
Dir.mkdir_p(secrets_mount)
|
||||
conf = Docr::Types::CreateContainerConfig.new(
|
||||
image: "faaso-#{name}:latest",
|
||||
hostname: name,
|
||||
hostname: "#{name}",
|
||||
# Port in the container side
|
||||
host_config: Docr::Types::HostConfig.new(
|
||||
network_mode: "faaso-net",
|
||||
@ -273,7 +299,7 @@ module Funko
|
||||
)
|
||||
|
||||
docker_api = Docr::API.new(Docr::Client.new)
|
||||
response = docker_api.containers.create(name: "faaso-#{name}", config: conf)
|
||||
response = docker_api.containers.create(name: "faaso-#{name}-#{randstr}", config: conf)
|
||||
response.@warnings.each { |msg| Log.warn { msg } }
|
||||
docker_api.containers.start(response.@id) if autostart
|
||||
response.@id
|
||||
@ -313,3 +339,8 @@ module Funko
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def randstr(length = 6) : String
|
||||
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
String.new(Bytes.new(chars.to_slice.sample(length).to_unsafe, length))
|
||||
end
|
||||
|
37
src/main.cr
37
src/main.cr
@ -2,21 +2,6 @@ require "./faaso.cr"
|
||||
require "colorize"
|
||||
require "docopt"
|
||||
|
||||
doc = <<-DOC
|
||||
FaaSO CLI tool.
|
||||
|
||||
Usage:
|
||||
faaso build FOLDER ... [-l] [-v=<level>]
|
||||
faaso scale FUNKO_NAME SCALE [-l] [-v=<level>]
|
||||
faaso export SOURCE DESTINATION [-v=<level>]
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
--version Show version.
|
||||
-l --local Run commands locally instead of against a FaaSO server.
|
||||
-v=level Control the logging verbosity, 0 to 5 [default: 3]
|
||||
DOC
|
||||
|
||||
# Log formatter for
|
||||
struct LogFormat < Log::StaticFormatter
|
||||
@@colors = {
|
||||
@ -29,7 +14,7 @@ struct LogFormat < Log::StaticFormatter
|
||||
}
|
||||
|
||||
def run
|
||||
string "[#{Time.local}] #{@entry.severity.label}: #{@entry.message}".colorize(@@colors[@entry.severity.label])
|
||||
string "#{@entry.message}".colorize(@@colors[@entry.severity.label])
|
||||
end
|
||||
|
||||
def self.setup(verbosity)
|
||||
@ -48,6 +33,22 @@ struct LogFormat < Log::StaticFormatter
|
||||
end
|
||||
end
|
||||
|
||||
doc = <<-DOC
|
||||
FaaSO CLI tool.
|
||||
|
||||
Usage:
|
||||
faaso build FOLDER ... [-l] [-v=<level>]
|
||||
faaso scale FUNKO_NAME [SCALE] [-l] [-v=<level>]
|
||||
faaso status FUNKO_NAME [-l] [-v=<level>]
|
||||
faaso export SOURCE DESTINATION [-v=<level>]
|
||||
|
||||
Options:
|
||||
-l --local Run commands locally instead of against a FaaSO server.
|
||||
-h --help Show this screen.
|
||||
--version Show version.
|
||||
-v=level Control the logging verbosity, 0 to 5 [default: 3]
|
||||
DOC
|
||||
|
||||
ans = Docopt.docopt(doc, ARGV)
|
||||
LogFormat.setup(ans["-v"].to_s.to_i)
|
||||
|
||||
@ -56,4 +57,8 @@ when .fetch("build", false)
|
||||
Faaso::Commands::Build.new.run(ans, ans["FOLDER"].as(Array(String)))
|
||||
when .fetch("export", false)
|
||||
Faaso::Commands::Export.new.run(ans, ans["SOURCE"].as(String), ans["DESTINATION"].as(String))
|
||||
when .fetch("scale", false)
|
||||
Faaso::Commands::Scale.new.run(ans, ans["FUNKO_NAME"].as(String), ans["SCALE"])
|
||||
when .fetch("status", false)
|
||||
Faaso::Commands::Status.new.run(ans, ans["FUNKO_NAME"].as(String))
|
||||
end
|
||||
|
@ -8,4 +8,23 @@
|
||||
ReverseOnly Yes
|
||||
ReverseMagic Yes
|
||||
ReversePath "/admin/" "http://127.0.0.1:3000/"
|
||||
ReversePath "/faaso/hello/" "http://hello:3000/"
|
||||
ReversePath "/faaso/hello-101807275100116/" "http://hello-101807275100116:3000/"
|
||||
ReversePath "/faaso/hello-109717610410253/" "http://hello-109717610410253:3000/"
|
||||
ReversePath "/faaso/hello-115791188481102/" "http://hello-115791188481102:3000/"
|
||||
ReversePath "/faaso/hello-489850679780/" "http://hello-489850679780:3000/"
|
||||
ReversePath "/faaso/hello-52122101707950/" "http://hello-52122101707950:3000/"
|
||||
ReversePath "/faaso/hello-53828586108120/" "http://hello-53828586108120:3000/"
|
||||
ReversePath "/faaso/hello-5412177121100122/" "http://hello-5412177121100122:3000/"
|
||||
ReversePath "/faaso/hello-679912011112183/" "http://hello-679912011112183:3000/"
|
||||
ReversePath "/faaso/hello-687849738368/" "http://hello-687849738368:3000/"
|
||||
ReversePath "/faaso/hello-689880877456/" "http://hello-689880877456:3000/"
|
||||
ReversePath "/faaso/hello-6987113768753/" "http://hello-6987113768753:3000/"
|
||||
ReversePath "/faaso/hello-7273704811390/" "http://hello-7273704811390:3000/"
|
||||
ReversePath "/faaso/hello-761221081008155/" "http://hello-761221081008155:3000/"
|
||||
ReversePath "/faaso/hello-9798100678476/" "http://hello-9798100678476:3000/"
|
||||
ReversePath "/faaso/hello-98103104100103100/" "http://hello-98103104100103100:3000/"
|
||||
ReversePath "/faaso/hello-foo/" "http://hello-foo:3000/"
|
||||
ReversePath "/faaso/hello-gfvij3/" "http://hello-gfvij3:3000/"
|
||||
ReversePath "/faaso/hello-ngisvh/" "http://hello-ngisvh:3000/"
|
||||
ReversePath "/faaso/hello-rqp8o3/" "http://hello-rqp8o3:3000/"
|
||||
ReversePath "/faaso/hello-xtpu69/" "http://hello-xtpu69:3000/"
|
Loading…
Reference in New Issue
Block a user