5 module: rancher_k8s_environment
7 - This module will create or delete Kubernetes environment.
8 - It will also delete other environments when variables are set accordingly.
10 - It identifies environment only by name. Expect problems with same named environments.
11 - All hosts running Kubernetes cluster should have same OS otherwise there
12 is possibility of misbehavement.
17 - Url of rancher server i.e. "http://10.0.0.1:8080".
21 - Name of the environment to create/remove.
24 - Description of environment to create.
27 - If "present" environment will be created or setup depending if it exists.
28 With multiple environments with same name expect error.
29 If "absent" environment will be removed. If multiple environments have same
30 name all will be deleted.
32 choices: [present, absent]
35 - Indicates if environments with different orchestration than Kubernetes should
41 - Indicates if environments with different name than specified should
47 - Indicates if environment should be deleted and recreated.
53 - OS (family from ansible_os_family variable) of the hosts running cluster. If
54 "RedHat" then datavolume fix will be applied.
56 https://github.com/rancher/rancher/issues/10015
63 from ansible.module_utils.basic import AnsibleModule
67 def get_existing_environments(rancher_address):
68 req = requests.get('{}/v2-beta/projects'.format(rancher_address))
69 envs = req.json()['data']
73 def not_k8s_ids(environments):
74 envs = filter(lambda x: x['orchestration'] != 'kubernetes', environments)
75 return [env['id'] for env in envs]
78 def other_k8s_ids(environments, name):
79 envs = filter(lambda x: x['orchestration'] == 'kubernetes' and x['name'] != name,
81 return [env['id'] for env in envs]
84 def env_ids_by_name(environments, name):
85 envs = filter(lambda x: x['name'] == name, environments)
86 return [env['id'] for env in envs]
89 def env_info_by_id(environments, env_id):
90 env = filter(lambda x: x['id'] == env_id, environments)
91 return [{'id': x['id'], 'name': x['name']} for x in env][0]
94 def delete_multiple_environments(rancher_address, env_ids):
96 for env_id in env_ids:
97 deleted.append(delete_environment(rancher_address, env_id))
101 def delete_environment(rancher_address, env_id):
102 req = requests.delete('{}/v2-beta/projects/{}'.format(rancher_address, env_id))
103 deleted = req.json()['data'][0]
104 return {'id': deleted['id'],
105 'name': deleted['name'],
106 'orchestration': deleted['orchestration']}
109 def create_k8s_environment(rancher_address, name, descr):
110 k8s_template_id = None
112 k8s_template = requests.get(
113 '{}/v2-beta/projecttemplates?name=Kubernetes'.format(rancher_address)).json()
114 if k8s_template['data']:
115 k8s_template_id = k8s_template['data'][0]['id']
118 if k8s_template_id is None:
119 raise ValueError('Template for kubernetes not found.')
122 'description': descr,
123 'projectTemplateId': k8s_template_id,
124 'allowSystemRole': False,
126 'virtualMachine': False,
127 'servicesPortRange': None,
131 body_json = json.dumps(body)
132 req = requests.post('{}/v2-beta/projects'.format(rancher_address), data=body_json)
134 return {'id': created['id'], 'name': created['name']}
137 def get_kubelet_service(rancher_address, env_id):
139 response = requests.get(
140 '{}/v2-beta/projects/{}/services/?name=kubelet'.format(rancher_address,
143 if response.status_code >= 400:
144 # too early or too late for obtaining data
145 # small delay will improve our chances to collect it
149 content = response.json()
152 return content['data'][0]
154 # this is unfortunate, response from service api received but data
155 # not available, lets try again
161 def fix_datavolume_rhel(rancher_address, env_id):
162 kubelet_svc = get_kubelet_service(rancher_address, env_id)
165 data_volume_index = kubelet_svc['launchConfig']['dataVolumes'].index(
166 '/sys:/sys:ro,rprivate')
168 return 'Already changed'
169 kubelet_svc['launchConfig']['dataVolumes'][
170 data_volume_index] = '/sys/fs/cgroup:/sys/fs/cgroup:ro,rprivate'
172 'inServiceStrategy': {
174 'intervalMillis': 2000,
176 'launchConfig': kubelet_svc['launchConfig'],
177 'secondaryLaunchConfigs': []
180 body_json = json.dumps(body)
182 '{}/v2-beta/projects/{}/services/{}?action=upgrade'.format(rancher_address,
188 req_svc = requests.get(
189 '{}/v2-beta/projects/{}/services/{}'.format(rancher_address, env_id,
191 req_svc_content = req_svc.json()
192 if 'finishupgrade' in req_svc_content['actions']:
193 req_finish = requests.post(
194 req_svc_content['actions']['finishupgrade'])
196 'dataVolumes': req_finish.json()['upgrade']['inServiceStrategy'][
197 'launchConfig']['dataVolumes']}
200 raise ValueError('Could not get kubelet service')
203 def create_registration_tokens(rancher_address, env_id):
204 body = {'name': str(env_id)}
205 body_json = json.dumps(body)
206 response = requests.post(
207 '{}/v2-beta/projects/{}/registrationtokens'.format(rancher_address, env_id,
210 tokens = requests.get(response.json()['links']['self'])
211 tokens_content = tokens.json()
212 if tokens_content['image'] is not None and tokens_content[
213 'registrationUrl'] is not None:
214 return {'image': tokens_content['image'],
215 'reg_url': tokens_content['registrationUrl']}
220 def get_registration_tokens(rancher_address, env_id):
221 reg_tokens = requests.get(
222 '{}/v2-beta/projects/{}/registrationtokens'.format(rancher_address, env_id))
223 reg_tokens_content = reg_tokens.json()
224 tokens = reg_tokens_content['data']
227 return {'image': tokens[0]['image'], 'reg_url': tokens[0]['registrationUrl']}
230 def create_apikey(rancher_address, env_id):
232 'name': 'kubectl_env_{}'.format(env_id),
233 'description': "Provides access to kubectl"
235 body_json = json.dumps(body)
236 apikey_req = requests.post(
237 '{}/v2-beta/apikey'.format(rancher_address, env_id, data=body_json))
238 apikey_content = apikey_req.json()
239 return {'public': apikey_content['publicValue'],
240 'private': apikey_content['secretValue']}
244 module = AnsibleModule(
246 server=dict(type='str', required=True),
247 name=dict(type='str', required=True),
248 descr=dict(type='str'),
249 state=dict(type='str', choices=['present', 'absent'], default='present'),
250 delete_other_k8s=dict(type='bool', default=False),
251 delete_not_k8s=dict(type='bool', default=True),
252 force=dict(type='bool', default=True),
253 host_os=dict(type='str', required=True)
257 params = module.params
258 rancher_address = params['server']
259 name = params['name']
260 descr = params['descr']
261 delete_not_k8s = params['delete_not_k8s']
262 delete_other_k8s = params['delete_other_k8s']
263 force = params['force']
264 host_os = params['host_os']
265 state = params['state']
267 existing_envs = get_existing_environments(rancher_address)
268 same_name_ids = env_ids_by_name(existing_envs, name)
274 to_delete_ids += other_k8s_ids(existing_envs, name)
277 to_delete_ids += not_k8s_ids(existing_envs)
278 if force or state == 'absent':
279 to_delete_ids += same_name_ids
281 deleted = delete_multiple_environments(rancher_address, to_delete_ids)
284 changes['deleted'] = deleted
285 if state == 'absent':
286 module.exit_json(changed=True, deleted=changes['deleted'])
288 if state == 'absent':
289 module.exit_json(changed=False)
291 if len(same_name_ids) > 1 and not force:
292 module.fail_json(msg='Multiple environments with same name. '
293 'Use "force: yes" to delete '
294 'all environments with same name.')
296 if same_name_ids and not force:
297 changes['environment'] = env_info_by_id(existing_envs, same_name_ids[0])
298 if host_os == 'RedHat':
300 rhel_fix = fix_datavolume_rhel(rancher_address, same_name_ids[0])
301 changes['rhel_fix'] = rhel_fix
302 except ValueError as err:
304 msg='Error: {} Try to recreate k8s environment.'.format(err))
306 reg_tokens = get_registration_tokens(rancher_address, same_name_ids[0])
308 reg_tokens = create_registration_tokens(rancher_address, same_name_ids[0])
309 changes['registration_tokens'] = reg_tokens
311 apikey = create_apikey(rancher_address, same_name_ids[0])
312 changes['apikey'] = apikey
313 module.exit_json(changed=True, data=changes,
314 msg='New environment was not created. Only set up was done')
316 new_env = create_k8s_environment(rancher_address, name, descr)
317 except ValueError as err:
318 module.fail_json(msg='Error: {} Try to recreate k8s environment.'.format(err))
320 if host_os == 'RedHat':
322 rhel_fix = fix_datavolume_rhel(rancher_address, new_env['id'])
323 changes['rhel_fix'] = rhel_fix
324 except ValueError as err:
325 module.fail_json(msg='Error: {} Try to recreate k8s environment.'.format(
328 reg_tokens = create_registration_tokens(rancher_address, new_env['id'])
330 apikey = create_apikey(rancher_address, new_env['id'])
332 changes['environment'] = new_env
333 changes['registration_tokens'] = reg_tokens
334 changes['apikey'] = apikey
336 module.exit_json(changed=True, data=changes)
339 if __name__ == '__main__':