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