forked from toolshed/abra
WIP: still hacking on the app new command
Finally had to fork godotenv because it strips comments and we need
those to parse length values (e.g. "FOO=v1 # length=10") (or in other
words, motivation to move to the YAML format).
There is a new secret module now, with functionality for dealing with
generation and parsing of secrets.
The final output needs some work and there is also the final step of
implementing the sending of secrets to the docker daemon. Coming Soon
™️.
This commit is contained in:
99
cli/app.go
99
cli/app.go
@ -3,11 +3,8 @@ package cli
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"coopcloud.tech/abra/catalogue"
|
||||
@ -28,19 +25,23 @@ var appNewCommand = &cli.Command{
|
||||
Name: "new",
|
||||
Usage: "Create a new app",
|
||||
Description: `
|
||||
This command takes a recipe and uses it to cook up a new app. This app
|
||||
This command takes an app recipe and uses it to create a new app. This new app
|
||||
configuration is stored in your ~/.abra directory under the appropriate server.
|
||||
|
||||
This command does not deploy your app for you. You will need to run "abra app
|
||||
deploy <app>" to do so.
|
||||
|
||||
You can see what apps can be created (i.e. values for the <type> argument) by
|
||||
running "abra recipe ls".
|
||||
|
||||
Passing the "--secrets" flag will automatically generate secrets for your app
|
||||
and store them encrypted at rest on the chosen target server. These generated
|
||||
secrets are only visible at generation time, so please take care to store them
|
||||
somewhere safe. You can use the "--pass" to store these generated passwords
|
||||
locally in a pass store (see passwordstore.org for more).
|
||||
Passing the "--secrets/-S" flag will automatically generate secrets for your
|
||||
app and store them encrypted at rest on the chosen target server. These
|
||||
generated secrets are only visible at generation time, so please take care to
|
||||
store them somewhere safe.
|
||||
|
||||
You can use the "--pass/-P" to store these generated passwords locally in a
|
||||
pass store (see passwordstore.org for more). The pass command must be available
|
||||
on your $PATH.
|
||||
`,
|
||||
Flags: []cli.Flag{
|
||||
ServerFlag,
|
||||
@ -70,13 +71,9 @@ locally in a pass store (see passwordstore.org for more).
|
||||
}
|
||||
|
||||
app := catl[appType]
|
||||
var latestVersion string
|
||||
for tag := range app.Versions {
|
||||
// apps.json versions are sorted so the last key is latest
|
||||
latestVersion = tag
|
||||
}
|
||||
|
||||
app.EnsureExists()
|
||||
|
||||
latestVersion := app.LatestVersion()
|
||||
if err := app.EnsureVersion(latestVersion); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
@ -116,69 +113,43 @@ locally in a pass store (see passwordstore.org for more).
|
||||
logrus.Fatal(fmt.Errorf("'%s' cannot be longer than 45 characters", sanitisedAppName))
|
||||
}
|
||||
|
||||
envSamplePath := path.Join(config.ABRA_DIR, "apps", appType, ".env.sample")
|
||||
envSample, err := ioutil.ReadFile(envSamplePath)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
appEnvPath := path.Join(config.ABRA_DIR, "servers", Server, fmt.Sprintf("%s.env", sanitisedAppName))
|
||||
err = ioutil.WriteFile(appEnvPath, envSample, 0755)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
config.CopyAppEnvSample(appType, AppName, Server)
|
||||
|
||||
secrets := make(map[string]string)
|
||||
if Secrets {
|
||||
appEnvPath := path.Join(config.ABRA_DIR, "servers", Server, fmt.Sprintf("%s.env", sanitisedAppName))
|
||||
appEnv, err := config.ReadEnv(appEnvPath)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var secretEnvVars []string
|
||||
for envVar := range appEnv {
|
||||
regex := regexp.MustCompile(`^SECRET.*VERSION.*`)
|
||||
secretEnvVar := regex.Find([]byte(envVar))
|
||||
secretEnvVars = append(secretEnvVars, string(secretEnvVar))
|
||||
secretEnvVars := secret.ReadSecretEnvVars(appEnv)
|
||||
secrets, err = secret.GenerateSecrets(secretEnvVars, Server)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
var length int
|
||||
var secretValue string
|
||||
var secrets map[string]string
|
||||
for _, secretEnvVar := range secretEnvVars {
|
||||
withoutPrefix := strings.TrimPrefix(secretEnvVar, "SECRET_")
|
||||
regex := regexp.MustCompile(`_VERSION=.*`)
|
||||
secretName := string(regex.Find([]byte(withoutPrefix)))
|
||||
|
||||
if strings.Contains(secretEnvVar, "length") {
|
||||
regex := regexp.MustCompile(`s/.*[^0-9]\([0-9]\+\)[^0-9]*$/\1/`)
|
||||
match := regex.Find([]byte(secretEnvVar))
|
||||
length, err = strconv.Atoi(string(match))
|
||||
if err != nil {
|
||||
if Pass {
|
||||
for secretName := range secrets {
|
||||
secretValue := secrets[secretName]
|
||||
if err := secret.PassInsertSecret(secretValue, secretName, sanitisedAppName, Server); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
passwords, err := secret.GeneratePasswords(1, uint(length))
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
secretValue = passwords[0]
|
||||
secrets[secretEnvVar] = secretValue
|
||||
} else {
|
||||
passphrases, err := secret.GeneratePassphrases(1)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
secretValue = passphrases[0]
|
||||
secrets[secretEnvVar] = secretValue
|
||||
}
|
||||
go client.StoreSecret(secretName, secretValue, Server)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: save them in a pass store if asked to do so
|
||||
if Pass {
|
||||
}
|
||||
tableCol := []string{"Name", "Domain", "Type", "Server"}
|
||||
table := createTable(tableCol)
|
||||
table.Append([]string{sanitisedAppName, Domain, appType, Server})
|
||||
table.Render()
|
||||
|
||||
// TODO: Output some instructions on how to deploy this thing
|
||||
if Secrets {
|
||||
secretCols := []string{"Name", "Value"}
|
||||
secretTable := createTable(secretCols)
|
||||
for secret := range secrets {
|
||||
secretTable.Append([]string{secret, secrets[secret]})
|
||||
}
|
||||
secretTable.Render()
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
|
Reference in New Issue
Block a user