blob: 6bdaa5f435c5877905e9a5d6d7cf9c7301ad1f03 [file] [log] [blame]
David K. Bainbridge6e23ac82016-12-07 12:55:41 -08001#!/usr/bin/python
2
Jonathan Hart93956f52017-08-22 13:12:42 -07003# Copyright 2017-present Open Networking Foundation
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
David K. Bainbridge6e23ac82016-12-07 12:55:41 -080017DOCUMENTATION = '''
18---
19module: maas_sshkey
20short_description: Manage MAAS Clusters Interfaces
21options:
22 maas:
23 description:
24 - URL of MAAS server
25 default: http://localhost/MAAS/api/1.0/
26 key:
27 description:
28 - MAAS API key
29 required: yes
30 sshkey:
31 description:
32 - sshkey on which to operate
33 required: yes
34 state:
35 description:
36 - possible states for this sshkey
37 choices: ['present', 'absent', 'query']
38 default: present
39
40requirements: [ipaddress, requests_oauthlib, maasclient]
41author: David Bainbridge
42'''
43
44EXAMPLES = '''
45examples:
46 maas_sshkey:
47 maas: http://my.maas.server.com/MAAS/api/1.0/
48 key: 'xBvr9dx5k7S52myufC:fqBXV7hJgXegNZDw9c:K8hsmL47XjAppfQy2pDVW7G49p6PELgp'
49 sshkey: ... foo@company.com
50 state: present
51
52 maas_sshkeys:
53 maas: http://my.maas.server.com/MAAS/api/1.0/
54 key: 'xBvr9dx5k7S52myufC:fqBXV7hJgXegNZDw9c:K8hsmL47XjAppfQy2pDVW7G49p6PELgp'
55 sshkey: ... foo@company.com
56 state: absent
57'''
58
59import sys
60import json
61import ipaddress
62import requests
63from maasclient.auth import MaasAuth
64from maasclient import MaasClient
65
66# For some reason the maasclient doesn't provide a put method. So
67# we will add it here
68def put(client, url, params=None):
69 return requests.put(url=client.auth.api_url + url,
70 auth=client._oauth(), data=params)
71
72# Attempt to interpret the given value as a JSON object, if that fails
73# just return it as a string
74def string_or_object(val):
75 try:
76 return json.loads(val)
77 except:
78 return val
79
80# Return a copy of the given dictionary with any `null` valued entries
81# removed
82def remove_null(d_in):
83 d = d_in.copy()
84 to_remove = []
85 for k in d.keys():
86 if d[k] == None:
87 to_remove.append(k)
88 for k in to_remove:
89 del d[k]
90 return d
91
92def filter(filter_type, d, keys):
93 if filter_type == 'include':
94 for k in d.keys():
95 if k not in keys:
96 d.pop(k, None)
97 else:
98 for k in d.keys():
99 if k in keys:
100 d.pop(k, None)
101
102# Get an item from MAAS using its name, if not found return None
103def get_sshkey(maas, name):
104 res = maas.get('/account/prefs/sshkeys/', dict(op='list'))
105 if res.ok:
106 for sshkey in json.loads(res.text):
107 if sshkey['key'] == name:
108 return sshkey
109 return None
110
111# Create an item based on the value given
112def create_sshkey(maas, sshkey):
113 merged = sshkey.copy()
114 filter('include', merged, ['key'])
115 merged['op'] = 'new'
116 res = maas.post('/account/prefs/sshkeys/', merged)
117 if res.ok:
118 return { 'error': False, 'status': get_sshkey(maas, merged['key']) }
119 return { 'error': True, 'status': string_or_object(res.text) }
120
121# Delete an item based on the name
122def delete_sshkey(maas, id):
123 res = maas.delete('/account/prefs/sshkeys/%s/' % id)
124 if res.ok:
125 return { 'error': False }
126 return { 'error': True, 'status': string_or_object(res.text) }
127
128def main():
129 module = AnsibleModule(
130 argument_spec = dict(
131 maas=dict(default='http://localhost/MAAS/api/1.0/'),
132 key=dict(required=True),
133 sshkey=dict(required=True),
134 state=dict(default='present', choices=['present', 'absent', 'query'])
135 ),
136 supports_check_mode = False
137 )
138
139 maas = module.params['maas']
140 key = module.params['key']
141 state = module.params['state']
142
143 # Construct a sparsely populate desired state
144 desired = remove_null({
145 'key': module.params['sshkey'],
146 })
147
148 # Authenticate into MAAS
149 auth = MaasAuth(maas, key)
150 maas = MaasClient(auth)
151
152 # Attempt to get the item from MAAS
153 sshkey = get_sshkey(maas, desired['key'])
154
155 # Actions if the item does not currently exist
156 if not sshkey:
157 if state == 'query':
158 # If this is a query, return it is not found
159 module.exit_json(changed=False, found=False)
160 elif state == 'present':
161 # If this should be present, then attempt to create it
162 res = create_sshkey(maas, desired)
163 if res['error']:
164 module.fail_json(msg=res['status'])
165 else:
166 module.exit_json(changed=True, sshkey=res['status'])
167 else:
168 # If this should be absent, then we are done and in the desired state
169 module.exit_json(changed=False)
170
171 # Done with items does not exists actions
172 return
173
174 # Actions if the item does exist
175 if state == 'query':
176 # If this is a query, return the sshkey
177 module.exit_json(changed=False, found=True, sshkey=sshkey)
178 elif state == 'present':
179 # If we want this to exists check to see if this is different and
180 # needs updated
181 # No differences, to nothing to change
182 module.exit_json(changed=False, sshkey=sshkey)
183 else:
184 # If we don't want this item, then delete it
185 res = delete_sshkey(maas, item['id'])
186 if res['error']:
187 module.fail_json(msg=res['status'])
188 else:
189 module.exit_json(changed=True, sshkey=sshkey)
190
191# this is magic, see lib/ansible/module_common.py
192#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
193if __name__ == '__main__':
194 main()