Compare commits
10 Commits
56ff326098
...
main
Author | SHA1 | Date | |
---|---|---|---|
21893fe612 | |||
665b4f9ab7 | |||
3b2297e954 | |||
4f4daf5943 | |||
2d333c3df1 | |||
f015afe7f0 | |||
81ec077928 | |||
afb6e8df0c | |||
50e8ff7e56 | |||
6489ec0dc2 |
3
.hadolint.yml
Normal file
3
.hadolint.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
ignored:
|
||||||
|
- DL3018
|
||||||
|
- DL3059
|
@ -31,3 +31,8 @@ repos:
|
|||||||
entry: test ! -s config/funkos
|
entry: test ! -s config/funkos
|
||||||
language: system
|
language: system
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
|
- repo: https://github.com/hadolint/hadolint
|
||||||
|
rev: v2.12.0
|
||||||
|
hooks:
|
||||||
|
- id: hadolint-docker
|
||||||
|
exclude: 'j2$'
|
||||||
|
33
Dockerfile
33
Dockerfile
@ -1,5 +1,13 @@
|
|||||||
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine as build
|
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.20 AS build
|
||||||
RUN apk update && apk add crystal shards yaml-dev openssl-dev zlib-dev libxml2-dev make && apk cache clean
|
RUN apk add --no-cache \
|
||||||
|
crystal \
|
||||||
|
shards \
|
||||||
|
yaml-dev \
|
||||||
|
openssl-dev \
|
||||||
|
zlib-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
make
|
||||||
|
RUN rm -rf /var/cache/apk/*
|
||||||
RUN addgroup -S app && adduser app -S -G app
|
RUN addgroup -S app && adduser app -S -G app
|
||||||
WORKDIR /home/app
|
WORKDIR /home/app
|
||||||
COPY shard.yml Makefile ./
|
COPY shard.yml Makefile ./
|
||||||
@ -9,8 +17,22 @@ COPY runtimes/ runtimes/
|
|||||||
RUN make
|
RUN make
|
||||||
# RUN strip bin/*
|
# RUN strip bin/*
|
||||||
|
|
||||||
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine as ship
|
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.20 AS ship
|
||||||
RUN apk update && apk add caddy nss-tools multirun docker openssl zlib yaml pcre2 gc libevent libgcc libxml2 ttyd && apk cache clean
|
RUN apk add --no-cache \
|
||||||
|
caddy \
|
||||||
|
nss-tools \
|
||||||
|
multirun \
|
||||||
|
docker \
|
||||||
|
openssl \
|
||||||
|
zlib \
|
||||||
|
yaml \
|
||||||
|
pcre2 \
|
||||||
|
gc \
|
||||||
|
libevent \
|
||||||
|
libgcc \
|
||||||
|
libxml2 \
|
||||||
|
ttyd
|
||||||
|
RUN rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
# Unprivileged user
|
# Unprivileged user
|
||||||
RUN addgroup -S app && adduser app -S -G app
|
RUN addgroup -S app && adduser app -S -G app
|
||||||
@ -21,7 +43,6 @@ COPY public/ public/
|
|||||||
COPY --from=build /home/app/bin/faaso-daemon /home/app/bin/faaso /usr/bin/
|
COPY --from=build /home/app/bin/faaso-daemon /home/app/bin/faaso /usr/bin/
|
||||||
|
|
||||||
# Mount points for persistent data
|
# Mount points for persistent data
|
||||||
RUN mkdir /secrets
|
RUN mkdir /secrets /config
|
||||||
RUN mkdir /config
|
|
||||||
|
|
||||||
CMD ["/usr/bin/multirun", "-v", "faaso-daemon", "caddy run --config config/Caddyfile"]
|
CMD ["/usr/bin/multirun", "-v", "faaso-daemon", "caddy run --config config/Caddyfile"]
|
||||||
|
1
Makefile
1
Makefile
@ -8,6 +8,7 @@ proxy:
|
|||||||
all: build proxy
|
all: build proxy
|
||||||
|
|
||||||
start-proxy:
|
start-proxy:
|
||||||
|
docker network create faaso-net || true
|
||||||
docker run --name faaso-proxy-one \
|
docker run --name faaso-proxy-one \
|
||||||
--rm --network=faaso-net \
|
--rm --network=faaso-net \
|
||||||
-e FAASO_SECRET_PATH=${PWD}/secrets \
|
-e FAASO_SECRET_PATH=${PWD}/secrets \
|
||||||
|
14
TODO.md
14
TODO.md
@ -12,11 +12,12 @@
|
|||||||
* ✅ Crystal + Kemal
|
* ✅ Crystal + Kemal
|
||||||
* ✅ Python + Flask
|
* ✅ Python + Flask
|
||||||
* ✅ Nodejs + Express
|
* ✅ Nodejs + Express
|
||||||
* Document
|
* Create a site
|
||||||
* How to create a runtime
|
* Document
|
||||||
* How to create a funko
|
* FaaSO for app developers
|
||||||
* How to setup the proxy
|
* FaaSO for runtime developers
|
||||||
* APIs
|
* FaaSO server setup
|
||||||
|
* APIs
|
||||||
* Sanitize all inputs
|
* Sanitize all inputs
|
||||||
* ✅ Streaming responses in slow operations like scaling down
|
* ✅ Streaming responses in slow operations like scaling down
|
||||||
or building
|
or building
|
||||||
@ -34,7 +35,8 @@
|
|||||||
* ✅ Fix `export examples/hello_crystal` it has a `template/`
|
* ✅ Fix `export examples/hello_crystal` it has a `template/`
|
||||||
* ✅ Implement zero-downtime rollout (`faaso deploy`)
|
* ✅ Implement zero-downtime rollout (`faaso deploy`)
|
||||||
* ✅ Cleanup `tmp/whatever` after use
|
* ✅ Cleanup `tmp/whatever` after use
|
||||||
* `faaso scale` remote is broken
|
* ✅ `faaso scale` remote is broken
|
||||||
|
* ✅ Setup linters/pre-commit/etc
|
||||||
|
|
||||||
## Things to do but not before release
|
## Things to do but not before release
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" href="https://matcha.mizu.sh/matcha.css" />
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css" />
|
||||||
<script src="https://unpkg.com/htmx.org@2.0.0"></script>
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.colors.min.css" /> <script src="https://unpkg.com/htmx.org@2.0.0"></script>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -11,15 +11,20 @@
|
|||||||
<header class="container">
|
<header class="container">
|
||||||
<h1>FaaSO Admin Interface</h1>
|
<h1>FaaSO Admin Interface</h1>
|
||||||
</header>
|
</header>
|
||||||
<main class=container>
|
<article>
|
||||||
<h2>Your Funko Collection
|
<nav>
|
||||||
<button id="update-funkos" style="float:right; display:inline;" hx-trigger="load, click, every 60s"
|
<ul>
|
||||||
|
<li><strong style="font-size: 200%;">Your Funko Collection</strong></li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><button id="update-funkos" style="float:right; display:inline;" hx-trigger="load, click, every 60s"
|
||||||
hx-get="funkos/?format=html" hx-target="#funko-list">
|
hx-get="funkos/?format=html" hx-target="#funko-list">
|
||||||
Refresh
|
Refresh
|
||||||
</button>
|
</button>
|
||||||
</h2>
|
</ul>
|
||||||
|
</nav>
|
||||||
<span id="message"></span>
|
<span id="message"></span>
|
||||||
<table hx-target="#message">
|
<table hx-target="#message" class="striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
@ -31,23 +36,27 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div id="terminal" style="resize: vertical; overflow: auto;"></div>
|
<div id="terminal" style="resize: vertical; overflow: auto;"></div>
|
||||||
</main>
|
</article>
|
||||||
<script>
|
<script>
|
||||||
update_funkos = function () {
|
update_funkos = function () {
|
||||||
document.getElementById("update-funkos").click()
|
document.getElementById("update-funkos").click()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<main class=container>
|
<article>
|
||||||
<h2>
|
<nav>
|
||||||
Your Secrets
|
<ul>
|
||||||
<button id="update-secrets" style="float:right; display:inline;" hx-trigger="load, click, every 60s"
|
<li><strong style="font-size: 200%;">Your Secrets</strong>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li><button id="update-secrets" style="float:right; display:inline;" hx-trigger="load, click, every 60s"
|
||||||
hx-get="secrets/?format=html" hx-target="#secret-list">
|
hx-get="secrets/?format=html" hx-target="#secret-list">
|
||||||
Refresh
|
Refresh
|
||||||
</button>
|
</button>
|
||||||
<button style="float:right; display:inline;" onclick="show_new_secret()">
|
<li><button style="float:right; display:inline;" onclick="show_new_secret()">
|
||||||
Add
|
Add
|
||||||
</button>
|
</button>
|
||||||
</h2>
|
</ul>
|
||||||
|
</nav>
|
||||||
<span id="message"></span>
|
<span id="message"></span>
|
||||||
<table hx-target="#message">
|
<table hx-target="#message">
|
||||||
<thead>
|
<thead>
|
||||||
@ -60,14 +69,20 @@
|
|||||||
<tbody id="secret-list">
|
<tbody id="secret-list">
|
||||||
</tbody>
|
</tbody>
|
||||||
<dialog id="add-secret">
|
<dialog id="add-secret">
|
||||||
<topic>New Secret</topic>
|
<article>
|
||||||
|
<header>
|
||||||
|
New Secret
|
||||||
|
</header>
|
||||||
<form hx-post="secrets/">
|
<form hx-post="secrets/">
|
||||||
<input placeholder="funko name" id="new-secret-funko" name="funko">
|
<input placeholder="funko name" id="new-secret-funko" name="funko">
|
||||||
<input placeholder="secret name" id="new-secret-name" name="name">
|
<input placeholder="secret name" id="new-secret-name" name="name">
|
||||||
<input placeholder="secret value" type="password" id="new-secret-password" name="value">
|
<input placeholder="secret value" type="password" id="new-secret-password" name="value">
|
||||||
<button type="submit" hx-on:htmx:after-request="hide_new_secret()">CREATE</button>
|
<fieldset role="group" style="text-align: right;">
|
||||||
|
<button style="width:9em; display: inline;" type="submit" hx-on:htmx:after-request="hide_new_secret()">CREATE</button>
|
||||||
|
<button style="width:9em; display: inline;" onclick="hide_new_secret(); close();" aria-label="Close" rel="prev">CLOSE</button>
|
||||||
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
<button onclick="hide_new_secret(); close();">CLOSE</button>
|
</article>
|
||||||
</dialog>
|
</dialog>
|
||||||
<script>
|
<script>
|
||||||
update_secrets = function() {
|
update_secrets = function() {
|
||||||
@ -87,5 +102,5 @@
|
|||||||
update_secrets()
|
update_secrets()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</main>
|
</article>
|
||||||
</body>
|
</body>
|
||||||
|
@ -4,6 +4,10 @@ shards:
|
|||||||
git: https://github.com/sija/backtracer.cr.git
|
git: https://github.com/sija/backtracer.cr.git
|
||||||
version: 1.2.2
|
version: 1.2.2
|
||||||
|
|
||||||
|
base58:
|
||||||
|
git: https://github.com/crystal-china/base58.cr.git
|
||||||
|
version: 0.1.0+git.commit.d1150d4a6f086013a475640ad00e561a2fe1082a
|
||||||
|
|
||||||
cr-config:
|
cr-config:
|
||||||
git: https://github.com/crystal-community/cr-config.git
|
git: https://github.com/crystal-community/cr-config.git
|
||||||
version: 5.1.0+git.commit.5eae3dfbf97da7dfa7c6e64a2a508069948518d3
|
version: 5.1.0+git.commit.5eae3dfbf97da7dfa7c6e64a2a508069948518d3
|
||||||
@ -40,10 +44,6 @@ shards:
|
|||||||
git: https://github.com/mamantoha/http_proxy.git
|
git: https://github.com/mamantoha/http_proxy.git
|
||||||
version: 0.10.3
|
version: 0.10.3
|
||||||
|
|
||||||
inotify:
|
|
||||||
git: https://github.com/petoem/inotify.cr.git
|
|
||||||
version: 1.0.3
|
|
||||||
|
|
||||||
kemal:
|
kemal:
|
||||||
git: https://github.com/kemalcr/kemal.git
|
git: https://github.com/kemalcr/kemal.git
|
||||||
version: 1.5.0
|
version: 1.5.0
|
||||||
|
@ -15,6 +15,8 @@ crystal: ">= 1.12.2"
|
|||||||
license: MIT
|
license: MIT
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
base58:
|
||||||
|
github: crystal-china/base58.cr
|
||||||
crest:
|
crest:
|
||||||
github: mamantoha/crest
|
github: mamantoha/crest
|
||||||
crinja:
|
crinja:
|
||||||
@ -28,8 +30,6 @@ dependencies:
|
|||||||
docr:
|
docr:
|
||||||
github: ralsina/docr
|
github: ralsina/docr
|
||||||
branch: add_exposed_ports
|
branch: add_exposed_ports
|
||||||
inotify:
|
|
||||||
github: petoem/inotify.cr
|
|
||||||
kemal:
|
kemal:
|
||||||
github: kemalcr/kemal
|
github: kemalcr/kemal
|
||||||
kemal-basic-auth:
|
kemal-basic-auth:
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
require "base58"
|
||||||
|
|
||||||
module Faaso
|
module Faaso
|
||||||
module Commands
|
module Commands
|
||||||
# Build images for one or more funkos from source
|
# Build images for one or more funkos from source
|
||||||
@ -7,7 +9,7 @@ module Faaso
|
|||||||
# Create temporary build location
|
# Create temporary build location
|
||||||
|
|
||||||
funkos.each do |funko|
|
funkos.each do |funko|
|
||||||
tmp_dir = Path.new("tmp", UUID.random.to_s)
|
tmp_dir = Path.new("tmp", Random.base58(8))
|
||||||
Dir.mkdir_p(tmp_dir) unless File.exists? tmp_dir
|
Dir.mkdir_p(tmp_dir) unless File.exists? tmp_dir
|
||||||
|
|
||||||
funko.runtime = nil if options["--no-runtime"]
|
funko.runtime = nil if options["--no-runtime"]
|
||||||
@ -56,10 +58,7 @@ module Faaso
|
|||||||
{"funko.tgz" => File.open(tmp), "name" => "funko.tgz"},
|
{"funko.tgz" => File.open(tmp), "name" => "funko.tgz"},
|
||||||
user: user, password: password
|
user: user, password: password
|
||||||
) do |response|
|
) do |response|
|
||||||
loop do
|
IO.copy(response.body_io, STDOUT)
|
||||||
Log.info { response.body_io.gets }
|
|
||||||
break if response.body_io.closed?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
Log.info { "Build finished successfully." }
|
Log.info { "Build finished successfully." }
|
||||||
rescue ex : Crest::InternalServerError
|
rescue ex : Crest::InternalServerError
|
||||||
|
@ -41,10 +41,7 @@ module Faaso
|
|||||||
Crest.get(
|
Crest.get(
|
||||||
"#{Config.server}funkos/#{funko_name}/deploy/", \
|
"#{Config.server}funkos/#{funko_name}/deploy/", \
|
||||||
user: user, password: password) do |response|
|
user: user, password: password) do |response|
|
||||||
loop do
|
IO.copy(response.body_io, STDOUT)
|
||||||
Log.info { response.body_io.gets }
|
|
||||||
break if response.body_io.closed?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
@ -10,14 +10,14 @@ module Faaso
|
|||||||
# In both cases stopped instances after the required
|
# In both cases stopped instances after the required
|
||||||
# scale is reached are deleted.
|
# scale is reached are deleted.
|
||||||
struct Scale
|
struct Scale
|
||||||
def local(options, name : String, scale : Int) : Int32
|
def local(options, name : String, scale : Int | Nil) : Int32
|
||||||
funko = Funko::Funko.from_names([name])[0]
|
funko = Funko::Funko.from_names([name])[0]
|
||||||
# Asked about scale
|
# Asked about scale
|
||||||
if funko.image_history.empty?
|
if funko.image_history.empty?
|
||||||
Log.error { "Unknown funko #{funko.name}" }
|
Log.error { "Unknown funko #{funko.name}" }
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
if !scale
|
if scale.nil?
|
||||||
Log.info { "Funko #{name} has a scale of #{funko.scale}" }
|
Log.info { "Funko #{name} has a scale of #{funko.scale}" }
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
@ -26,19 +26,21 @@ module Faaso
|
|||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
def remote(options, name : String, scale : Int) : Int32
|
def remote(options, name : String, scale : Int | Nil) : Int32
|
||||||
user, password = Config.auth
|
user, password = Config.auth
|
||||||
Faaso.check_version
|
Faaso.check_version
|
||||||
if !scale
|
if scale.nil?
|
||||||
response = Crest.get(
|
Crest.get(
|
||||||
"#{Config.server}funkos/#{name}/scale/", \
|
"#{Config.server}funkos/#{name}/scale/", \
|
||||||
user: user, password: password)
|
user: user, password: password) do |response|
|
||||||
Log.info { " => " + response.body }
|
IO.copy(response.body_io, STDOUT)
|
||||||
else
|
end
|
||||||
response = Crest.post(
|
return 0
|
||||||
"#{Config.server}funkos/#{name}/scale/",
|
end
|
||||||
{"scale" => scale}, user: user, password: password)
|
Crest.post(
|
||||||
Log.info { " => " + response.body }
|
"#{Config.server}funkos/#{name}/scale/",
|
||||||
|
{"scale" => scale}, user: user, password: password) do |response|
|
||||||
|
IO.copy(response.body_io, STDOUT)
|
||||||
end
|
end
|
||||||
0
|
0
|
||||||
rescue ex : Crest::InternalServerError
|
rescue ex : Crest::InternalServerError
|
||||||
@ -46,7 +48,8 @@ module Faaso
|
|||||||
1
|
1
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(options, name : String, scale : Int) : Int32
|
def run(options, name : String, scale) : Int32
|
||||||
|
scale = scale.try &.to_s.to_i
|
||||||
if options["--local"]
|
if options["--local"]
|
||||||
return local(options, name, scale)
|
return local(options, name, scale)
|
||||||
end
|
end
|
||||||
|
@ -31,10 +31,7 @@ module Faaso
|
|||||||
Crest.get(
|
Crest.get(
|
||||||
"#{Config.server}funkos/#{name}/status/", \
|
"#{Config.server}funkos/#{name}/status/", \
|
||||||
user: user, password: password) do |response|
|
user: user, password: password) do |response|
|
||||||
loop do
|
IO.copy(response.body_io, STDOUT)
|
||||||
Log.info { response.body_io.gets }
|
|
||||||
break if response.body_io.closed?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
0
|
0
|
||||||
rescue ex : Crest::InternalServerError
|
rescue ex : Crest::InternalServerError
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
require "base58"
|
||||||
require "docr"
|
require "docr"
|
||||||
require "kemal"
|
require "kemal"
|
||||||
require "../funko.cr"
|
require "../funko.cr"
|
||||||
@ -34,7 +35,7 @@ module Funko
|
|||||||
# mosquito-cr/mosquito to make it a job queue
|
# mosquito-cr/mosquito to make it a job queue
|
||||||
post "/funkos/build/" do |env|
|
post "/funkos/build/" do |env|
|
||||||
# Create place to build funko
|
# Create place to build funko
|
||||||
tmp_dir = Path.new("tmp", UUID.random.to_s)
|
tmp_dir = Path.new("tmp", Random.base58(8))
|
||||||
Dir.mkdir_p(tmp_dir) unless File.exists? tmp_dir
|
Dir.mkdir_p(tmp_dir) unless File.exists? tmp_dir
|
||||||
|
|
||||||
# Expand tarball in there
|
# Expand tarball in there
|
||||||
@ -132,20 +133,21 @@ module Funko
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Helper to run faaso locally and respond via env
|
# Helper to run faaso locally and respond via env
|
||||||
def run_faaso(args : Array(String), env) : Bool
|
def run_faaso(args : Array(String), env)
|
||||||
Log.info { "Running faaso [#{args.join(", ")}, -l, 2>&1]" }
|
args << "-l" # Always local in the server
|
||||||
|
Log.info { "Running faaso [#{args}" }
|
||||||
Process.run(
|
Process.run(
|
||||||
command: "faaso",
|
command: "faaso",
|
||||||
args: args + ["-l", "2>&1"], # Always local in the server
|
args: args,
|
||||||
shell: true,
|
env: {"FAASO_SERVER_SIDE" => "true"},
|
||||||
) do |process|
|
) do |process|
|
||||||
loop do
|
loop do
|
||||||
env.response.print process.output.gets(chomp: false)
|
data = process.output.gets(chomp: false)
|
||||||
|
env.response.print data
|
||||||
env.response.flush
|
env.response.flush
|
||||||
Fiber.yield
|
Fiber.yield # Without this the process never ends
|
||||||
break if process.terminated?
|
break if process.terminated?
|
||||||
end
|
end
|
||||||
true
|
|
||||||
end
|
end
|
||||||
# FIXME: find a way to raise an exception on failure
|
# FIXME: find a way to raise an exception on failure
|
||||||
# of the faaso process
|
# of the faaso process
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
require "./funko.cr"
|
require "./funko.cr"
|
||||||
require "docr"
|
require "docr"
|
||||||
require "inotify"
|
|
||||||
require "kemal"
|
require "kemal"
|
||||||
|
|
||||||
module Proxy
|
module Proxy
|
||||||
CADDY_CONFIG_PATH = "config/funkos"
|
CADDY_CONFIG_PATH = "config/Caddyfile"
|
||||||
@@current_config = File.read(CADDY_CONFIG_PATH)
|
CADDY_CONFIG_FUNKOS = "config/funkos"
|
||||||
|
@@current_config = File.read(CADDY_CONFIG_FUNKOS)
|
||||||
@@watcher = Inotify.watch(CADDY_CONFIG_PATH) do |_|
|
|
||||||
Log.info { "Reloading caddy config" }
|
|
||||||
Process.run(command: "caddy", args: ["reload", "--config", CADDY_CONFIG_PATH])
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get current proxy config
|
# Get current proxy config
|
||||||
get "/proxy/" do
|
get "/proxy/" do
|
||||||
@ -25,7 +20,7 @@ module Proxy
|
|||||||
update_proxy_config
|
update_proxy_config
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.update_proxy_config
|
def self.update_proxy_config : Nil
|
||||||
docker_api = Docr::API.new(Docr::Client.new)
|
docker_api = Docr::API.new(Docr::Client.new)
|
||||||
containers = docker_api.containers.list(all: true)
|
containers = docker_api.containers.list(all: true)
|
||||||
|
|
||||||
@ -50,13 +45,13 @@ module Proxy
|
|||||||
|
|
||||||
if @@current_config != config
|
if @@current_config != config
|
||||||
Log.info { "Updating proxy config" }
|
Log.info { "Updating proxy config" }
|
||||||
File.open(CADDY_CONFIG_PATH, "w") do |file|
|
File.open(CADDY_CONFIG_FUNKOS, "w") do |file|
|
||||||
file << config
|
file << config
|
||||||
end
|
end
|
||||||
# Reload config
|
# Reload config
|
||||||
@@current_config = config
|
@@current_config = config
|
||||||
|
Process.run(command: "caddy", args: ["reload", "--config", CADDY_CONFIG_PATH])
|
||||||
end
|
end
|
||||||
config
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
13
src/funko.cr
13
src/funko.cr
@ -90,7 +90,11 @@ module Funko
|
|||||||
docker_api = Docr::API.new(Docr::Client.new)
|
docker_api = Docr::API.new(Docr::Client.new)
|
||||||
current_scale = self.scale
|
current_scale = self.scale
|
||||||
result = [] of String
|
result = [] of String
|
||||||
return result if current_scale == new_scale
|
|
||||||
|
if current_scale == new_scale
|
||||||
|
Log.info { "Funko #{name} already at scale #{new_scale}" }
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
Log.info { "Scaling #{name} from #{current_scale} to #{new_scale}" }
|
Log.info { "Scaling #{name} from #{current_scale} to #{new_scale}" }
|
||||||
if new_scale > current_scale
|
if new_scale > current_scale
|
||||||
@ -309,7 +313,7 @@ module Funko
|
|||||||
)
|
)
|
||||||
|
|
||||||
docker_api = Docr::API.new(Docr::Client.new)
|
docker_api = Docr::API.new(Docr::Client.new)
|
||||||
response = docker_api.containers.create(name: "faaso-#{name}-#{randstr}", config: conf)
|
response = docker_api.containers.create(name: "faaso-#{name}-#{Random.base58(6)}", config: conf)
|
||||||
response.@warnings.each { |msg| Log.warn { msg } }
|
response.@warnings.each { |msg| Log.warn { msg } }
|
||||||
docker_api.containers.start(response.@id) if autostart
|
docker_api.containers.start(response.@id) if autostart
|
||||||
response.@id
|
response.@id
|
||||||
@ -349,8 +353,3 @@ module Funko
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def randstr(length = 6) : String
|
|
||||||
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
|
||||||
String.new(Bytes.new(chars.to_slice.sample(length).to_unsafe, length))
|
|
||||||
end
|
|
||||||
|
21
src/main.cr
21
src/main.cr
@ -35,29 +35,28 @@ Options:
|
|||||||
DOC
|
DOC
|
||||||
|
|
||||||
ans = Docopt.docopt(doc, ARGV)
|
ans = Docopt.docopt(doc, ARGV)
|
||||||
Oplog.setup(ans["-v"].to_s.to_i)
|
Oplog.setup(ans["-v"].to_s.to_i) unless ENV.fetch("FAASO_SERVER_SIDE", nil)
|
||||||
Log.debug { ans }
|
Log.debug { ans }
|
||||||
|
|
||||||
status : Int32 = 0
|
|
||||||
case ans
|
case ans
|
||||||
when .fetch("build", false)
|
when .fetch("build", false)
|
||||||
status = Faaso::Commands::Build.new.run(ans, ans["FOLDER"].as(Array(String)))
|
exit Faaso::Commands::Build.new.run(ans, ans["FOLDER"].as(Array(String)))
|
||||||
when .fetch("deploy", false)
|
when .fetch("deploy", false)
|
||||||
status = Faaso::Commands::Deploy.new.run(ans, ans["FUNKO"].as(String))
|
exit Faaso::Commands::Deploy.new.run(ans, ans["FUNKO"].as(String))
|
||||||
when .fetch("export", false)
|
when .fetch("export", false)
|
||||||
status = Faaso::Commands::Export.new.run(ans, ans["SOURCE"].as(String), ans["DESTINATION"].as(String))
|
exit Faaso::Commands::Export.new.run(ans, ans["SOURCE"].as(String), ans["DESTINATION"].as(String))
|
||||||
when .fetch("login", false)
|
when .fetch("login", false)
|
||||||
status = Faaso::Commands::Login.new.run(ans)
|
exit Faaso::Commands::Login.new.run(ans)
|
||||||
when .fetch("new", false)
|
when .fetch("new", false)
|
||||||
status = Faaso::Commands::New.new.run(ans, ans["FOLDER"].as(Array(String))[0])
|
exit Faaso::Commands::New.new.run(ans, ans["FOLDER"].as(Array(String))[0])
|
||||||
when .fetch("scale", false)
|
when .fetch("scale", false)
|
||||||
status = Faaso::Commands::Scale.new.run(ans, ans["FUNKO"].as(String), ans["SCALE"].as(String).to_i)
|
exit Faaso::Commands::Scale.new.run(ans, ans["FUNKO"].as(String), ans["SCALE"])
|
||||||
when .fetch("secret", false)
|
when .fetch("secret", false)
|
||||||
status = Faaso::Commands::Secret.new.run(ans, ans["FUNKO"].as(String), ans["SECRET"].as(String))
|
exit Faaso::Commands::Secret.new.run(ans, ans["FUNKO"].as(String), ans["SECRET"].as(String))
|
||||||
when .fetch("status", false)
|
when .fetch("status", false)
|
||||||
status = Faaso::Commands::Status.new.run(ans, ans["FUNKO"].as(String))
|
exit Faaso::Commands::Status.new.run(ans, ans["FUNKO"].as(String))
|
||||||
when .fetch("version", false)
|
when .fetch("version", false)
|
||||||
Log.info { "#{version}" }
|
Log.info { "#{version}" }
|
||||||
end
|
end
|
||||||
|
|
||||||
exit(status)
|
exit 0
|
||||||
|
@ -1,39 +1,32 @@
|
|||||||
<%- result.each do |f| -%>
|
<%- result.each do |f| -%>
|
||||||
<tr hx-indicator="#spinner-<%= f["name"] %>">
|
<tr hx-indicator="#spinner-<%= f["name"] %>">
|
||||||
<td>
|
<td style="vertical-align: top;">
|
||||||
<%= f["name"] %>
|
<%= f["name"] %>
|
||||||
<img id="spinner-<%= f["name"] %>" src="bars.svg" class="htmx-indicator">
|
<img id="spinner-<%= f["name"] %>" src="bars.svg" class="htmx-indicator">
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td style="vertical-align: top;">
|
||||||
<table>
|
<%- f["containers"].as(Array(Docr::Types::ContainerSummary)).each do |c| -%>
|
||||||
<thead>
|
<div class="grid">
|
||||||
<th>ID</th>
|
<div>
|
||||||
<th>Current?</th>
|
<tt><%= c.@names[0].split("-")[-1] %></tt>
|
||||||
<th>Actions</th>
|
</div>
|
||||||
</thead>
|
<div>
|
||||||
<tbody>
|
|
||||||
<%- f["containers"].as(Array(Docr::Types::ContainerSummary)).each do |c| -%>
|
|
||||||
<tr>
|
|
||||||
<td><tt><%= c.@names[0].split("-")[-1] %></tt></td>
|
|
||||||
<td>
|
|
||||||
<%- if c.image_id == f["latest_image"] -%>
|
<%- if c.image_id == f["latest_image"] -%>
|
||||||
<span style="color:green;""> 🟢</span>
|
<span style="color:green;""> 🟢</span>
|
||||||
<%- else -%>
|
<%- else -%>
|
||||||
<span style="color:red;""> 🟢</span>
|
<span style="color:red;""> 🟢</span>
|
||||||
<%- end -%>
|
<%- end -%>
|
||||||
</td>
|
</div>
|
||||||
<td>
|
<div role="group">
|
||||||
<button hx-target="#terminal" hx-get="funkos/terminal/logs/<%= c.@names[0].lstrip("/") %>/">Logs</button>
|
<button hx-target="#terminal" hx-get="funkos/terminal/logs/<%= c.@names[0].lstrip("/") %>/">Logs</button>
|
||||||
<button hx-target="#terminal" hx-get="funkos/terminal/shell/<%= c.@names[0].lstrip("/") %>/">Shell</button>
|
<button hx-target="#terminal" hx-get="funkos/terminal/shell/<%= c.@names[0].lstrip("/") %>/">Shell</button>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
<%- end -%>
|
<%- end -%>
|
||||||
</tbody>
|
|
||||||
</p>
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
</table>
|
|
||||||
<td>
|
<td>
|
||||||
|
<div role="group">
|
||||||
<%- if f["name"] == "proxy" -%>
|
<%- if f["name"] == "proxy" -%>
|
||||||
<%- else -%>
|
<%- else -%>
|
||||||
<%- if f["scale"].as(String).to_i > 0 -%>
|
<%- if f["scale"].as(String).to_i > 0 -%>
|
||||||
@ -47,6 +40,7 @@
|
|||||||
<%- end -%>
|
<%- end -%>
|
||||||
<button hx-get="funkos/<%= f["name"] %>/restart" hx-on:htmx:after-request="update_funkos()">Restart</button>
|
<button hx-get="funkos/<%= f["name"] %>/restart" hx-on:htmx:after-request="update_funkos()">Restart</button>
|
||||||
<%- end -%>
|
<%- end -%>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<%- end -%>
|
<%- end -%>
|
||||||
|
Reference in New Issue
Block a user