Skip to content

Commit bad0ca5

Browse files
Jamstahcamilamacedo86
authored andcommitted
ansible: Support vars in watches (#2147)
This adds support for extra vars in top level watches for ansible, to allow for the same playbook to be used for multiple GVKs with different vars. closes #2138
1 parent 5006ea8 commit bad0ca5

File tree

7 files changed

+70
-18
lines changed

7 files changed

+70
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## Unreleased
22

33
### Added
4+
- Support for vars in top level ansible watches. ([#2147](https://github.com/operator-framework/operator-sdk/pull/2147))
45

56
### Changed
67
- Upgrade minimal Ansible version in the init projects from `2.4` to `2.6`. ([#2107](https://github.com/operator-framework/operator-sdk/pull/2107))

doc/ansible/user-guide.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ expects this mapping file in a predefined location: `/opt/ansible/watches.yaml`
5757
* **playbook**: This is the path to the playbook that you have added to the
5858
container. This playbook is expected to be simply a way to call roles. This
5959
field is mutually exclusive with the "role" field.
60+
* **vars**: This is an arbitrary map of key-value pairs. The contents will be
61+
passed as `extra_vars` to the playbook or role specified for this watch.
6062
* **reconcilePeriod** (optional): The reconciliation interval, how often the
6163
role/playbook is run, for a given CR.
6264
* **manageStatus** (optional): When true (default), the operator will manage
@@ -80,13 +82,16 @@ An example Watches file:
8082
playbook: /opt/ansible/playbook.yml
8183

8284
# More complex example for our Baz kind
83-
# Here we will disable requeuing and be managing the CR status in the playbook
85+
# Here we will disable requeuing and be managing the CR status in the playbook,
86+
# and specify additional variables.
8487
- version: v1alpha1
8588
group: baz.example.com
8689
kind: Baz
8790
playbook: /opt/ansible/baz.yml
8891
reconcilePeriod: 0
8992
manageStatus: false
93+
vars:
94+
foo: bar
9095
```
9196
9297
## Customize the operator logic
@@ -145,7 +150,7 @@ resource is modified.
145150

146151
Defining the spec for an Ansible Operator can be done entirely in Ansible. The
147152
Ansible Operator will simply pass all key value pairs listed in the Custom
148-
Resource spec field along to Ansible as
153+
Resource spec field along to Ansible as extra
149154
[variables](https://docs.ansible.com/ansible/2.5/user_guide/playbooks_variables.html#passing-variables-on-the-command-line).
150155
The names of all variables in the spec field are converted to snake_case
151156
by the operator before running ansible. For example, `serviceAccount` in

pkg/ansible/runner/runner.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,14 @@ func New(watch watches.Watch) (Runner, error) {
103103
finalizerCmdFunc = playbookCmdFunc(verbosityString, watch.Finalizer.Playbook)
104104
case watch.Finalizer.Role != "":
105105
finalizerCmdFunc = roleCmdFunc(verbosityString, watch.Finalizer.Role)
106-
case len(watch.Finalizer.Vars) != 0:
106+
default:
107107
finalizerCmdFunc = cmdFunc
108108
}
109109

110110
return &runner{
111111
Path: path,
112112
cmdFunc: cmdFunc,
113+
Vars: watch.Vars,
113114
Finalizer: watch.Finalizer,
114115
finalizerCmdFunc: finalizerCmdFunc,
115116
GVK: watch.GroupVersionKind,
@@ -123,6 +124,7 @@ type runner struct {
123124
GVK schema.GroupVersionKind // GVK being watched that corresponds to the Path
124125
Finalizer *watches.Finalizer
125126
cmdFunc func(ident, inputDirPath string, maxArtifacts int) *exec.Cmd // returns a Cmd that runs ansible-runner
127+
Vars map[string]interface{}
126128
finalizerCmdFunc func(ident, inputDirPath string, maxArtifacts int) *exec.Cmd
127129
maxRunnerArtifacts int
128130
}
@@ -249,7 +251,8 @@ func (r *runner) isFinalizerRun(u *unstructured.Unstructured) bool {
249251
// "namespace": <object_namespace>,
250252
// },
251253
// <cr_spec_fields_as_snake_case>,
252-
// ...
254+
// <watch vars>,
255+
// <finalizer vars>,
253256
// _<group_as_snake>_<kind>: {
254257
// <cr_object> as is
255258
// }
@@ -274,6 +277,9 @@ func (r *runner) makeParameters(u *unstructured.Unstructured) map[string]interfa
274277
specKey := fmt.Sprintf("%s_spec", objKey)
275278
parameters[specKey] = spec
276279

280+
for k, v := range r.Vars {
281+
parameters[k] = v
282+
}
277283
if r.isFinalizerRun(u) {
278284
for k, v := range r.Finalizer.Vars {
279285
parameters[k] = v

pkg/ansible/runner/runner_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ func TestNew(t *testing.T) {
6262
gvk schema.GroupVersionKind
6363
playbook string
6464
role string
65+
vars map[string]interface{}
6566
finalizer *watches.Finalizer
6667
}{
6768
{
@@ -123,11 +124,29 @@ func TestNew(t *testing.T) {
123124
},
124125
},
125126
},
127+
{
128+
name: "basic runner with playbook, vars + finalizer vars",
129+
gvk: schema.GroupVersionKind{
130+
Group: "operator.example.com",
131+
Version: "v1alpha1",
132+
Kind: "Example",
133+
},
134+
playbook: validPlaybook,
135+
vars: map[string]interface{}{
136+
"type": "this",
137+
},
138+
finalizer: &watches.Finalizer{
139+
Name: "example.finalizer.com",
140+
Vars: map[string]interface{}{
141+
"state": "absent",
142+
},
143+
},
144+
},
126145
}
127146

128147
for _, tc := range testCases {
129148
t.Run(tc.name, func(t *testing.T) {
130-
testWatch := watches.New(tc.gvk, tc.role, tc.playbook, tc.finalizer)
149+
testWatch := watches.New(tc.gvk, tc.role, tc.playbook, tc.vars, tc.finalizer)
131150

132151
testRunner, err := New(*testWatch)
133152
if err != nil {

pkg/ansible/watches/testdata/valid.yaml.tmpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,9 @@
8181
group: app.example.com
8282
kind: AnsibleVerbosityEnv
8383
role: {{ .ValidRole }}
84+
- version: v1alpha1
85+
group: app.example.com
86+
kind: WatchWithVars
87+
role: {{ .ValidRole }}
88+
vars:
89+
sentinel: reconciling

pkg/ansible/watches/watches.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type Watch struct {
4040
GroupVersionKind schema.GroupVersionKind `yaml:",inline"`
4141
Playbook string `yaml:"playbook"`
4242
Role string `yaml:"role"`
43+
Vars map[string]interface{} `yaml:"vars"`
4344
MaxRunnerArtifacts int `yaml:"maxRunnerArtifacts"`
4445
ReconcilePeriod time.Duration `yaml:"reconcilePeriod"`
4546
ManageStatus bool `yaml:"manageStatus"`
@@ -80,17 +81,18 @@ var (
8081
func (w *Watch) UnmarshalYAML(unmarshal func(interface{}) error) error {
8182
// Use an alias struct to handle complex types
8283
type alias struct {
83-
Group string `yaml:"group"`
84-
Version string `yaml:"version"`
85-
Kind string `yaml:"kind"`
86-
Playbook string `yaml:"playbook"`
87-
Role string `yaml:"role"`
88-
MaxRunnerArtifacts int `yaml:"maxRunnerArtifacts"`
89-
ReconcilePeriod string `yaml:"reconcilePeriod"`
90-
ManageStatus bool `yaml:"manageStatus"`
91-
WatchDependentResources bool `yaml:"watchDependentResources"`
92-
WatchClusterScopedResources bool `yaml:"watchClusterScopedResources"`
93-
Finalizer *Finalizer `yaml:"finalizer"`
84+
Group string `yaml:"group"`
85+
Version string `yaml:"version"`
86+
Kind string `yaml:"kind"`
87+
Playbook string `yaml:"playbook"`
88+
Role string `yaml:"role"`
89+
Vars map[string]interface{} `yaml:"vars"`
90+
MaxRunnerArtifacts int `yaml:"maxRunnerArtifacts"`
91+
ReconcilePeriod string `yaml:"reconcilePeriod"`
92+
ManageStatus bool `yaml:"manageStatus"`
93+
WatchDependentResources bool `yaml:"watchDependentResources"`
94+
WatchClusterScopedResources bool `yaml:"watchClusterScopedResources"`
95+
Finalizer *Finalizer `yaml:"finalizer"`
9496
}
9597
var tmp alias
9698

@@ -125,6 +127,7 @@ func (w *Watch) UnmarshalYAML(unmarshal func(interface{}) error) error {
125127
w.GroupVersionKind = gvk
126128
w.Playbook = tmp.Playbook
127129
w.Role = tmp.Role
130+
w.Vars = tmp.Vars
128131
w.MaxRunnerArtifacts = tmp.MaxRunnerArtifacts
129132
w.MaxWorkers = getMaxWorkers(gvk, maxWorkersDefault)
130133
w.ReconcilePeriod = reconcilePeriod
@@ -166,12 +169,13 @@ func (w *Watch) Validate() error {
166169
}
167170

168171
// New - returns a Watch with sensible defaults.
169-
func New(gvk schema.GroupVersionKind, role, playbook string, finalizer *Finalizer) *Watch {
172+
func New(gvk schema.GroupVersionKind, role, playbook string, vars map[string]interface{}, finalizer *Finalizer) *Watch {
170173
reconcilePeriod, _ := time.ParseDuration(reconcilePeriodDefault)
171174
return &Watch{
172175
GroupVersionKind: gvk,
173176
Playbook: playbook,
174177
Role: role,
178+
Vars: vars,
175179
MaxRunnerArtifacts: maxRunnerArtifactsDefault,
176180
MaxWorkers: maxWorkersDefault,
177181
ReconcilePeriod: reconcilePeriod,

pkg/ansible/watches/watches_test.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ func TestNew(t *testing.T) {
3737
gvk schema.GroupVersionKind
3838
role string
3939
playbook string
40+
vars map[string]interface{}
4041
finalizer *Finalizer
4142
shouldValidate bool
4243
}{
@@ -50,7 +51,7 @@ func TestNew(t *testing.T) {
5051

5152
for _, tc := range testCases {
5253
t.Run(tc.name, func(t *testing.T) {
53-
watch := New(tc.gvk, tc.role, tc.playbook, tc.finalizer)
54+
watch := New(tc.gvk, tc.role, tc.playbook, tc.vars, tc.finalizer)
5455
if watch.GroupVersionKind != tc.gvk {
5556
t.Fatalf("Unexpected GVK %v expected %v", watch.GroupVersionKind, tc.gvk)
5657
}
@@ -348,6 +349,16 @@ func TestLoad(t *testing.T) {
348349
ManageStatus: true,
349350
AnsibleVerbosity: 4,
350351
},
352+
Watch{
353+
GroupVersionKind: schema.GroupVersionKind{
354+
Version: "v1alpha1",
355+
Group: "app.example.com",
356+
Kind: "WatchWithVars",
357+
},
358+
Role: validTemplate.ValidRole,
359+
ManageStatus: true,
360+
Vars: map[string]interface{}{"sentinel": "reconciling"},
361+
},
351362
},
352363
},
353364
}

0 commit comments

Comments
 (0)