Skip to content
This repository has been archived by the owner on Mar 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2333 from ibuildthecloud/main
Browse files Browse the repository at this point in the history
Add secret update and secret create --replace/--update
  • Loading branch information
ibuildthecloud authored Nov 15, 2023
2 parents 117e72e + 4c9bf68 commit 53f9540
Show file tree
Hide file tree
Showing 21 changed files with 197 additions and 27 deletions.
2 changes: 1 addition & 1 deletion docs/docs/100-reference/01-command-line/acorn.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ acorn [flags]
* [acorn credential](acorn_credential.md) - Manage registry credentials
* [acorn dashboard](acorn_dashboard.md) - Open the web dashboard for the project
* [acorn dev](acorn_dev.md) - Run an app from an image or Acornfile in dev mode or attach a dev session to a currently running app
* [acorn edit](acorn_edit.md) - Edits an acorn or secret
* [acorn edit](acorn_edit.md) - Edits an acorn or secret interactively
* [acorn events](acorn_events.md) - List events about Acorn resources
* [acorn exec](acorn_exec.md) - Run a command in a container
* [acorn fmt](acorn_fmt.md) - Format an Acornfile
Expand Down
1 change: 1 addition & 0 deletions docs/docs/100-reference/01-command-line/acorn_dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ acorn dev --name wandering-sound --clone [acorn args]
--clone Clone the vcs repository and infer the build context for the given app allowing for local development
--compute-class strings Set computeclass for a workload in the format of workload=computeclass. Specify a single computeclass to set all workloads. (ex foo=example-class or example-class)
-e, --env strings Environment variables to set on running containers
--env-file string Default env vars to apply (default ".acorn.env")
-f, --file string Name of the build file (default "DIRECTORY/Acornfile")
-h, --help help for dev
--interval string If configured for auto-upgrade, this is the time interval at which to check for new releases (ex: 1h, 5m)
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/100-reference/01-command-line/acorn_edit.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "acorn edit"
---
## acorn edit

Edits an acorn or secret
Edits an acorn or secret interactively

```
acorn edit ACORN_NAME|SECRET_NAME [flags]
Expand Down
1 change: 1 addition & 0 deletions docs/docs/100-reference/01-command-line/acorn_run.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Volume Syntax
--dangerous Automatically approve all privileges requested by the application
-i, --dev Enable interactive dev mode: build image, stream logs/status in the foreground and stop on exit
-e, --env strings Environment variables to set on running containers
--env-file string Default env vars to apply (default ".acorn.env")
-f, --file string Name of the build file (default "DIRECTORY/Acornfile")
-h, --help help for run
--interval string If configured for auto-upgrade, this is the time interval at which to check for new releases (ex: 1h, 5m)
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/100-reference/01-command-line/acorn_secret.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ acorn secret

* [acorn](acorn.md) -
* [acorn secret create](acorn_secret_create.md) - Create a secret
* [acorn secret edit](acorn_secret_edit.md) - Edits a secret
* [acorn secret edit](acorn_secret_edit.md) - Edits a secret interactively
* [acorn secret encrypt](acorn_secret_encrypt.md) - Encrypt string information with clusters public key
* [acorn secret reveal](acorn_secret_reveal.md) - Manage secrets
* [acorn secret rm](acorn_secret_rm.md) - Delete a secret
* [acorn secret update](acorn_secret_update.md) - Update a secret

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ acorn secret create [flags] SECRET_NAME
# Create secret with specific keys
acorn secret create --data key-name=value --data key-name2=value2 my-secret
# Read full secret from a file
# Read full secret from a file. The file should have a type and data field.
acorn secret create --file secret.yaml my-secret
# Read key value from a file
Expand All @@ -27,9 +27,11 @@ acorn secret create --data @key-name=secret.yaml my-secret

```
--data strings Secret data format key=value or @key=filename to read from file
--file string File to read for entire secret in cue/yaml/json format
--file string File to read for entire secret in aml/yaml/json format
-h, --help help for create
--replace Replace the secret with only defined values, resetting undefined fields to default values
--type string Secret type
-u, --update Update the secret if it already exists
```

### Options inherited from parent commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "acorn secret edit"
---
## acorn secret edit

Edits a secret
Edits a secret interactively

```
acorn secret edit SECRET_NAME [flags]
Expand Down
50 changes: 50 additions & 0 deletions docs/docs/100-reference/01-command-line/acorn_secret_update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: "acorn secret update"
---
## acorn secret update

Update a secret

```
acorn secret update [flags] SECRET_NAME
```

### Examples

```
# Create secret with specific keys
acorn secret update --data key-name=value --data key-name2=value2 my-secret
# Read full secret from a file. The file should have a type and data field.
acorn secret update --file secret.yaml my-secret
# Read key value from a file
acorn secret update --data @key-name=secret.yaml my-secret
```

### Options

```
--data strings Secret data format key=value or @key=filename to read from file
--file string File to read for entire secret in aml/yaml/json format
-h, --help help for update
--type string Secret type
```

### Options inherited from parent commands

```
--config-file string Path of the acorn config file to use
--debug Enable debug logging
--debug-level int Debug log level (valid 0-9) (default 7)
--kubeconfig string Explicitly use kubeconfig file, overriding the default context
-o, --output string Output format (json, yaml, {{gotemplate}})
-j, --project string Project to work in
-q, --quiet Output only names
```

### SEE ALSO

* [acorn secret](acorn_secret.md) - Manage secrets

1 change: 1 addition & 0 deletions docs/docs/100-reference/01-command-line/acorn_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ acorn update [flags] ACORN_NAME [deploy flags]
--confirm-upgrade When an auto-upgrade app is marked as having an upgrade available, pass this flag to confirm the upgrade. Used in conjunction with --notify-upgrade.
--dangerous Automatically approve all privileges requested by the application
-e, --env strings Environment variables to set on running containers
--env-file string Default env vars to apply to update command
-f, --file string Name of the build file (default "DIRECTORY/Acornfile")
-h, --help help for update
--image string Acorn image name
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ replace (
require (
cuelang.org/go v0.6.0
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/acorn-io/aml v0.0.0-20231115002431-c08b165964de
github.com/acorn-io/aml v0.0.0-20231115044900-37e80122de99
github.com/acorn-io/aml/cli v0.0.0-20231113171943-4844e2f3e1a2
github.com/acorn-io/aml/legacy v0.0.0-20230929081514-1e9f3394432e
github.com/acorn-io/baaah v0.0.0-20231009165317-af2b68361b8a
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/acorn-io/aml v0.0.0-20231115002431-c08b165964de h1:vFVPRhT87Js+8S6WyyABZdtUpgrwMP6/US+4ChaolhQ=
github.com/acorn-io/aml v0.0.0-20231115002431-c08b165964de/go.mod h1:jImvyZGYOReKDJEEjS2SLjvVAEFcXFMA7OPQ96l1JYA=
github.com/acorn-io/aml v0.0.0-20231115044900-37e80122de99 h1:gsGIU3LyIi8WobSnYwEJsJ+LyhdA4m1zlI///YXRtb0=
github.com/acorn-io/aml v0.0.0-20231115044900-37e80122de99/go.mod h1:jImvyZGYOReKDJEEjS2SLjvVAEFcXFMA7OPQ96l1JYA=
github.com/acorn-io/aml/cli v0.0.0-20231113171943-4844e2f3e1a2 h1:CtflOEPAvtpALuC3SM1WApsfTuECXcDuq25E3fZaPdg=
github.com/acorn-io/aml/cli v0.0.0-20231113171943-4844e2f3e1a2/go.mod h1:D4tWmJlLdsmMbQ/MI4T+Tj4j2PjgTAdde2QDGkeWH20=
github.com/acorn-io/aml/legacy v0.0.0-20230929081514-1e9f3394432e h1:W67DG9AcoNvBwIOR9OFUCZlSJBaHuvM2kXQ2+C6EnLk=
Expand Down
11 changes: 7 additions & 4 deletions pkg/apis/internal.acorn.io/v1/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -1421,15 +1421,18 @@ func ParseQuantity(s string) (Quantity, error) {

func ParseNameValues(fillEnv bool, s ...string) (result []NameValue) {
for _, s := range s {
s = strings.TrimSpace(s)
k, v, _ := strings.Cut(s, "=")
if v == "" && fillEnv {
parts := strings.Split(k, ".")
v = os.Getenv(parts[len(parts)-1])
}
result = append(result, NameValue{
Name: k,
Value: v,
})
if k != "" {
result = append(result, NameValue{
Name: k,
Value: v,
})
}
}
return result
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func NewEdit(c CommandContext) *cobra.Command {
Use: "edit ACORN_NAME|SECRET_NAME",
Example: `acorn edit my-acorn`,
SilenceUsage: true,
Short: "Edits an acorn or secret",
Short: "Edits an acorn or secret interactively",
Args: cobra.ExactArgs(1),
ValidArgsFunction: newCompletion(c.ClientFactory, appsThenSecretsCompletion).complete,
})
Expand Down
14 changes: 13 additions & 1 deletion pkg/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io"
"os"
"strings"

apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1"
v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1"
Expand Down Expand Up @@ -114,7 +115,8 @@ type Run struct {

type RunArgs struct {
UpdateArgs
Name string `usage:"Name of app to create" short:"n"`
EnvFile string `usage:"Default env vars to apply" default:".acorn.env"`
Name string `usage:"Name of app to create" short:"n"`
}

func (s RunArgs) ToOpts() (client.AppRunOptions, error) {
Expand Down Expand Up @@ -156,6 +158,16 @@ func (s RunArgs) ToOpts() (client.AppRunOptions, error) {

opts.Env = v1.ParseNameValues(true, s.Env...)

if s.EnvFile != "" {
envData, err := os.ReadFile(s.EnvFile)
if os.IsNotExist(err) {
} else if err != nil {
return opts, err
} else {
opts.Env = append(opts.Env, v1.ParseNameValues(false, strings.Split(string(envData), "\n")...)...)
}
}

opts.Labels, err = v1.ParseScopedLabels(s.Label...)
if err != nil {
return opts, err
Expand Down
1 change: 1 addition & 0 deletions pkg/cli/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ acorn secret`,
ValidArgsFunction: newCompletion(c.ClientFactory, secretsCompletion).complete,
})
cmd.AddCommand(NewSecretCreate(c))
cmd.AddCommand(NewSecretUpdate(c))
cmd.AddCommand(NewSecretDelete(c))
cmd.AddCommand(NewSecretReveal(c))
cmd.AddCommand(NewSecretEncrypt(c))
Expand Down
43 changes: 36 additions & 7 deletions pkg/cli/secret_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1"
cli "github.com/acorn-io/runtime/pkg/cli/builder"
"github.com/spf13/cobra"
apierrors "k8s.io/apimachinery/pkg/api/errors"
)

func NewSecretCreate(c CommandContext) *cobra.Command {
Expand All @@ -18,7 +19,7 @@ func NewSecretCreate(c CommandContext) *cobra.Command {
# Create secret with specific keys
acorn secret create --data key-name=value --data key-name2=value2 my-secret
# Read full secret from a file
# Read full secret from a file. The file should have a type and data field.
acorn secret create --file secret.yaml my-secret
# Read key value from a file
Expand All @@ -30,14 +31,20 @@ acorn secret create --data @key-name=secret.yaml my-secret`,
return cmd
}

type SecretFactory struct {
Data []string `usage:"Secret data format key=value or @key=filename to read from file"`
File string `usage:"File to read for entire secret in aml/yaml/json format"`
Type string `usage:"Secret type"`
}

type SecretCreate struct {
Data []string `usage:"Secret data format key=value or @key=filename to read from file"`
File string `usage:"File to read for entire secret in cue/yaml/json format"`
Type string `usage:"Secret type"`
client ClientFactory
SecretFactory
Update bool `usage:"Update the secret if it already exists" short:"u"`
Replace bool `usage:"Replace the secret with only defined values, resetting undefined fields to default values" json:"replace,omitempty"`
client ClientFactory
}

func (a *SecretCreate) buildSecret() (*apiv1.Secret, error) {
func (a *SecretFactory) buildSecret() (*apiv1.Secret, error) {
secret := &struct {
apiv1.Secret `json:",inline"`
StringData map[string]string `json:"stringData,omitempty"`
Expand Down Expand Up @@ -94,7 +101,29 @@ func (a *SecretCreate) Run(cmd *cobra.Command, args []string) error {
}

newSecret, err := client.SecretCreate(cmd.Context(), args[0], secret.Type, secret.Data)
if err != nil {
if apierrors.IsAlreadyExists(err) {
if a.Replace {
newSecret, err = client.SecretUpdate(cmd.Context(), args[0], secret.Data)
if err != nil {
return err
}
} else if a.Update {
existing, err := client.SecretReveal(cmd.Context(), args[0])
if err != nil {
return err
}
if existing.Data == nil {
existing.Data = map[string][]byte{}
}
for k, v := range secret.Data {
existing.Data[k] = v
}
newSecret, err = client.SecretUpdate(cmd.Context(), args[0], existing.Data)
if err != nil {
return err
}
}
} else if err != nil {
return err
}

Expand Down
8 changes: 5 additions & 3 deletions pkg/cli/secret_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import (

func TestBuildSecret(t *testing.T) {
c := SecretCreate{
Data: []string{"key1=value1", "@key2=testdata/secret/value2.txt"},
File: "testdata/secret/secret.yaml",
Type: "fancy",
SecretFactory: SecretFactory{
Data: []string{"key1=value1", "@key2=testdata/secret/value2.txt"},
File: "testdata/secret/secret.yaml",
Type: "fancy",
},
}

secret, err := c.buildSecret()
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/secret_edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func NewSecretEdit(c CommandContext) *cobra.Command {
Use: "edit SECRET_NAME",
Example: `acorn secret edit my-secret`,
SilenceUsage: true,
Short: "Edits a secret",
Short: "Edits a secret interactively",
Args: cobra.ExactArgs(1),
ValidArgsFunction: newCompletion(c.ClientFactory, secretsCompletion).complete,
})
Expand Down
65 changes: 65 additions & 0 deletions pkg/cli/secret_update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package cli

import (
"fmt"

cli "github.com/acorn-io/runtime/pkg/cli/builder"
"github.com/spf13/cobra"
)

func NewSecretUpdate(c CommandContext) *cobra.Command {
cmd := cli.Command(&SecretUpdate{client: c.ClientFactory}, cobra.Command{
Use: "update [flags] SECRET_NAME",
Example: `
# Create secret with specific keys
acorn secret update --data key-name=value --data key-name2=value2 my-secret
# Read full secret from a file. The file should have a type and data field.
acorn secret update --file secret.yaml my-secret
# Read key value from a file
acorn secret update --data @key-name=secret.yaml my-secret`,
SilenceUsage: true,
Short: "Update a secret",
Args: cobra.ExactArgs(1),
})
return cmd
}

type SecretUpdate struct {
SecretFactory
client ClientFactory
}

func (a *SecretUpdate) Run(cmd *cobra.Command, args []string) error {
client, err := a.client.CreateDefault()
if err != nil {
return err
}

secret, err := a.buildSecret()
if err != nil {
return err
}

existing, err := client.SecretReveal(cmd.Context(), args[0])
if err != nil {
return err
}

if existing.Data == nil {
existing.Data = map[string][]byte{}
}

for k, v := range secret.Data {
existing.Data[k] = v
}

newSecret, err := client.SecretUpdate(cmd.Context(), args[0], existing.Data)
if err != nil {
return err
}

fmt.Println(newSecret.Name)
return nil
}
Loading

0 comments on commit 53f9540

Please sign in to comment.