From 71814cc27382110605f732dce9a1cfe5c37b97ae Mon Sep 17 00:00:00 2001 From: Venkat Ramaraju Date: Mon, 6 Jul 2020 08:05:57 -0700 Subject: [PATCH 01/10] Added flags, added fields to runner struct Changed runner args to just args Testing Changelog file Changes based on review Error checking Changes docs: arbitrary args + ansible-vault support Changes from review Changes Changes Changes --- changelog/fragments/arbitraryArgs.yaml | 10 ++ cmd/ansible-operator/main.go | 139 ++++++++++++++++++ internal/ansible/flags/flag.go | 8 + .../runner/internal/inputdir/inputdir.go | 14 ++ internal/ansible/runner/runner.go | 45 +++--- internal/ansible/runner/runner_test.go | 2 +- test/ansible/build/Dockerfile | 4 +- .../crds/test.example.com_argstest_crd.yaml | 22 +++ .../molecule/cluster/tasks/args_test.yml | 26 ++++ .../molecule/templates/operator.yaml.j2 | 1 + test/ansible/playbooks/args.yml | 20 +++ test/ansible/watches.yaml | 7 + .../ansible/reference/advanced_options.md | 48 ++++++ 13 files changed, 323 insertions(+), 23 deletions(-) create mode 100644 changelog/fragments/arbitraryArgs.yaml create mode 100644 test/ansible/deploy/crds/test.example.com_argstest_crd.yaml create mode 100644 test/ansible/molecule/cluster/tasks/args_test.yml create mode 100644 test/ansible/playbooks/args.yml diff --git a/changelog/fragments/arbitraryArgs.yaml b/changelog/fragments/arbitraryArgs.yaml new file mode 100644 index 0000000000..abcbe30cdf --- /dev/null +++ b/changelog/fragments/arbitraryArgs.yaml @@ -0,0 +1,10 @@ +entries: + - description: > + Added the "--ansible-args" command-line flag that allows users to specify arbitrary + CLI arguments for ansible-based operators that are passed through ansible-runner. + For example, passing --ansible-vault as an arbitrary argument allows the user to store + sensitive data in encrypted files. + + kind: "addition" + + breaking: false \ No newline at end of file diff --git a/cmd/ansible-operator/main.go b/cmd/ansible-operator/main.go index 78db568b61..8f5f8f95b2 100644 --- a/cmd/ansible-operator/main.go +++ b/cmd/ansible-operator/main.go @@ -24,8 +24,147 @@ import ( ) func main() { +<<<<<<< HEAD root := cobra.Command{ Use: "ansible-operator", +======= + f := &flags.Flags{} + f.AddTo(pflag.CommandLine) + pflag.Parse() + logf.SetLogger(zap.Logger()) + + printVersion() + + cfg, err := config.GetConfig() + if err != nil { + log.Error(err, "Failed to get config.") + os.Exit(1) + } + + // Deprecated: OPERATOR_NAME environment variable is an artifact of the + // legacy operator-sdk project scaffolding. Flag `--leader-election-id` + // should be used instead. + if operatorName, found := os.LookupEnv("OPERATOR_NAME"); found { + log.Info("Environment variable OPERATOR_NAME has been deprecated, use --leader-election-id instead.") + if pflag.CommandLine.Lookup("leader-election-id").Changed { + log.Info("Ignoring OPERATOR_NAME environment variable since --leader-election-id is set") + } else { + f.LeaderElectionID = operatorName + } + } + + // Set default manager options + // TODO: probably should expose the host & port as an environment variables + options := manager.Options{ + HealthProbeBindAddress: fmt.Sprintf("%s:%d", metricsHost, healthProbePort), + MetricsBindAddress: f.MetricsAddress, + LeaderElection: f.EnableLeaderElection, + LeaderElectionID: f.LeaderElectionID, + LeaderElectionNamespace: f.LeaderElectionNamespace, + NewClient: func(cache cache.Cache, config *rest.Config, options client.Options) (client.Client, error) { + c, err := client.New(config, options) + if err != nil { + return nil, err + } + return &client.DelegatingClient{ + Reader: cache, + Writer: c, + StatusClient: c, + }, nil + }, + } + + namespace, found := os.LookupEnv(k8sutil.WatchNamespaceEnvVar) + log = log.WithValues("Namespace", namespace) + if found { + if namespace == metav1.NamespaceAll { + log.Info("Watching all namespaces.") + options.Namespace = metav1.NamespaceAll + } else { + if strings.Contains(namespace, ",") { + log.Info("Watching multiple namespaces.") + options.NewCache = cache.MultiNamespacedCacheBuilder(strings.Split(namespace, ",")) + } else { + log.Info("Watching single namespace.") + options.Namespace = namespace + } + } + } else { + log.Info(fmt.Sprintf("%v environment variable not set. Watching all namespaces.", + k8sutil.WatchNamespaceEnvVar)) + options.Namespace = metav1.NamespaceAll + } + + err = setAnsibleEnvVars(f) + if err != nil { + log.Error(err, "Failed to set environment variable.") + os.Exit(1) + } + + // Create a new manager to provide shared dependencies and start components + mgr, err := manager.New(cfg, options) + if err != nil { + log.Error(err, "Failed to create a new manager.") + os.Exit(1) + } + + cMap := controllermap.NewControllerMap() + watches, err := watches.Load(f.WatchesFile, f.MaxConcurrentReconciles, f.AnsibleVerbosity) + if err != nil { + log.Error(err, "Failed to load watches.") + os.Exit(1) + } + for _, w := range watches { + runner, err := runner.New(w, flags.AnsibleArgs) + if err != nil { + log.Error(err, "Failed to create runner") + os.Exit(1) + } + + ctr := controller.Add(mgr, controller.Options{ + GVK: w.GroupVersionKind, + Runner: runner, + ManageStatus: w.ManageStatus, + AnsibleDebugLogs: getAnsibleDebugLog(), + MaxConcurrentReconciles: w.MaxConcurrentReconciles, + ReconcilePeriod: w.ReconcilePeriod, + Selector: w.Selector, + }) + if ctr == nil { + log.Error(fmt.Errorf("failed to add controller for GVK %v", w.GroupVersionKind.String()), "") + os.Exit(1) + } + + cMap.Store(w.GroupVersionKind, &controllermap.Contents{Controller: *ctr, + WatchDependentResources: w.WatchDependentResources, + WatchClusterScopedResources: w.WatchClusterScopedResources, + OwnerWatchMap: controllermap.NewWatchMap(), + AnnotationWatchMap: controllermap.NewWatchMap(), + }, w.Blacklist) + } + + err = mgr.AddHealthzCheck("ping", healthz.Ping) + if err != nil { + log.Error(err, "Failed to add Healthz check.") + } + + done := make(chan error) + + // start the proxy + err = proxy.Run(done, proxy.Options{ + Address: "localhost", + Port: 8888, + KubeConfig: mgr.GetConfig(), + Cache: mgr.GetCache(), + RESTMapper: mgr.GetRESTMapper(), + ControllerMap: cMap, + OwnerInjection: f.InjectOwnerRef, + WatchedNamespaces: []string{namespace}, + }) + if err != nil { + log.Error(err, "Error starting proxy.") + os.Exit(1) +>>>>>>> Added flags, added fields to runner struct } root.AddCommand(run.NewCmd()) diff --git a/internal/ansible/flags/flag.go b/internal/ansible/flags/flag.go index 350bf31efd..f6bf7b5b3f 100644 --- a/internal/ansible/flags/flag.go +++ b/internal/ansible/flags/flag.go @@ -34,6 +34,7 @@ type Flags struct { MetricsAddress string LeaderElectionID string LeaderElectionNamespace string + AnsibleArgs string } const AnsibleRolesPathEnvVar = "ANSIBLE_ROLES_PATH" @@ -99,4 +100,11 @@ func (f *Flags) AddTo(flagSet *pflag.FlagSet) { " holding the leader lock (required if running locally with leader"+ " election enabled).", ) + flagSet.StringVar(&f.AnsibleArgs, + "ansible-args", + "", + strings.Join(append(helpTextPrefix, + "Ansible args. Allows user to specify arbitrary arguments for ansible-based operators."), + " "), + ) } diff --git a/internal/ansible/runner/internal/inputdir/inputdir.go b/internal/ansible/runner/internal/inputdir/inputdir.go index 3bc4c96c6a..5dc167938b 100644 --- a/internal/ansible/runner/internal/inputdir/inputdir.go +++ b/internal/ansible/runner/internal/inputdir/inputdir.go @@ -36,6 +36,7 @@ type InputDir struct { Parameters map[string]interface{} EnvVars map[string]string Settings map[string]string + CmdLine string } // makeDirs creates the required directory structure. @@ -131,6 +132,19 @@ func (i *InputDir) Write() error { return err } + if strings.HasPrefix(i.CmdLine, string("'")) && i.CmdLine[0] == i.CmdLine[len(i.CmdLine)-1] { + i.CmdLine = i.CmdLine[1 : len(i.CmdLine)-1] + } + + cmdLineBytes := []byte(i.CmdLine) + + if len(cmdLineBytes) > 0 { + err = i.addFile("env/cmdline", cmdLineBytes) + if err != nil { + return err + } + } + // ANSIBLE_INVENTORY takes precedence over our generated hosts file // so if the envvar is set we don't bother making it, we just copy // the inventory into our runner directory diff --git a/internal/ansible/runner/runner.go b/internal/ansible/runner/runner.go index 0d99c080f2..2d061551c0 100644 --- a/internal/ansible/runner/runner.go +++ b/internal/ansible/runner/runner.go @@ -89,17 +89,17 @@ func roleCmdFunc(path string) cmdFuncType { // check the verbosity since the exec.Command will fail if an arg as "" or " " be informed if verbosity > 0 { return exec.Command("ansible-runner", ansibleVerbosityString(verbosity), "--rotate-artifacts", - fmt.Sprintf("%v", maxArtifacts), "--role", roleName, "--roles-path", rolePath, "--hosts", - "localhost", "-i", ident, "run", inputDirPath) + fmt.Sprintf("%v", maxArtifacts), "--role", roleName, "--roles-path", rolePath, + "--hosts", "localhost", "-i", ident, "run", inputDirPath) } return exec.Command("ansible-runner", "--rotate-artifacts", - fmt.Sprintf("%v", maxArtifacts), "--role", roleName, "--roles-path", rolePath, "--hosts", - "localhost", "-i", ident, "run", inputDirPath) + fmt.Sprintf("%v", maxArtifacts), "--role", roleName, "--roles-path", rolePath, + "--hosts", "localhost", "-i", ident, "run", inputDirPath) } } // New - creates a Runner from a Watch struct -func New(watch watches.Watch) (Runner, error) { +func New(watch watches.Watch, runnerArgs string) (Runner, error) { var path string var cmdFunc, finalizerCmdFunc cmdFuncType @@ -131,29 +131,31 @@ func New(watch watches.Watch) (Runner, error) { } return &runner{ - Path: path, - cmdFunc: cmdFunc, - Vars: watch.Vars, - Finalizer: watch.Finalizer, - finalizerCmdFunc: finalizerCmdFunc, - GVK: watch.GroupVersionKind, - maxRunnerArtifacts: watch.MaxRunnerArtifacts, - ansibleVerbosity: watch.AnsibleVerbosity, + Path: path, + cmdFunc: cmdFunc, + Vars: watch.Vars, + Finalizer: watch.Finalizer, + finalizerCmdFunc: finalizerCmdFunc, + GVK: watch.GroupVersionKind, + maxRunnerArtifacts: watch.MaxRunnerArtifacts, + ansibleVerbosity: watch.AnsibleVerbosity, + ansibleArgs: runnerArgs, snakeCaseParameters: watch.SnakeCaseParameters, }, nil } // runner - implements the Runner interface for a GVK that's being watched. type runner struct { - Path string // path on disk to a playbook or role depending on what cmdFunc expects - GVK schema.GroupVersionKind // GVK being watched that corresponds to the Path - Finalizer *watches.Finalizer - Vars map[string]interface{} - cmdFunc cmdFuncType // returns a Cmd that runs ansible-runner - finalizerCmdFunc cmdFuncType - maxRunnerArtifacts int - ansibleVerbosity int + Path string // path on disk to a playbook or role depending on what cmdFunc expects + GVK schema.GroupVersionKind // GVK being watched that corresponds to the Path + Finalizer *watches.Finalizer + Vars map[string]interface{} + cmdFunc cmdFuncType // returns a Cmd that runs ansible-runner + finalizerCmdFunc cmdFuncType + maxRunnerArtifacts int + ansibleVerbosity int snakeCaseParameters bool + ansibleArgs string } func (r *runner) Run(ident string, u *unstructured.Unstructured, kubeconfig string) (RunResult, error) { @@ -188,6 +190,7 @@ func (r *runner) Run(ident string, u *unstructured.Unstructured, kubeconfig stri "runner_http_url": receiver.SocketPath, "runner_http_path": receiver.URLPath, }, + CmdLine: r.ansibleArgs, } // If Path is a dir, assume it is a role path. Otherwise assume it's a // playbook path diff --git a/internal/ansible/runner/runner_test.go b/internal/ansible/runner/runner_test.go index 0c369438ba..4133c1a835 100644 --- a/internal/ansible/runner/runner_test.go +++ b/internal/ansible/runner/runner_test.go @@ -159,7 +159,7 @@ func TestNew(t *testing.T) { t.Run(tc.name, func(t *testing.T) { testWatch := watches.New(tc.gvk, tc.role, tc.playbook, tc.vars, tc.finalizer) - testRunner, err := New(*testWatch) + testRunner, err := New(*testWatch, "") if err != nil { t.Fatalf("Error occurred unexpectedly: %v", err) } diff --git a/test/ansible/build/Dockerfile b/test/ansible/build/Dockerfile index 9f9f4e9ce3..8b89901254 100644 --- a/test/ansible/build/Dockerfile +++ b/test/ansible/build/Dockerfile @@ -15,4 +15,6 @@ USER root RUN chmod -R ug+rwx /tmp/fixture_collection USER 1001 RUN ansible-galaxy collection build /tmp/fixture_collection/ --output-path /tmp/fixture_collection/ \ - && ansible-galaxy collection install /tmp/fixture_collection/operator_sdk-test_fixtures-0.0.0.tar.gz + && ansible-galaxy collection install /tmp/fixture_collection/operator_sdk-test_fixtures-0.0.0.tar.gz +RUN echo abc123 > /opt/ansible/pwd.yml \ + && ansible-vault encrypt_string --vault-password-file /opt/ansible/pwd.yml 'thisisatest' --name 'the_secret' > /opt/ansible/vars.yml \ No newline at end of file diff --git a/test/ansible/deploy/crds/test.example.com_argstest_crd.yaml b/test/ansible/deploy/crds/test.example.com_argstest_crd.yaml new file mode 100644 index 0000000000..8b3ebe8b21 --- /dev/null +++ b/test/ansible/deploy/crds/test.example.com_argstest_crd.yaml @@ -0,0 +1,22 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: argstests.test.example.com +spec: + group: test.example.com + names: + kind: ArgsTest + listKind: ArgsTestList + plural: argstests + singular: argstest + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + served: true + storage: true + subresources: + status: {} diff --git a/test/ansible/molecule/cluster/tasks/args_test.yml b/test/ansible/molecule/cluster/tasks/args_test.yml new file mode 100644 index 0000000000..aa91e3b983 --- /dev/null +++ b/test/ansible/molecule/cluster/tasks/args_test.yml @@ -0,0 +1,26 @@ +--- +- name: Create the test.example.com/v1alpha1.ArgsTest + k8s: + state: present + definition: + apiVersion: test.example.com/v1alpha1 + kind: ArgsTest + metadata: + name: args-test + namespace: '{{ namespace }}' + spec: + field: value + wait: yes + wait_timeout: 300 + wait_condition: + type: Running + reason: Successful + status: "True" + register: args_test + +- name: Assert sentinel ConfigMap has been created for Molecule Test + assert: + that: cm.data.msg == "The decrypted value is thisisatest" + vars: + cm: "{{ q('k8s', api_version='v1', kind='ConfigMap', namespace=namespace, + resource_name='args-test').0 }}" diff --git a/test/ansible/molecule/templates/operator.yaml.j2 b/test/ansible/molecule/templates/operator.yaml.j2 index 8c72325a11..01b7d83b18 100644 --- a/test/ansible/molecule/templates/operator.yaml.j2 +++ b/test/ansible/molecule/templates/operator.yaml.j2 @@ -48,6 +48,7 @@ spec: port: 6789 initialDelaySeconds: 5 periodSeconds: 3 + args: ["--ansible-args='--vault-password-file /opt/ansible/pwd.yml' "] volumes: - name: runner emptyDir: {} diff --git a/test/ansible/playbooks/args.yml b/test/ansible/playbooks/args.yml new file mode 100644 index 0000000000..c7a6670d12 --- /dev/null +++ b/test/ansible/playbooks/args.yml @@ -0,0 +1,20 @@ +--- +- hosts: localhost + gather_facts: no + collections: + - community.kubernetes + tasks: + - name: Get the decrypted message variable + include_vars: + file: /opt/ansible/vars.yml + name: the_secret + - name: Create configmap + k8s: + definition: + apiVersion: v1 + kind: ConfigMap + metadata: + name: '{{ meta.name }}' + namespace: '{{ meta.namespace }}' + data: + msg: The decrypted value is {{the_secret.the_secret}} diff --git a/test/ansible/watches.yaml b/test/ansible/watches.yaml index 2a76caf314..492e7cb510 100644 --- a/test/ansible/watches.yaml +++ b/test/ansible/watches.yaml @@ -45,3 +45,10 @@ snakeCaseParameters: false vars: meta: '{{ ansible_operator_meta }}' + +- version: v1alpha1 + group: test.example.com + kind: ArgsTest + playbook: playbooks/args.yml + vars: + meta: '{{ ansible_operator_meta }}' diff --git a/website/content/en/docs/building-operators/ansible/reference/advanced_options.md b/website/content/en/docs/building-operators/ansible/reference/advanced_options.md index 3ec789c336..eb0287d258 100644 --- a/website/content/en/docs/building-operators/ansible/reference/advanced_options.md +++ b/website/content/en/docs/building-operators/ansible/reference/advanced_options.md @@ -211,3 +211,51 @@ spec: served: true storage: true ``` + +## Passing Arbitrary Arguments to Ansible + +You are able to use the flag `--ansible-args` to pass an arbitrary argument to the Ansible-based Operator. With this option we can, for example, allow a playbook to run a specific part of the configuration without running the whole playbook: + +```shell +operator-sdk run local --ansible-args='--tags "configuration,packages"' +``` +``` +operator-sdk run local --ansible-args='--skip-tags "notification"' +``` +Ansible-runner will perform the task relevant to the command specified by the user in the ```---ansible-args``` flag. + + +## Using Ansible-Vault + +[Ansible Vault][ansible-vault-doc] allows you to keep sensitive data such as passwords or keys in encrypted files, rather than as plaintext in playbooks or roles. You can specify Ansible-Vault file via an arbitrary argument by using the `--ansible-args` flag. For example, let's assume that a playbook reads in a file `vars.yml` which contains an encrypted text and stores it in a variable `secret`: + +``` +--- +- name: Playbook to print debug messages + gather_facts: false + hosts: localhost + tasks: + - name: Get the decrypted message variable + include_vars: + file: vars.yml + name: secret + - debug: + msg: The decrypted value is {{secret.the_secret}} +``` + +Now, let's also assume that we have a password file, `pwd.yml`, that contains the password to decrypt the encrypted text. Then, by running the command `ansible-operator run --ansible-args='--vault-password-file pwd.yml'` the operator will read in the encrypted text from the file and perform decryption using the password stored in the `pwd.yml` file: + +``` +--------------------------- Ansible Task StdOut ------------------------------- + + TASK [debug] ******************************** +ok: [localhost] => { + "msg": "The decrypted value is DECRYPTED-TEST-VALUE" +} + +------------------------------------------------------------------------------- +``` +[ansible-vault-doc]: https://docs.ansible.com/ansible/latest/user_guide/vault.html + + + From 6cdddd7f0d76851936c30be627a61db454a35766 Mon Sep 17 00:00:00 2001 From: Venkat Ramaraju Date: Wed, 15 Jul 2020 11:38:58 -0700 Subject: [PATCH 02/10] Changes --- cmd/ansible-operator/main.go | 2 +- internal/ansible/flags/flag.go | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cmd/ansible-operator/main.go b/cmd/ansible-operator/main.go index 8f5f8f95b2..3b451e74a7 100644 --- a/cmd/ansible-operator/main.go +++ b/cmd/ansible-operator/main.go @@ -115,7 +115,7 @@ func main() { os.Exit(1) } for _, w := range watches { - runner, err := runner.New(w, flags.AnsibleArgs) + runner, err := runner.New(w, f.AnsibleArgs) if err != nil { log.Error(err, "Failed to create runner") os.Exit(1) diff --git a/internal/ansible/flags/flag.go b/internal/ansible/flags/flag.go index f6bf7b5b3f..8e8168d78a 100644 --- a/internal/ansible/flags/flag.go +++ b/internal/ansible/flags/flag.go @@ -103,8 +103,6 @@ func (f *Flags) AddTo(flagSet *pflag.FlagSet) { flagSet.StringVar(&f.AnsibleArgs, "ansible-args", "", - strings.Join(append(helpTextPrefix, - "Ansible args. Allows user to specify arbitrary arguments for ansible-based operators."), - " "), + "Ansible args. Allows user to specify arbitrary arguments for ansible-based operators.", ) } From af1eab207e1f7e8fe5bbccee9c46ec355a9987c1 Mon Sep 17 00:00:00 2001 From: VenkatRamaraju Date: Tue, 21 Jul 2020 14:31:51 -0700 Subject: [PATCH 03/10] Changes + Travis --- internal/ansible/runner/internal/inputdir/inputdir.go | 7 +++++-- test/ansible/molecule/templates/operator.yaml.j2 | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/ansible/runner/internal/inputdir/inputdir.go b/internal/ansible/runner/internal/inputdir/inputdir.go index 5dc167938b..74d1f5181c 100644 --- a/internal/ansible/runner/internal/inputdir/inputdir.go +++ b/internal/ansible/runner/internal/inputdir/inputdir.go @@ -133,11 +133,14 @@ func (i *InputDir) Write() error { } if strings.HasPrefix(i.CmdLine, string("'")) && i.CmdLine[0] == i.CmdLine[len(i.CmdLine)-1] { - i.CmdLine = i.CmdLine[1 : len(i.CmdLine)-1] + i.CmdLine = i.CmdLine[1 : len(i.CmdLine)-1] } - cmdLineBytes := []byte(i.CmdLine) + fmt.Println("------------------------>") + fmt.Println(i.CmdLine) + fmt.Println("------------------------>") + cmdLineBytes := []byte(i.CmdLine) if len(cmdLineBytes) > 0 { err = i.addFile("env/cmdline", cmdLineBytes) if err != nil { diff --git a/test/ansible/molecule/templates/operator.yaml.j2 b/test/ansible/molecule/templates/operator.yaml.j2 index 01b7d83b18..ac940a6030 100644 --- a/test/ansible/molecule/templates/operator.yaml.j2 +++ b/test/ansible/molecule/templates/operator.yaml.j2 @@ -48,7 +48,7 @@ spec: port: 6789 initialDelaySeconds: 5 periodSeconds: 3 - args: ["--ansible-args='--vault-password-file /opt/ansible/pwd.yml' "] + args: ["--ansible-args='--vault-password-file /opt/ansible/pwd.yml'"] volumes: - name: runner emptyDir: {} From e5f1205b6ce46857075f2631cbf35d9f9906c9f4 Mon Sep 17 00:00:00 2001 From: VenkatRamaraju Date: Tue, 21 Jul 2020 14:37:27 -0700 Subject: [PATCH 04/10] Changes + Travis --- internal/ansible/runner/internal/inputdir/inputdir.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/ansible/runner/internal/inputdir/inputdir.go b/internal/ansible/runner/internal/inputdir/inputdir.go index 74d1f5181c..bce6f991e5 100644 --- a/internal/ansible/runner/internal/inputdir/inputdir.go +++ b/internal/ansible/runner/internal/inputdir/inputdir.go @@ -136,10 +136,6 @@ func (i *InputDir) Write() error { i.CmdLine = i.CmdLine[1 : len(i.CmdLine)-1] } - fmt.Println("------------------------>") - fmt.Println(i.CmdLine) - fmt.Println("------------------------>") - cmdLineBytes := []byte(i.CmdLine) if len(cmdLineBytes) > 0 { err = i.addFile("env/cmdline", cmdLineBytes) From 0da45dd2972b50488e06a6158b4e50a61ed89b6d Mon Sep 17 00:00:00 2001 From: VenkatRamaraju Date: Tue, 21 Jul 2020 18:25:36 -0700 Subject: [PATCH 05/10] Formatting --- .../runner/internal/inputdir/inputdir.go | 2 +- internal/ansible/runner/runner.go | 36 +++++++++---------- .../ansible/reference/advanced_options.md | 4 +-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/internal/ansible/runner/internal/inputdir/inputdir.go b/internal/ansible/runner/internal/inputdir/inputdir.go index bce6f991e5..6a28fc3bc6 100644 --- a/internal/ansible/runner/internal/inputdir/inputdir.go +++ b/internal/ansible/runner/internal/inputdir/inputdir.go @@ -133,7 +133,7 @@ func (i *InputDir) Write() error { } if strings.HasPrefix(i.CmdLine, string("'")) && i.CmdLine[0] == i.CmdLine[len(i.CmdLine)-1] { - i.CmdLine = i.CmdLine[1 : len(i.CmdLine)-1] + i.CmdLine = i.CmdLine[1 : len(i.CmdLine)-1] } cmdLineBytes := []byte(i.CmdLine) diff --git a/internal/ansible/runner/runner.go b/internal/ansible/runner/runner.go index 2d061551c0..6b20c9eb64 100644 --- a/internal/ansible/runner/runner.go +++ b/internal/ansible/runner/runner.go @@ -131,31 +131,31 @@ func New(watch watches.Watch, runnerArgs string) (Runner, error) { } return &runner{ - Path: path, - cmdFunc: cmdFunc, - Vars: watch.Vars, - Finalizer: watch.Finalizer, - finalizerCmdFunc: finalizerCmdFunc, - GVK: watch.GroupVersionKind, - maxRunnerArtifacts: watch.MaxRunnerArtifacts, - ansibleVerbosity: watch.AnsibleVerbosity, - ansibleArgs: runnerArgs, + Path: path, + cmdFunc: cmdFunc, + Vars: watch.Vars, + Finalizer: watch.Finalizer, + finalizerCmdFunc: finalizerCmdFunc, + GVK: watch.GroupVersionKind, + maxRunnerArtifacts: watch.MaxRunnerArtifacts, + ansibleVerbosity: watch.AnsibleVerbosity, + ansibleArgs: runnerArgs, snakeCaseParameters: watch.SnakeCaseParameters, }, nil } // runner - implements the Runner interface for a GVK that's being watched. type runner struct { - Path string // path on disk to a playbook or role depending on what cmdFunc expects - GVK schema.GroupVersionKind // GVK being watched that corresponds to the Path - Finalizer *watches.Finalizer - Vars map[string]interface{} - cmdFunc cmdFuncType // returns a Cmd that runs ansible-runner - finalizerCmdFunc cmdFuncType - maxRunnerArtifacts int - ansibleVerbosity int + Path string // path on disk to a playbook or role depending on what cmdFunc expects + GVK schema.GroupVersionKind // GVK being watched that corresponds to the Path + Finalizer *watches.Finalizer + Vars map[string]interface{} + cmdFunc cmdFuncType // returns a Cmd that runs ansible-runner + finalizerCmdFunc cmdFuncType + maxRunnerArtifacts int + ansibleVerbosity int snakeCaseParameters bool - ansibleArgs string + ansibleArgs string } func (r *runner) Run(ident string, u *unstructured.Unstructured, kubeconfig string) (RunResult, error) { diff --git a/website/content/en/docs/building-operators/ansible/reference/advanced_options.md b/website/content/en/docs/building-operators/ansible/reference/advanced_options.md index eb0287d258..487c2c27d3 100644 --- a/website/content/en/docs/building-operators/ansible/reference/advanced_options.md +++ b/website/content/en/docs/building-operators/ansible/reference/advanced_options.md @@ -217,10 +217,10 @@ spec: You are able to use the flag `--ansible-args` to pass an arbitrary argument to the Ansible-based Operator. With this option we can, for example, allow a playbook to run a specific part of the configuration without running the whole playbook: ```shell -operator-sdk run local --ansible-args='--tags "configuration,packages"' +ansible-operator run --ansible-args='--tags "configuration,packages"' ``` ``` -operator-sdk run local --ansible-args='--skip-tags "notification"' +ansible-operator run --ansible-args='--skip-tags "notification"' ``` Ansible-runner will perform the task relevant to the command specified by the user in the ```---ansible-args``` flag. From c61ddf77b4f0c4d4b4e2d8e5f5b65d4e51e6b996 Mon Sep 17 00:00:00 2001 From: Venkat Ramaraju Date: Tue, 28 Jul 2020 13:52:29 -0700 Subject: [PATCH 06/10] Format --- test/ansible/watches.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ansible/watches.yaml b/test/ansible/watches.yaml index 492e7cb510..a658f5447d 100644 --- a/test/ansible/watches.yaml +++ b/test/ansible/watches.yaml @@ -47,7 +47,7 @@ meta: '{{ ansible_operator_meta }}' - version: v1alpha1 - group: test.example.com + group: test.example.com kind: ArgsTest playbook: playbooks/args.yml vars: From 6b10eac6574cd7b49ef3f8152a1bab3eaffedcd0 Mon Sep 17 00:00:00 2001 From: Venkat Ramaraju Date: Thu, 30 Jul 2020 14:37:43 -0700 Subject: [PATCH 07/10] Reviews --- internal/ansible/runner/internal/inputdir/inputdir.go | 8 ++++---- internal/cmd/ansible-operator/run/cmd.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/ansible/runner/internal/inputdir/inputdir.go b/internal/ansible/runner/internal/inputdir/inputdir.go index 6a28fc3bc6..e84b117edf 100644 --- a/internal/ansible/runner/internal/inputdir/inputdir.go +++ b/internal/ansible/runner/internal/inputdir/inputdir.go @@ -132,11 +132,11 @@ func (i *InputDir) Write() error { return err } - if strings.HasPrefix(i.CmdLine, string("'")) && i.CmdLine[0] == i.CmdLine[len(i.CmdLine)-1] { - i.CmdLine = i.CmdLine[1 : len(i.CmdLine)-1] - } + argValue := i.CmdLine + argValue = strings.TrimLeft(argValue, "'") + argValue = strings.TrimRight(argValue, "'") - cmdLineBytes := []byte(i.CmdLine) + cmdLineBytes := []byte(argValue) if len(cmdLineBytes) > 0 { err = i.addFile("env/cmdline", cmdLineBytes) if err != nil { diff --git a/internal/cmd/ansible-operator/run/cmd.go b/internal/cmd/ansible-operator/run/cmd.go index c3828aec44..2449373e37 100644 --- a/internal/cmd/ansible-operator/run/cmd.go +++ b/internal/cmd/ansible-operator/run/cmd.go @@ -161,7 +161,7 @@ func run(cmd *cobra.Command, f *flags.Flags) { os.Exit(1) } for _, w := range watches { - runner, err := runner.New(w) + runner, err := runner.New(w, "") if err != nil { log.Error(err, "Failed to create runner") os.Exit(1) From 05e3a44c0bf5c867abf9c7900c8b55ead23703b0 Mon Sep 17 00:00:00 2001 From: Venkat Ramaraju Date: Thu, 30 Jul 2020 15:04:43 -0700 Subject: [PATCH 08/10] new changes --- cmd/ansible-operator/main.go | 139 ----------------------------------- 1 file changed, 139 deletions(-) diff --git a/cmd/ansible-operator/main.go b/cmd/ansible-operator/main.go index 3b451e74a7..78db568b61 100644 --- a/cmd/ansible-operator/main.go +++ b/cmd/ansible-operator/main.go @@ -24,147 +24,8 @@ import ( ) func main() { -<<<<<<< HEAD root := cobra.Command{ Use: "ansible-operator", -======= - f := &flags.Flags{} - f.AddTo(pflag.CommandLine) - pflag.Parse() - logf.SetLogger(zap.Logger()) - - printVersion() - - cfg, err := config.GetConfig() - if err != nil { - log.Error(err, "Failed to get config.") - os.Exit(1) - } - - // Deprecated: OPERATOR_NAME environment variable is an artifact of the - // legacy operator-sdk project scaffolding. Flag `--leader-election-id` - // should be used instead. - if operatorName, found := os.LookupEnv("OPERATOR_NAME"); found { - log.Info("Environment variable OPERATOR_NAME has been deprecated, use --leader-election-id instead.") - if pflag.CommandLine.Lookup("leader-election-id").Changed { - log.Info("Ignoring OPERATOR_NAME environment variable since --leader-election-id is set") - } else { - f.LeaderElectionID = operatorName - } - } - - // Set default manager options - // TODO: probably should expose the host & port as an environment variables - options := manager.Options{ - HealthProbeBindAddress: fmt.Sprintf("%s:%d", metricsHost, healthProbePort), - MetricsBindAddress: f.MetricsAddress, - LeaderElection: f.EnableLeaderElection, - LeaderElectionID: f.LeaderElectionID, - LeaderElectionNamespace: f.LeaderElectionNamespace, - NewClient: func(cache cache.Cache, config *rest.Config, options client.Options) (client.Client, error) { - c, err := client.New(config, options) - if err != nil { - return nil, err - } - return &client.DelegatingClient{ - Reader: cache, - Writer: c, - StatusClient: c, - }, nil - }, - } - - namespace, found := os.LookupEnv(k8sutil.WatchNamespaceEnvVar) - log = log.WithValues("Namespace", namespace) - if found { - if namespace == metav1.NamespaceAll { - log.Info("Watching all namespaces.") - options.Namespace = metav1.NamespaceAll - } else { - if strings.Contains(namespace, ",") { - log.Info("Watching multiple namespaces.") - options.NewCache = cache.MultiNamespacedCacheBuilder(strings.Split(namespace, ",")) - } else { - log.Info("Watching single namespace.") - options.Namespace = namespace - } - } - } else { - log.Info(fmt.Sprintf("%v environment variable not set. Watching all namespaces.", - k8sutil.WatchNamespaceEnvVar)) - options.Namespace = metav1.NamespaceAll - } - - err = setAnsibleEnvVars(f) - if err != nil { - log.Error(err, "Failed to set environment variable.") - os.Exit(1) - } - - // Create a new manager to provide shared dependencies and start components - mgr, err := manager.New(cfg, options) - if err != nil { - log.Error(err, "Failed to create a new manager.") - os.Exit(1) - } - - cMap := controllermap.NewControllerMap() - watches, err := watches.Load(f.WatchesFile, f.MaxConcurrentReconciles, f.AnsibleVerbosity) - if err != nil { - log.Error(err, "Failed to load watches.") - os.Exit(1) - } - for _, w := range watches { - runner, err := runner.New(w, f.AnsibleArgs) - if err != nil { - log.Error(err, "Failed to create runner") - os.Exit(1) - } - - ctr := controller.Add(mgr, controller.Options{ - GVK: w.GroupVersionKind, - Runner: runner, - ManageStatus: w.ManageStatus, - AnsibleDebugLogs: getAnsibleDebugLog(), - MaxConcurrentReconciles: w.MaxConcurrentReconciles, - ReconcilePeriod: w.ReconcilePeriod, - Selector: w.Selector, - }) - if ctr == nil { - log.Error(fmt.Errorf("failed to add controller for GVK %v", w.GroupVersionKind.String()), "") - os.Exit(1) - } - - cMap.Store(w.GroupVersionKind, &controllermap.Contents{Controller: *ctr, - WatchDependentResources: w.WatchDependentResources, - WatchClusterScopedResources: w.WatchClusterScopedResources, - OwnerWatchMap: controllermap.NewWatchMap(), - AnnotationWatchMap: controllermap.NewWatchMap(), - }, w.Blacklist) - } - - err = mgr.AddHealthzCheck("ping", healthz.Ping) - if err != nil { - log.Error(err, "Failed to add Healthz check.") - } - - done := make(chan error) - - // start the proxy - err = proxy.Run(done, proxy.Options{ - Address: "localhost", - Port: 8888, - KubeConfig: mgr.GetConfig(), - Cache: mgr.GetCache(), - RESTMapper: mgr.GetRESTMapper(), - ControllerMap: cMap, - OwnerInjection: f.InjectOwnerRef, - WatchedNamespaces: []string{namespace}, - }) - if err != nil { - log.Error(err, "Error starting proxy.") - os.Exit(1) ->>>>>>> Added flags, added fields to runner struct } root.AddCommand(run.NewCmd()) From 8303ef95a6503e5da8df2eed5b31f70cf885f6db Mon Sep 17 00:00:00 2001 From: Venkat Ramaraju Date: Thu, 30 Jul 2020 21:13:36 -0700 Subject: [PATCH 09/10] Reverted changes on command parsing --- internal/ansible/runner/internal/inputdir/inputdir.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/ansible/runner/internal/inputdir/inputdir.go b/internal/ansible/runner/internal/inputdir/inputdir.go index e84b117edf..1a3ac5205e 100644 --- a/internal/ansible/runner/internal/inputdir/inputdir.go +++ b/internal/ansible/runner/internal/inputdir/inputdir.go @@ -132,11 +132,12 @@ func (i *InputDir) Write() error { return err } - argValue := i.CmdLine - argValue = strings.TrimLeft(argValue, "'") - argValue = strings.TrimRight(argValue, "'") + // Trimming off the first and last characters if the command is wrapped by single quotations + if strings.HasPrefix(i.CmdLine, string("'")) && i.CmdLine[0] == i.CmdLine[len(i.CmdLine)-1] { + i.CmdLine = i.CmdLine[1 : len(i.CmdLine)-1] + } - cmdLineBytes := []byte(argValue) + cmdLineBytes := []byte(i.CmdLine) if len(cmdLineBytes) > 0 { err = i.addFile("env/cmdline", cmdLineBytes) if err != nil { From e35d950014a46cfe8866f40ca4ea69984a999de7 Mon Sep 17 00:00:00 2001 From: Venkat Ramaraju Date: Fri, 31 Jul 2020 07:55:08 -0700 Subject: [PATCH 10/10] Travis changes --- changelog/fragments/arbitraryArgs.yaml | 2 +- internal/cmd/ansible-operator/run/cmd.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog/fragments/arbitraryArgs.yaml b/changelog/fragments/arbitraryArgs.yaml index abcbe30cdf..5229567281 100644 --- a/changelog/fragments/arbitraryArgs.yaml +++ b/changelog/fragments/arbitraryArgs.yaml @@ -7,4 +7,4 @@ entries: kind: "addition" - breaking: false \ No newline at end of file + breaking: false diff --git a/internal/cmd/ansible-operator/run/cmd.go b/internal/cmd/ansible-operator/run/cmd.go index 2449373e37..b825c320a1 100644 --- a/internal/cmd/ansible-operator/run/cmd.go +++ b/internal/cmd/ansible-operator/run/cmd.go @@ -161,7 +161,7 @@ func run(cmd *cobra.Command, f *flags.Flags) { os.Exit(1) } for _, w := range watches { - runner, err := runner.New(w, "") + runner, err := runner.New(w, f.AnsibleArgs) if err != nil { log.Error(err, "Failed to create runner") os.Exit(1)