From f9a0e671b7d471b4951b25864d5b5f43743827bb Mon Sep 17 00:00:00 2001 From: Ivan Shvedunov Date: Tue, 14 Aug 2018 22:50:33 +0300 Subject: [PATCH] Add timeoutSeconds to secretArgs --- docs/kustomization.yaml | 3 +++ pkg/app/application_test.go | 30 +++++++++++++++++++++++++ pkg/configmapandsecret/secretfactory.go | 25 ++++++++++++++------- pkg/resmap/secret_test.go | 24 ++++++++++++++++++++ pkg/types/kustomization.go | 3 +++ 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/docs/kustomization.yaml b/docs/kustomization.yaml index f81f437ee9..01571fb172 100644 --- a/docs/kustomization.yaml +++ b/docs/kustomization.yaml @@ -83,6 +83,9 @@ secretGenerator: tls.key: "cat secret/tls.key" type: "kubernetes.io/tls" - name: downloaded_secret + # timeoutSeconds specifies the number of seconds to + # wait for the commands below. It defaults to 5 seconds. + timeoutSeconds: 30 commands: username: "curl -s https://path/to/secrets/username.yaml" password: "curl -s https://path/to/secrets/password.yaml" diff --git a/pkg/app/application_test.go b/pkg/app/application_test.go index 555f381110..1a095acc57 100644 --- a/pkg/app/application_test.go +++ b/pkg/app/application_test.go @@ -19,6 +19,7 @@ package app import ( "encoding/base64" "reflect" + "strings" "testing" "github.com/kubernetes-sigs/kustomize/pkg/constants" @@ -53,6 +54,14 @@ secretGenerator: DB_USERNAME: "printf admin" DB_PASSWORD: "printf somepw" type: Opaque +` + kustomizationContent2 = ` +secretGenerator: +- name: secret + timeoutSeconds: 1 + commands: + USER: "sleep 2" + type: Opaque ` deploymentContent = `apiVersion: apps/v1 metadata: @@ -340,3 +349,24 @@ func TestRawResources2(t *testing.T) { t.Fatalf("unexpected inequality: %v", err) } } + +func TestSecretTimeout(t *testing.T) { + l := loadertest.NewFakeLoader("/testpath") + err := l.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContent2)) + if err != nil { + t.Fatalf("Failed to setup fake ldr.") + } + fakeFs := fs.MakeFakeFS() + fakeFs.Mkdir("/") + app, err := NewApplication(l, fakeFs) + if err != nil { + t.Fatalf("Unexpected construction error %v", err) + } + _, err = app.MakeCustomizedResMap() + if err == nil { + t.Fatalf("Didn't get the expected error for an unknown resource") + } + if !strings.Contains(err.Error(), "killed") { + t.Fatalf("Unpexpected error message %q", err) + } +} diff --git a/pkg/configmapandsecret/secretfactory.go b/pkg/configmapandsecret/secretfactory.go index 815224bea7..038a4c3216 100644 --- a/pkg/configmapandsecret/secretfactory.go +++ b/pkg/configmapandsecret/secretfactory.go @@ -31,6 +31,10 @@ import ( "k8s.io/apimachinery/pkg/util/validation" ) +const ( + defaultCommandTimeout = 5 * time.Second +) + // SecretFactory makes Secrets. type SecretFactory struct { fSys fs.FileSystem @@ -61,7 +65,12 @@ func (f *SecretFactory) MakeSecret(args *types.SecretArgs) (*corev1.Secret, erro var err error s := f.makeFreshSecret(args) - pairs, err := f.keyValuesFromEnvFileCommand(args.EnvCommand) + timeout := defaultCommandTimeout + if args.TimeoutSeconds != nil { + timeout = time.Duration(*args.TimeoutSeconds) * time.Second + } + + pairs, err := f.keyValuesFromEnvFileCommand(args.EnvCommand, timeout) if err != nil { return nil, errors.Wrap(err, fmt.Sprintf( "env source file: %s", @@ -69,7 +78,7 @@ func (f *SecretFactory) MakeSecret(args *types.SecretArgs) (*corev1.Secret, erro } all = append(all, pairs...) - pairs, err = f.keyValuesFromCommands(args.Commands) + pairs, err = f.keyValuesFromCommands(args.Commands, timeout) if err != nil { return nil, errors.Wrap(err, fmt.Sprintf( "commands %v", args.Commands)) @@ -98,18 +107,18 @@ func addKvToSecret(secret *corev1.Secret, keyName, data string) error { return nil } -func (f *SecretFactory) keyValuesFromEnvFileCommand(cmd string) ([]kvPair, error) { - content, err := f.createSecretKey(cmd) +func (f *SecretFactory) keyValuesFromEnvFileCommand(cmd string, timeout time.Duration) ([]kvPair, error) { + content, err := f.createSecretKey(cmd, timeout) if err != nil { return nil, err } return keyValuesFromLines(content) } -func (f *SecretFactory) keyValuesFromCommands(sources map[string]string) ([]kvPair, error) { +func (f *SecretFactory) keyValuesFromCommands(sources map[string]string, timeout time.Duration) ([]kvPair, error) { var kvs []kvPair for k, cmd := range sources { - content, err := f.createSecretKey(cmd) + content, err := f.createSecretKey(cmd, timeout) if err != nil { return nil, err } @@ -119,14 +128,14 @@ func (f *SecretFactory) keyValuesFromCommands(sources map[string]string) ([]kvPa } // Run a command, return its output as the secret. -func (f *SecretFactory) createSecretKey(command string) ([]byte, error) { +func (f *SecretFactory) createSecretKey(command string, timeout time.Duration) ([]byte, error) { if !f.fSys.IsDir(f.wd) { f.wd = filepath.Dir(f.wd) if !f.fSys.IsDir(f.wd) { return nil, errors.New("not a directory: " + f.wd) } } - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() cmd := exec.CommandContext(ctx, "sh", "-c", command) cmd.Dir = f.wd diff --git a/pkg/resmap/secret_test.go b/pkg/resmap/secret_test.go index b43a1fcc29..e36470690b 100644 --- a/pkg/resmap/secret_test.go +++ b/pkg/resmap/secret_test.go @@ -94,3 +94,27 @@ func TestNewResMapFromSecretArgs(t *testing.T) { t.Fatalf("%#v\ndoesn't match expected:\n%#v", actual, expected) } } + +func TestSecretTimeout(t *testing.T) { + timeout := int64(1) + secrets := []types.SecretArgs{ + { + Name: "slow", + TimeoutSeconds: &timeout, + CommandSources: types.CommandSources{ + Commands: map[string]string{ + "USER": "sleep 2", + }, + }, + Type: "Opaque", + }, + } + fakeFs := fs.MakeFakeFS() + fakeFs.Mkdir(".") + _, err := NewResMapFromSecretArgs( + configmapandsecret.NewSecretFactory(fakeFs, "."), secrets) + + if err == nil { + t.Fatal("didn't get the expected timeout error", err) + } +} diff --git a/pkg/types/kustomization.go b/pkg/types/kustomization.go index fe3ae3cab2..45d2bc1d83 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -117,6 +117,9 @@ type SecretArgs struct { // CommandSources for secret. CommandSources `json:",inline,omitempty" yaml:",inline,omitempty"` + + // TimeoutSeconds specifies the timeout for commands. + TimeoutSeconds *int64 `json:"timeoutSeconds,omitempty" yaml:"timeoutSeconds,omitempty"` } // CommandSources contains some generic sources for secrets.