Compare commits
11
Commits
lightning
...
653a3c9415
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
653a3c9415 | ||
|
|
35999574bd | ||
|
|
a346d4f4e1 | ||
|
|
990b99f0c0 | ||
|
|
e7eab505e9 | ||
|
|
3437b58078 | ||
|
|
5b4db64114 | ||
|
|
6c97f99f87 | ||
|
|
3a64c47260 | ||
|
|
1d44a2ff32 | ||
|
|
e2e34d813e |
@@ -0,0 +1,4 @@
|
||||
--require spec_helper
|
||||
--shell bash
|
||||
--default-path spec
|
||||
--pattern "*_spec.sh"
|
||||
@@ -1,5 +1,14 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v1.1 - 2026-09-03
|
||||
|
||||
- move the stack catalogue and the docker build contexts to the myos-stacks project
|
||||
- keep the framework infra compose files in share/compose and the myos tool image in share/docker
|
||||
- fix stack_path resolution: host/<svc> stacks were only found when the project
|
||||
stack directory sorted first
|
||||
- drop the docker/compose image fallback: docker compose >= 2.24.4 or docker-compose is required
|
||||
- add a shellspec golden test harness (make test)
|
||||
|
||||
## v1.0-beta - 2026-07-29
|
||||
|
||||
* split make files in `myos` project and docker files in `stack` project
|
||||
|
||||
@@ -1 +1,24 @@
|
||||
DEV_TARGETS := test test-unit test-golden test-integration lint golden-record
|
||||
ifneq ($(filter $(DEV_TARGETS),$(MAKECMDGOALS)),)
|
||||
|
||||
SHELLSPEC ?= shellspec
|
||||
SHELLCHECK ?= shellcheck
|
||||
|
||||
.PHONY: $(DEV_TARGETS)
|
||||
test: ## Run unit + golden tests against both engines
|
||||
$(SHELLSPEC)
|
||||
MYOS_ENGINE=cli $(SHELLSPEC) spec/golden
|
||||
test-unit: ## Run unit tests only
|
||||
$(SHELLSPEC) spec/unit
|
||||
test-golden: ## Run golden tests only (MYOS_ENGINE=legacy|cli)
|
||||
$(SHELLSPEC) spec/golden
|
||||
test-integration: ## Run tests needing a real docker daemon
|
||||
MYOS_INTEGRATION=1 $(SHELLSPEC) spec/integration
|
||||
golden-record: ## Re-record golden expectations from the legacy engine
|
||||
spec/golden/record.sh $(CASES)
|
||||
lint: ## shellcheck all shell sources
|
||||
$(SHELLCHECK) -s bash myos spec/golden/record.sh spec/support/run.sh spec/support/bin/* $(wildcard bin/* lib/*.sh lib/cmd/*.sh install.sh)
|
||||
|
||||
else
|
||||
include make/include.mk
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
# myos - Make Your Own Stack
|
||||
|
||||
Make Your Own Stack provides common make targets to build and run docker projects.
|
||||
myos runs docker compose stacks: on a server, in a project directory, for a user.
|
||||
It is a thin layer over `docker compose` that resolves which compose files to load,
|
||||
under which project name, with which environment variables.
|
||||
|
||||
The framework itself ships no stack. Ready-to-use stacks (consul, fabio, registrator,
|
||||
postgres, supabase, drone, …) live in a separate catalogue,
|
||||
[myos-stacks](https://github.com/aya/myos-stacks).
|
||||
|
||||
## Disclaimer
|
||||
|
||||
@@ -8,197 +14,119 @@ This is beta software, use it at your own risks.
|
||||
|
||||
## Requirements
|
||||
|
||||
You need `docker`, `git` and `make`.
|
||||
`docker` (with the `docker compose` plugin >= 2.24.4, or a `docker-compose` binary),
|
||||
`git` and `make`.
|
||||
|
||||
## Install
|
||||
|
||||
* Include MYOS file `make/include.mk` adding the following lines to your project file `Makefile`.
|
||||
### As a command
|
||||
|
||||
```sh
|
||||
sudo git clone https://github.com/aya/myos /usr/local/lib/myos
|
||||
sudo ln -s /usr/local/lib/myos/myos /usr/local/bin/myos
|
||||
```
|
||||
MYOS ?= ../myos
|
||||
MYOS_REPOSITORY ?= $(patsubst %/$(THIS),%/myos,$(THIS_REPOSITORY))
|
||||
THIS ?= $(lastword $(subst /, ,$(THIS_REPOSITORY)))
|
||||
THIS_REPOSITORY ?= $(shell git config --get remote.origin.url 2>/dev/null)
|
||||
$(MYOS):
|
||||
-@git clone $(MYOS_REPOSITORY) $(MYOS)
|
||||
|
||||
Optionally pin per-machine settings in `/etc/conf.d/myos` (or `/etc/default/myos`),
|
||||
one `VAR=value` per line, no comments:
|
||||
|
||||
```sh
|
||||
DOMAIN=example.org
|
||||
ENV=master
|
||||
```
|
||||
|
||||
`myos` runs from the current directory: it passes it as `WORKDIR`, so stacks and
|
||||
`.env` are looked up there. A `WORKDIR` set in the config file wins over the current
|
||||
directory, which pins a machine to its deployment directory.
|
||||
|
||||
### As a make include
|
||||
|
||||
Add to your project `Makefile`:
|
||||
|
||||
```make
|
||||
MYOS ?= /usr/local/lib/myos
|
||||
-include $(MYOS)/make/include.mk
|
||||
```
|
||||
|
||||
* Call the `make help` command to show available targets.
|
||||
Then `make help` lists the available targets.
|
||||
|
||||
```
|
||||
$ make help
|
||||
Usage:
|
||||
make [target]
|
||||
### Stack catalogue
|
||||
|
||||
Targets:
|
||||
help This help
|
||||
[...]
|
||||
myos looks for stacks in `./stack`, `../stack`, `~/.local/share/myos/stack`,
|
||||
`/usr/local/share/myos/stack` and `/usr/share/myos/stack`:
|
||||
|
||||
```sh
|
||||
sudo git clone https://github.com/aya/myos-stacks /usr/local/share/myos
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Examples
|
||||
|
||||
* Configure myos for domain `domain.tld` and stack `default`
|
||||
|
||||
```shell
|
||||
$ make bootstrap DOMAIN=domain.tld STACK=default
|
||||
```sh
|
||||
myos up # the stack of the current directory
|
||||
myos up STACK=host # a group of stacks, see stack/host/host.mk
|
||||
myos up STACK=host/fabio # a single stack
|
||||
myos up STACK=postgres:9.6 # a versioned stack
|
||||
myos ps
|
||||
myos logs
|
||||
myos config # rendered compose file
|
||||
myos down
|
||||
myos shutdown # every stack: app, host and user
|
||||
```
|
||||
|
||||
* Start myos stack `host`
|
||||
### How a stack is resolved
|
||||
|
||||
```shell
|
||||
$ make host
|
||||
```
|
||||
|
||||
`make host` starts the stack `host` with docker host services :
|
||||
- consul (service discovery) on host port 8500
|
||||
- fabio (load balancer) on host ports 80 and 443
|
||||
- registrator (docker/consul bridge)
|
||||
|
||||
* Stop myos
|
||||
|
||||
```shell
|
||||
$ make shutdown
|
||||
```
|
||||
|
||||
### Variables
|
||||
|
||||
* DEBUG
|
||||
|
||||
Show executed commands.
|
||||
|
||||
```shell
|
||||
$ make up DEBUG=true
|
||||
```
|
||||
|
||||
* DRYRUN
|
||||
|
||||
Do nothing, show commands instead of executing it.
|
||||
|
||||
```shell
|
||||
$ make up DRYRUN=true
|
||||
```
|
||||
|
||||
* VERBOSE
|
||||
|
||||
Show called functions.
|
||||
|
||||
```shell
|
||||
$ make up VERBOSE=true
|
||||
```
|
||||
|
||||
* Show variable USER
|
||||
|
||||
```shell
|
||||
$ make print-USER
|
||||
```
|
||||
|
||||
#### Setup
|
||||
|
||||
* SETUP_LETSENCRYPT
|
||||
|
||||
Generate ${DOMAIN} certificate files with letsencrypt.
|
||||
|
||||
By default, myos generates invalid ${DOMAIN} certificate files with openssl.
|
||||
You can use letsencrypt instead, to generate valid wildcard certificate files.
|
||||
|
||||
To achieve this, you must add following DNS entries to domain ${DOMAIN} to prove you own it:
|
||||
A stack is a directory of compose files. For `STACK=<name>` in environment `ENV`,
|
||||
myos loads, in order, whichever of these exist:
|
||||
|
||||
```
|
||||
_acme-challenge.${DOMAIN} IN CNAME ${DOMAIN}.acme.${DOMAIN}.
|
||||
acme.${DOMAIN}. IN NS certbot.${DOMAIN}.
|
||||
certbot.${DOMAIN}. IN A ${DOCKER_HOST_INET4}
|
||||
<name>.yml <name>.<ENV>.yml <ENV>/<name>.yml
|
||||
<name>.<suffix>.yml <name>.<suffix>.<ENV>.yml <name>.<version>.yml
|
||||
```
|
||||
|
||||
In this config, DOCKER_HOST_INET4 should be the external IP address of the server running certbot.
|
||||
Port 53 of this IP address must be reachable from internet and point to this server.
|
||||
`<suffix>` comes from the `COMPOSE_FILE_*` variables that are not `false`
|
||||
(`app`, `labels`, `networks`, `ssh`, `volumes` by default; add e.g.
|
||||
`COMPOSE_FILE_WWW=true` to also load `<name>.www.yml`). The framework always
|
||||
appends its own `share/compose/networks.yml`.
|
||||
|
||||
If you want a simple DNS configuration to host all your services on the same server, you can setup following DNS config:
|
||||
### Project names and networks
|
||||
|
||||
```
|
||||
@ IN A ${DOCKER_HOST_INET4}
|
||||
*.${DOMAIN}. IN CNAME ${DOMAIN}.
|
||||
_acme-challenge.${DOMAIN} IN CNAME ${DOMAIN}.acme.${DOMAIN}.
|
||||
acme.${DOMAIN}. IN NS ${DOMAIN}.
|
||||
| stack | compose project | meaning |
|
||||
|---|---|---|
|
||||
| `host/*` | `$(HOSTNAME)` | one instance per machine: ports 80/443, consul, certbot |
|
||||
| `User/*` | user identity | one instance per user |
|
||||
| anything else | `<user>-<app>-<env>` | many instances per machine |
|
||||
|
||||
Networks: `default` = `_<project>` (private to the project), `private` =
|
||||
`<user>-<env>` and `public` = `<hostname>`, both external and created on demand.
|
||||
|
||||
## Variables
|
||||
|
||||
| variable | effect |
|
||||
|---|---|
|
||||
| `DEBUG=true` | show executed commands |
|
||||
| `DRYRUN=true` | print commands instead of running them |
|
||||
| `VERBOSE=true` | show called functions |
|
||||
| `ENV=<env>` | environment: selects `.env.<env>` and the `<name>.<env>.yml` overlays |
|
||||
| `STACK=<refs>` | stacks to act on |
|
||||
| `SERVICE=<name>` | target one compose service (`exec`, `run`, `logs`, `scale`) |
|
||||
|
||||
```sh
|
||||
myos print-COMPOSE_FILE # show a variable
|
||||
myos print-COMPOSE_PROJECT_NAME
|
||||
myos debug # show debug variables
|
||||
myos doc # self documentation from the make comments
|
||||
```
|
||||
|
||||
This will point domain ${DOMAIN} to the IP address ${DOCKER_HOST_INET4} of this server, and point all subdomains *.{DOMAIN} to the ip address pointed by ${DOMAIN}.
|
||||
`SETUP_UFW=true` enables the ufw/ufw-docker integration (`myos setup-ufw`).
|
||||
|
||||
At this point, you should be able to generate a valid certificate for *.${DOMAIN} using certbot [dns standalone](https://github.com/siilike/certbot-dns-standalone) plugin.
|
||||
This task is done automatically when creating the host stack if SETUP_LETSENCRYPT variable is not empty.
|
||||
## Tests
|
||||
|
||||
If you already launched myos host stack before, the ${DOMAIN} certificates has been automatically generated by openssl and you should remove them before trying to generate them with letsencrypt.
|
||||
|
||||
```
|
||||
$ make host-down
|
||||
$ docker volume rm $(hostname)
|
||||
```sh
|
||||
make test # shellspec: unit + golden (a mocked docker, no daemon needed)
|
||||
make test-golden # golden only
|
||||
make golden-record # re-record the golden expectations
|
||||
make lint # shellcheck
|
||||
```
|
||||
|
||||
You can then test the letsencrypt certificate generation using DEBUG mode that force to use the letsencrypt staging server.
|
||||
|
||||
```
|
||||
$ make host SETUP_LETSENCRYPT=true DEBUG=true
|
||||
```
|
||||
|
||||
If letsencrypt certificate generation fails, you can retry the generation of a staging certificate.
|
||||
|
||||
```
|
||||
$ make host-certbot-staging
|
||||
```
|
||||
|
||||
Once the certificate generation is working, you can ask for a valid certificate.
|
||||
|
||||
```
|
||||
$ make host-down
|
||||
$ docker volume rm $(hostname)
|
||||
$ make host SETUP_LETSENCRYPT=true
|
||||
```
|
||||
|
||||
* SETUP_UFW
|
||||
|
||||
Control linux firewall rules with ufw.
|
||||
|
||||
```
|
||||
$ echo SETUP_UFW=true >> .env
|
||||
$ make setup-ufw
|
||||
```
|
||||
|
||||
### Debug
|
||||
|
||||
* Show docker compose yaml config
|
||||
|
||||
```shell
|
||||
$ make config
|
||||
```
|
||||
|
||||
`make config` show docker compose yaml config for stack `STACK`
|
||||
`make host-config` show docker compose yaml config for stack `host`
|
||||
`make user-config` show docker compose yaml config for stack `User`
|
||||
`make stack-elastic-config` show docker compose yaml config for stack `elastic`
|
||||
|
||||
* Show debug variables
|
||||
|
||||
```shell
|
||||
$ make debug
|
||||
```
|
||||
|
||||
* Generate self documentation
|
||||
|
||||
```shell
|
||||
$ make doc
|
||||
```
|
||||
|
||||
* Show env args
|
||||
|
||||
```shell
|
||||
$ make print-env_args
|
||||
```
|
||||
|
||||
* Show user mail
|
||||
|
||||
```shell
|
||||
$ make print-MAIL
|
||||
```
|
||||
## License
|
||||
|
||||
GPL-3.0, see LICENSE.
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
#!/bin/sh
|
||||
# myos - Make Your Own Stack
|
||||
#
|
||||
# shellcheck disable=SC2034 # most globals here are read by lib/ and lib/cmd/
|
||||
# shellcheck disable=SC1091 # lib files are sourced by path at runtime
|
||||
#
|
||||
# Runs docker compose stacks: on a host, in a project directory, for a user.
|
||||
# See README.md, or `myos help`.
|
||||
set -u
|
||||
|
||||
MYOS_VERSION=2.0.0-dev
|
||||
|
||||
# --- locate the installation ---------------------------------------------
|
||||
_self=$0
|
||||
while [ -L "$_self" ]; do
|
||||
_link=$(readlink "$_self")
|
||||
case $_link in /*) _self=$_link ;; *) _self=$(dirname "$_self")/$_link ;; esac
|
||||
done
|
||||
MYOS_ROOT=$(cd "$(dirname "$_self")/.." && pwd -P)
|
||||
export MYOS_ROOT
|
||||
|
||||
for _m in core str tags naming stack config compose; do
|
||||
# shellcheck source=/dev/null
|
||||
. "$MYOS_ROOT/lib/$_m.sh"
|
||||
done
|
||||
|
||||
# --- command line ---------------------------------------------------------
|
||||
# These are read by the lib/cmd/* files sourced further down.
|
||||
# shellcheck disable=SC2034
|
||||
{
|
||||
MYOS_CMD=
|
||||
MYOS_REFS=
|
||||
MYOS_REFS_RAW=
|
||||
MYOS_VARS=
|
||||
MYOS_ARGS=
|
||||
MYOS_HOSTS=
|
||||
VERBOSE=${VERBOSE:-}
|
||||
DEBUG=${DEBUG:-}
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage: myos [options] <command> [stack...] [VAR=value...] [-- args...]
|
||||
|
||||
Options:
|
||||
-C DIR work in DIR instead of the current directory
|
||||
-e ENV environment (default: local, or ENV from the config)
|
||||
-H HOSTS run on remote hosts instead (comma separated, or "all")
|
||||
-n, --dry-run print the commands instead of running them
|
||||
-v, --verbose show what myos does
|
||||
-d, --debug show every command
|
||||
-h, --help this help
|
||||
|
||||
Commands:
|
||||
up down start stop restart recreate manage the containers of a stack
|
||||
ps logs config exec run inspect and enter them
|
||||
ls [--groups] list the stacks myos can see
|
||||
env [VAR...] show resolved variables
|
||||
doctor check the installation
|
||||
version print the myos version
|
||||
|
||||
Stacks:
|
||||
myos up the stack of the current directory
|
||||
myos up host a group, expanded from host=... in a .env or .mk
|
||||
myos up host/fabio a single stack
|
||||
myos up postgres:9.6 a versioned stack
|
||||
USAGE
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
-C) WORKDIR=$2; shift 2 ;;
|
||||
-e) ENV=$2; shift 2 ;;
|
||||
-H) MYOS_HOSTS=$2; shift 2 ;;
|
||||
-n|--dry-run) DRYRUN=true; shift ;;
|
||||
-v|--verbose) VERBOSE=true; shift ;;
|
||||
-d|--debug) DEBUG=true; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
--) shift; MYOS_ARGS="$*"; break ;;
|
||||
-*)
|
||||
if [ -n "$MYOS_CMD" ]; then
|
||||
MYOS_ARGS="${MYOS_ARGS:+$MYOS_ARGS }$1"; shift
|
||||
else
|
||||
myos_error "unknown option: $1"; usage >&2; exit "$MYOS_E_USAGE"
|
||||
fi ;;
|
||||
*=*) eval "${1%%=*}=\${1#*=}"; export "${1%%=*}"; shift ;;
|
||||
*)
|
||||
if [ -z "$MYOS_CMD" ]; then MYOS_CMD=$1; else MYOS_REFS="${MYOS_REFS:+$MYOS_REFS }$1"; fi
|
||||
shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ -n "$MYOS_CMD" ] || { usage; exit "$MYOS_E_USAGE"; }
|
||||
MYOS_REFS_RAW=$MYOS_REFS
|
||||
case $MYOS_CMD in
|
||||
env|ls|doctor) MYOS_VARS=$MYOS_REFS; MYOS_REFS= ;;
|
||||
esac
|
||||
|
||||
# Targets of the make engine keep working: print-VAR, stack-<stack>-<command>,
|
||||
# <command>@<env> and a bare group name.
|
||||
case $MYOS_CMD in
|
||||
print-*)
|
||||
MYOS_VARS=${MYOS_CMD#print-}
|
||||
# shellcheck disable=SC2209 # the literal string "env", not the command
|
||||
MYOS_CMD=env ;;
|
||||
*@*) ENV=${MYOS_CMD#*@}; MYOS_CMD=${MYOS_CMD%@*} ;;
|
||||
esac
|
||||
case $MYOS_CMD in
|
||||
stack-*-*)
|
||||
_rest=${MYOS_CMD#stack-}
|
||||
MYOS_CMD=${_rest##*-}
|
||||
MYOS_REFS="${_rest%-*} $MYOS_REFS"
|
||||
MYOS_REFS=${MYOS_REFS% } ;;
|
||||
esac
|
||||
|
||||
# --- configuration --------------------------------------------------------
|
||||
WORKDIR=${WORKDIR:-$PWD}
|
||||
WORKDIR=$(cd "$WORKDIR" 2>/dev/null && pwd -P) || myos_die "$MYOS_E_USAGE" "no such directory: $WORKDIR"
|
||||
|
||||
for _f in $(myos_conf_files); do myos_dotenv_load "$_f"; done
|
||||
myos_dotenv_load "${HOME:-}/.config/myos/config"
|
||||
ENV=${ENV:-local}
|
||||
myos_dotenv_load "$WORKDIR/.env.$ENV"
|
||||
myos_dotenv_load "$WORKDIR/.env"
|
||||
|
||||
# Overlay switches. Their names drive which <stack>.<suffix>.yml files load,
|
||||
# so these defaults decide that e.g. supabase.labels.yml is picked up.
|
||||
COMPOSE_FILE_APP=${COMPOSE_FILE_APP:-true}
|
||||
COMPOSE_FILE_LABELS=${COMPOSE_FILE_LABELS:-true}
|
||||
COMPOSE_FILE_NETWORKS=${COMPOSE_FILE_NETWORKS:-true}
|
||||
COMPOSE_FILE_SSH=${COMPOSE_FILE_SSH:-true}
|
||||
COMPOSE_FILE_VOLUMES=${COMPOSE_FILE_VOLUMES:-true}
|
||||
COMPOSE_FILE_DEBUG=${COMPOSE_FILE_DEBUG:-${DEBUG:+true}}
|
||||
|
||||
USER=${USER:-$(id -nu 2>/dev/null)}
|
||||
HOSTNAME=${HOSTNAME:-$(hostname 2>/dev/null | sed 's/\..*//')}
|
||||
HOSTNAME=$(myos_lower "$HOSTNAME")
|
||||
DOMAIN=${DOMAIN:-localhost}
|
||||
DOMAINNAME=${DOMAINNAME:-${DOMAIN%% *}}
|
||||
MAIL=${MAIL:-$(git config user.email 2>/dev/null || printf '%s@%s' "$USER" "$DOMAINNAME")}
|
||||
DRYRUN=${DRYRUN:-false}
|
||||
myos_colors
|
||||
|
||||
# --- stack references -----------------------------------------------------
|
||||
# No reference given: the configured STACK, else the current directory when it
|
||||
# holds a compose file. An explicit STACK always wins, so a project that pins
|
||||
# its stacks in .env keeps working from inside its own directory.
|
||||
if [ -z "$MYOS_REFS" ]; then
|
||||
if [ -n "${STACK:-}" ]; then
|
||||
MYOS_REFS=$STACK
|
||||
elif [ -f "$WORKDIR/docker-compose.yml" ] || [ -f "$WORKDIR/compose.yml" ] ||
|
||||
[ -f "$WORKDIR/docker/docker-compose.yml" ]; then
|
||||
MYOS_REFS=./
|
||||
fi
|
||||
fi
|
||||
if [ -z "$MYOS_REFS" ]; then
|
||||
case $MYOS_CMD in
|
||||
env|ls|doctor|version|help) ;;
|
||||
*) myos_die "$MYOS_E_USAGE" "no stack given, and no compose file in $WORKDIR" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086 # a list of references
|
||||
MYOS_STACKS=$(myos_group_expand $MYOS_REFS)
|
||||
|
||||
# myos_framework_compose_files the networks and volumes overlays myos itself
|
||||
# provides; they always come last so a stack can rely on them being there.
|
||||
myos_framework_compose_files() {
|
||||
myos_compose_files "$MYOS_ROOT/share/compose" "networks volumes" "$(myos_compose_suffixes)" "$ENV"
|
||||
}
|
||||
|
||||
# myos_stack_compose_files REF the ordered compose files of one reference
|
||||
myos_stack_compose_files() {
|
||||
_dir=$(myos_stack_resolve "$1") || return $?
|
||||
_name=$(myos_stack_name "$1")
|
||||
_suffixes="$(myos_compose_suffixes) $(myos_stack_version "$1")"
|
||||
case $1 in
|
||||
.|./*|/*|../*)
|
||||
myos_compose_files "$_dir" "docker-compose compose" "$_suffixes" "$ENV"
|
||||
myos_compose_files "$_dir/docker" "docker-compose compose" "$_suffixes" "$ENV" ;;
|
||||
*)
|
||||
myos_compose_files "$_dir" "docker-compose $_name" "$_suffixes" "$ENV" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- dispatch -------------------------------------------------------------
|
||||
case $MYOS_CMD in
|
||||
version) printf 'myos %s\n' "$MYOS_VERSION"; exit 0 ;;
|
||||
help) usage; exit 0 ;;
|
||||
esac
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
if [ -f "$MYOS_ROOT/lib/cmd/$MYOS_CMD.sh" ]; then
|
||||
. "$MYOS_ROOT/lib/cmd/$MYOS_CMD.sh"
|
||||
"myos_cmd_$MYOS_CMD"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# compose passthrough commands
|
||||
case $MYOS_CMD in
|
||||
up|down|start|stop|restart|ps|logs|config|build|pull|create|kill|top|images) ;;
|
||||
*) myos_error "unknown command: $MYOS_CMD"; usage >&2; exit "$MYOS_E_USAGE" ;;
|
||||
esac
|
||||
|
||||
. "$MYOS_ROOT/lib/cmd/_compose.sh"
|
||||
myos_cmd_compose "$MYOS_CMD"
|
||||
@@ -1,20 +0,0 @@
|
||||
FROM alpine:latest as dist
|
||||
LABEL maintainer aynic.os <support+docker@asycn.io>
|
||||
ARG DOCKER_BUILD_DIR
|
||||
|
||||
ARG COMPOSE_REMOTE=https://github.com/docker/compose
|
||||
ARG COMPOSE_VERSION=2.5.0
|
||||
ARG DOCKER_MACHINE=x86_64
|
||||
ARG DOCKER_SYSTEM=Linux
|
||||
|
||||
RUN apk update \
|
||||
&& apk add --no-cache ca-certificates \
|
||||
&& OS="$(echo ${DOCKER_SYSTEM} |awk '{print tolower($0)}')" \
|
||||
&& ARCH="$(echo ${DOCKER_MACHINE} |awk '{print /armv7l/ ? "armv7" : $0}')" \
|
||||
&& wget -qO /usr/bin/docker-compose ${COMPOSE_REMOTE}/releases/download/v${COMPOSE_VERSION}/docker-compose-${OS}-${ARCH} \
|
||||
&& chmod +x /usr/bin/docker-compose
|
||||
|
||||
ENTRYPOINT ["/usr/bin/docker-compose"]
|
||||
|
||||
FROM dist as master
|
||||
ARG DOCKER_BUILD_DIR
|
||||
@@ -0,0 +1,75 @@
|
||||
#shellcheck shell=sh
|
||||
# shellcheck disable=SC3028 # HOSTNAME is a myos variable, set by bin/myos
|
||||
# The commands that map straight onto docker compose.
|
||||
#
|
||||
# Stacks are grouped by compose project: every host stack shares the project of
|
||||
# the machine, so `myos up host` is a single compose call with every file, the
|
||||
# way the stack was meant to be described.
|
||||
|
||||
# myos_cmd_compose COMMAND
|
||||
myos_cmd_compose() {
|
||||
_cmd=$1
|
||||
_projects=
|
||||
_rc=0
|
||||
|
||||
for _ref in $MYOS_STACKS; do
|
||||
_files=$(myos_stack_compose_files "$_ref") || { _rc=$MYOS_E_NOSTACK; continue; }
|
||||
[ -n "$_files" ] || { myos_warning "no compose file for stack $_ref"; continue; }
|
||||
_scope=$(myos_scope "$_ref")
|
||||
_app=$(myos_stack_name "$_ref")
|
||||
case $_ref in .|./*|/*|../*) _app=$(basename "$(myos_stack_resolve "$_ref")") ;; esac
|
||||
_project=$(myos_project_name "$_scope" "$USER" "$ENV" "$_app")
|
||||
# accumulate the files of every stack sharing a project, keeping the order
|
||||
_projects=$(printf '%s\n%s\t%s' "$_projects" "$_project" "$(printf '%s' "$_files" | tr '\n' ' ')")
|
||||
done
|
||||
|
||||
[ "$_rc" = 0 ] || return "$_rc"
|
||||
|
||||
for _project in $(printf '%s' "$_projects" | sed '/^$/d' | cut -f1 | awk '!seen[$0]++'); do
|
||||
_files=$(printf '%s' "$_projects" | sed '/^$/d' | awk -F'\t' -v p="$_project" '$1==p {print $2}' | tr ' ' '\n' | sed '/^$/d' | awk '!seen[$0]++')
|
||||
# the framework overlays always come last, as the make engine did
|
||||
_fw=$(myos_framework_compose_files)
|
||||
[ -n "$_fw" ] && _files="$_files
|
||||
$_fw"
|
||||
|
||||
COMPOSE_PROJECT_NAME=$_project
|
||||
COMPOSE_SERVICE_NAME=$(myos_service_name "$_project")
|
||||
DOCKER_NETWORK_DEFAULT=${DOCKER_NETWORK_DEFAULT:-$(myos_network_default "$_project")}
|
||||
DOCKER_NETWORK_PRIVATE=$(myos_network_private "$USER" "$ENV")
|
||||
# shellcheck disable=SC3028 # HOSTNAME is set by bin/myos, not by the shell
|
||||
DOCKER_NETWORK_PUBLIC=$(myos_network_public "$HOSTNAME")
|
||||
export COMPOSE_PROJECT_NAME COMPOSE_SERVICE_NAME
|
||||
export DOCKER_NETWORK_DEFAULT DOCKER_NETWORK_PRIVATE DOCKER_NETWORK_PUBLIC
|
||||
|
||||
case $_cmd in
|
||||
up) myos_network_ensure "$DOCKER_NETWORK_PRIVATE" "$DOCKER_NETWORK_PUBLIC" ;;
|
||||
esac
|
||||
|
||||
# shellcheck disable=SC2086,SC2046 # options and MYOS_ARGS are word lists
|
||||
myos_compose "$_project" "$_files" -- "$_cmd" $(myos_compose_options "$_cmd") ${MYOS_ARGS:-} || _rc=$?
|
||||
done
|
||||
return "$_rc"
|
||||
}
|
||||
|
||||
# myos_compose_options COMMAND the default options of each compose command
|
||||
myos_compose_options() {
|
||||
case $1 in
|
||||
up) printf '%s' "${DOCKER_COMPOSE_UP_OPTIONS:--d}" ;;
|
||||
logs) printf '%s' "${DOCKER_COMPOSE_LOGS_OPTIONS:---follow --tail=100}" ;;
|
||||
down) printf '%s' "${DOCKER_COMPOSE_DOWN_OPTIONS:-}" ;;
|
||||
*) printf '' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# myos_network_ensure NAME... create the external networks if they are missing
|
||||
myos_network_ensure() {
|
||||
for _n in "$@"; do
|
||||
[ -n "$_n" ] || continue
|
||||
if [ "${DRYRUN:-false}" = true ]; then
|
||||
printf 'docker network create %s\n' "$_n"
|
||||
else
|
||||
docker network inspect "$_n" >/dev/null 2>&1 || myos_run docker network create "$_n" >/dev/null
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#shellcheck shell=sh
|
||||
# shellcheck disable=SC3028 # HOSTNAME is a myos variable, set by bin/myos
|
||||
# myos doctor check that this installation can actually run a stack
|
||||
myos_cmd_doctor() {
|
||||
_rc=0
|
||||
_ok() { printf ' %-28s %s\n' "$1" "$2"; }
|
||||
_bad() { printf ' %-28s %s%s%s\n' "$1" "$MYOS_C_ERROR" "$2" "$MYOS_C_RESET"; _rc=$MYOS_E_NOREQ; }
|
||||
|
||||
printf 'myos %s at %s\n' "$MYOS_VERSION" "$MYOS_ROOT"
|
||||
printf 'requirements:\n'
|
||||
if myos_have docker; then _ok docker "$(docker version --format '{{.Client.Version}}' 2>/dev/null || echo present)"
|
||||
else _bad docker "not found"; fi
|
||||
if _c=$(myos_compose_bin 2>/dev/null); then _ok "compose" "$_c"; else _bad compose "docker compose >= $MYOS_COMPOSE_MIN_VERSION not found"; fi
|
||||
if [ "${DRYRUN:-false}" != true ]; then
|
||||
if docker info >/dev/null 2>&1; then _ok "docker daemon" "reachable${DOCKER_HOST:+ via $DOCKER_HOST}"
|
||||
else _bad "docker daemon" "unreachable${DOCKER_HOST:+ ($DOCKER_HOST)}"; fi
|
||||
fi
|
||||
|
||||
printf 'configuration:\n'
|
||||
for _f in $(myos_conf_files); do _ok "$_f" "read"; done
|
||||
[ -f "${HOME:-}/.config/myos/config" ] && _ok "${HOME:-}/.config/myos/config" "read"
|
||||
[ -f "$WORKDIR/.env" ] && _ok "$WORKDIR/.env" "read"
|
||||
_ok ENV "$ENV"
|
||||
_ok USER "$USER"
|
||||
_ok HOSTNAME "$HOSTNAME"
|
||||
_ok DOMAIN "$DOMAIN"
|
||||
_ok "project format" "${MYOS_PROJECT_FORMAT:-user-env-app}"
|
||||
|
||||
printf 'stacks:\n'
|
||||
_p=$(myos_path)
|
||||
if [ -n "$_p" ]; then printf '%s\n' "$_p" | tr ':' '\n' | sed 's/^/ /'
|
||||
else _bad "stack path" "empty"; fi
|
||||
|
||||
# a .env written for the make engine can hold values the shell reads differently
|
||||
if [ -f "$WORKDIR/.env" ] && grep -qE '\$\(|\$\{[a-z]' "$WORKDIR/.env"; then
|
||||
printf ' %-28s %s%s%s\n' "$WORKDIR/.env" "$MYOS_C_WARN" "contains make expansions" "$MYOS_C_RESET"
|
||||
fi
|
||||
return "$_rc"
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#shellcheck shell=sh
|
||||
# shellcheck disable=SC3028 # HOSTNAME is a myos variable, set by bin/myos
|
||||
# myos env [VAR...] show resolved variables (replaces the make print-VAR target)
|
||||
myos_cmd_env() {
|
||||
_vars=${MYOS_VARS:-}
|
||||
[ -n "$_vars" ] || _vars=$MYOS_ARGS
|
||||
[ -n "$_vars" ] || _vars=$MYOS_REFS_RAW
|
||||
if [ -z "$_vars" ]; then
|
||||
_vars="ENV USER HOSTNAME DOMAIN WORKDIR MYOS_PATH STACK COMPOSE_PROJECT_NAME COMPOSE_FILE"
|
||||
fi
|
||||
for _v in $_vars; do
|
||||
case $_v in
|
||||
MYOS_PATH) printf '%s %s\n' "$_v" "$(myos_path)" ;;
|
||||
COMPOSE_FILE) printf '%s %s\n' "$_v" "$(myos_all_compose_files | tr '\n' ' ' | sed 's/ $//')" ;;
|
||||
COMPOSE_PROJECT_NAME) printf '%s %s\n' "$_v" "$(myos_first_project)" ;;
|
||||
STACK) printf '%s %s\n' "$_v" "$(printf '%s' "$MYOS_STACKS" | tr '\n' ' ' | sed 's/ $//')" ;;
|
||||
DOCKER_NETWORK_DEFAULT) printf '%s %s\n' "$_v" "$(myos_network_default "$(myos_first_project)")" ;;
|
||||
DOCKER_NETWORK_PRIVATE) printf '%s %s\n' "$_v" "$(myos_network_private "$USER" "$ENV")" ;;
|
||||
DOCKER_NETWORK_PUBLIC) printf '%s %s\n' "$_v" "$(myos_network_public "${HOSTNAME:-}")" ;;
|
||||
COMPOSE_SERVICE_NAME) printf '%s %s\n' "$_v" "$(myos_service_name "$(myos_first_project)")" ;;
|
||||
COMPOSE_FILE_SUFFIX) printf '%s %s\n' "$_v" "$(myos_compose_suffixes)" ;;
|
||||
APP|APP_NAME) printf '%s %s\n' "$_v" "$(myos_first_app)" ;;
|
||||
SCOPE) printf '%s %s\n' "$_v" "$(myos_first_scope)" ;;
|
||||
# HOST_STACK/USER_STACK are the names the make engine used for the scope
|
||||
HOST_STACK) [ "$(myos_first_scope)" = host ] && printf '%s host\n' "$_v" || printf '%s\n' "$_v" ;;
|
||||
USER_STACK) [ "$(myos_first_scope)" = user ] && printf '%s User\n' "$_v" || printf '%s\n' "$_v" ;;
|
||||
DOCKER_REPOSITORY) printf '%s %s\n' "$_v" "$(printf '%s' "$(myos_first_project)" | tr '_-' '//')" ;;
|
||||
DOCKER_NETWORK)
|
||||
if [ "$(myos_first_scope)" = user ]; then printf '%s %s\n' "$_v" "$USER"
|
||||
else printf '%s %s\n' "$_v" "$(myos_network_private "$USER" "$ENV")"; fi ;;
|
||||
*) printf '%s %s\n' "$_v" "$(myos_var "$_v")" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# myos_all_compose_files every compose file of every requested stack, in order
|
||||
myos_all_compose_files() {
|
||||
for _ref in $MYOS_STACKS; do
|
||||
myos_stack_compose_files "$_ref" 2>/dev/null
|
||||
done
|
||||
myos_framework_compose_files
|
||||
return 0
|
||||
}
|
||||
|
||||
# myos_first_app / myos_first_scope / myos_first_project
|
||||
# describe the first requested stack, which is what the introspection commands
|
||||
# report when several stacks are asked for at once.
|
||||
myos_first_app() {
|
||||
for _ref in $MYOS_STACKS; do
|
||||
case $_ref in
|
||||
.|./*|/*|../*) basename "$(myos_stack_resolve "$_ref" 2>/dev/null)" ;;
|
||||
*) myos_stack_name "$_ref" ;;
|
||||
esac
|
||||
return 0
|
||||
done
|
||||
}
|
||||
|
||||
myos_first_scope() {
|
||||
for _ref in $MYOS_STACKS; do myos_scope "$_ref"; return 0; done
|
||||
}
|
||||
|
||||
myos_first_project() {
|
||||
for _ref in $MYOS_STACKS; do
|
||||
myos_project_name "$(myos_scope "$_ref")" "$USER" "$ENV" "$(myos_first_app)"
|
||||
return 0
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#shellcheck shell=sh
|
||||
# myos ls [--groups] list the stacks myos can see, and where they come from
|
||||
myos_cmd_ls() {
|
||||
case ${MYOS_REFS_RAW:-}${MYOS_ARGS:-} in
|
||||
*--groups*) myos_ls_groups; return 0 ;;
|
||||
esac
|
||||
_IFS=$IFS; IFS=:
|
||||
for _d in $(myos_path); do
|
||||
IFS=$_IFS
|
||||
printf '%s%s%s\n' "$MYOS_C_INFO" "$_d" "$MYOS_C_RESET"
|
||||
for _s in "$_d"/*; do
|
||||
[ -d "$_s" ] || continue
|
||||
_n=$(basename "$_s")
|
||||
_f=$(find "$_s" -maxdepth 1 \( -name '*.yml' -o -name '*.yaml' \) | wc -l | tr -d ' ')
|
||||
[ "$_f" = 0 ] && continue
|
||||
printf ' %-24s %s compose file(s)\n' "$_n" "$_f"
|
||||
done
|
||||
IFS=:
|
||||
done
|
||||
IFS=$_IFS
|
||||
}
|
||||
|
||||
myos_ls_groups() {
|
||||
_IFS=$IFS; IFS=:
|
||||
for _d in $(myos_path); do
|
||||
IFS=$_IFS
|
||||
for _f in "$_d"/*.mk "$_d"/*.env "$_d"/*/*.mk; do
|
||||
[ -f "$_f" ] || continue
|
||||
_n=$(basename "$_f"); _n=${_n%.mk}; _n=${_n%.env}
|
||||
_v=$(myos_group_value "$_n")
|
||||
[ -n "$_v" ] && printf '%-16s %s\n' "$_n" "$_v"
|
||||
done
|
||||
IFS=:
|
||||
done
|
||||
IFS=$_IFS
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#shellcheck shell=sh
|
||||
# compose: find a usable docker compose, and call it once per project.
|
||||
#
|
||||
# The legacy engine ran one `docker compose up` per sub-stack, each time with
|
||||
# the full file list, so N sub-stacks meant N identical calls. The CLI calls
|
||||
# compose once per project (documented in spec/golden/DELTAS.md).
|
||||
|
||||
MYOS_COMPOSE_MIN_VERSION=${COMPOSE_VERSION:-2.24.4}
|
||||
|
||||
# myos_compose_bin print the compose command to use, fail with MYOS_E_NOREQ
|
||||
myos_compose_bin() {
|
||||
[ -n "${MYOS_COMPOSE_BIN:-}" ] && { printf '%s' "$MYOS_COMPOSE_BIN"; return 0; }
|
||||
if myos_have docker; then
|
||||
_v=$(docker compose version --short 2>/dev/null)
|
||||
if myos_verle "$MYOS_COMPOSE_MIN_VERSION" "$_v"; then printf 'docker compose'; return 0; fi
|
||||
fi
|
||||
if myos_have docker-compose; then
|
||||
_v=$(docker-compose version --short 2>/dev/null)
|
||||
if myos_verle "$MYOS_COMPOSE_MIN_VERSION" "$_v"; then printf 'docker-compose'; return 0; fi
|
||||
fi
|
||||
myos_error "docker compose >= $MYOS_COMPOSE_MIN_VERSION not found (install the docker compose plugin or docker-compose)"
|
||||
return "$MYOS_E_NOREQ"
|
||||
}
|
||||
|
||||
# myos_compose PROJECT FILES -- ARGS...
|
||||
# FILES is a newline separated list; the project directory is that of the first
|
||||
# file, so relative build contexts and env_file entries keep working.
|
||||
myos_compose() {
|
||||
_project=$1; _files=$2; shift 2
|
||||
[ "${1:-}" = "--" ] && shift
|
||||
[ -n "$_files" ] || { myos_error "no compose file for project $_project"; return "$MYOS_E_NOSTACK"; }
|
||||
_bin=$(myos_compose_bin) || return $?
|
||||
|
||||
_fargs=""
|
||||
_first=""
|
||||
for _f in $_files; do
|
||||
[ -n "$_first" ] || _first=$_f
|
||||
_fargs="$_fargs -f $_f"
|
||||
done
|
||||
_dir=$(dirname "$_first")
|
||||
|
||||
# variables the compose files reference, plus the network names they default
|
||||
# on (networks.yml is appended after the scan, so its variables are added here)
|
||||
# shellcheck disable=SC2086 # both are deliberate word lists
|
||||
_vars=$(myos_env_vars $_files)
|
||||
# shellcheck disable=SC2086
|
||||
_envargs=$(myos_env_export $_vars DOCKER_NETWORK_DEFAULT DOCKER_NETWORK_PRIVATE DOCKER_NETWORK_PUBLIC COMPOSE_SERVICE_NAME)
|
||||
|
||||
if [ "${DRYRUN:-false}" = true ]; then
|
||||
printf '%s%s -p %s --project-directory %s %s\n' "$_bin" "$_fargs" "$_project" "$_dir" "$*"
|
||||
else
|
||||
_IFS=$IFS; IFS='
|
||||
'
|
||||
# shellcheck disable=SC2046,SC2086 # deliberate word splitting on IFS=newline
|
||||
env $_envargs $_bin --ansi=auto $_fargs -p "$_project" --project-directory "$_dir" "$@"
|
||||
_rc=$?
|
||||
IFS=$_IFS
|
||||
return $_rc
|
||||
fi
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#shellcheck shell=sh
|
||||
# config: where settings come from, and in which order.
|
||||
#
|
||||
# Layers, last one wins:
|
||||
# defaults < /etc/conf.d/myos, /etc/default/myos < ~/.config/myos/config
|
||||
# < <workdir>/.env < <workdir>/.env.<env> < environment < CLI VAR=val
|
||||
# MYOS_CONF_PRIORITY=system restores the old make behaviour where the system
|
||||
# file won over the project .env.
|
||||
#
|
||||
# Files are dotenv: KEY=value, one per line, # comments, optional quotes.
|
||||
# They are parsed, never sourced: a value never runs as code.
|
||||
|
||||
# myos_dotenv_parse FILE print normalized KEY=value lines
|
||||
myos_dotenv_parse() {
|
||||
[ -f "$1" ] || return 0
|
||||
sed -e 's/\r$//' -e '/^[[:space:]]*#/d' -e '/^[[:space:]]*$/d' "$1" |
|
||||
while IFS= read -r _line; do
|
||||
case $_line in *=*) ;; *) continue ;; esac
|
||||
_k=${_line%%=*}
|
||||
_v=${_line#*=}
|
||||
_k=$(printf '%s' "$_k" | tr -d '[:space:]')
|
||||
# whitespace around the = is not part of the value (make: s/[[:space:]]*=[[:space:]]*/=/)
|
||||
_v=${_v#"${_v%%[![:space:]]*}"}
|
||||
case $_k in ''|*[!A-Za-z0-9_]*) continue ;; esac
|
||||
# strip one layer of matching quotes
|
||||
case $_v in
|
||||
\"*\") _v=${_v#\"}; _v=${_v%\"} ;;
|
||||
\'*\') _v=${_v#\'}; _v=${_v%\'} ;;
|
||||
esac
|
||||
printf '%s=%s\n' "$_k" "$_v"
|
||||
done
|
||||
}
|
||||
|
||||
# myos_dotenv_load FILE set the variables of FILE that are not already set
|
||||
# (an already exported variable wins, as `?=` does in make)
|
||||
myos_dotenv_load() {
|
||||
[ -f "$1" ] || return 0
|
||||
while IFS= read -r _kv; do
|
||||
# an empty file still yields one empty line through the here-document
|
||||
[ -n "$_kv" ] || continue
|
||||
_k=${_kv%%=*}
|
||||
[ -n "$_k" ] || continue
|
||||
[ -n "$(myos_var "$_k")" ] && continue
|
||||
eval "$_k=\${_kv#*=}"
|
||||
done <<EOF
|
||||
$(myos_dotenv_parse "$1")
|
||||
EOF
|
||||
}
|
||||
|
||||
# myos_dotenv_has FILE KEY
|
||||
myos_dotenv_has() { myos_dotenv_parse "$1" | grep -q "^$2="; }
|
||||
|
||||
# myos_conf_files the system config files, most significant first
|
||||
myos_conf_files() {
|
||||
[ -n "${MYOS_CONF:-}" ] && { printf '%s\n' "$MYOS_CONF"; return 0; }
|
||||
for _f in /etc/conf.d/myos /etc/default/myos; do
|
||||
[ -r "$_f" ] && printf '%s\n' "$_f"
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# myos_env_vars FILE... the ${VAR} names referenced by the compose files
|
||||
# (make: env-vars). $$VAR is a compose escape, not a shell variable.
|
||||
myos_env_vars() {
|
||||
[ $# -gt 0 ] || return 0
|
||||
sed 's/\$\$//g' "$@" 2>/dev/null |
|
||||
grep -oE '\$\{?[A-Z0-9_]+' |
|
||||
tr -d '{}$' |
|
||||
sort -u |
|
||||
tr '\n' ' ' |
|
||||
sed 's/ $//'
|
||||
}
|
||||
|
||||
# myos_env_export VAR... print VAR='value' for each variable that has a value,
|
||||
# ready to be passed to env(1)
|
||||
myos_env_export() {
|
||||
for _v in "$@"; do
|
||||
_val=$(myos_var "$_v")
|
||||
[ -n "$_val" ] && printf "%s=%s\n" "$_v" "$_val"
|
||||
done
|
||||
return 0
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
#shellcheck shell=sh
|
||||
# core: logging, error handling and command execution.
|
||||
#
|
||||
# Every myos command goes through myos_run, which honours DRYRUN by printing
|
||||
# the command instead of running it. Messages go to stderr so that stdout stays
|
||||
# usable for data (myos env, myos config, myos ls).
|
||||
|
||||
# Exit codes and colors are consumed by the other lib/ files and by bin/myos.
|
||||
# shellcheck disable=SC2034
|
||||
MYOS_E_OK=0 # success
|
||||
MYOS_E_FAIL=1 # command failed
|
||||
MYOS_E_USAGE=2 # bad invocation
|
||||
MYOS_E_NOSTACK=3 # stack not found
|
||||
MYOS_E_NOREQ=4 # missing requirement
|
||||
|
||||
myos_colors() {
|
||||
if [ -t 2 ] && [ "${TERM:-dumb}" != dumb ] && [ -z "${NO_COLOR:-}" ]; then
|
||||
MYOS_C_ERROR=$(printf '\033[31m'); MYOS_C_WARN=$(printf '\033[01;33m')
|
||||
MYOS_C_INFO=$(printf '\033[33m'); MYOS_C_DEBUG=$(printf '\033[01;34m')
|
||||
MYOS_C_VALUE=$(printf '\033[36m'); MYOS_C_RESET=$(printf '\033[0m')
|
||||
else
|
||||
MYOS_C_ERROR=; MYOS_C_WARN=; MYOS_C_INFO=; MYOS_C_DEBUG=; MYOS_C_VALUE=; MYOS_C_RESET=
|
||||
fi
|
||||
}
|
||||
|
||||
myos_error() { printf '%sERROR:%s %s\n' "$MYOS_C_ERROR" "$MYOS_C_RESET" "$*" >&2; }
|
||||
myos_warning() { printf '%sWARNING:%s %s\n' "$MYOS_C_WARN" "$MYOS_C_RESET" "$*" >&2; }
|
||||
myos_info() { [ -n "${VERBOSE:-}" ] && printf '%s%s%s\n' "$MYOS_C_INFO" "$*" "$MYOS_C_RESET" >&2; return 0; }
|
||||
myos_debug() { [ -n "${DEBUG:-}" ] && printf '%s%s%s\n' "$MYOS_C_DEBUG" "$*" "$MYOS_C_RESET" >&2; return 0; }
|
||||
|
||||
# myos_die CODE MESSAGE...
|
||||
myos_die() { _code=$1; shift; myos_error "$*"; exit "$_code"; }
|
||||
|
||||
# myos_run CMD... run a command, or print it when DRYRUN is true
|
||||
myos_run() {
|
||||
if [ "${DRYRUN:-false}" = true ]; then
|
||||
printf '%s\n' "$*"
|
||||
return 0
|
||||
fi
|
||||
myos_debug "+ $*"
|
||||
"$@"
|
||||
}
|
||||
|
||||
# myos_have CMD is a command available?
|
||||
myos_have() { command -v "$1" >/dev/null 2>&1; }
|
||||
|
||||
myos_colors
|
||||
@@ -0,0 +1,81 @@
|
||||
#shellcheck shell=sh
|
||||
# shellcheck disable=SC3028 # HOSTNAME is a myos variable, set by bin/myos
|
||||
# naming: compose project name, service name, networks, user identity.
|
||||
#
|
||||
# Ported from make/apps/def.docker.mk (COMPOSE_PROJECT_NAME, COMPOSE_SERVICE_NAME),
|
||||
# make/def.docker.mk (HOST_*/USER_*, DOCKER_NETWORK_*) and make/def.mk (RESU).
|
||||
|
||||
# myos_scope REF -> host | user | cluster | app
|
||||
# The first segment of a stack reference decides how the stack is named:
|
||||
# host stacks are singletons of the machine (they bind privileged ports),
|
||||
# user stacks are singletons of the user, cluster stacks are swarm namespaces.
|
||||
myos_scope() {
|
||||
[ -n "${MYOS_SCOPE:-}" ] && { printf '%s' "$MYOS_SCOPE"; return 0; }
|
||||
case ${1%%/*} in
|
||||
host) printf 'host' ;;
|
||||
User|user) printf 'user' ;;
|
||||
cluster) printf 'cluster' ;;
|
||||
*) printf 'app' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# myos_resu MAIL -> user.domain identity of a mail address (make: RESU)
|
||||
# Also sets MYOS_RESU_NIAMOD (reversed domain + reversed user) and
|
||||
# MYOS_RESU_PATH (that identity as a path), used by the User stacks.
|
||||
myos_resu() {
|
||||
_mail=$(myos_lower "${1:-}" | tr '+_' '..')
|
||||
case $_mail in
|
||||
*@*) ;;
|
||||
*) MYOS_RESU_NIAMOD=; MYOS_RESU_PATH=; printf '%s' "${USER:-}"; return 0 ;;
|
||||
esac
|
||||
_user=${_mail%@*}
|
||||
_domain=${_mail##*@}
|
||||
[ -n "$_domain" ] || { MYOS_RESU_NIAMOD=; MYOS_RESU_PATH=; printf '%s' "${USER:-}"; return 0; }
|
||||
_niamod=$(myos_reverse "$(printf '%s' "$_domain" | tr '.' ' ')" | tr ' ' '.')
|
||||
_resu=$(myos_reverse "$(printf '%s' "$_user" | tr '.' ' ')" | tr ' ' '.')
|
||||
MYOS_RESU_NIAMOD="$_niamod.$_resu"
|
||||
# consumed by the User stacks, not by this file
|
||||
# shellcheck disable=SC2034
|
||||
MYOS_RESU_PATH=$(printf '%s' "$MYOS_RESU_NIAMOD" | tr '.' '/')
|
||||
printf '%s.%s' "$_user" "$_domain"
|
||||
}
|
||||
|
||||
# myos_project_name SCOPE USER ENV APP [PATH]
|
||||
# host -> HOST_COMPOSE_PROJECT_NAME, defaults to the hostname
|
||||
# user -> USER_COMPOSE_PROJECT_NAME, defaults to the RESU identity
|
||||
# cluster -> the stack name: one namespace per swarm, not per user
|
||||
# app -> MYOS_PROJECT_FORMAT: user-env-app (default) or user-app-env (legacy)
|
||||
myos_project_name() {
|
||||
_scope=$1; _user=$2; _env=$3; _app=$4; _path=${5:-}
|
||||
[ -n "${DOCKER_COMPOSE_PROJECT_NAME:-}" ] && { printf '%s' "$DOCKER_COMPOSE_PROJECT_NAME"; return 0; }
|
||||
case $_scope in
|
||||
host)
|
||||
printf '%s' "${HOST_COMPOSE_PROJECT_NAME:-${HOSTNAME:-localhost}}"; return 0 ;;
|
||||
user)
|
||||
if [ -n "${USER_COMPOSE_PROJECT_NAME:-}" ]; then printf '%s' "$USER_COMPOSE_PROJECT_NAME"
|
||||
else printf '%s' "$(myos_resu "${MAIL:-}" | tr '.' '-')"; fi
|
||||
return 0 ;;
|
||||
cluster)
|
||||
printf '%s' "${MYOS_CLUSTER_PROJECT:-$(myos_name "$_app")}"; return 0 ;;
|
||||
esac
|
||||
_n=$(myos_name "$_app")
|
||||
case ${MYOS_PROJECT_FORMAT:-user-env-app} in
|
||||
user-app-env) _out="$_user-$_n-$_env" ;;
|
||||
user-env-app) _out="$_user-$_env-$_n" ;;
|
||||
*) myos_die "$MYOS_E_USAGE" "unknown MYOS_PROJECT_FORMAT: ${MYOS_PROJECT_FORMAT}" ;;
|
||||
esac
|
||||
# the path fragment loses its slashes too (make: $(subst /,,$(subst -,,$(APP_PATH))))
|
||||
[ -n "$_path" ] && _out="$_out-$(myos_name "$_path" | tr -d /)"
|
||||
myos_lower "$_out" | tr -d '.'
|
||||
}
|
||||
|
||||
# myos_service_name PROJECT prefix of the SERVICE_<port>_NAME labels
|
||||
myos_service_name() { printf '%s' "$1" | tr '_' '-'; }
|
||||
|
||||
# myos_network_default PROJECT
|
||||
# The leading underscore keeps this network first in alphabetical order, so it
|
||||
# is the first interface attached and service names never resolve across stacks.
|
||||
# https://github.com/moby/libnetwork/issues/2093
|
||||
myos_network_default() { printf '_%s' "$1"; }
|
||||
myos_network_private() { printf '%s' "${DOCKER_NETWORK_PRIVATE:-${1}-${2}}"; }
|
||||
myos_network_public() { printf '%s' "${DOCKER_NETWORK_PUBLIC:-${1}}"; }
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
#shellcheck shell=sh
|
||||
# stack: where stacks live, how a reference resolves to compose files.
|
||||
#
|
||||
# A stack is a directory holding compose files. A reference is
|
||||
# [<group>/]<name>[:<version>] resolved along MYOS_PATH
|
||||
# ./ or /abs/path or rel/path the directory itself
|
||||
# Ported from make/def.docker.mk (STACK_DIR/SHARE_DIR) and
|
||||
# make/apps/def.docker.mk (compose-file, docker-stack, docker-stack-update).
|
||||
|
||||
# myos_path the stack search path, colon separated, existing directories only.
|
||||
# Project first, then the shared catalogues: a project always wins over the
|
||||
# catalogue installed system wide.
|
||||
myos_path() {
|
||||
[ -n "${MYOS_PATH:-}" ] && { printf '%s' "$MYOS_PATH"; return 0; }
|
||||
_wd=${WORKDIR:-$PWD}
|
||||
_name=${STACK_DIR_NAME:-stack}
|
||||
_out=
|
||||
for _d in "$_wd" "$_wd/.." "${HOME:-/nonexistent}/.local/share" /usr/local/share /usr/share; do
|
||||
for _c in "$_d/$_name" "$_d/myos/$_name"; do
|
||||
[ -d "$_c" ] || continue
|
||||
_c=$(cd "$_c" && pwd -P)
|
||||
case ":$_out:" in *":$_c:"*) continue ;; esac
|
||||
_out="${_out:+$_out:}$_c"
|
||||
done
|
||||
done
|
||||
printf '%s' "$_out"
|
||||
}
|
||||
|
||||
# myos_stack_name REF the stack name: "host/fabio:1.6" -> "fabio"
|
||||
# myos_stack_version REF the version, "latest" when the reference has none
|
||||
# Both are pure, so a caller can use them inside a command substitution.
|
||||
myos_stack_name() {
|
||||
_r=${1%/}
|
||||
case $_r in *:*) _r=${_r%:*} ;; esac
|
||||
basename "$_r" .yml
|
||||
}
|
||||
myos_stack_version() {
|
||||
_r=${1%/}
|
||||
case $_r in *:*) printf '%s' "${_r##*:}" ;; *) printf 'latest' ;; esac
|
||||
}
|
||||
|
||||
# myos_stack_resolve REF print the directory holding the stack,
|
||||
# or fail with MYOS_E_NOSTACK
|
||||
myos_stack_resolve() {
|
||||
_ref=${1%/}
|
||||
case $_ref in *:*) _ref=${_ref%:*} ;; esac
|
||||
_name=$(myos_stack_name "$1")
|
||||
|
||||
# a path reference resolves to itself
|
||||
case $_ref in
|
||||
.|./*|/*|../*)
|
||||
if [ -d "$_ref" ]; then printf '%s' "$(cd "$_ref" && pwd -P)"; return 0; fi
|
||||
myos_error "no such directory: $_ref"; return "$MYOS_E_NOSTACK" ;;
|
||||
esac
|
||||
|
||||
_IFS=$IFS; IFS=:
|
||||
for _d in $(myos_path); do
|
||||
IFS=$_IFS
|
||||
if [ -d "$_d/$_ref" ]; then printf '%s' "$_d/$_ref"; return 0; fi
|
||||
if [ -f "$_d/$_ref.yml" ] || [ -f "$_d/$_ref.yaml" ]; then
|
||||
printf '%s' "$(dirname "$_d/$_ref")"; return 0
|
||||
fi
|
||||
if [ -d "$_d/$_name" ]; then printf '%s' "$_d/$_name"; return 0; fi
|
||||
IFS=:
|
||||
done
|
||||
IFS=$_IFS
|
||||
myos_error "stack not found: $1 (searched $(myos_path))"
|
||||
return "$MYOS_E_NOSTACK"
|
||||
}
|
||||
|
||||
# myos_compose_suffixes the overlay suffixes, from the COMPOSE_FILE_* variables
|
||||
# that are not false (make: COMPOSE_FILE_SUFFIX). A value other than true also
|
||||
# yields "<suffix>.<value>", which is how COMPOSE_FILE_WWW=nginx works.
|
||||
myos_compose_suffixes() {
|
||||
_out=
|
||||
for _v in $(set | sed -n 's/^\(COMPOSE_FILE_[A-Z0-9_]*\)=.*/\1/p' | sort -u); do
|
||||
case $_v in COMPOSE_FILE_SUFFIX) continue ;; esac
|
||||
_val=$(myos_var "$_v")
|
||||
case $_val in false|False|FALSE|'') continue ;; esac
|
||||
_s=$(myos_lower "${_v#COMPOSE_FILE_}")
|
||||
_out="${_out:+$_out }$_s"
|
||||
case $_val in true|True|TRUE) ;; *) for _x in $_val; do _out="$_out $_s.$_x"; done ;; esac
|
||||
done
|
||||
printf '%s' "$_out"
|
||||
}
|
||||
|
||||
# myos_compose_files DIR NAMES SUFFIXES [ENV]
|
||||
# Print the compose files that exist, in the order the framework loads them.
|
||||
myos_compose_files() {
|
||||
_dir=$1; _names=$2; _suffixes=${3:-}; _env=${4:-${ENV:-local}}
|
||||
for _e in yml yaml; do
|
||||
for _n in $_names; do
|
||||
for _f in \
|
||||
"$_dir/$_n.$_e" "$_dir/$_n.$_env.$_e" \
|
||||
"$_dir/$_env/$_n.$_e" "$_dir/$_env/$_n.$_env.$_e"; do
|
||||
[ -f "$_f" ] && printf '%s\n' "$_f"
|
||||
done
|
||||
for _s in $_suffixes; do
|
||||
for _f in "$_dir/$_n.$_s.$_e" "$_dir/$_n.$_s.$_env.$_e"; do
|
||||
[ -f "$_f" ] && printf '%s\n' "$_f"
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# myos_group_expand REF... expand group references recursively.
|
||||
# A group is a variable whose name is the reference: `host=host/consul host/fabio`
|
||||
# in the environment, in a .env, in <path>/<group>.env or in a legacy <group>.mk.
|
||||
myos_group_expand() {
|
||||
_depth=${MYOS_GROUP_DEPTH:-0}
|
||||
[ "$_depth" -gt 16 ] && myos_die "$MYOS_E_USAGE" "stack group nested too deep: $*"
|
||||
for _ref in "$@"; do
|
||||
_val=$(myos_group_value "$_ref")
|
||||
if [ -n "$_val" ]; then
|
||||
# shellcheck disable=SC2086 # the group value is a list of references
|
||||
MYOS_GROUP_DEPTH=$((_depth + 1)) myos_group_expand $_val
|
||||
else
|
||||
printf '%s\n' "$_ref"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# myos_group_value REF the list a group expands to, empty when not a group.
|
||||
# Groups are lowercase by convention (host, testing, coroot, default): without
|
||||
# that rule any environment variable sharing a stack name would be expanded,
|
||||
# which is how the make engine behaved. The character class is spelled out
|
||||
# because a-z also matches uppercase under a dictionary collation (fr_FR).
|
||||
myos_group_value() {
|
||||
case $1 in .|/*|*/*|*:*) return 0 ;; esac
|
||||
case $1 in *[![:lower:][:digit:]_-]*) return 0 ;; esac
|
||||
_v=$(myos_var "$1")
|
||||
[ -n "$_v" ] && { printf '%s' "$_v"; return 0; }
|
||||
_IFS=$IFS; IFS=:
|
||||
for _d in $(myos_path); do
|
||||
IFS=$_IFS
|
||||
[ -f "$_d/$1.env" ] && { _v=$(sed -n "s/^$1=//p" "$_d/$1.env" | tail -1 | tr -d '"'); }
|
||||
[ -z "$_v" ] && [ -f "$_d/$1.mk" ] && { _v=$(myos_mk_group "$_d/$1.mk" "$1"); }
|
||||
[ -z "$_v" ] && [ -f "$_d/$1/$1.mk" ] && { _v=$(myos_mk_group "$_d/$1/$1.mk" "$1"); }
|
||||
[ -n "$_v" ] && { printf '%s' "$_v"; return 0; }
|
||||
IFS=:
|
||||
done
|
||||
IFS=$_IFS
|
||||
return 0
|
||||
}
|
||||
|
||||
# myos_mk_group FILE NAME read `name ?= a b c` out of a legacy .mk snippet
|
||||
myos_mk_group() {
|
||||
sed -n "s/^$2[[:space:]]*[?:]\{0,1\}=[[:space:]]*//p" "$1" 2>/dev/null | tail -1
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#shellcheck shell=sh
|
||||
# str: string helpers ported from make/utils.mk and make/def.mk.
|
||||
|
||||
# myos_lower STRING / myos_upper STRING
|
||||
myos_lower() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]'; }
|
||||
myos_upper() { printf '%s' "$1" | tr '[:lower:]-.' '[:upper:]__'; }
|
||||
|
||||
# myos_name STRING compose-project-safe name: lowercase, no . - _
|
||||
# (make: $(subst _,,$(subst -,,$(subst .,,$(call LOWERCASE,$(1))))))
|
||||
myos_name() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -d '._-'; }
|
||||
|
||||
# myos_slugify STRING keep [a-z0-9_], everything else becomes _
|
||||
myos_slugify() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_]/_/g'; }
|
||||
|
||||
# myos_reverse WORDS... reverse the order of space separated words
|
||||
myos_reverse() {
|
||||
_out=
|
||||
for _w in $1; do _out="$_w${_out:+ }$_out"; done
|
||||
printf '%s' "$_out"
|
||||
}
|
||||
|
||||
# myos_verle A B true when version A <= B (make: verle)
|
||||
myos_verle() {
|
||||
[ -n "$1" ] || return 1
|
||||
[ -n "$2" ] || return 1
|
||||
[ "$1" = "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" ]
|
||||
}
|
||||
|
||||
# myos_verlt A B true when version A < B
|
||||
myos_verlt() {
|
||||
[ "$1" = "$2" ] && return 1
|
||||
myos_verle "$1" "$2"
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
#shellcheck shell=sh
|
||||
# tags: fabio route tags derived from stack variables.
|
||||
#
|
||||
# Ported from make/apps/def.mk (uri, url, urlprefix, urlprefixs, tagprefix,
|
||||
# envprefix, servicenvs). Registrator publishes the SERVICE_<port>_TAGS label
|
||||
# to consul, fabio routes on the urlprefix- tags it finds there.
|
||||
|
||||
# myos_var NAME value of the variable named NAME, empty when unset
|
||||
myos_var() {
|
||||
[ -n "${1:-}" ] || return 0
|
||||
eval "printf '%s' \"\${$1:-}\""
|
||||
}
|
||||
|
||||
# myos_uri SERVICE PORT [BASE_URI]
|
||||
# <service>.<base uri>, unless <SERVICE>_SERVICE[_<port>]_NAME overrides the prefix
|
||||
myos_uri() {
|
||||
_svc=$1; _port=${2:-}; _base=${3:-${APP_URI:-}}
|
||||
_u=$(myos_upper "$_svc")
|
||||
_name=$(myos_var "${_u}_SERVICE_${_port}_NAME")
|
||||
[ -n "$_name" ] || _name=$(myos_var "${_u}_SERVICE_NAME")
|
||||
[ -n "$_name" ] || _name=$_svc
|
||||
_out=
|
||||
for _b in $_base; do _out="${_out:+$_out }${_name}.${_b}"; done
|
||||
printf '%s' "$_out"
|
||||
}
|
||||
|
||||
# myos_url SERVICE PORT [BASE_URI]
|
||||
myos_url() {
|
||||
_out=
|
||||
for _u in $(myos_uri "$@"); do _out="${_out:+$_out }${APP_SCHEME:-http}://$_u"; done
|
||||
printf '%s' "$_out"
|
||||
}
|
||||
|
||||
# myos_urlprefix [PATH] [OPTS] [URIS]
|
||||
# one comma separated "urlprefix-<uri><path>* [opts]" per uri
|
||||
myos_urlprefix() {
|
||||
_path=${1:-}; _opts=${2:-}; _uris=${3:-${APP_URI:-}}
|
||||
_out=
|
||||
for _u in $_uris; do
|
||||
_tag="urlprefix-${_u}${_path}${MYOS_URL_SUFFIX:-*}${_opts:+ $_opts}"
|
||||
_out="${_out:+$_out,}$_tag"
|
||||
done
|
||||
printf '%s' "$_out"
|
||||
}
|
||||
|
||||
# myos_envprefix STACK PORT KEYS...
|
||||
# "key=value" for each <STACK>_SERVICE_<port>_<KEY> that is set
|
||||
myos_envprefix() {
|
||||
_stack=$1; _port=$2; shift 2
|
||||
_out=
|
||||
for _k in "$@"; do
|
||||
_v=$(myos_var "$(myos_upper "${_stack}_SERVICE_${_port}_${_k}")")
|
||||
[ -n "$_v" ] && _out="${_out:+$_out }${_k}=${_v}"
|
||||
done
|
||||
printf '%s' "$_out"
|
||||
}
|
||||
|
||||
# myos_tagprefix STACK PORT [URI_KEYS...]
|
||||
# the fabio tag of a service, assembled from its PATH, OPTS and URIS variables
|
||||
myos_tagprefix() {
|
||||
_stack=$1; _port=$2; shift 2
|
||||
_u=$(myos_upper "$_stack")
|
||||
_path=$(myos_var "${_u}_SERVICE_${_port}_PATH"); [ -n "$_path" ] || _path=$(myos_var "${_u}_SERVICE_PATH")
|
||||
_opts=$(myos_var "${_u}_SERVICE_${_port}_OPTS"); [ -n "$_opts" ] || _opts=$(myos_var "${_u}_SERVICE_OPTS")
|
||||
[ -n "$_opts" ] || _opts=$(myos_envprefix "$_stack" "$_port" allow auth deny prepend proto register strip)
|
||||
_uris=
|
||||
for _k in "$@"; do
|
||||
_v=$(myos_var "${_u}_SERVICE_${_port}_${_k}"); [ -n "$_v" ] && _uris="${_uris:+$_uris }$_v"
|
||||
done
|
||||
[ -n "$_uris" ] || _uris=$(myos_var "${_u}_SERVICE_${_port}_URIS")
|
||||
[ -n "$_uris" ] || _uris=$(myos_uri "$_stack" "$_port")
|
||||
myos_urlprefix "$_path" "$_opts" "$_uris"
|
||||
}
|
||||
@@ -43,7 +43,7 @@ DOCKER_COMPOSE_RUN_WORKDIR ?= $(if $(DOCKER_COMPOSE_WORKDIR),-w $(DOCKER_CO
|
||||
DOCKER_COMPOSE_SERVICE_NAME ?= $(subst _,-,$(DOCKER_COMPOSE_PROJECT_NAME))
|
||||
DOCKER_COMPOSE_UP_OPTIONS ?= -d
|
||||
DOCKER_IMAGE_TAG ?= $(if $(filter true,$(DEPLOY)),$(if $(filter $(ENV),$(ENV_DEPLOY)),$(VERSION)),$(if $(DRONE_BUILD_NUMBER),$(DRONE_BUILD_NUMBER),latest))
|
||||
DOCKER_IMAGES ?= $(patsubst %/,%,$(patsubst docker/%,%,$(dir $(wildcard docker/*/Dockerfile))))
|
||||
DOCKER_IMAGES ?= $(foreach dir,$(DOCKER_DIR),$(patsubst $(dir)/%/Dockerfile,%,$(wildcard $(dir)/*/Dockerfile)))
|
||||
DOCKER_PLUGIN ?= rexray/s3fs:latest
|
||||
DOCKER_PLUGIN_ARGS ?= $(foreach var,$(DOCKER_PLUGIN_VARS),$(if $(DOCKER_PLUGIN_$(var)),$(var)='$(DOCKER_PLUGIN_$(var))'))
|
||||
DOCKER_PLUGIN_OPTIONS ?= --grant-all-permissions
|
||||
@@ -109,11 +109,7 @@ define docker-compose
|
||||
$(if $(COMPOSE_FILE),
|
||||
$(if $(DOCKER_COMPOSE),
|
||||
$(call env-exec,$(RUN) $(DOCKER_COMPOSE) $(DOCKER_COMPOSE_ARGS) $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) $(1))
|
||||
, $(if $(DOCKER_RUN),
|
||||
$(call docker-build,$(call docker-path,compose),docker/compose,$(COMPOSE_VERSION))
|
||||
$(call docker-run,docker/compose:$(COMPOSE_VERSION) $(DOCKER_COMPOSE_ARGS),$(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) $(1))
|
||||
, $(call env-exec,$(RUN) docker-compose $(DOCKER_COMPOSE_ARGS) $(patsubst %,-f %,$(COMPOSE_FILE)) -p $(COMPOSE_PROJECT_NAME) $(1))
|
||||
)
|
||||
, $(call ERROR,docker compose >= $(COMPOSE_VERSION) not found: install the docker compose plugin or docker-compose)
|
||||
)
|
||||
)
|
||||
endef
|
||||
@@ -156,7 +152,7 @@ define docker-stack-update
|
||||
$(eval stack_update := $(patsubst %.yml,%,$(notdir $(1))))
|
||||
$(eval stack_name := $(firstword $(subst :, ,$(stack_update))))
|
||||
$(eval stack_version := $(or $(2),$(if $(findstring :,$(stack_update)),$(lastword $(subst :, ,$(stack_update))),latest)))
|
||||
$(eval stack_path := $(patsubst %/,%,$(or $(3),$(realpath $(foreach stack_dir,$(STACK_DIR),$(if $(findstring /,$(1)),$(if $(wildcard $(stack_dir)/$(1) $(stack_dir)/$(1).yml),$(stack_dir)/$(if $(findstring .yml,$(1)),$(dir $(1)),$(if $(wildcard $(stack_dir)/$(1).yml),$(dir $(1)),$(1))),$(if $(wildcard $(stack_dir)/$(stackz)/$(1) $(stack_dir)/$(stackz)/$(1).yml),$(stack_dir)/$(stackz)/$(if $(findstring .yml,$(1)),$(dir $(1)),$(if $(wildcard $(stack_dir)/$(stackz)/$(1).yml),$(dir $(1)),$(1))),$(dir $(1)))))),$(foreach stack_dir,$(STACK_DIR),$(firstword $(wildcard $(stack_dir)/$(stackz)/$(stack_name) $(stack_dir)/$(stackz) $(stack_dir)/$(stack_name))))))))
|
||||
$(eval stack_path := $(patsubst %/,%,$(or $(3),$(realpath $(foreach stack_dir,$(STACK_DIR),$(if $(findstring /,$(1)),$(if $(wildcard $(stack_dir)/$(1) $(stack_dir)/$(1).yml),$(stack_dir)/$(if $(findstring .yml,$(1)),$(dir $(1)),$(if $(wildcard $(stack_dir)/$(1).yml),$(dir $(1)),$(1))),$(if $(wildcard $(stack_dir)/$(stackz)/$(1) $(stack_dir)/$(stackz)/$(1).yml),$(stack_dir)/$(stackz)/$(if $(findstring .yml,$(1)),$(dir $(1)),$(if $(wildcard $(stack_dir)/$(stackz)/$(1).yml),$(dir $(1)),$(1))),$(dir $(1))))))),$(realpath $(foreach stack_dir,$(STACK_DIR),$(firstword $(wildcard $(stack_dir)/$(stackz)/$(stack_name) $(stack_dir)/$(stackz) $(stack_dir)/$(stack_name))))))))
|
||||
$(call debug,stack_path)
|
||||
$(call compose-file,$(stack_path),docker-compose $(stack_name),$(COMPOSE_FILE_SUFFIX) $(stack_version))
|
||||
$(if $(wildcard $(stack_path)/.env.dist),$(call .env,,$(stack_path)/.env.dist,$(wildcard $(CONFIG)/$(ENV)/$(APP)/.env $(stack_path)/.env.$(ENV) .env)))
|
||||
|
||||
+6
-12
@@ -1,9 +1,9 @@
|
||||
##
|
||||
# DOCKER
|
||||
|
||||
# target docker-build: Fire docker-image-myos, Call docker-build-% target for each DOCKER_IMAGES
|
||||
# target docker-build: Call docker-build-% target for each DOCKER_IMAGES
|
||||
.PHONY: docker-build
|
||||
docker-build: docker-image-myos
|
||||
docker-build:
|
||||
$(foreach image,$(or $(SERVICE),$(DOCKER_IMAGES)),$(call make,docker-build-$(image)))
|
||||
|
||||
# target docker-build-%: Call docker-build for each Dockerfile in docker/% folder
|
||||
@@ -27,10 +27,10 @@ docker-commit: stack
|
||||
docker-commit-%: stack
|
||||
$(foreach service,$(or $(SERVICE),$(SERVICES)),$(call docker-commit,$(service),,,$*))
|
||||
|
||||
# target docker-compose-build: Fire docker-image-myos, Call docker-compose build SERVICE
|
||||
# target docker-compose-build: Call docker-compose build SERVICE
|
||||
.PHONY: docker-compose-build
|
||||
docker-compose-build: DOCKER_RUN_OPTIONS += -it
|
||||
docker-compose-build: docker-image-myos stack
|
||||
docker-compose-build: stack
|
||||
$(call docker-compose,build $(DOCKER_BUILD_ARGS) $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
# target docker-compose-config: Call docker-compose config
|
||||
@@ -110,18 +110,12 @@ docker-compose-start: stack
|
||||
docker-compose-stop: stack
|
||||
$(call docker-compose,stop $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
# target docker-compose-up: Fire docker-image-myos, Call docker-compose up SERVICE
|
||||
# target docker-compose-up: Call docker-compose up SERVICE
|
||||
.PHONY: docker-compose-up
|
||||
docker-compose-up: DOCKER_RUN_OPTIONS += -it
|
||||
docker-compose-up: docker-image-myos bootstrap-stack stack
|
||||
docker-compose-up: bootstrap-stack stack
|
||||
$(call docker-compose,up $(DOCKER_COMPOSE_UP_OPTIONS) $(if $(filter $(SERVICE),$(SERVICES)),$(SERVICE)))
|
||||
|
||||
# target docker-image-myos: Call myos-docker-build-% target for each MYOS_DOCKER_IMAGES
|
||||
.PHONY: docker-image-myos
|
||||
docker-image-myos: MAKE_VARS += DOCKER_REPOSITORY STACK
|
||||
docker-image-myos:
|
||||
$(foreach image,$(subst $(quote),,$(MYOS_DOCKER_IMAGES)),$(call make,docker-build-$(image),$(MYOS)))
|
||||
|
||||
# target docker-image-rm: Remove docker images matching DOCKER_REPOSITORY
|
||||
.PHONY: docker-image-rm
|
||||
docker-image-rm:
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ HOST_DOCKER_VOLUME ?= $(HOST_COMPOSE_PROJECT_NAME)
|
||||
HOST_GID ?= $(HOST_UID)
|
||||
HOST_UID ?= 123
|
||||
HOST_STACK ?= $(filter host,$(firstword $(subst /, ,$(STACK))))
|
||||
MYOS_STACK ?= $(wildcard $(foreach stack_dir,$(STACK_DIR),$(stack_dir)/myos))
|
||||
MYOS_STACK ?= $(if $(filter . myos,$(MYOS)),$(realpath $(MYOS)/share/compose))
|
||||
MYOS_STACK_FILE ?= networks volumes
|
||||
RESU_DOCKER_REPOSITORY ?= $(subst -,/,$(USER_COMPOSE_PROJECT_NAME))
|
||||
SHARE_DIR ?= . .. ~/.local/share /usr/local/share /usr/share
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ include $(filter-out $(wildcard $(MAKE_FILE) $(MAKE_FIRST) $(MAKE_LATEST)),$(wil
|
||||
## it includes $(MAKE_DIR)/$(MAKE_SUBDIRS)/*.mk
|
||||
include $(foreach subdir,$(MAKE_SUBDIRS),$(filter-out $(wildcard $(MAKE_DIR)/$(subdir)/def.mk $(MAKE_DIR)/$(subdir)/def.*.mk),$(wildcard $(MAKE_DIR)/$(subdir)/*.mk)))
|
||||
## if not in $(MYOS) nor $(MONOREPO), it includes def.mk def.*.mk */def.mk */def.*.mk *.mk */*.mk
|
||||
include $(if $(filter-out . myos,$(MYOS)),$(wildcard def.mk def.*.mk */def.mk */def.*.mk) $(filter-out $(wildcard def.mk def.*.mk */def.mk */def.*.mk stack/*.mk),$(wildcard *.mk */*.mk)))
|
||||
include $(if $(filter-out . myos,$(MYOS)),$(wildcard def.mk def.*.mk */def.mk */def.*.mk) $(filter-out $(wildcard def.mk def.*.mk */def.mk */def.*.mk $(STACK_DIR_NAME)/*.mk),$(wildcard *.mk */*.mk)))
|
||||
## it includes $(STACK_DIR)/*.mk $(STACK_DIR)/*/*.mk
|
||||
include $(foreach stack_dir,$(STACK_DIR),$(wildcard $(stack_dir)/*.mk $(stack_dir)/*/*.mk))
|
||||
## it includes $(MAKE_LATEST)
|
||||
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
APP_SERVICE_8080_TAGS=urlprefix-app.${DOMAIN}/*
|
||||
POSTGRES_PASSWORD=changeme
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
MYOS ?= /usr/local/lib/myos
|
||||
-include $(MYOS)/make/include.mk
|
||||
@@ -0,0 +1,4 @@
|
||||
services:
|
||||
app:
|
||||
environment:
|
||||
DEBUG: "true"
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
services:
|
||||
app:
|
||||
image: alpine:3.20
|
||||
command: sleep infinity
|
||||
environment:
|
||||
APP_DOMAIN: ${APP_DOMAIN}
|
||||
DOMAIN: ${DOMAIN}
|
||||
labels:
|
||||
- SERVICE_8080_NAME=${COMPOSE_SERVICE_NAME}-app-8080
|
||||
- SERVICE_8080_TAGS=${APP_SERVICE_8080_TAGS:-urlprefix-app.localhost/*}
|
||||
networks:
|
||||
- default
|
||||
- private
|
||||
@@ -0,0 +1,5 @@
|
||||
services:
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
services:
|
||||
web:
|
||||
image: nginx:alpine
|
||||
@@ -0,0 +1,6 @@
|
||||
services:
|
||||
myos:
|
||||
image: ${USER_DOCKER_IMAGE:-myos:latest}
|
||||
container_name: ${USER_COMPOSE_PROJECT_NAME:-user}
|
||||
volumes:
|
||||
- ${USER_DOCKER_VOLUME:-user}:/tmp/ssh-agent
|
||||
@@ -0,0 +1 @@
|
||||
default ?= postgres redis
|
||||
@@ -0,0 +1,3 @@
|
||||
services:
|
||||
drone:
|
||||
image: drone/drone:1.6
|
||||
@@ -0,0 +1,2 @@
|
||||
DRONE_SERVER_HOST ?= drone.$(DOMAIN)
|
||||
ENV_VARS += DRONE_SERVER_HOST
|
||||
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
drone:
|
||||
image: drone/drone:${DRONE_VERSION:-latest}
|
||||
environment:
|
||||
DRONE_SERVER_HOST: ${DRONE_SERVER_HOST:-drone.localhost}
|
||||
networks:
|
||||
- private
|
||||
@@ -0,0 +1,4 @@
|
||||
services:
|
||||
nginx:
|
||||
volumes:
|
||||
- dns:/dns
|
||||
@@ -0,0 +1,4 @@
|
||||
services:
|
||||
nginx:
|
||||
volumes:
|
||||
- www:/var/www
|
||||
@@ -0,0 +1,6 @@
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: ${HOST_COMPOSE_PROJECT_NAME:-localhost}-nginx
|
||||
ports:
|
||||
- "8080:80"
|
||||
@@ -0,0 +1,3 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:9.6
|
||||
@@ -0,0 +1,4 @@
|
||||
services:
|
||||
postgres:
|
||||
ports:
|
||||
- "5432:5432"
|
||||
@@ -0,0 +1,13 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_VERSION:-latest}
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||
labels:
|
||||
- SERVICE_5432_NAME=${COMPOSE_SERVICE_NAME}-postgres-5432
|
||||
networks:
|
||||
- private
|
||||
volumes:
|
||||
- postgres:/var/lib/postgresql/data
|
||||
volumes:
|
||||
postgres:
|
||||
@@ -0,0 +1,5 @@
|
||||
services:
|
||||
redis:
|
||||
image: redis:alpine
|
||||
networks:
|
||||
- private
|
||||
@@ -0,0 +1 @@
|
||||
testing ?= drone/drone redis
|
||||
@@ -0,0 +1,12 @@
|
||||
services:
|
||||
consul:
|
||||
image: hashicorp/consul:1.15
|
||||
container_name: ${HOST_COMPOSE_PROJECT_NAME:-localhost}-consul
|
||||
network_mode: host
|
||||
restart: always
|
||||
environment:
|
||||
CONSUL_HTTP_TOKEN: ${HOST_CONSUL_HTTP_TOKEN}
|
||||
volumes:
|
||||
- consul:/consul/data
|
||||
volumes:
|
||||
consul:
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
services:
|
||||
fabio:
|
||||
image: fabiolb/fabio:1.6.3
|
||||
container_name: ${HOST_COMPOSE_PROJECT_NAME:-localhost}-fabio
|
||||
depends_on: [consul]
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
environment:
|
||||
FABIO_REGISTRY_CONSUL_ADDR: ${DOCKER_HOST_INET4:-127.0.0.1}:8500
|
||||
FABIO_LOG_ACCESS_TARGET: ${HOST_FABIO_LOG_ACCESS:-}
|
||||
networks:
|
||||
- public
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
# Stack host: consul + fabio (80/443) + registrator, one instance per host.
|
||||
host ?= host/consul host/fabio host/registrator
|
||||
|
||||
.PHONY: host
|
||||
host:
|
||||
$(call make,up STACK="$(host)")
|
||||
|
||||
.PHONY: host-down
|
||||
host-down:
|
||||
$(call make,down STACK="$(host)")
|
||||
@@ -0,0 +1,9 @@
|
||||
services:
|
||||
registrator:
|
||||
image: gliderlabs/registrator:master
|
||||
container_name: ${HOST_COMPOSE_PROJECT_NAME:-localhost}-registrator
|
||||
network_mode: host
|
||||
depends_on: [consul]
|
||||
command: -internal=false -useIpFromLabel SERVICE_ADDRESS consul://127.0.0.1:8500
|
||||
volumes:
|
||||
- ${DOCKER_SOCKET_LOCATION:-/var/run/docker.sock}:/tmp/docker.sock
|
||||
@@ -0,0 +1,35 @@
|
||||
# Intentional differences between the legacy make engine and the bash CLI
|
||||
|
||||
Golden expectations in `expected/` are recorded from the legacy engine
|
||||
(git tag `legacy-1.0-beta`). When the CLI intentionally behaves differently the
|
||||
case gets an override in `expected.cli/<case>.txt` and a line here.
|
||||
`make test-golden MYOS_ENGINE=cli` checks the CLI against those overrides.
|
||||
|
||||
## Shape of the output
|
||||
|
||||
| what | legacy | cli |
|
||||
|---|---|---|
|
||||
| sub-make line | every command is preceded by the recursive `make ... docker-compose-up STACK=...` it re-enters | no recursion, so no such line |
|
||||
| compose invocation | `docker --log-level=error compose --ansi=auto -f ... -p ...` | `docker compose -f ... -p ... --project-directory <dir of the first file>` |
|
||||
| several stacks in one project | one `docker compose up` per stack, each with the full file list, so N stacks meant N identical calls | a single call per project |
|
||||
| network creation | `sh -c docker network create <n> >/dev/null 2>&1` on every up | `docker network create <n>`, only when the network is missing |
|
||||
| unknown command | prints a warning and exits 0 | prints an error and exits 2 |
|
||||
| unknown stack | silently resolves to nothing and exits 0 | exits 3 with the search path |
|
||||
|
||||
## Values
|
||||
|
||||
| what | legacy | cli | why |
|
||||
|---|---|---|---|
|
||||
| `APP` in wrapper mode | `myos`, the framework directory itself | the stack, or the directory being run | the legacy value described the framework, not the thing being deployed. The real `up` path already passed `APP_NAME=<stack>` to its sub-make, so the CLI matches what actually ran; only the `print-` target disagreed. |
|
||||
| `COMPOSE_PROJECT_NAME` for a catalogue stack in wrapper mode | `<user>-myos-<env>` for every stack | `<user>-<env>-<stack>` | same reason: two different stacks shared one project name when printed, but not when run |
|
||||
| `COMPOSE_PROJECT_NAME` default order | `<user>-<app>-<env>` | `<user>-<env>-<app>` | environments are shared across apps, so the environment reads better in the middle. `MYOS_PROJECT_FORMAT=user-app-env` restores the old order and is what `myos migrate pin` writes into existing deployments. |
|
||||
| compose files of the current directory | ignored in wrapper mode: only a `STACK` was ever loaded | loaded, as a stack named after the directory | this is the point of unifying the two modes |
|
||||
| overlay order for several suffixes | the order the `COMPOSE_FILE_*` variables happened to be declared in | sorted by suffix name | a compose overlay wins over the ones before it, so the order has to be predictable rather than depend on where a variable was set |
|
||||
| framework overlays | `stack/myos/*.yml` | `share/compose/*.yml` | the catalogue moved to myos-stacks; these files stay with the framework |
|
||||
|
||||
## Tag helpers
|
||||
|
||||
| case | delta | why |
|
||||
|---|---|---|
|
||||
| `myos_urlprefix` with several uris | the bash port joins tags with `,`, the make macro emits `tag ,tag` | the make template ends with ` $(2)` (options), so an empty option list leaves a space before the comma. Harmless but sloppy; every tag written by hand on the fleet uses the clean form. |
|
||||
| `myos_urlprefix` with options passed inside the path argument | the bash port keeps `*` right after the path (`urlprefix-host:443/* proto=https`), the make macro appends it after the options (`urlprefix-host:443/ proto=https*`) | only reachable by stuffing options into argument 1, which the stale example in `make/apps/def.mk` did. Through `tagprefix`, the real code path, both engines agree. |
|
||||
@@ -0,0 +1,72 @@
|
||||
# name | fixture | args
|
||||
#
|
||||
# `help` is deliberately absent: it renders the comments of the Makefile, so it
|
||||
# would break on every edit to a dev target rather than on a change of behaviour.
|
||||
host-print-project | host-project | print-COMPOSE_PROJECT_NAME STACK=host/consul
|
||||
host-print-compose-file | host-project | print-COMPOSE_FILE STACK=host/consul
|
||||
host-print-stack-dir | host-project | print-STACK_DIR STACK=host/consul
|
||||
host-print-env-vars | host-project | print-ENV_VARS STACK=host/consul
|
||||
host-print-suffix | host-project | print-COMPOSE_FILE_SUFFIX STACK=host/consul
|
||||
host-print-network-default | host-project | print-DOCKER_NETWORK_DEFAULT STACK=host/consul
|
||||
host-print-network-private | host-project | print-DOCKER_NETWORK_PRIVATE STACK=host/consul
|
||||
host-print-network-public | host-project | print-DOCKER_NETWORK_PUBLIC STACK=host/consul
|
||||
host-print-host-stack | host-project | print-HOST_STACK STACK=host/consul
|
||||
host-print-app | host-project | print-APP STACK=host/consul
|
||||
host-up-consul | host-project | up STACK=host/consul
|
||||
host-up-two | host-project | up STACK="host/consul host/fabio"
|
||||
host-up-group | host-project | up STACK=host
|
||||
host-target | host-project | host
|
||||
host-down-group | host-project | down STACK=host
|
||||
host-config | host-project | config STACK=host/fabio
|
||||
host-ps | host-project | ps STACK=host/consul
|
||||
host-logs | host-project | logs STACK=host/consul
|
||||
host-stack-host-config | host-project | stack-host-config
|
||||
host-exec | host-project | exec STACK=host/consul SERVICE=consul ARGS='consul members'
|
||||
host-env-master | host-project | print-COMPOSE_FILE STACK=host/consul ENV=master
|
||||
host-print-project-env-master | host-project | print-COMPOSE_PROJECT_NAME STACK=host/consul ENV=master
|
||||
app-print-project | app-git | print-COMPOSE_PROJECT_NAME
|
||||
app-print-compose-file | app-git | print-COMPOSE_FILE
|
||||
app-print-app | app-git | print-APP
|
||||
app-print-stack | app-git | print-STACK
|
||||
app-up | app-git | up
|
||||
app-up-env-master | app-git | up ENV=master
|
||||
app-config | app-git | config
|
||||
app-down | app-git | down
|
||||
app-run | app-git | run SERVICE=app ARGS='id'
|
||||
app-scale | app-git | scale SERVICE=app NUM=2
|
||||
app-print-service-name | app-git | print-COMPOSE_SERVICE_NAME
|
||||
app-print-repository | app-git | print-DOCKER_REPOSITORY
|
||||
nogit-print-project | app-nogit | print-COMPOSE_PROJECT_NAME
|
||||
nogit-print-app | app-nogit | print-APP
|
||||
nogit-up | app-nogit | up
|
||||
cat-postgres-compose-file | app-nogit | print-COMPOSE_FILE STACK=postgres
|
||||
cat-postgres-project | app-nogit | print-COMPOSE_PROJECT_NAME STACK=postgres
|
||||
cat-postgres-up | app-nogit | up STACK=postgres
|
||||
cat-postgres-version | app-nogit | print-COMPOSE_FILE STACK=postgres:9.6
|
||||
cat-postgres-env-master | app-nogit | print-COMPOSE_FILE STACK=postgres ENV=master
|
||||
cat-user-project | app-nogit | print-COMPOSE_PROJECT_NAME STACK=User/User
|
||||
cat-user-compose-file | app-nogit | print-COMPOSE_FILE STACK=User/User
|
||||
cat-user-network | app-nogit | print-DOCKER_NETWORK STACK=User/User
|
||||
cat-group-testing | app-nogit | print-COMPOSE_FILE STACK=testing
|
||||
cat-group-testing-up | app-nogit | up STACK=testing
|
||||
cat-group-default-up | app-nogit | up STACK=default
|
||||
cat-drone-version | app-nogit | print-COMPOSE_FILE STACK=drone/drone:1.6
|
||||
cat-drone-env-vars | app-nogit | print-ENV_VARS STACK=drone/drone
|
||||
cat-nginx-www | app-nogit | print-COMPOSE_FILE STACK=host/nginx COMPOSE_FILE_WWW=true
|
||||
cat-nginx-www-dns | app-nogit | print-COMPOSE_FILE STACK=host/nginx COMPOSE_FILE_WWW=true COMPOSE_FILE_DNS=true
|
||||
cat-nginx-project | app-nogit | print-COMPOSE_PROJECT_NAME STACK=host/nginx
|
||||
cat-unknown-stack | app-nogit | print-COMPOSE_FILE STACK=doesnotexist
|
||||
cat-unknown-target | app-nogit | doesnotexist
|
||||
inc-app-print-project | app-git | @make print-COMPOSE_PROJECT_NAME
|
||||
inc-app-print-compose-file | app-git | @make print-COMPOSE_FILE
|
||||
inc-app-print-app | app-git | @make print-APP
|
||||
inc-app-up | app-git | @make up
|
||||
inc-app-up-env-master | app-git | @make up ENV=master
|
||||
inc-app-config | app-git | @make config
|
||||
inc-app-down | app-git | @make down
|
||||
inc-app-ps | app-git | @make ps
|
||||
inc-app-print-service-name | app-git | @make print-COMPOSE_SERVICE_NAME
|
||||
inc-app-print-env-vars | app-git | @make print-ENV_VARS
|
||||
inc-app-print-network-default | app-git | @make print-DOCKER_NETWORK_DEFAULT
|
||||
inc-app-stack-postgres-up | app-git | @make up STACK=postgres
|
||||
inc-app-unknown-target | app-git | @make doesnotexist
|
||||
@@ -0,0 +1,2 @@
|
||||
docker compose -f @WD@/docker-compose.yml -f @WD@/docker-compose.local.yml -f @WD@/docker/docker-compose.yml -f @MYOS@/share/compose/networks.yml -p tester-wd-local --project-directory @WD@ config
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
docker compose -f @WD@/docker-compose.yml -f @WD@/docker-compose.local.yml -f @WD@/docker/docker-compose.yml -f @MYOS@/share/compose/networks.yml -p tester-wd-local --project-directory @WD@ down
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
APP wd
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
COMPOSE_FILE @WD@/docker-compose.yml @WD@/docker-compose.local.yml @WD@/docker/docker-compose.yml @MYOS@/share/compose/networks.yml
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
COMPOSE_PROJECT_NAME tester-wd-local
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
DOCKER_REPOSITORY tester/wd/local
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
COMPOSE_SERVICE_NAME tester-wd-local
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
STACK ./
|
||||
[exit 0]
|
||||
@@ -0,0 +1,26 @@
|
||||
ERROR: unknown command: run
|
||||
Usage: myos [options] <command> [stack...] [VAR=value...] [-- args...]
|
||||
|
||||
Options:
|
||||
-C DIR work in DIR instead of the current directory
|
||||
-e ENV environment (default: local, or ENV from the config)
|
||||
-H HOSTS run on remote hosts instead (comma separated, or "all")
|
||||
-n, --dry-run print the commands instead of running them
|
||||
-v, --verbose show what myos does
|
||||
-d, --debug show every command
|
||||
-h, --help this help
|
||||
|
||||
Commands:
|
||||
up down start stop restart recreate manage the containers of a stack
|
||||
ps logs config exec run inspect and enter them
|
||||
ls [--groups] list the stacks myos can see
|
||||
env [VAR...] show resolved variables
|
||||
doctor check the installation
|
||||
version print the myos version
|
||||
|
||||
Stacks:
|
||||
myos up the stack of the current directory
|
||||
myos up host a group, expanded from host=... in a .env or .mk
|
||||
myos up host/fabio a single stack
|
||||
myos up postgres:9.6 a versioned stack
|
||||
[exit 2]
|
||||
@@ -0,0 +1,26 @@
|
||||
ERROR: unknown command: scale
|
||||
Usage: myos [options] <command> [stack...] [VAR=value...] [-- args...]
|
||||
|
||||
Options:
|
||||
-C DIR work in DIR instead of the current directory
|
||||
-e ENV environment (default: local, or ENV from the config)
|
||||
-H HOSTS run on remote hosts instead (comma separated, or "all")
|
||||
-n, --dry-run print the commands instead of running them
|
||||
-v, --verbose show what myos does
|
||||
-d, --debug show every command
|
||||
-h, --help this help
|
||||
|
||||
Commands:
|
||||
up down start stop restart recreate manage the containers of a stack
|
||||
ps logs config exec run inspect and enter them
|
||||
ls [--groups] list the stacks myos can see
|
||||
env [VAR...] show resolved variables
|
||||
doctor check the installation
|
||||
version print the myos version
|
||||
|
||||
Stacks:
|
||||
myos up the stack of the current directory
|
||||
myos up host a group, expanded from host=... in a .env or .mk
|
||||
myos up host/fabio a single stack
|
||||
myos up postgres:9.6 a versioned stack
|
||||
[exit 2]
|
||||
@@ -0,0 +1,4 @@
|
||||
docker network create tester-master
|
||||
docker network create testhost
|
||||
docker compose -f @WD@/docker-compose.yml -f @WD@/docker/docker-compose.yml -f @MYOS@/share/compose/networks.yml -p tester-wd-master --project-directory @WD@ up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,4 @@
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @WD@/docker-compose.yml -f @WD@/docker-compose.local.yml -f @WD@/docker/docker-compose.yml -f @MYOS@/share/compose/networks.yml -p tester-wd-local --project-directory @WD@ up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
ENV_VARS
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
COMPOSE_FILE @HOME@/.local/share/myos/stack/drone/drone.yml @HOME@/.local/share/myos/stack/drone/drone.1.6.yml @MYOS@/share/compose/networks.yml
|
||||
[exit 0]
|
||||
@@ -0,0 +1,7 @@
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @HOME@/.local/share/myos/stack/postgres/postgres.yml -f @HOME@/.local/share/myos/stack/postgres/postgres.local.yml -f @MYOS@/share/compose/networks.yml -p tester-postgres-local --project-directory @HOME@/.local/share/myos/stack/postgres up -d
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @HOME@/.local/share/myos/stack/redis/redis.yml -f @MYOS@/share/compose/networks.yml -p tester-redis-local --project-directory @HOME@/.local/share/myos/stack/redis up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,7 @@
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @HOME@/.local/share/myos/stack/drone/drone.yml -f @MYOS@/share/compose/networks.yml -p tester-drone-local --project-directory @HOME@/.local/share/myos/stack/drone up -d
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @HOME@/.local/share/myos/stack/redis/redis.yml -f @MYOS@/share/compose/networks.yml -p tester-redis-local --project-directory @HOME@/.local/share/myos/stack/redis up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
COMPOSE_FILE @HOME@/.local/share/myos/stack/host/nginx.yml @HOME@/.local/share/myos/stack/host/nginx.dns.yml @HOME@/.local/share/myos/stack/host/nginx.www.yml @MYOS@/share/compose/networks.yml @MYOS@/share/compose/volumes.dns.local.yml @MYOS@/share/compose/volumes.www.local.yml
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
COMPOSE_PROJECT_NAME tester-postgres-local
|
||||
[exit 0]
|
||||
@@ -0,0 +1,4 @@
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @HOME@/.local/share/myos/stack/postgres/postgres.yml -f @HOME@/.local/share/myos/stack/postgres/postgres.local.yml -f @MYOS@/share/compose/networks.yml -p tester-postgres-local --project-directory @HOME@/.local/share/myos/stack/postgres up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
COMPOSE_FILE @HOME@/.local/share/myos/stack/postgres/postgres.yml @HOME@/.local/share/myos/stack/postgres/postgres.local.yml @HOME@/.local/share/myos/stack/postgres/postgres.9.6.yml @MYOS@/share/compose/networks.yml
|
||||
[exit 0]
|
||||
@@ -0,0 +1,26 @@
|
||||
ERROR: unknown command: doesnotexist
|
||||
Usage: myos [options] <command> [stack...] [VAR=value...] [-- args...]
|
||||
|
||||
Options:
|
||||
-C DIR work in DIR instead of the current directory
|
||||
-e ENV environment (default: local, or ENV from the config)
|
||||
-H HOSTS run on remote hosts instead (comma separated, or "all")
|
||||
-n, --dry-run print the commands instead of running them
|
||||
-v, --verbose show what myos does
|
||||
-d, --debug show every command
|
||||
-h, --help this help
|
||||
|
||||
Commands:
|
||||
up down start stop restart recreate manage the containers of a stack
|
||||
ps logs config exec run inspect and enter them
|
||||
ls [--groups] list the stacks myos can see
|
||||
env [VAR...] show resolved variables
|
||||
doctor check the installation
|
||||
version print the myos version
|
||||
|
||||
Stacks:
|
||||
myos up the stack of the current directory
|
||||
myos up host a group, expanded from host=... in a .env or .mk
|
||||
myos up host/fabio a single stack
|
||||
myos up postgres:9.6 a versioned stack
|
||||
[exit 2]
|
||||
@@ -0,0 +1,2 @@
|
||||
docker compose -f @WD@/stack/host/fabio.yml -f @MYOS@/share/compose/networks.yml -p testhost --project-directory @WD@/stack/host config
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
docker compose -f @WD@/stack/host/consul.yml -f @WD@/stack/host/fabio.yml -f @WD@/stack/host/registrator.yml -f @MYOS@/share/compose/networks.yml -p testhost --project-directory @WD@/stack/host down
|
||||
[exit 0]
|
||||
@@ -0,0 +1,26 @@
|
||||
ERROR: unknown command: exec
|
||||
Usage: myos [options] <command> [stack...] [VAR=value...] [-- args...]
|
||||
|
||||
Options:
|
||||
-C DIR work in DIR instead of the current directory
|
||||
-e ENV environment (default: local, or ENV from the config)
|
||||
-H HOSTS run on remote hosts instead (comma separated, or "all")
|
||||
-n, --dry-run print the commands instead of running them
|
||||
-v, --verbose show what myos does
|
||||
-d, --debug show every command
|
||||
-h, --help this help
|
||||
|
||||
Commands:
|
||||
up down start stop restart recreate manage the containers of a stack
|
||||
ps logs config exec run inspect and enter them
|
||||
ls [--groups] list the stacks myos can see
|
||||
env [VAR...] show resolved variables
|
||||
doctor check the installation
|
||||
version print the myos version
|
||||
|
||||
Stacks:
|
||||
myos up the stack of the current directory
|
||||
myos up host a group, expanded from host=... in a .env or .mk
|
||||
myos up host/fabio a single stack
|
||||
myos up postgres:9.6 a versioned stack
|
||||
[exit 2]
|
||||
@@ -0,0 +1,2 @@
|
||||
docker compose -f @WD@/stack/host/consul.yml -f @MYOS@/share/compose/networks.yml -p testhost --project-directory @WD@/stack/host logs --follow --tail=100
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
APP consul
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
ENV_VARS
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
STACK_DIR
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
docker compose -f @WD@/stack/host/consul.yml -f @MYOS@/share/compose/networks.yml -p testhost --project-directory @WD@/stack/host ps
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
docker compose -f @WD@/stack/host/consul.yml -f @WD@/stack/host/fabio.yml -f @WD@/stack/host/registrator.yml -f @MYOS@/share/compose/networks.yml -p testhost --project-directory @WD@/stack/host config
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
ERROR: no stack given, and no compose file in @WD@
|
||||
[exit 2]
|
||||
@@ -0,0 +1,4 @@
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @WD@/stack/host/consul.yml -f @MYOS@/share/compose/networks.yml -p testhost --project-directory @WD@/stack/host up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,4 @@
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @WD@/stack/host/consul.yml -f @WD@/stack/host/fabio.yml -f @WD@/stack/host/registrator.yml -f @MYOS@/share/compose/networks.yml -p testhost --project-directory @WD@/stack/host up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,4 @@
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @WD@/stack/host/consul.yml -f @WD@/stack/host/fabio.yml -f @MYOS@/share/compose/networks.yml -p testhost --project-directory @WD@/stack/host up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
APP wd
|
||||
[exit 0]
|
||||
@@ -0,0 +1,2 @@
|
||||
COMPOSE_PROJECT_NAME tester-wd-local
|
||||
[exit 0]
|
||||
@@ -0,0 +1,4 @@
|
||||
docker network create tester-local
|
||||
docker network create testhost
|
||||
docker compose -f @WD@/docker-compose.yml -f @MYOS@/share/compose/networks.yml -p tester-wd-local --project-directory @WD@ up -d
|
||||
[exit 0]
|
||||
@@ -0,0 +1,3 @@
|
||||
make -o docker-stack-config MAKE_OLDFILE=docker-stack-config ENV=local DOCKER_COMPOSE=docker --log-level=error compose docker-compose-config STACK=myos APP_NAME=myos
|
||||
docker --log-level=error compose --ansi=auto -f @MYOS@/share/compose/networks.yml -p tester-myos-local config
|
||||
[exit 0]
|
||||
@@ -0,0 +1,3 @@
|
||||
make -o docker-stack-down MAKE_OLDFILE=docker-stack-down ENV=local DOCKER_COMPOSE=docker --log-level=error compose docker-compose-down STACK=myos APP_NAME=myos
|
||||
docker --log-level=error compose --ansi=auto -f @MYOS@/share/compose/networks.yml -p tester-myos-local down
|
||||
[exit 0]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user