Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ansible): Configure verbosity via annotation #2102

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Added
- Support for vars in top level ansible watches. ([#2147](https://github.com/operator-framework/operator-sdk/pull/2147))
- Support for `"ansible.operator-sdk/verbosity"` annotation on Custom Resources watched by Ansible based operators to override verbosity on an individual resource. ([#2102](https://github.com/operator-framework/operator-sdk/pull/2102))

### Changed
- Upgrade minimal Ansible version in the init projects from `2.4` to `2.6`. ([#2107](https://github.com/operator-framework/operator-sdk/pull/2107))
Expand Down
21 changes: 19 additions & 2 deletions doc/ansible/dev/advanced_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ here, where higher values mean more output. Acceptable values range from 0
(only the most severe messages are output) to 7 (all debugging messages are
output).

There are two ways to configure the verbosity argument to the `ansible-runner`
There are three ways to configure the verbosity argument to the `ansible-runner`
command:

1. Operator **authors and admins** can set the Ansible verbosity by including
Expand All @@ -129,8 +129,11 @@ command:
variable in the format `ANSIBLE_VERBOSITY_<kind>_<group>`. This variable must
be all uppercase and all periods (e.g. in the group name) are replaced with
underscore.
1. Operator **users, authors, and admins** can set the Ansible verbosity by
setting the `"ansible.operator-sdk/verbosity"` annotation on the Custom
Resource.

### Example
### Examples

For demonstration purposes, let us assume that we have a database operator that
supports two Kinds -- `MongoDB` and `PostgreSQL` -- in the `db.example.com`
Expand All @@ -152,3 +155,17 @@ spec in our `deploy/operator.yaml` might look something like:
- name: ANSIBLE_VERBOSITY_MONGODB_DB_EXAMPLE_COM
value: "4"
```

Once the Operator is deployed, the only way to change the verbosity is via the
`"ansible.operator-sdk/verbosity"` annotation. Continuing with our example, our
CR may look like:

```yaml
apiVersion: "db.example.com/v1"
kind: "PostgreSQL"
metadata:
name: "example-db"
annotations:
"ansible.operator-sdk/verbosity": 5
spec: {}
```
20 changes: 13 additions & 7 deletions doc/ansible/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,16 +357,22 @@ kubectl logs deployment/memcached-operator -c operator
The `ansible` logs contain all of the information about the Ansible run and will make it much easier to debug issues within your Ansible tasks,
whereas the `operator` logs will contain much more detailed information about the Ansible Operator's internals and interface with Kubernetes.

### Additional Ansible debug
### Additional Ansible Debug

Occasionally while developing additional debug in the Operator logs is nice to have. To enable Ansible debug output, ie `-vvvv`.
Add the following to the `operator.yaml` manifest.
Occasionally while developing additional debug in the Operator logs is nice to have.
Using the memcached operator as an example, we can simply add the
`"ansible.operator-sdk/verbosity"` annotation to the Custom
Resource with the desired verbosity.

```yaml
env:
...
- name: ANSIBLE_VERBOSITY
value: "4"
apiVersion: "cache.example.com/v1alpha1"
kind: "Memcached"
metadata:
name: "example-memcached"
annotations:
"ansible.operator-sdk/verbosity": 4
spec:
size: 4
```

### Update the size
Expand Down
48 changes: 32 additions & 16 deletions pkg/ansible/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ const (
// particular CR. Setting this to zero will cause all artifact directories to be kept.
// Example usage "ansible.operator-sdk/max-runner-artifacts: 100"
MaxRunnerArtifactsAnnotation = "ansible.operator-sdk/max-runner-artifacts"

// AnsibleVerbosityAnnotation - annotation used by a user to specify the verbosity given
// to the ansible-runner command. This will override the value for a particular CR.
// Example usage "ansible.operator-sdk/verbosity: 5"
AnsibleVerbosityAnnotation = "ansible.operator-sdk/verbosity"
)

// Runner - a runnable that should take the parameters and name and namespace
Expand All @@ -59,18 +64,18 @@ func ansibleVerbosityString(verbosity int) string {
return ""
}

type cmdFuncType func(ident, inputDirPath string, maxArtifacts int) *exec.Cmd
type cmdFuncType func(ident, inputDirPath string, maxArtifacts, verbosity int) *exec.Cmd

func playbookCmdFunc(verbosity, path string) cmdFuncType {
return func(ident, inputDirPath string, maxArtifacts int) *exec.Cmd {
return exec.Command("ansible-runner", verbosity, "--rotate-artifacts", fmt.Sprintf("%v", maxArtifacts), "-p", path, "-i", ident, "run", inputDirPath)
func playbookCmdFunc(path string) cmdFuncType {
return func(ident, inputDirPath string, maxArtifacts, verbosity int) *exec.Cmd {
return exec.Command("ansible-runner", ansibleVerbosityString(verbosity), "--rotate-artifacts", fmt.Sprintf("%v", maxArtifacts), "-p", path, "-i", ident, "run", inputDirPath)
}
}

func roleCmdFunc(verbosity, path string) cmdFuncType {
func roleCmdFunc(path string) cmdFuncType {
rolePath, roleName := filepath.Split(path)
return func(ident, inputDirPath string, maxArtifacts int) *exec.Cmd {
return exec.Command("ansible-runner", verbosity, "--rotate-artifacts", fmt.Sprintf("%v", maxArtifacts), "--role", roleName, "--roles-path", rolePath, "--hosts", "localhost", "-i", ident, "run", inputDirPath)
return func(ident, inputDirPath string, maxArtifacts, verbosity int) *exec.Cmd {
return exec.Command("ansible-runner", ansibleVerbosityString(verbosity), "--rotate-artifacts", fmt.Sprintf("%v", maxArtifacts), "--role", roleName, "--roles-path", rolePath, "--hosts", "localhost", "-i", ident, "run", inputDirPath)
}
}

Expand All @@ -84,25 +89,24 @@ func New(watch watches.Watch) (Runner, error) {
log.Error(err, "Failed to validate watch")
return nil, err
}
verbosityString := ansibleVerbosityString(watch.AnsibleVerbosity)

switch {
case watch.Playbook != "":
path = watch.Playbook
cmdFunc = playbookCmdFunc(verbosityString, path)
cmdFunc = playbookCmdFunc(path)
case watch.Role != "":
path = watch.Role
cmdFunc = roleCmdFunc(verbosityString, path)
cmdFunc = roleCmdFunc(path)
}

// handle finalizer
switch {
case watch.Finalizer == nil:
finalizerCmdFunc = nil
case watch.Finalizer.Playbook != "":
finalizerCmdFunc = playbookCmdFunc(verbosityString, watch.Finalizer.Playbook)
finalizerCmdFunc = playbookCmdFunc(watch.Finalizer.Playbook)
case watch.Finalizer.Role != "":
finalizerCmdFunc = roleCmdFunc(verbosityString, watch.Finalizer.Role)
finalizerCmdFunc = roleCmdFunc(watch.Finalizer.Role)
default:
finalizerCmdFunc = cmdFunc
}
Expand All @@ -115,6 +119,7 @@ func New(watch watches.Watch) (Runner, error) {
finalizerCmdFunc: finalizerCmdFunc,
GVK: watch.GroupVersionKind,
maxRunnerArtifacts: watch.MaxRunnerArtifacts,
ansibleVerbosity: watch.AnsibleVerbosity,
}, nil
}

Expand All @@ -123,10 +128,11 @@ 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
cmdFunc func(ident, inputDirPath string, maxArtifacts int) *exec.Cmd // returns a Cmd that runs ansible-runner
Vars map[string]interface{}
finalizerCmdFunc func(ident, inputDirPath string, maxArtifacts int) *exec.Cmd
cmdFunc cmdFuncType // returns a Cmd that runs ansible-runner
finalizerCmdFunc cmdFuncType
maxRunnerArtifacts int
ansibleVerbosity int
}

func (r *runner) Run(ident string, u *unstructured.Unstructured, kubeconfig string) (RunResult, error) {
Expand Down Expand Up @@ -184,13 +190,23 @@ func (r *runner) Run(ident string, u *unstructured.Unstructured, kubeconfig stri
}
}

verbosity := r.ansibleVerbosity
if av, ok := u.GetAnnotations()[AnsibleVerbosityAnnotation]; ok {
i, err := strconv.Atoi(av)
if err != nil {
log.Info("Invalid ansible verbosity annotation", "err", err, "value", av)
} else {
verbosity = i
}
}

go func() {
var dc *exec.Cmd
if r.isFinalizerRun(u) {
logger.V(1).Info("Resource is marked for deletion, running finalizer", "Finalizer", r.Finalizer.Name)
dc = r.finalizerCmdFunc(ident, inputDir.Path, maxArtifacts)
dc = r.finalizerCmdFunc(ident, inputDir.Path, maxArtifacts, verbosity)
} else {
dc = r.cmdFunc(ident, inputDir.Path, maxArtifacts)
dc = r.cmdFunc(ident, inputDir.Path, maxArtifacts, verbosity)
}
// Append current environment since setting dc.Env to anything other than nil overwrites current env
dc.Env = append(dc.Env, os.Environ()...)
Expand Down
7 changes: 3 additions & 4 deletions pkg/ansible/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,14 @@ func checkCmdFunc(t *testing.T, cmdFunc cmdFuncType, playbook, role string, verb
inputDirPath := "/test/path"
maxArtifacts := 1
var expectedCmd, gotCmd *exec.Cmd
verbosityString := ansibleVerbosityString(verbosity)
switch {
case playbook != "":
expectedCmd = playbookCmdFunc(verbosityString, playbook)(ident, inputDirPath, maxArtifacts)
expectedCmd = playbookCmdFunc(playbook)(ident, inputDirPath, maxArtifacts, verbosity)
case role != "":
expectedCmd = roleCmdFunc(verbosityString, role)(ident, inputDirPath, maxArtifacts)
expectedCmd = roleCmdFunc(role)(ident, inputDirPath, maxArtifacts, verbosity)
}

gotCmd = cmdFunc(ident, inputDirPath, maxArtifacts)
gotCmd = cmdFunc(ident, inputDirPath, maxArtifacts, verbosity)

if expectedCmd.Path != gotCmd.Path {
t.Fatalf("Unexpected cmd path %v expected cmd path %v", gotCmd.Path, expectedCmd.Path)
Expand Down