Skip to content

Commit f9f0d18

Browse files
feat: add support for relative paths (ansible) (#2273)
**Description** - Allow users to inform relative paths and names for roles and playbook - Allow using the `operator-SDK run --local` with the roles and playbooks using relative paths - Allow users setup ANSIBLE_ROLES_PATH env var to the customized path when it is running locally - Allow users setup ANSIBLE_ROLES_PATH env var by using flag to the customized path when it is running locally - Support multipaths in the ANSIBLE_ROLES_PATH informed concat by `:` - Update the docs
1 parent 5709ff3 commit f9f0d18

28 files changed

+459
-250
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Add a new option to set the minimum log level that triggers stack trace generation in logs (`--zap-stacktrace-level`) ([#2319](https://github.com/operator-framework/operator-sdk/pull/2319))
66
- Added `pkg/status` with several new types and interfaces that can be used in `Status` structs to simplify handling of [status conditions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties). ([#1143](https://github.com/operator-framework/operator-sdk/pull/1143))
7+
- Added support for relative Ansible roles and playbooks paths in the Ansible operator's file. ([#2273](https://github.com/operator-framework/operator-sdk/pull/2273))
78

89
### Changed
910

cmd/operator-sdk/execentrypoint/ansible.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@
1515
package execentrypoint
1616

1717
import (
18-
"github.com/operator-framework/operator-sdk/pkg/ansible"
19-
aoflags "github.com/operator-framework/operator-sdk/pkg/ansible/flags"
20-
"github.com/operator-framework/operator-sdk/pkg/log/zap"
18+
"fmt"
19+
"os"
2120

21+
"github.com/prometheus/common/log"
2222
"github.com/spf13/cobra"
2323
logf "sigs.k8s.io/controller-runtime/pkg/log"
24+
25+
"github.com/operator-framework/operator-sdk/pkg/ansible"
26+
aoflags "github.com/operator-framework/operator-sdk/pkg/ansible/flags"
27+
"github.com/operator-framework/operator-sdk/pkg/log/zap"
2428
)
2529

2630
// newRunAnsibleCmd returns a command that will run an ansible operator.
@@ -34,11 +38,28 @@ in a Pod inside a cluster. Developers wanting to run their operator locally
3438
should use "run --local" instead.`,
3539
RunE: func(cmd *cobra.Command, args []string) error {
3640
logf.SetLogger(zap.Logger())
37-
41+
err := setAnsibleRolePathEnvVar(flags)
42+
if err != nil {
43+
log.Error(err)
44+
os.Exit(1)
45+
}
3846
return ansible.Run(flags)
3947
},
4048
}
4149
flags = aoflags.AddTo(runAnsibleCmd.Flags())
4250

4351
return runAnsibleCmd
4452
}
53+
54+
// setAnsibleRolePathEnvVar will set the default role path for the ANSIBLE_ROLES_PATH
55+
func setAnsibleRolePathEnvVar(flags *aoflags.AnsibleOperatorFlags) error {
56+
if flags != nil && len(flags.AnsibleRolesPath) > 0 {
57+
if err := os.Setenv(aoflags.AnsibleRolesPathEnvVar, flags.AnsibleRolesPath); err != nil {
58+
return fmt.Errorf("failed to set %s environment variable: (%v)", aoflags.AnsibleRolesPathEnvVar, err)
59+
}
60+
log.Info(fmt.Sprintf("set the value %v for environment variable %v.", flags.AnsibleRolesPath,
61+
aoflags.AnsibleRolesPathEnvVar))
62+
}
63+
64+
return nil
65+
}

cmd/operator-sdk/run/local.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ func (c runLocalArgs) runGo() error {
116116
}
117117
dc.Env = append(dc.Env, fmt.Sprintf("%v=%v", k8sutil.WatchNamespaceEnvVar, c.namespace))
118118

119+
// Set the ANSIBLE_ROLES_PATH
120+
if c.ansibleOperatorFlags != nil && len(c.ansibleOperatorFlags.AnsibleRolesPath) > 0 {
121+
log.Info(fmt.Sprintf("set the value %v for environment variable %v.", c.ansibleOperatorFlags.AnsibleRolesPath,
122+
aoflags.AnsibleRolesPathEnvVar))
123+
dc.Env = append(dc.Env, fmt.Sprintf("%v=%v", aoflags.AnsibleRolesPathEnvVar, c.ansibleOperatorFlags.AnsibleRolesPath))
124+
}
125+
119126
if err := projutil.ExecCmd(dc); err != nil {
120127
return fmt.Errorf("failed to run operator locally: %v", err)
121128
}

doc/ansible/dev/advanced_options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Some features can be overridden per resource via an annotation on that CR. The o
2525
- version: v1alpha1
2626
group: app.example.com
2727
kind: AppService
28-
playbook: /opt/ansible/playbook.yml
28+
playbook: playbook.yml
2929
maxRunnerArtifacts: 30
3030
reconcilePeriod: 5s
3131
manageStatus: False

doc/ansible/dev/dependent_watches.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ This is an example of a watches file with the `watchDependentResources` field se
2424
- version: v1alpha1
2525
group: app.example.com
2626
kind: AppService
27-
playbook: /opt/ansible/playbook.yml
27+
playbook: playbook.yml
2828
maxRunnerArtifacts: 30
2929
reconcilePeriod: 5s
3030
manageStatus: False

doc/ansible/dev/developer_guide.md

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -193,20 +193,8 @@ communicate with a Kubernetes cluster just as the `k8s` modules do. This
193193
section assumes the developer has read the [Ansible Operator user
194194
guide][ansible_operator_user_guide] and has the proper dependencies installed.
195195

196-
Since `run --local` reads from `./watches.yaml`, there are a couple options
197-
available to the developer. If `role` is left alone (by default
198-
`/opt/ansible/roles/<name>`) the developer must copy the role over to
199-
`/opt/ansible/roles` from the operator directly. This is cumbersome because
200-
changes will not be reflected from the current directory. It is recommended
201-
that the developer instead change the `role` field to point to the current
202-
directory and simply comment out the existing line:
203-
```yaml
204-
- version: v1alpha1
205-
group: foo.example.com
206-
kind: Foo
207-
# role: /opt/ansible/roles/Foo
208-
role: /home/user/foo-operator/Foo
209-
```
196+
**NOTE:** You can customize the roles path by setting the environment variable `ANSIBLE_ROLES_PATH` or using the flag `ansible-roles-path`. Note that, if the role not be found in the
197+
customized path informed in `ANSIBLE_ROLES_PATH` then, the operator will look for it in the `{{current directory}}/roles`.
210198

211199
Create a Custom Resource Definition (CRD) and proper Role-Based Access Control
212200
(RBAC) definitions for resource Foo. `operator-sdk` auto-generates these files
@@ -379,7 +367,7 @@ application, then simply update the watches file with `manageStatus`:
379367
- version: v1
380368
group: api.example.com
381369
kind: Foo
382-
role: /opt/ansible/roles/Foo
370+
role: Foo
383371
manageStatus: false
384372
```
385373

doc/ansible/dev/finalizers.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ or `role` was set for the finalizer.
5656
Here are a few examples of `watches.yaml` files that specify a finalizer:
5757

5858
### Run top-level playbook or role with new variables
59+
5960
```yaml
6061
---
6162
- version: v1alpha1
@@ -68,7 +69,7 @@ Here are a few examples of `watches.yaml` files that specify a finalizer:
6869
state: absent
6970
```
7071
71-
This example will run `/opt/ansible/playbook.yml` when the Custom Resource
72+
This example will run `playbook.yml` when the Custom Resource
7273
is deleted. Because `vars` is set, the playbook will be run with `state` set to `absent`. Inside the playbook,
7374
the author can check this value and perform whatever cleanup is necessary.
7475

@@ -77,7 +78,7 @@ the author can check this value and perform whatever cleanup is necessary.
7778
- version: v1alpha1
7879
group: app.example.com
7980
kind: Database
80-
role: /opt/ansible/roles/database
81+
role: database
8182
finalizer:
8283
name: finalizer.app.example.com
8384
vars:
@@ -93,10 +94,10 @@ role, rather than a playbook, with the `state` variable set to `absent`.
9394
- version: v1alpha1
9495
group: app.example.com
9596
kind: Database
96-
playbook: /opt/ansible/playbook.yml
97+
playbook: playbook.yml
9798
finalizer:
9899
name: finalizer.app.example.com
99-
role: /opt/ansible/roles/teardown_database
100+
role: teardown_database
100101
```
101102

102103
This example will run the `/opt/ansible/roles/teardown_database` role when the Custom Resource is deleted.
@@ -106,10 +107,10 @@ This example will run the `/opt/ansible/roles/teardown_database` role when the C
106107
- version: v1alpha1
107108
group: app.example.com
108109
kind: Database
109-
playbook: /opt/ansible/playbook.yml
110+
playbook: playbook.yml
110111
finalizer:
111112
name: finalizer.app.example.com
112-
playbook: /opt/ansible/destroy.yml
113+
playbook: destroy.yml
113114
```
114115

115116
This example will run the `/opt/ansible/destroy.yml` playbook when the Custom Resource is deleted.
@@ -126,10 +127,10 @@ interaction, with a different variable set.
126127
- version: v1alpha1
127128
group: app.example.com
128129
kind: Database
129-
playbook: /opt/ansible/playbook.yml
130+
playbook: playbook.yml
130131
finalizer:
131132
name: finalizer.app.example.com
132-
role: /opt/ansible/roles/manage_credentials
133+
role: manage_credentials
133134
vars:
134135
state: revoked
135136
```

doc/ansible/user-guide.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,16 @@ be monitored for updates and cached.
5151
* **group**: The group of the Custom Resource that you will be watching.
5252
* **version**: The version of the Custom Resource that you will be watching.
5353
* **kind**: The kind of the Custom Resource that you will be watching.
54-
* **role** (default): This is the path to the role that you have added to the
55-
container. For example if your roles directory is at `/opt/ansible/roles/`
56-
and your role is named `busybox`, this value will be
57-
`/opt/ansible/roles/busybox`. This field is mutually exclusive with the
58-
"playbook" field.
59-
* **playbook**: This is the path to the playbook that you have added to the
54+
* **role** (default): This is the name of the role that you have added to the
55+
container. This field is mutually exclusive with the
56+
"playbook" field. If the path is relative, it is relative to the `roles` directory in the current working directory
57+
which in the image by default is `/opt/ansible/roles`. Also, when it is running locally it is by default the directory
58+
`roles` in the current project directory in the local machine. Note that it can be customized by using the flag
59+
`ansible-roles-path` or the envinroment variable `ANSIBLE_ROLES_PATH`.
60+
* **playbook**: This is the playbook name that you have added to the
6061
container. This playbook is expected to be simply a way to call roles. This
61-
field is mutually exclusive with the "role" field.
62+
field is mutually exclusive with the "role" field. Also, when it is running locally it looking for the playbook in the
63+
current project directory in the local machine.
6264
* **vars**: This is an arbitrary map of key-value pairs. The contents will be
6365
passed as `extra_vars` to the playbook or role specified for this watch.
6466
* **reconcilePeriod** (optional): The reconciliation interval, how often the
@@ -76,21 +78,21 @@ An example Watches file:
7678
- version: v1alpha1
7779
group: foo.example.com
7880
kind: Foo
79-
role: /opt/ansible/roles/Foo
81+
role: Foo
8082

8183
# Simple example mapping Bar to a playbook
8284
- version: v1alpha1
8385
group: bar.example.com
8486
kind: Bar
85-
playbook: /opt/ansible/playbook.yml
87+
playbook: playbook.yml
8688

8789
# More complex example for our Baz kind
8890
# Here we will disable requeuing and be managing the CR status in the playbook,
8991
# and specify additional variables.
9092
- version: v1alpha1
9193
group: baz.example.com
9294
kind: Baz
93-
playbook: /opt/ansible/baz.yml
95+
playbook: baz.yml
9496
reconcilePeriod: 0
9597
manageStatus: false
9698
vars:
@@ -138,7 +140,7 @@ should go.
138140
- version: v1alpha1
139141
group: cache.example.com
140142
kind: Memcached
141-
role: /opt/ansible/roles/memcached
143+
role: memcached
142144
```
143145

144146
**Playbook**
@@ -150,7 +152,7 @@ Playbook
150152
- version: v1alpha1
151153
group: cache.example.com
152154
kind: Memcached
153-
playbook: /opt/ansible/playbook.yaml
155+
playbook: playbook.yaml
154156
```
155157

156158
## Building the Memcached Ansible Role

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ require (
3030
github.com/pborman/uuid v1.2.0
3131
github.com/pkg/errors v0.8.1
3232
github.com/prometheus/client_golang v1.2.1
33+
github.com/prometheus/common v0.7.0
3334
github.com/rogpeppe/go-internal v1.5.0
3435
github.com/rubenv/sql-migrate v0.0.0-20191025130928-9355dd04f4b3 // indirect
3536
github.com/sergi/go-diff v1.0.0

go.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H
6767
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
6868
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
6969
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
70+
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
7071
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
7172
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
73+
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
7274
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
7375
github.com/ant31/crd-validation v0.0.0-20180702145049-30f8a35d0ac2/go.mod h1:X0noFIik9YqfhGYBLEHg8LJKEwy7QIitLQuFMpKLcPk=
7476
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
@@ -949,6 +951,7 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
949951
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
950952
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
951953
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
954+
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
952955
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
953956
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
954957
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

internal/scaffold/ansible/entrypoint.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ if ! whoami &>/dev/null; then
4545
fi
4646
fi
4747
48-
exec ${OPERATOR} exec-entrypoint ansible --watches-file=/opt/ansible/watches.yaml $@
48+
cd $HOME
49+
exec ${OPERATOR} exec-entrypoint ansible --watches-file=$HOME/watches.yaml $@
4950
`

internal/scaffold/ansible/watches.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ const watchesAnsibleTmpl = `---
4444
group: [[.Resource.FullGroup]]
4545
kind: [[.Resource.Kind]]
4646
[[- if .GeneratePlaybook ]]
47-
playbook: /opt/ansible/playbook.yml
47+
playbook: playbook.yml
4848
[[- else ]]
49-
role: /opt/ansible/[[.RolesDir]]/[[.Resource.LowerKind]]
49+
role: [[.Resource.LowerKind]]
5050
[[- end ]]
5151
`

pkg/ansible/flags/flag.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ type AnsibleOperatorFlags struct {
2828
InjectOwnerRef bool
2929
MaxWorkers int
3030
AnsibleVerbosity int
31+
AnsibleRolesPath string
3132
}
3233

34+
const AnsibleRolesPathEnvVar = "ANSIBLE_ROLES_PATH"
35+
3336
// AddTo - Add the ansible operator flags to the the flagset
3437
// helpTextPrefix will allow you add a prefix to default help text. Joined by a space.
3538
func AddTo(flagSet *pflag.FlagSet, helpTextPrefix ...string) *AnsibleOperatorFlags {
@@ -56,5 +59,12 @@ func AddTo(flagSet *pflag.FlagSet, helpTextPrefix ...string) *AnsibleOperatorFla
5659
"Ansible verbosity. Overridden by environment variable."),
5760
" "),
5861
)
62+
flagSet.StringVar(&aof.AnsibleRolesPath,
63+
"ansible-roles-path",
64+
"",
65+
strings.Join(append(helpTextPrefix,
66+
"Ansible Roles Path. By default, it will be {{CWD}}/roles."),
67+
" "),
68+
)
5969
return aof
6070
}

pkg/ansible/watches/testdata/duplicate_gvk.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
- version: v1alpha1
33
group: app.example.com
44
kind: Database
5-
playbook: /opt/ansible/playbook.yaml
5+
playbook: playbook.yaml
66
finalizer:
77
name: finalizer.app.example.com
88
vars:
99
sentinel: finalizer_running
1010
- version: v1alpha1
1111
group: app.example.com
1212
kind: Database
13-
playbook: /opt/ansible/playbook.yaml
13+
playbook: playbook.yaml
1414
finalizer:
1515
name: finalizer.app.example.com
1616
vars:

pkg/ansible/watches/testdata/invalid.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
version: v1alpha1
33
group: app.example.com
44
kind: Database
5-
playbook: /opt/ansible/playbook.yaml
5+
playbook: playbook.yaml
66
finalizer:
77
name: finalizer.app.example.com
88
vars:

pkg/ansible/watches/testdata/invalid_duration.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
- version: v1alpha1
33
group: app.example.com
44
kind: Database
5-
playbook: /opt/ansible/playbook.yaml
5+
playbook: playbook.yaml
66
reconcilePeriod: invalid

pkg/ansible/watches/testdata/invalid_finalizer_no_vars.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
- version: v1alpha1
33
group: app.example.com
44
kind: Database
5-
playbook: /opt/ansible/playbook.yaml
5+
playbook: playbook.yaml
66
finalizer:
77
name: foo.app.example.com

pkg/ansible/watches/testdata/invalid_finalizer_playbook_path.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
- version: v1alpha1
33
group: app.example.com
44
kind: Database
5-
playbook: /opt/ansible/playbook.yaml
5+
playbook: playbook.yaml
66
finalizer:
77
name: finalizer.app.example.com
8-
playbook: opt/ansible/playbook.yaml
8+
playbook: playbook.yaml
99
vars:
1010
sentinel: finalizer_running

pkg/ansible/watches/testdata/invalid_finalizer_role_path.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
- version: v1alpha1
33
group: app.example.com
44
kind: Database
5-
playbook: /ansible/playbook.yaml
5+
playbook: playbook.yaml
66
finalizer:
77
name: finalizer.app.example.com
88
role: ansible/role
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
- version: v1alpha1
3+
group: app.example.com
4+
kind: Database
5+
playbook: playbook.yaml
6+
finalizer:
7+
name:
8+

0 commit comments

Comments
 (0)