Wolfgang Kulhanek
2020-03-16 96f73bbfe948e2a2789c7f609bfac6308926eaa3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
= ocp-workload-example - Example Workload Role
 
== Role overview
 
* This is a working no-op role that can be used to develop new ocp-workload roles. It consists of the following playbooks:
** Playbook: link:./tasks/pre_workload.yml[pre_workload.yml] - Sets up an
 environment for the workload deployment
*** Debug task will print out: `pre_workload Tasks completed successfully.`
 
** Playbook: link:./tasks/workload.yml[workload.yml] - Used to deploy the actual
 workload, i.e, 3scale, Mobile, some Demo or OpenShift customization
*** This role only prints the current username for which this role is provisioning.
*** Debug task will print out: `workload Tasks completed successfully.`
 
** Playbook: link:./tasks/post_workload.yml[post_workload.yml] - Used to
 configure the workload after deployment
*** This role doesn't do anything here
*** Debug task will print out: `post_workload Tasks completed successfully.`
 
** Playbook: link:./tasks/remove_workload.yml[remove_workload.yml] - Used to
 delete the workload
*** This role doesn't do anything here
*** Debug task will print out: `remove_workload Tasks completed successfully.`
 
== Review the defaults variable file
 
* This file link:./defaults/main.yml[./defaults/main.yml] contains all the variables you need to define to control the deployment of your workload.
* The variable *ocp_username* is mandatory to assign the workload to the correct OpenShift user.
* A variable *silent=True* can be passed to suppress debug messages.
* You can modify any of these default values by adding `-e "variable_name=variable_value"` to the command line
* Add a dictionary for workload parameters.
 
== Understand how paremeters to your workload should be specified
 
=== Overview
 
A `dictionary` approach should be used in order to neatly encapsulate parameters to roles.
 
The role itself defines a dictionary `<role name>_defaults` in the file link:./defaults/main.yml[./defaults/main.yml]. Because this example role is `ocp-workload-example` the dictionary is called `ocp_workload_example_defaults`. Note that `_` is used instead of `-` in the dictionary name to create a valid Ansible dictionary name.
 
When deploying a workload you can specify another dictionary with the specific parameters for this deployment. This dictionary should be called `<role name>_vars`. In our example this dictionary would be called `ocp_workload_example_vars`.
 
=== Handling secret parameters
 
In case you need to pass a secret parameter (e.g. the Bind Password for an LDAP server) you may define another dictionary, `<role name>_secrets`, and pass that as well.
 
[TIP]
When setting default values for secrets in the *defaults* dictionary be careful what you set. `""` is probably a good choice. Some workloads (ocp4-workload-authentication for example) generate passwords if a password is not being specified. If you set a default password in the defaults dictionary this logic will never be executed.
 
For deployment via AgnosticD/AgnosticV the contents of this secrets dictionary need to be placed on the provisioning host and referenced in the AgnosticV configuration.
 
=== Combined dictionary
 
When running your workload the first task in link:./tasks/workload.yml[./tasks/workload.yml] sets up the combined dictionary with name `<role name>`. The defaults are combined with vars and secrets. In that order. This means that values in *defaults* can be overridden with values in *vars* and *secrets*.
 
When adapting this example role for your particular workload make sure to update the dictionary names in both link:./tasks/workload.yml[./tasks/workload.yml] and link:./tasks/remove_workload.yml[./tasks/remove_workload.yml] files.
 
 
=== Deploy a Workload with the `ocp-workload` playbook [Mostly for testing]
 
. If your workload uses parameters create a `<role name>_vars.yaml` input file.
+
.ocp_workload_example_vars.yaml
[source,yaml]
----
# You can set any variable, not just the dictionary
silent: true
 
# Set up the `vars` dictionary
ocp_workload_example_vars:
  variable_2: "My variable 2"
----
 
. If your workload uses secrets create a `<role name>_secrets.yaml` input file.
+
.ocp_workload_example_secrets.yaml
[source,yaml]
----
# Set up the `secrets` dictionary
ocp_workload_example_secrets:
  variable_secret: "top secret data"
----
 
. Set up Environment Variables for the bastion you want to run this role on.
+
[source,yaml]
----
TARGET_HOST="bastion.dev.openshift.opentlc.com"
OCP_USERNAME="wkulhane-redhat.com"
ANSIBLE_USER="ec2-user"
WORKLOAD="ocp-workload-example"
GUID=1001
----
 
. Finally run the workload passing the input files as parameters:
+
[source,sh]
----
# a TARGET_HOST is specified in the command line, without using an inventory file
ansible-playbook -i ${TARGET_HOST}, ./configs/ocp-workloads/ocp-workload.yml \
    -e"ansible_ssh_private_key_file=~/.ssh/keytoyourhost.pem" \
    -e"ansible_user=${ANSIBLE_USER}" \
    -e"ocp_username=${OCP_USERNAME}" \
    -e"ocp_workload=${WORKLOAD}" \
    -e"guid=${GUID}" \
    -e"ACTION=create" \
    -e @./ocp_workload_example_vars.yaml \
    -e @./ocp_workload_example_secrets.yaml
----
+
Note how the dictionary got set up:
 
* *Variable 1: value 1* This value comes from the *defaults* dictionary. It did not get overwritten anywhere
* *Variable 2: My variable 2* This value comes from the *vars* dictionary that was passed as a parameter
* *Variable Secret: top secret data* This value comes from the *secrets* dictionary that was passed as a parameter
+
.Example output when using the examples above:
[source,text,options="nowrap"]
----
[...]
 
TASK [ocp-workload-example : Running Pre Workload Tasks] *****************************************************************************************************************************************************************
Monday 16 March 2020  15:27:10 -0400 (0:00:00.070)       0:00:05.383 **********
included: /Users/wkulhane/Development/agnosticd/ansible/roles/ocp-workload-example/tasks/./pre_workload.yml for bastion.dev4.openshift.opentlc.com
 
TASK [ocp-workload-example : Set up ocp4_workload_example combined dictionary] *******************************************************************************************************************************************
Monday 16 March 2020  15:27:10 -0400 (0:00:00.051)       0:00:05.434 **********
ok: [bastion.dev4.openshift.opentlc.com]
 
[...]
 
TASK [ocp-workload-example : Setting up workload for user] ***************************************************************************************************************************************************************
Monday 16 March 2020  15:27:10 -0400 (0:00:00.047)       0:00:05.625 **********
ok: [bastion.dev4.openshift.opentlc.com] => {
    "msg": "Setting up workload for user ocp_username = wkulhane-redhat.com"
}
 
TASK [ocp-workload-example : Print Example Variables] ********************************************************************************************************************************************************************
Monday 16 March 2020  15:27:10 -0400 (0:00:00.032)       0:00:05.658 **********
ok: [bastion.dev4.openshift.opentlc.com] => (item=Variable 1: value 1.) => {
    "msg": "Variable 1: value 1."
}
ok: [bastion.dev4.openshift.opentlc.com] => (item=Variable 2: My variable 2.) => {
    "msg": "Variable 2: My variable 2."
}
ok: [bastion.dev4.openshift.opentlc.com] => (item=Variable Secret: top secret data) => {
    "msg": "Variable Secret: top secret data"
}
 
[...]
----
 
=== To Delete an environment
 
----
TARGET_HOST="bastion.dev.openshift.opentlc.com"
OCP_USERNAME="wkulhane-redhat.com"
ANSIBLE_USER="ec2-user"
WORKLOAD="ocp-workload-example"
GUID=1002
 
# a TARGET_HOST is specified in the command line, without using an inventory file
ansible-playbook -i ${TARGET_HOST}, ./configs/ocp-workloads/ocp-workload.yml \
    -e"ansible_ssh_private_key_file=~/.ssh/keytoyourhost.pem" \
    -e"ansible_user=ec2-user" \
    -e"ocp_username=${OCP_USERNAME}" \
    -e"ocp_workload=${WORKLOAD}" \
    -e"guid=${GUID}" \
    -e"ACTION=remove" \
    -e @./ocp_workload_example_vars.yaml \
    -e @./ocp_workload_example_secrets.yaml
----
 
== Deploying a Workload with AgnosticV
 
When creating a configuration in AgnosticV that includes the deployment of the workload you can specify the dictionary straight in the AgnosticV config. Because AgnosticV configs are usually created by combining a `common.yaml` file with either `dev.yaml`, `test.yaml` or `prod.yaml` you can specify parts of the dictionary in each of these files. For example you could have common values defined in the `common.yaml` file and then specific values for development or production environments in `dev.yaml` or `prod.yaml`.
 
AgnosticV merges the definition files starting with `common.yaml` and then adding/overwriting what comes from either `dev.yaml` or `prod.yaml`.
 
Example of a simple AgnosticV config:
 
.common.yaml
[source,yaml]
----
# --- Quay Shared Workload Deployment for RPDS
# --- System: RHPDS
# --- Catalog: OpenShift Demos
# --- Catalog Item: Quay 3 on OpenShift 4
 
# --- Platform
platform: rhpds
 
# --- Cloud Provider
cloud_provider: none
 
# --- Config
env_type: ocp-workloads
ocp_workload: ocp4-workload-quay-operator
# This workload must be run as ec2-user (or cloud-user on OpenStack)
# because it has tasks requiring sudo.
ansible_user: ec2-user
ansible_ssh_private_key_file: /home/opentlc-mgr/.ssh/opentlc_admin_backdoor.pem
 
# --- Ensure the workload prints the correct statements for CloudForms to realize it finished
workload_shared_deployment: true
 
# --- Workload Configuration
ocp4_workload_quay_operator_vars:
  project: "quay-{{ guid }}"
 
# --- AgnosticV Meta variables
agnosticv_meta:
  params_to_variables:
    user: ocp_username
  secrets:
  # This secret file holds the token to pull the Quay image
  - ocp4_workload_quay_secrets
----
 
.dev.yaml
[source,yaml]
----
purpose: development
 
# --- Use specific variable values for Development
target_host: bastion.dev4.openshift.opentlc.com
 
# --- Workload Configuration Overrides
# Deploy Quay v3.2.0
ocp4_workload_quay_operator_vars:
  quay_image_tag: "v3.2.0"
  clair_image_tag: "v3.2.0"
----
 
.prod.yaml
[source,yaml]
----
---
purpose: production
 
# --- Use specific variable values for Production
target_host: bastion.rhpds.openshift.opentlc.com
 
# --- Workload Configuration Overrides
ocp4_workload_quay_operator_vars:
  quay_image_tag: "v3.1.3"
  clair_image_tag: "v3.1.3"
 
# --- AgnosticV Meta variables
agnosticv_meta:
  agnosticd_git_tag_prefix: ocp4-workload-quay-rhpds-prod
----
 
 
== Complex Examples
 
If you want to see more examples of how this works in a real world workload the following workloads already use this approach:
 
* ocp4-workload-authentication
* ocp4-workload-machinesets
* ocp4-workload-logging
* ocp4-workload-quay-operator