blob: 5a3f4b707a9986edf4380d0dbfeae00544f3e1c3 [file] [log] [blame]
David K. Bainbridge6e23ac82016-12-07 12:55:41 -08001#!/usr/bin/python
2
3DOCUMENTATION = '''
4---
5module: maas_cluster
6short_description: Manage MAAS Clusters Interfaces
7options:
8 maas:
9 description:
10 - URL of MAAS server
11 default: http://localhost/MAAS/api/1.0/
12 key:
13 description:
14 - MAAS API key
15 required: yes
16 name:
17 description:
18 - name of the cluster
19 required: yes
20 status:
21 description:
22 - indicates the enabled state of the cluster
23 choices: ['enabled', 'disabled']
24 default: enabled
25 domain:
26 description:
27 - DNS zone name
28 required: no
29 state:
30 description:
31 - possible states for this cluster
32 choices: ['present', 'query']
33 default: present
34
35requirements: [ipaddress, requests_oauthlib, maasclient]
36author: David Bainbridge
37'''
38
39EXAMPLES = '''
40examples:
41 maas_cluster:
42 maas: http://my.maas.server.com/MAAS/api/1.0/
43 key: 'xBvr9dx5k7S52myufC:fqBXV7hJgXegNZDw9c:K8hsmL47XjAppfQy2pDVW7G49p6PELgp'
44 name: MyCluster
45 status: enabled
46 domain: company.com
47 state: present
48
49 maas_cluster:
50 maas: http://my.maas.server.com/MAAS/api/1.0/
51 key: 'xBvr9dx5k7S52myufC:fqBXV7hJgXegNZDw9c:K8hsmL47XjAppfQy2pDVW7G49p6PELgp'
52 name: MyDeadCluster
53 state: query
54'''
55
56import sys
57import json
58import ipaddress
59import requests
60from maasclient.auth import MaasAuth
61from maasclient import MaasClient
62
63# For some reason the maasclient doesn't provide a put method. So
64# we will add it here
65def put(client, url, params=None):
66 return requests.put(url=client.auth.api_url + url,
67 auth=client._oauth(), data=params)
68
69# Attempt to interpret the given value as a JSON object, if that fails
70# just return it as a string
71def string_or_object(val):
72 try:
73 return json.loads(val)
74 except:
75 return val
76
77# Return a copy of the given dictionary with any `null` valued entries
78# removed
79def remove_null(d_in):
80 d = d_in.copy()
81 to_remove = []
82 for k in d.keys():
83 if d[k] == None:
84 to_remove.append(k)
85 for k in to_remove:
86 del d[k]
87 return d
88
89# Deterine if two dictionaries are different
90def different(have, want):
91 have_keys = have.keys()
92 for key in want.keys():
93 if (key in have_keys and want[key] != have[key]) or key not in have_keys:
94 return True
95 return False
96
97# Get an cluster from MAAS using its name, if not found return None
98def get_cluster(maas, name):
99 res = maas.get('/nodegroups/', dict(op='list'))
100 if res.ok:
101 for ng in json.loads(res.text):
102 if ng['cluster_name'] == name:
103 return ng
104 return None
105
106def update_cluster(maas, have, want):
107 merged = have.copy()
108 merged.update(want)
109 res = put(maas, '/nodegroups/%s/' % merged['uuid'], merged)
110 if res.ok:
111 return { 'error': False, 'status': get_cluster(maas, merged['cluster_name']) }
112 return { 'error': True, 'status': string_or_object(res.text) }
113
114def main():
115 module = AnsibleModule(
116 argument_spec = dict(
117 maas=dict(default='http://localhost/MAAS/api/1.0/'),
118 key=dict(required=True),
119 name=dict(required=True),
120 status=dict(default='enabled', choices=['enabled', 'disabled']),
121 domain=dict(required=False),
122 state=dict(default='present', choices=['present', 'query'])
123 ),
124 supports_check_mode = False
125 )
126
127 maas = module.params['maas']
128 key = module.params['key']
129 state = module.params['state']
130
131 status_map = {
132 'enabled': 1,
133 'disabled': 2
134 }
135
136 # Construct a sparsely populate desired state
137 desired = remove_null({
138 'cluster_name': module.params['name'],
139 'status': status_map[module.params['status']],
140 'name' : module.params['domain'],
141 })
142
143 # Authenticate into MAAS
144 auth = MaasAuth(maas, key)
145 maas = MaasClient(auth)
146
147 # Attempt to get the cluster from MAAS
148 cluster = get_cluster(maas, desired['cluster_name'])
149
150 # Actions if the cluster does not currently exist
151 if not cluster:
152 if state == 'query':
153 # If this is a query, returne it is not found
154 module.exit_json(changed=False, found=False)
155 elif state == 'present':
156 # Not able to create clusters via the API
157 module.fail_json(msg='Named cluster does not exist and clusters cannot be programatically created')
158 else:
159 # If this should be absent, then we are done and in the desired state
160 module.exit_json(changed=False)
161
162 # Done with clusters does not exists actions
163 return
164
165 # Actions if the cluster does exist
166 if state == 'query':
167 # If this is a query, return the cluster
168 module.exit_json(changed=False, found=True, cluster=cluster)
169 elif state == 'present':
170 # If we want this to exists check to see if this is different and
171 # needs updated
172 if different(cluster, desired):
173 res = update_cluster(maas, cluster, desired)
174 if res['error']:
175 module.fail_json(msg=res['status'])
176 else:
177 module.exit_json(changed=True, cluster=res['status'])
178 else:
179 # No differences, to nothing to change
180 module.exit_json(changed=False, cluster=cluster)
181 else:
182 # Not able to delete clusters via the API
183 module.fail_json(msg='Named cluster exists and clusters cannot be programmatically deleted')
184
185# this is magic, see lib/ansible/module_common.py
186#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
187if __name__ == '__main__':
188 main()