def core(module): state = module.params['state'] name = module.params['name'] rest = DigitalOceanHelper(module) results = dict(changed=False) response = rest.get('certificates') status_code = response.status_code resp_json = response.json if status_code != 200: module.fail_json(msg="Failed to retrieve certificates for DigitalOcean") if state == 'present': for cert in resp_json['certificates']: if cert['name'] == name: module.fail_json(msg="Certificate name %s already exists" % name) # Certificate does not exist, let us create it cert_data = dict(name=name, private_key=module.params['private_key'], leaf_certificate=module.params['leaf_certificate']) if module.params['certificate_chain'] is not None: cert_data.update(certificate_chain=module.params['certificate_chain']) response = rest.post("certificates", data=cert_data) status_code = response.status_code if status_code == 500: module.fail_json(msg="Failed to upload certificates as the certificates are malformed.") resp_json = response.json if status_code == 201: results.update(changed=True, response=resp_json) elif status_code == 422: results.update(changed=False, response=resp_json) elif state == 'absent': cert_id_del = None for cert in resp_json['certificates']: if cert['name'] == name: cert_id_del = cert['id'] if cert_id_del is not None: url = "certificates/{0}".format(cert_id_del) response = rest.delete(url) if response.status_code == 204: results.update(changed=True) else: results.update(changed=False) else: module.fail_json(msg="Failed to find certificate %s" % name) module.exit_json(**results)
class DODroplet(object): def __init__(self, module): self.rest = DigitalOceanHelper(module) self.module = module self.wait = self.module.params.pop('wait', True) self.wait_timeout = self.module.params.pop('wait_timeout', 120) self.unique_name = self.module.params.pop('unique_name', False) # pop the oauth token so we don't include it in the POST data self.module.params.pop('oauth_token') def get_by_id(self, droplet_id): if not droplet_id: return None response = self.rest.get('droplets/{0}'.format(droplet_id)) json_data = response.json if response.status_code == 200: return json_data return None def get_by_name(self, droplet_name): if not droplet_name: return None page = 1 while page is not None: response = self.rest.get('droplets?page={0}'.format(page)) json_data = response.json if response.status_code == 200: for droplet in json_data['droplets']: if droplet['name'] == droplet_name: return {'droplet': droplet} if 'links' in json_data and 'pages' in json_data[ 'links'] and 'next' in json_data['links']['pages']: page += 1 else: page = None return None def get_addresses(self, data): """ Expose IP addresses as their own property allowing users extend to additional tasks """ _data = data for k, v in data.items(): setattr(self, k, v) networks = _data['droplet']['networks'] for network in networks.get('v4', []): if network['type'] == 'public': _data['ip_address'] = network['ip_address'] else: _data['private_ipv4_address'] = network['ip_address'] for network in networks.get('v6', []): if network['type'] == 'public': _data['ipv6_address'] = network['ip_address'] else: _data['private_ipv6_address'] = network['ip_address'] return _data def get_droplet(self): json_data = self.get_by_id(self.module.params['id']) if not json_data and self.unique_name: json_data = self.get_by_name(self.module.params['name']) return json_data def create(self): json_data = self.get_droplet() droplet_data = None if json_data: droplet_data = self.get_addresses(json_data) self.module.exit_json(changed=False, data=droplet_data) if self.module.check_mode: self.module.exit_json(changed=True) request_params = dict(self.module.params) del request_params['id'] response = self.rest.post('droplets', data=request_params) json_data = response.json if response.status_code >= 400: self.module.fail_json(changed=False, msg=json_data['message']) if self.wait: json_data = self.ensure_power_on(json_data['droplet']['id']) droplet_data = self.get_addresses(json_data) self.module.exit_json(changed=True, data=droplet_data) def delete(self): json_data = self.get_droplet() if json_data: if self.module.check_mode: self.module.exit_json(changed=True) response = self.rest.delete('droplets/{0}'.format( json_data['droplet']['id'])) json_data = response.json if response.status_code == 204: self.module.exit_json(changed=True, msg='Droplet deleted') self.module.fail_json(changed=False, msg='Failed to delete droplet') else: self.module.exit_json(changed=False, msg='Droplet not found') def ensure_power_on(self, droplet_id): end_time = time.time() + self.wait_timeout while time.time() < end_time: response = self.rest.get('droplets/{0}'.format(droplet_id)) json_data = response.json if json_data['droplet']['status'] == 'active': return json_data time.sleep(min(2, end_time - time.time())) self.module.fail_json(msg='Wait for droplet powering on timeout')
class DOBlockStorage(object): def __init__(self, module): self.module = module self.rest = DigitalOceanHelper(module) def get_key_or_fail(self, k): v = self.module.params[k] if v is None: self.module.fail_json(msg='Unable to load %s' % k) return v def poll_action_for_complete_status(self, action_id): url = 'actions/{0}'.format(action_id) end_time = time.time() + self.module.params['timeout'] while time.time() < end_time: time.sleep(2) response = self.rest.get(url) status = response.status_code json = response.json if status == 200: if json['action']['status'] == 'completed': return True elif json['action']['status'] == 'errored': raise DOBlockStorageException(json['message']) raise DOBlockStorageException('Unable to reach api.digitalocean.com') def get_attached_droplet_ID(self, volume_name, region): url = 'volumes?name={0}®ion={1}'.format(volume_name, region) response = self.rest.get(url) status = response.status_code json = response.json if status == 200: volumes = json['volumes'] if len(volumes) > 0: droplet_ids = volumes[0]['droplet_ids'] if len(droplet_ids) > 0: return droplet_ids[0] return None else: raise DOBlockStorageException(json['message']) def attach_detach_block_storage(self, method, volume_name, region, droplet_id): data = { 'type': method, 'volume_name': volume_name, 'region': region, 'droplet_id': droplet_id } response = self.rest.post('volumes/actions', data=data) status = response.status_code json = response.json if status == 202: return self.poll_action_for_complete_status(json['action']['id']) elif status == 200: return True elif status == 422: return False else: raise DOBlockStorageException(json['message']) def create_block_storage(self): volume_name = self.get_key_or_fail('volume_name') snapshot_id = self.module.params['snapshot_id'] if snapshot_id: self.module.params['block_size'] = None self.module.params['region'] = None block_size = None region = None else: block_size = self.get_key_or_fail('block_size') region = self.get_key_or_fail('region') description = self.module.params['description'] data = { 'size_gigabytes': block_size, 'name': volume_name, 'description': description, 'region': region, 'snapshot_id': snapshot_id, } response = self.rest.post("volumes", data=data) status = response.status_code json = response.json if status == 201: self.module.exit_json(changed=True, id=json['volume']['id']) elif status == 409 and json['id'] == 'conflict': self.module.exit_json(changed=False) else: raise DOBlockStorageException(json['message']) def delete_block_storage(self): volume_name = self.get_key_or_fail('volume_name') region = self.get_key_or_fail('region') url = 'volumes?name={0}®ion={1}'.format(volume_name, region) attached_droplet_id = self.get_attached_droplet_ID(volume_name, region) if attached_droplet_id is not None: self.attach_detach_block_storage('detach', volume_name, region, attached_droplet_id) response = self.rest.delete(url) status = response.status_code json = response.json if status == 204: self.module.exit_json(changed=True) elif status == 404: self.module.exit_json(changed=False) else: raise DOBlockStorageException(json['message']) def attach_block_storage(self): volume_name = self.get_key_or_fail('volume_name') region = self.get_key_or_fail('region') droplet_id = self.get_key_or_fail('droplet_id') attached_droplet_id = self.get_attached_droplet_ID(volume_name, region) if attached_droplet_id is not None: if attached_droplet_id == droplet_id: self.module.exit_json(changed=False) else: self.attach_detach_block_storage('detach', volume_name, region, attached_droplet_id) changed_status = self.attach_detach_block_storage( 'attach', volume_name, region, droplet_id) self.module.exit_json(changed=changed_status) def detach_block_storage(self): volume_name = self.get_key_or_fail('volume_name') region = self.get_key_or_fail('region') droplet_id = self.get_key_or_fail('droplet_id') changed_status = self.attach_detach_block_storage( 'detach', volume_name, region, droplet_id) self.module.exit_json(changed=changed_status)
def core(module): state = module.params['state'] name = module.params['name'] resource_id = module.params['resource_id'] resource_type = module.params['resource_type'] rest = DigitalOceanHelper(module) if state == 'present': response = rest.get('tags/{0}'.format(name)) status_code = response.status_code resp_json = response.json changed = False if status_code == 200 and resp_json['tag']['name'] == name: changed = False else: # Ensure Tag exists response = rest.post("tags", data={'name': name}) status_code = response.status_code resp_json = response.json if status_code == 201: changed = True elif status_code == 422: changed = False else: module.exit_json(changed=False, data=resp_json) if resource_id is None: # No resource defined, we're done. module.exit_json(changed=changed, data=resp_json) else: # Check if resource is already tagged or not found = False url = "{0}?tag_name={1}".format(resource_type, name) if resource_type == 'droplet': url = "droplets?tag_name={0}".format(name) response = rest.get(url) status_code = response.status_code resp_json = response.json if status_code == 200: for resource in resp_json['droplets']: if not found and resource['id'] == int(resource_id): found = True break if not found: # If resource is not tagged, tag a resource url = "tags/{0}/resources".format(name) payload = { 'resources': [{ 'resource_id': resource_id, 'resource_type': resource_type}]} response = rest.post(url, data=payload) if response.status_code == 204: module.exit_json(changed=True) else: module.fail_json(msg="error tagging resource '{0}': {1}".format(resource_id, response.json["message"])) else: # Already tagged resource module.exit_json(changed=False) else: # Unable to find resource specified by user module.fail_json(msg=resp_json['message']) elif state == 'absent': if resource_id: url = "tags/{0}/resources".format(name) payload = { 'resources': [{ 'resource_id': resource_id, 'resource_type': resource_type}]} response = rest.delete(url, data=payload) else: url = "tags/{0}".format(name) response = rest.delete(url) if response.status_code == 204: module.exit_json(changed=True) else: module.exit_json(changed=False, data=response.json)