1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3#
4# Copyright: Ansible Project
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7from __future__ import absolute_import, division, print_function
8__metaclass__ = type
9
10
11ANSIBLE_METADATA = {'metadata_version': '1.1',
12                    'status': ['stableinterface'],
13                    'supported_by': 'community'}
14
15
16DOCUMENTATION = '''
17---
18module: digital_ocean_domain
19short_description: Create/delete a DNS domain in DigitalOcean
20description:
21     - Create/delete a DNS domain in DigitalOcean.
22version_added: "1.6"
23author: "Michael Gregson (@mgregson)"
24options:
25  state:
26    description:
27     - Indicate desired state of the target.
28    default: present
29    choices: ['present', 'absent']
30  id:
31    description:
32     - Numeric, the droplet id you want to operate on.
33    aliases: ['droplet_id']
34  name:
35    description:
36     - String, this is the name of the droplet - must be formatted by hostname rules, or the name of a SSH key, or the name of a domain.
37  ip:
38    description:
39     - An 'A' record for '@' ($ORIGIN) will be created with the value 'ip'.  'ip' is an IP version 4 address.
40extends_documentation_fragment: digital_ocean.documentation
41notes:
42  - Environment variables DO_OAUTH_TOKEN can be used for the oauth_token.
43  - As of Ansible 1.9.5 and 2.0, Version 2 of the DigitalOcean API is used, this removes C(client_id) and C(api_key) options in favor of C(oauth_token).
44  - If you are running Ansible 1.9.4 or earlier you might not be able to use the included version of this module as the API version used has been retired.
45
46requirements:
47  - "python >= 2.6"
48'''
49
50
51EXAMPLES = '''
52# Create a domain
53
54- digital_ocean_domain:
55    state: present
56    name: my.digitalocean.domain
57    ip: 127.0.0.1
58
59# Create a droplet and a corresponding domain
60
61- digital_ocean:
62    state: present
63    name: test_droplet
64    size_id: 1gb
65    region_id: sgp1
66    image_id: ubuntu-14-04-x64
67
68
69  register: test_droplet
70
71- digital_ocean_domain:
72    state: present
73    name: "{{ test_droplet.droplet.name }}.my.domain"
74    ip: "{{ test_droplet.droplet.ip_address }}"
75
76'''
77
78import traceback
79from ansible.module_utils.basic import AnsibleModule
80from ansible.module_utils.digital_ocean import DigitalOceanHelper
81from ansible.module_utils._text import to_native
82
83
84class DoManager(DigitalOceanHelper, object):
85    def __init__(self, module):
86        super(DoManager, self).__init__(module)
87        self.domain_name = module.params.get('name', None)
88        self.domain_ip = module.params.get('ip', None)
89        self.domain_id = module.params.get('id', None)
90
91    @staticmethod
92    def jsonify(response):
93        return response.status_code, response.json
94
95    def all_domains(self):
96        resp = self.get('domains/')
97        return resp
98
99    def find(self):
100        if self.domain_name is None and self.domain_id is None:
101            return False
102
103        domains = self.all_domains()
104        status, json = self.jsonify(domains)
105        for domain in json['domains']:
106            if domain['name'] == self.domain_name:
107                return True
108        return False
109
110    def add(self):
111        params = {'name': self.domain_name, 'ip_address': self.domain_ip}
112        resp = self.post('domains/', data=params)
113        status = resp.status_code
114        json = resp.json
115        if status == 201:
116            return json['domain']
117        else:
118            return json
119
120    def all_domain_records(self):
121        resp = self.get('domains/%s/records/' % self.domain_name)
122        return resp.json
123
124    def domain_record(self):
125        resp = self.get('domains/%s' % self.domain_name)
126        status, json = self.jsonify(resp)
127        return json
128
129    def destroy_domain(self):
130        resp = self.delete('domains/%s' % self.domain_name)
131        status, json = self.jsonify(resp)
132        if status == 204:
133            return True
134        else:
135            return json
136
137    def edit_domain_record(self, record):
138        params = {'name': '@',
139                  'data': self.module.params.get('ip')}
140        resp = self.put('domains/%s/records/%s' % (self.domain_name, record['id']), data=params)
141        status, json = self.jsonify(resp)
142
143        return json['domain_record']
144
145    def create_domain_record(self):
146        params = {'name': '@',
147                  'type': 'A',
148                  'data': self.module.params.get('ip')}
149
150        resp = self.post('domains/%s/records' % (self.domain_name), data=params)
151        status, json = self.jsonify(resp)
152
153        return json['domain_record']
154
155
156def core(module):
157    do_manager = DoManager(module)
158    state = module.params.get('state')
159
160    domain = do_manager.find()
161    if state == 'present':
162        if not domain:
163            domain = do_manager.add()
164            if 'message' in domain:
165                module.fail_json(changed=False, msg=domain['message'])
166            else:
167                module.exit_json(changed=True, domain=domain)
168        else:
169            records = do_manager.all_domain_records()
170            at_record = None
171            for record in records['domain_records']:
172                if record['name'] == "@" and record['type'] == 'A':
173                    at_record = record
174
175            if not at_record:
176                do_manager.create_domain_record()
177                module.exit_json(changed=True, domain=do_manager.find())
178            elif not at_record['data'] == module.params.get('ip'):
179                do_manager.edit_domain_record(at_record)
180                module.exit_json(changed=True, domain=do_manager.find())
181            else:
182                module.exit_json(changed=False, domain=do_manager.domain_record())
183
184    elif state == 'absent':
185        if not domain:
186            module.exit_json(changed=False, msg="Domain not found")
187        else:
188            delete_event = do_manager.destroy_domain()
189            if not delete_event:
190                module.fail_json(changed=False, msg=delete_event['message'])
191            else:
192                module.exit_json(changed=True, event=None)
193        delete_event = do_manager.destroy_domain()
194        module.exit_json(changed=delete_event)
195
196
197def main():
198    argument_spec = DigitalOceanHelper.digital_ocean_argument_spec()
199    argument_spec.update(
200        state=dict(choices=['present', 'absent'], default='present'),
201        name=dict(type='str'),
202        id=dict(aliases=['droplet_id'], type='int'),
203        ip=dict(type='str')
204    )
205
206    module = AnsibleModule(
207        argument_spec=argument_spec,
208        required_one_of=(
209            ['id', 'name'],
210        ),
211    )
212
213    try:
214        core(module)
215    except Exception as e:
216        module.fail_json(msg=to_native(e), exception=traceback.format_exc())
217
218
219if __name__ == '__main__':
220    main()
221