Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 78 additions & 15 deletions internal/cli/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,10 @@ func install(ctx context.Context, f Flags) error {

controller := func() bool { return p.role == compose.RoleController }
runner := func() bool { return p.role == compose.RoleRunner }
kubernetes := func() bool { return controller() && p.mode == string(state.Kubernetes) }
// on Kubernetes : a controller (the whole chart) or a Runner (the chart's runner mode)
onKube := func() bool { return p.mode == string(state.Kubernetes) }
kubernetes := func() bool { return controller() && onKube() }
kubeRunner := func() bool { return runner() && onKube() }
composeCtl := func() bool { return controller() && !kubernetes() }
nativeMode := func() bool { return p.mode == string(state.Native) }

Expand Down Expand Up @@ -257,7 +260,7 @@ func install(ctx context.Context, f Flags) error {
return nil
}},
// compose : the folder and the instance
{label: "folder", skip: kubernetes, ask: func() error {
{label: "folder", skip: onKube, ask: func() error {
def := "/opt/ansibleforms"
if runner() {
def = "/opt/ansibleforms-runner"
Expand All @@ -278,7 +281,7 @@ func install(ctx context.Context, f Flags) error {
p.dir, _ = filepath.Abs(d)
return nil
}},
{label: "folder", skip: kubernetes, ask: func() error {
{label: "folder", skip: onKube, ask: func() error {
def := map[bool]string{true: "runner", false: "af"}[runner()]
help, title := i18n.T("install.nameHelp"), i18n.T("install.name")
if nativeMode() {
Expand All @@ -298,7 +301,8 @@ func install(ctx context.Context, f Flags) error {
{label: "app", skip: func() bool { return !runner() }, ask: func() error {
return askApp(ctx, f, p)
}},
{label: "mode", skip: func() bool { return !runner() || f.RunnerMode != "" }, ask: func() error {
// on Kubernetes a Runner dials the app (outbound) : nothing reaches it from outside
{label: "mode", skip: func() bool { return !runner() || f.RunnerMode != "" || kubeRunner() }, ask: func() error {
ui.Explain(i18n.T("runner.modeHelp"))
m, err := ui.Select(i18n.T("runner.mode"), []ui.Option{
{Label: i18n.T("runner.modeOutbound"), Value: "outbound", Hint: i18n.T("runner.modeOutboundHint")},
Expand All @@ -311,7 +315,7 @@ func install(ctx context.Context, f Flags) error {
return err
}},
// the network : the controller's web port, a runner's port (and address, inbound)
{label: "network", skip: func() bool { return kubernetes() || f.Port != 0 }, ask: func() error {
{label: "network", skip: func() bool { return onKube() || f.Port != 0 }, ask: func() error {
title, def := i18n.T("install.port"), compose.FreePort("0.0.0.0", 443)
ui.Explain(i18n.T("install.portHelp"))
if runner() {
Expand All @@ -328,7 +332,7 @@ func install(ctx context.Context, f Flags) error {
p.port, _ = strconv.Atoi(s)
return nil
}},
{label: "network", skip: func() bool { return !runner() || p.runnerMode != "inbound" }, ask: func() error {
{label: "network", skip: func() bool { return !runner() || p.runnerMode != "inbound" || kubeRunner() }, ask: func() error {
def := orStr(p.host, orStr(f.Host, compose.OutboundIP()))
ui.Explain(i18n.T("runner.addressHelp"))
h, err := textAgain(f.Host, i18n.T("runner.address"), def, notEmpty)
Expand Down Expand Up @@ -378,14 +382,19 @@ func install(ctx context.Context, f Flags) error {
}
return nil
}},
// Kubernetes : the release, its ingress, its volumes
{label: "cluster", skip: func() bool { return !kubernetes() }, ask: func() error {
// Kubernetes : the release, its ingress (a controller), its volumes
{label: "cluster", skip: func() bool { return !onKube() }, ask: func() error {
ns, err := textAgain(f.Namespace, i18n.T("kube.namespace"), orStr(p.namespace, "ansibleforms"), notEmpty)
p.namespace = ns
return err
}},
{label: "cluster", skip: func() bool { return !kubernetes() }, ask: func() error {
r, err := textAgain(f.Release, i18n.T("kube.release"), orStr(p.release, "ansibleforms"), notEmpty)
{label: "cluster", skip: func() bool { return !onKube() }, ask: func() error {
// a Runner's release is also its runner's name under Connections > Runners
def := map[bool]string{true: "ansibleforms-runner", false: "ansibleforms"}[runner()]
if runner() {
ui.Explain(i18n.T("kube.releaseRunnerHelp"))
}
r, err := textAgain(f.Release, i18n.T("kube.release"), orStr(p.release, def), notEmpty)
p.release = r
if err == nil {
ui.Answered(p.namespace + " / " + r)
Expand All @@ -410,7 +419,7 @@ func install(ctx context.Context, f Flags) error {
}
return err
}},
{label: "storage", skip: func() bool { return !kubernetes() }, ask: func() error {
{label: "storage", skip: func() bool { return !onKube() }, ask: func() error {
s, err := choice(f.StorageClass, i18n.T("kube.storageClass"), append([]string{""}, kube.StorageClasses(ctx)...), p.storageClass)
p.storageClass = s
return err
Expand Down Expand Up @@ -441,6 +450,8 @@ func install(ctx context.Context, f Flags) error {
switch {
case kubernetes():
return doKube(ctx, f, p)
case kubeRunner():
return doKubeRunner(ctx, f, p)
case runner():
return doRunner(ctx, p)
}
Expand Down Expand Up @@ -502,6 +513,15 @@ func review(p *plan) []string {
}
out := []string{row("version", p.version.String())}
switch {
case p.role == compose.RoleRunner && p.mode == string(state.Kubernetes):
out = append(out, row("role", i18n.T("install.roleRunnerShort")), row("engine", i18n.T("install.modeKubernetesShort")),
row("cluster", p.namespace+" / "+p.release), row("app", p.appURL), row("mode", i18n.T("runner.mode_outbound")),
row("storage", orStr(p.storageClass, i18n.T("kube.default"))))
if p.join != "" {
out = append(out, row("register", i18n.T("runner.registerJoinShort")))
} else {
out = append(out, row("register", i18n.T("runner.registerApproveShort")))
}
case p.role == compose.RoleRunner:
out = append(out, row("role", i18n.T("install.roleRunnerShort")), row("engine", engine),
row("folder", p.dir), row("name", p.name), row("app", p.appURL), row("mode", i18n.T("runner.mode_"+p.runnerMode)))
Expand Down Expand Up @@ -744,6 +764,49 @@ func doKube(ctx context.Context, f Flags, p *plan) error {
return nil
}

// doKubeRunner installs a Runner on Kubernetes : the chart's runner mode, an RTE alone that
// dials the app (outbound), approved at once with a join token, else by an admin.
//
// Args:
//
// ctx: the context, to cancel.
// f: the flags.
// p: the answers.
//
// Errors:
//
// When the join token is not valid or helm fails.
func doKubeRunner(ctx context.Context, f Flags, p *plan) error {
// its token made here, so its fingerprint is said for the admin who approves it
r := &kube.RunnerOptions{AppURL: p.appURL, Name: p.release, TrustAppCert: p.trust, Token: compose.Secret(32)}
if p.join != "" {
token, err := compose.ParseJoin(p.join)
if err != nil {
return err
}
r.JoinToken = token
}
st, err := kube.Install(ctx, kube.Options{Version: p.version.String(), Namespace: p.namespace, Release: p.release,
StorageClass: p.storageClass, ExtraValues: f.Values, Runner: r})
if err != nil {
return err
}
lines := []string{
i18n.T("runner.doneName", "name", p.release),
i18n.T("runner.doneMode", "mode", i18n.T("runner.mode_outbound")),
i18n.T("runner.doneApp", "url", r.AppURL),
"",
}
if r.JoinToken != "" {
lines = append(lines, i18n.T("runner.doneRegistered"))
} else {
lines = append(lines, i18n.T("runner.doneApprove"), "", i18n.T("runner.doneFingerprint", "fingerprint", compose.Fingerprint(r.Token)))
}
lines = append(lines, "", i18n.T("kube.doneValues", "file", st.ValuesFile))
ui.Summary(i18n.T("runner.done", "version", st.Version), lines)
return nil
}

// ─── container engines ────────────────────────────────────────────────────────

// chooseEngine picks Docker or Podman, or Kubernetes for a controller, in one list : the
Expand All @@ -757,7 +820,7 @@ func doKube(ctx context.Context, f Flags, p *plan) error {
// tools: what the server has.
// prev: the answer of before (Esc), the default.
// withKube: Kubernetes is listed (no --mode).
// runner: a runner, for which Kubernetes is always greyed out (the Helm chart installs it).
// runner: a runner : Kubernetes installs the chart's runner mode, an RTE alone.
//
// Returns:
//
Expand Down Expand Up @@ -787,7 +850,7 @@ func chooseEngine(ctx context.Context, f Flags, tools system.Tools, prev string,
}
opts = append(opts, ui.Option{Label: i18n.T("runtime.toInstall", "runtime", name), Value: string(r), Hint: i18n.T("runtime." + string(r) + "InstallHint")})
}
kube := withKube && !runner && tools.Kubectl && tools.Helm && tools.Cluster
kube := withKube && tools.Kubectl && tools.Helm && tools.Cluster
nativeOption := func() ui.Option {
hint := "install.modeNativeHint"
if runner {
Expand All @@ -800,8 +863,8 @@ func chooseEngine(ctx context.Context, f Flags, tools system.Tools, prev string,
}
if withKube {
switch {
case runner:
opts = append(opts, ui.Option{Label: i18n.T("install.modeKubernetesRunner"), Value: string(state.Kubernetes), Disabled: true})
case kube && runner:
opts = append(opts, ui.Option{Label: i18n.T("install.modeKubernetes"), Value: string(state.Kubernetes), Hint: i18n.T("install.modeKubernetesRunnerHint")})
case kube:
opts = append(opts, ui.Option{Label: i18n.T("install.modeKubernetes"), Value: string(state.Kubernetes), Hint: i18n.T("install.modeKubernetesHint")})
default:
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "Aquest no és un token d'unió vàlid.",
"kube.namespace": "Namespace",
"kube.release": "Nom de la release de Helm",
"kube.releaseRunnerHelp": "El nom del seu runner a Connexions > Runners.",
"kube.hostname": "Nom d'amfitrió servit per l'ingress (ansibleforms.example.com)",
"kube.ingressClass": "Classe d'ingress",
"kube.tls": "Voleu servir-lo per HTTPS (amb el certificat de l'ingress)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "surt",
"keys.stop": "atura",
"keys.close": "tanca",
"install.modeKubernetesRunner": "Kubernetes (allà, un Runner s'instal·la amb el chart de Helm)",
"install.modeKubernetesRunnerHint": "El mode runner del chart de Helm, al clúster que kubectl abasta.\nTruca a l'app: res no hi arriba des de fora.",
"install.modeNative": "Directament en aquest servidor, sense contenidors",
"install.modeNative_root": "Directament en aquest servidor (cal root: executeu-lo amb sudo)",
"install.modeNative_unsupported": "Directament en aquest servidor (no compatible amb aquest Linux)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "Das ist kein gültiges Beitritts-Token.",
"kube.namespace": "Namespace",
"kube.release": "Name des Helm-Release",
"kube.releaseRunnerHelp": "Der Name seines Runners unter Verbindungen > Runner.",
"kube.hostname": "Vom Ingress bereitgestellter Hostname (ansibleforms.example.com)",
"kube.ingressClass": "Ingress-Klasse",
"kube.tls": "Über HTTPS bereitstellen (mit dem Zertifikat des Ingress)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "beenden",
"keys.stop": "stoppen",
"keys.close": "schließen",
"install.modeKubernetesRunner": "Kubernetes (ein Runner dort wird mit dem Helm-Chart installiert)",
"install.modeKubernetesRunnerHint": "Der Runner-Modus des Helm-Charts, auf dem Cluster, den kubectl erreicht.\nEr ruft die App an: nichts erreicht ihn von außen.",
"install.modeNative": "Direkt auf diesem Server, ohne Container",
"install.modeNative_root": "Direkt auf diesem Server (erfordert root: Installer mit sudo starten)",
"install.modeNative_unsupported": "Direkt auf diesem Server (auf diesem Linux nicht unterstützt)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "This is not a valid join token.",
"kube.namespace": "Namespace",
"kube.release": "Helm release name",
"kube.releaseRunnerHelp": "Its runner's name under Connections > Runners.",
"kube.hostname": "Hostname served by the ingress (ansibleforms.example.com)",
"kube.ingressClass": "Ingress class",
"kube.tls": "Serve it over HTTPS (using the ingress certificate)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "quit",
"keys.stop": "stop",
"keys.close": "close",
"install.modeKubernetesRunner": "Kubernetes (a Runner there is installed with the Helm chart)",
"install.modeKubernetesRunnerHint": "The Helm chart's runner mode, on the cluster that kubectl reaches.\nIt dials the app: nothing reaches it from outside.",
"install.modeNative": "Directly on this server, no containers",
"install.modeNative_root": "Directly on this server (needs root: run the installer with sudo)",
"install.modeNative_unsupported": "Directly on this server (not supported on this Linux)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "Esto no es un token de unión válido.",
"kube.namespace": "Namespace",
"kube.release": "Nombre de la release de Helm",
"kube.releaseRunnerHelp": "El nombre de su runner en Conexiones > Runners.",
"kube.hostname": "Nombre de host servido por el ingress (ansibleforms.example.com)",
"kube.ingressClass": "Clase de ingress",
"kube.tls": "¿Servirlo por HTTPS (con el certificado del ingress)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "salir",
"keys.stop": "detener",
"keys.close": "cerrar",
"install.modeKubernetesRunner": "Kubernetes (allí, un Runner se instala con el chart de Helm)",
"install.modeKubernetesRunnerHint": "El modo runner del chart de Helm, en el clúster que alcanza kubectl.\nLlama a la app: nada le llega desde fuera.",
"install.modeNative": "Directamente en este servidor, sin contenedores",
"install.modeNative_root": "Directamente en este servidor (requiere root: ejecútalo con sudo)",
"install.modeNative_unsupported": "Directamente en este servidor (no compatible con este Linux)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "Ce n'est pas un jeton d'adhésion valide.",
"kube.namespace": "Namespace",
"kube.release": "Nom de la release Helm",
"kube.releaseRunnerHelp": "Le nom de son runner dans Connexions > Runners.",
"kube.hostname": "Nom d'hôte servi par l'ingress (ansibleforms.example.com)",
"kube.ingressClass": "Classe d'ingress",
"kube.tls": "Le servir en HTTPS (avec le certificat de l'ingress) ?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "quitter",
"keys.stop": "arrêter",
"keys.close": "fermer",
"install.modeKubernetesRunner": "Kubernetes (un Runner s'y installe avec le chart Helm)",
"install.modeKubernetesRunnerHint": "Le mode runner du chart Helm, sur le cluster que kubectl atteint.\nIl appelle l'app : rien ne l'atteint de l'extérieur.",
"install.modeNative": "Directement sur ce serveur, sans conteneurs",
"install.modeNative_root": "Directement sur ce serveur (nécessite root : lancez-le avec sudo)",
"install.modeNative_unsupported": "Directement sur ce serveur (non pris en charge sur ce Linux)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "Questo non è un token di adesione valido.",
"kube.namespace": "Namespace",
"kube.release": "Nome della release Helm",
"kube.releaseRunnerHelp": "Il nome del suo runner in Connessioni > Runner.",
"kube.hostname": "Hostname servito dall'ingress (ansibleforms.example.com)",
"kube.ingressClass": "Classe di ingress",
"kube.tls": "Servirlo in HTTPS (con il certificato dell'ingress)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "esci",
"keys.stop": "ferma",
"keys.close": "chiudi",
"install.modeKubernetesRunner": "Kubernetes (lì un Runner si installa con il chart Helm)",
"install.modeKubernetesRunnerHint": "La modalità runner del chart Helm, sul cluster che kubectl raggiunge.\nChiama l'app: niente lo raggiunge dall'esterno.",
"install.modeNative": "Direttamente su questo server, senza container",
"install.modeNative_root": "Direttamente su questo server (richiede root: eseguilo con sudo)",
"install.modeNative_unsupported": "Direttamente su questo server (non supportato su questo Linux)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "有効な参加トークンではありません。",
"kube.namespace": "Namespace",
"kube.release": "Helm リリース名",
"kube.releaseRunnerHelp": "接続 > Runner に表示される runner の名前です。",
"kube.hostname": "Ingress で公開するホスト名 (ansibleforms.example.com)",
"kube.ingressClass": "Ingress クラス",
"kube.tls": "HTTPS で公開しますか (Ingress の証明書を使用)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "終了",
"keys.stop": "中止",
"keys.close": "閉じる",
"install.modeKubernetesRunner": "Kubernetes (ランナーは Helm チャートでインストールします)",
"install.modeKubernetesRunnerHint": "kubectl が届くクラスター上の Helm chart の runner モード。\nアプリに接続します。外部から接続されることはありません。",
"install.modeNative": "このサーバーに直接 (コンテナーなし)",
"install.modeNative_root": "このサーバーに直接 (root が必要: sudo で実行)",
"install.modeNative_unsupported": "このサーバーに直接 (この Linux では非対応)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "Dit is geen geldig jointoken.",
"kube.namespace": "Namespace",
"kube.release": "Naam van de Helm-release",
"kube.releaseRunnerHelp": "De naam van zijn runner onder Verbindingen > Runners.",
"kube.hostname": "Hostnaam van de ingress (ansibleforms.example.com)",
"kube.ingressClass": "Ingress-klasse",
"kube.tls": "Aanbieden via HTTPS (met het certificaat van de ingress)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "afsluiten",
"keys.stop": "stoppen",
"keys.close": "sluiten",
"install.modeKubernetesRunner": "Kubernetes (daar installeert u een Runner met de Helm-chart)",
"install.modeKubernetesRunnerHint": "De runnermodus van de Helm-chart, op het cluster dat kubectl bereikt.\nHij belt de app: niets bereikt hem van buitenaf.",
"install.modeNative": "Direct op deze server, zonder containers",
"install.modeNative_root": "Direct op deze server (vereist root: start het met sudo)",
"install.modeNative_unsupported": "Direct op deze server (niet ondersteund op deze Linux)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "To nie jest prawidłowy token dołączenia.",
"kube.namespace": "Namespace",
"kube.release": "Nazwa wydania Helm",
"kube.releaseRunnerHelp": "Nazwa jego runnera w Połączenia > Runnery.",
"kube.hostname": "Nazwa hosta obsługiwana przez ingress (ansibleforms.example.com)",
"kube.ingressClass": "Klasa ingress",
"kube.tls": "Udostępniać przez HTTPS (z certyfikatem ingressu)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "zakończ",
"keys.stop": "zatrzymaj",
"keys.close": "zamknij",
"install.modeKubernetesRunner": "Kubernetes (tam Runner instaluje się chartem Helm)",
"install.modeKubernetesRunnerHint": "Tryb runnera chartu Helm, w klastrze, do którego dociera kubectl.\nŁączy się z aplikacją: nic nie łączy się z nim z zewnątrz.",
"install.modeNative": "Bezpośrednio na tym serwerze, bez kontenerów",
"install.modeNative_root": "Bezpośrednio na tym serwerze (wymaga root: uruchom przez sudo)",
"install.modeNative_unsupported": "Bezpośrednio na tym serwerze (nieobsługiwane w tym Linuksie)",
Expand Down
3 changes: 2 additions & 1 deletion internal/i18n/locales/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"join.invalid": "Isto não é um token de adesão válido.",
"kube.namespace": "Namespace",
"kube.release": "Nome da release Helm",
"kube.releaseRunnerHelp": "O nome do seu runner em Ligações > Runners.",
"kube.hostname": "Nome de anfitrião servido pelo ingress (ansibleforms.example.com)",
"kube.ingressClass": "Classe de ingress",
"kube.tls": "Servir por HTTPS (com o certificado do ingress)?",
Expand Down Expand Up @@ -247,7 +248,7 @@
"keys.quit": "sair",
"keys.stop": "parar",
"keys.close": "fechar",
"install.modeKubernetesRunner": "Kubernetes (aí, um Runner instala-se com o chart Helm)",
"install.modeKubernetesRunnerHint": "O modo runner do chart Helm, no cluster que o kubectl alcança.\nLiga à app: nada lhe chega de fora.",
"install.modeNative": "Diretamente neste servidor, sem contentores",
"install.modeNative_root": "Diretamente neste servidor (requer root: execute o instalador com sudo)",
"install.modeNative_unsupported": "Diretamente neste servidor (não suportado neste Linux)",
Expand Down
Loading
Loading