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

Commit 53f9540

Browse files
Merge pull request #2333 from ibuildthecloud/main
Add secret update and secret create --replace/--update
2 parents 117e72e + 4c9bf68 commit 53f9540

21 files changed

+197
-27
lines changed

docs/docs/100-reference/01-command-line/acorn.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ acorn [flags]
3434
* [acorn credential](acorn_credential.md) - Manage registry credentials
3535
* [acorn dashboard](acorn_dashboard.md) - Open the web dashboard for the project
3636
* [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
37-
* [acorn edit](acorn_edit.md) - Edits an acorn or secret
37+
* [acorn edit](acorn_edit.md) - Edits an acorn or secret interactively
3838
* [acorn events](acorn_events.md) - List events about Acorn resources
3939
* [acorn exec](acorn_exec.md) - Run a command in a container
4040
* [acorn fmt](acorn_fmt.md) - Format an Acornfile

docs/docs/100-reference/01-command-line/acorn_dev.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ acorn dev --name wandering-sound --clone [acorn args]
3131
--clone Clone the vcs repository and infer the build context for the given app allowing for local development
3232
--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)
3333
-e, --env strings Environment variables to set on running containers
34+
--env-file string Default env vars to apply (default ".acorn.env")
3435
-f, --file string Name of the build file (default "DIRECTORY/Acornfile")
3536
-h, --help help for dev
3637
--interval string If configured for auto-upgrade, this is the time interval at which to check for new releases (ex: 1h, 5m)

docs/docs/100-reference/01-command-line/acorn_edit.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: "acorn edit"
33
---
44
## acorn edit
55

6-
Edits an acorn or secret
6+
Edits an acorn or secret interactively
77

88
```
99
acorn edit ACORN_NAME|SECRET_NAME [flags]

docs/docs/100-reference/01-command-line/acorn_run.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Volume Syntax
7070
--dangerous Automatically approve all privileges requested by the application
7171
-i, --dev Enable interactive dev mode: build image, stream logs/status in the foreground and stop on exit
7272
-e, --env strings Environment variables to set on running containers
73+
--env-file string Default env vars to apply (default ".acorn.env")
7374
-f, --file string Name of the build file (default "DIRECTORY/Acornfile")
7475
-h, --help help for run
7576
--interval string If configured for auto-upgrade, this is the time interval at which to check for new releases (ex: 1h, 5m)

docs/docs/100-reference/01-command-line/acorn_secret.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ acorn secret
3838

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

docs/docs/100-reference/01-command-line/acorn_secret_create.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ acorn secret create [flags] SECRET_NAME
1616
# Create secret with specific keys
1717
acorn secret create --data key-name=value --data key-name2=value2 my-secret
1818
19-
# Read full secret from a file
19+
# Read full secret from a file. The file should have a type and data field.
2020
acorn secret create --file secret.yaml my-secret
2121
2222
# Read key value from a file
@@ -27,9 +27,11 @@ acorn secret create --data @key-name=secret.yaml my-secret
2727

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

3537
### Options inherited from parent commands

docs/docs/100-reference/01-command-line/acorn_secret_edit.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: "acorn secret edit"
33
---
44
## acorn secret edit
55

6-
Edits a secret
6+
Edits a secret interactively
77

88
```
99
acorn secret edit SECRET_NAME [flags]
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
title: "acorn secret update"
3+
---
4+
## acorn secret update
5+
6+
Update a secret
7+
8+
```
9+
acorn secret update [flags] SECRET_NAME
10+
```
11+
12+
### Examples
13+
14+
```
15+
16+
# Create secret with specific keys
17+
acorn secret update --data key-name=value --data key-name2=value2 my-secret
18+
19+
# Read full secret from a file. The file should have a type and data field.
20+
acorn secret update --file secret.yaml my-secret
21+
22+
# Read key value from a file
23+
acorn secret update --data @key-name=secret.yaml my-secret
24+
```
25+
26+
### Options
27+
28+
```
29+
--data strings Secret data format key=value or @key=filename to read from file
30+
--file string File to read for entire secret in aml/yaml/json format
31+
-h, --help help for update
32+
--type string Secret type
33+
```
34+
35+
### Options inherited from parent commands
36+
37+
```
38+
--config-file string Path of the acorn config file to use
39+
--debug Enable debug logging
40+
--debug-level int Debug log level (valid 0-9) (default 7)
41+
--kubeconfig string Explicitly use kubeconfig file, overriding the default context
42+
-o, --output string Output format (json, yaml, {{gotemplate}})
43+
-j, --project string Project to work in
44+
-q, --quiet Output only names
45+
```
46+
47+
### SEE ALSO
48+
49+
* [acorn secret](acorn_secret.md) - Manage secrets
50+

docs/docs/100-reference/01-command-line/acorn_update.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ acorn update [flags] ACORN_NAME [deploy flags]
3333
--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.
3434
--dangerous Automatically approve all privileges requested by the application
3535
-e, --env strings Environment variables to set on running containers
36+
--env-file string Default env vars to apply to update command
3637
-f, --file string Name of the build file (default "DIRECTORY/Acornfile")
3738
-h, --help help for update
3839
--image string Acorn image name

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ replace (
1212
require (
1313
cuelang.org/go v0.6.0
1414
github.com/AlecAivazis/survey/v2 v2.3.6
15-
github.com/acorn-io/aml v0.0.0-20231115002431-c08b165964de
15+
github.com/acorn-io/aml v0.0.0-20231115044900-37e80122de99
1616
github.com/acorn-io/aml/cli v0.0.0-20231113171943-4844e2f3e1a2
1717
github.com/acorn-io/aml/legacy v0.0.0-20230929081514-1e9f3394432e
1818
github.com/acorn-io/baaah v0.0.0-20231009165317-af2b68361b8a

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
109109
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
110110
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
111111
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
112-
github.com/acorn-io/aml v0.0.0-20231115002431-c08b165964de h1:vFVPRhT87Js+8S6WyyABZdtUpgrwMP6/US+4ChaolhQ=
113-
github.com/acorn-io/aml v0.0.0-20231115002431-c08b165964de/go.mod h1:jImvyZGYOReKDJEEjS2SLjvVAEFcXFMA7OPQ96l1JYA=
112+
github.com/acorn-io/aml v0.0.0-20231115044900-37e80122de99 h1:gsGIU3LyIi8WobSnYwEJsJ+LyhdA4m1zlI///YXRtb0=
113+
github.com/acorn-io/aml v0.0.0-20231115044900-37e80122de99/go.mod h1:jImvyZGYOReKDJEEjS2SLjvVAEFcXFMA7OPQ96l1JYA=
114114
github.com/acorn-io/aml/cli v0.0.0-20231113171943-4844e2f3e1a2 h1:CtflOEPAvtpALuC3SM1WApsfTuECXcDuq25E3fZaPdg=
115115
github.com/acorn-io/aml/cli v0.0.0-20231113171943-4844e2f3e1a2/go.mod h1:D4tWmJlLdsmMbQ/MI4T+Tj4j2PjgTAdde2QDGkeWH20=
116116
github.com/acorn-io/aml/legacy v0.0.0-20230929081514-1e9f3394432e h1:W67DG9AcoNvBwIOR9OFUCZlSJBaHuvM2kXQ2+C6EnLk=

pkg/apis/internal.acorn.io/v1/unmarshal.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,15 +1421,18 @@ func ParseQuantity(s string) (Quantity, error) {
14211421

14221422
func ParseNameValues(fillEnv bool, s ...string) (result []NameValue) {
14231423
for _, s := range s {
1424+
s = strings.TrimSpace(s)
14241425
k, v, _ := strings.Cut(s, "=")
14251426
if v == "" && fillEnv {
14261427
parts := strings.Split(k, ".")
14271428
v = os.Getenv(parts[len(parts)-1])
14281429
}
1429-
result = append(result, NameValue{
1430-
Name: k,
1431-
Value: v,
1432-
})
1430+
if k != "" {
1431+
result = append(result, NameValue{
1432+
Name: k,
1433+
Value: v,
1434+
})
1435+
}
14331436
}
14341437
return result
14351438
}

pkg/cli/edit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ func NewEdit(c CommandContext) *cobra.Command {
1111
Use: "edit ACORN_NAME|SECRET_NAME",
1212
Example: `acorn edit my-acorn`,
1313
SilenceUsage: true,
14-
Short: "Edits an acorn or secret",
14+
Short: "Edits an acorn or secret interactively",
1515
Args: cobra.ExactArgs(1),
1616
ValidArgsFunction: newCompletion(c.ClientFactory, appsThenSecretsCompletion).complete,
1717
})

pkg/cli/run.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io"
99
"os"
10+
"strings"
1011

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

115116
type RunArgs struct {
116117
UpdateArgs
117-
Name string `usage:"Name of app to create" short:"n"`
118+
EnvFile string `usage:"Default env vars to apply" default:".acorn.env"`
119+
Name string `usage:"Name of app to create" short:"n"`
118120
}
119121

120122
func (s RunArgs) ToOpts() (client.AppRunOptions, error) {
@@ -156,6 +158,16 @@ func (s RunArgs) ToOpts() (client.AppRunOptions, error) {
156158

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

161+
if s.EnvFile != "" {
162+
envData, err := os.ReadFile(s.EnvFile)
163+
if os.IsNotExist(err) {
164+
} else if err != nil {
165+
return opts, err
166+
} else {
167+
opts.Env = append(opts.Env, v1.ParseNameValues(false, strings.Split(string(envData), "\n")...)...)
168+
}
169+
}
170+
159171
opts.Labels, err = v1.ParseScopedLabels(s.Label...)
160172
if err != nil {
161173
return opts, err

pkg/cli/secret.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ acorn secret`,
1919
ValidArgsFunction: newCompletion(c.ClientFactory, secretsCompletion).complete,
2020
})
2121
cmd.AddCommand(NewSecretCreate(c))
22+
cmd.AddCommand(NewSecretUpdate(c))
2223
cmd.AddCommand(NewSecretDelete(c))
2324
cmd.AddCommand(NewSecretReveal(c))
2425
cmd.AddCommand(NewSecretEncrypt(c))

pkg/cli/secret_create.go

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1"
1010
cli "github.com/acorn-io/runtime/pkg/cli/builder"
1111
"github.com/spf13/cobra"
12+
apierrors "k8s.io/apimachinery/pkg/api/errors"
1213
)
1314

1415
func NewSecretCreate(c CommandContext) *cobra.Command {
@@ -18,7 +19,7 @@ func NewSecretCreate(c CommandContext) *cobra.Command {
1819
# Create secret with specific keys
1920
acorn secret create --data key-name=value --data key-name2=value2 my-secret
2021
21-
# Read full secret from a file
22+
# Read full secret from a file. The file should have a type and data field.
2223
acorn secret create --file secret.yaml my-secret
2324
2425
# Read key value from a file
@@ -30,14 +31,20 @@ acorn secret create --data @key-name=secret.yaml my-secret`,
3031
return cmd
3132
}
3233

34+
type SecretFactory struct {
35+
Data []string `usage:"Secret data format key=value or @key=filename to read from file"`
36+
File string `usage:"File to read for entire secret in aml/yaml/json format"`
37+
Type string `usage:"Secret type"`
38+
}
39+
3340
type SecretCreate struct {
34-
Data []string `usage:"Secret data format key=value or @key=filename to read from file"`
35-
File string `usage:"File to read for entire secret in cue/yaml/json format"`
36-
Type string `usage:"Secret type"`
37-
client ClientFactory
41+
SecretFactory
42+
Update bool `usage:"Update the secret if it already exists" short:"u"`
43+
Replace bool `usage:"Replace the secret with only defined values, resetting undefined fields to default values" json:"replace,omitempty"`
44+
client ClientFactory
3845
}
3946

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

96103
newSecret, err := client.SecretCreate(cmd.Context(), args[0], secret.Type, secret.Data)
97-
if err != nil {
104+
if apierrors.IsAlreadyExists(err) {
105+
if a.Replace {
106+
newSecret, err = client.SecretUpdate(cmd.Context(), args[0], secret.Data)
107+
if err != nil {
108+
return err
109+
}
110+
} else if a.Update {
111+
existing, err := client.SecretReveal(cmd.Context(), args[0])
112+
if err != nil {
113+
return err
114+
}
115+
if existing.Data == nil {
116+
existing.Data = map[string][]byte{}
117+
}
118+
for k, v := range secret.Data {
119+
existing.Data[k] = v
120+
}
121+
newSecret, err = client.SecretUpdate(cmd.Context(), args[0], existing.Data)
122+
if err != nil {
123+
return err
124+
}
125+
}
126+
} else if err != nil {
98127
return err
99128
}
100129

pkg/cli/secret_create_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88

99
func TestBuildSecret(t *testing.T) {
1010
c := SecretCreate{
11-
Data: []string{"key1=value1", "@key2=testdata/secret/value2.txt"},
12-
File: "testdata/secret/secret.yaml",
13-
Type: "fancy",
11+
SecretFactory: SecretFactory{
12+
Data: []string{"key1=value1", "@key2=testdata/secret/value2.txt"},
13+
File: "testdata/secret/secret.yaml",
14+
Type: "fancy",
15+
},
1416
}
1517

1618
secret, err := c.buildSecret()

pkg/cli/secret_edit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ func NewSecretEdit(c CommandContext) *cobra.Command {
1111
Use: "edit SECRET_NAME",
1212
Example: `acorn secret edit my-secret`,
1313
SilenceUsage: true,
14-
Short: "Edits a secret",
14+
Short: "Edits a secret interactively",
1515
Args: cobra.ExactArgs(1),
1616
ValidArgsFunction: newCompletion(c.ClientFactory, secretsCompletion).complete,
1717
})

pkg/cli/secret_update.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
6+
cli "github.com/acorn-io/runtime/pkg/cli/builder"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
func NewSecretUpdate(c CommandContext) *cobra.Command {
11+
cmd := cli.Command(&SecretUpdate{client: c.ClientFactory}, cobra.Command{
12+
Use: "update [flags] SECRET_NAME",
13+
Example: `
14+
# Create secret with specific keys
15+
acorn secret update --data key-name=value --data key-name2=value2 my-secret
16+
17+
# Read full secret from a file. The file should have a type and data field.
18+
acorn secret update --file secret.yaml my-secret
19+
20+
# Read key value from a file
21+
acorn secret update --data @key-name=secret.yaml my-secret`,
22+
SilenceUsage: true,
23+
Short: "Update a secret",
24+
Args: cobra.ExactArgs(1),
25+
})
26+
return cmd
27+
}
28+
29+
type SecretUpdate struct {
30+
SecretFactory
31+
client ClientFactory
32+
}
33+
34+
func (a *SecretUpdate) Run(cmd *cobra.Command, args []string) error {
35+
client, err := a.client.CreateDefault()
36+
if err != nil {
37+
return err
38+
}
39+
40+
secret, err := a.buildSecret()
41+
if err != nil {
42+
return err
43+
}
44+
45+
existing, err := client.SecretReveal(cmd.Context(), args[0])
46+
if err != nil {
47+
return err
48+
}
49+
50+
if existing.Data == nil {
51+
existing.Data = map[string][]byte{}
52+
}
53+
54+
for k, v := range secret.Data {
55+
existing.Data[k] = v
56+
}
57+
58+
newSecret, err := client.SecretUpdate(cmd.Context(), args[0], existing.Data)
59+
if err != nil {
60+
return err
61+
}
62+
63+
fmt.Println(newSecret.Name)
64+
return nil
65+
}

0 commit comments

Comments
 (0)