exo_dns_record: remove limitation for multiple records only for A type (#35173)

This commit is contained in:
René Moser 2018-02-05 22:40:02 +01:00 committed by GitHub
parent 57d5b8642a
commit 24b8f36f1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 100 deletions

View file

@ -1,31 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# # Copyright (c) 2016, René Moser <mail@renemoser.net>
# (c) 2016, René Moser <mail@renemoser.net> # Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
#
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import os import os
@ -43,7 +18,7 @@ def exo_dns_argument_spec():
api_secret=dict(default=os.environ.get('CLOUDSTACK_SECRET'), no_log=True), api_secret=dict(default=os.environ.get('CLOUDSTACK_SECRET'), no_log=True),
api_timeout=dict(type='int', default=os.environ.get('CLOUDSTACK_TIMEOUT') or 10), api_timeout=dict(type='int', default=os.environ.get('CLOUDSTACK_TIMEOUT') or 10),
api_region=dict(default=os.environ.get('CLOUDSTACK_REGION') or 'cloudstack'), api_region=dict(default=os.environ.get('CLOUDSTACK_REGION') or 'cloudstack'),
validate_certs=dict(default='yes', type='bool'), validate_certs=dict(default=True, type='bool'),
) )

View file

@ -34,12 +34,12 @@ options:
description: description:
- Type of the record. - Type of the record.
default: A default: A
choices: ['A', 'ALIAS', 'CNAME', 'MX', 'SPF', 'URL', 'TXT', 'NS', 'SRV', 'NAPTR', 'PTR', 'AAAA', 'SSHFP', 'HINFO', 'POOL'] choices: [ A, ALIAS, CNAME, MX, SPF, URL, TXT, NS, SRV, NAPTR, PTR, AAAA, SSHFP, HINFO, POOL ]
aliases: ['rtype', 'type'] aliases: [ rtype, type ]
content: content:
description: description:
- Content of the record. - Content of the record.
- Required if C(state=present) or C(name="") - Required if C(state=present) or C(multiple=yes).
aliases: ['value', 'address'] aliases: ['value', 'address']
ttl: ttl:
description: description:
@ -48,19 +48,19 @@ options:
prio: prio:
description: description:
- Priority of the record. - Priority of the record.
aliases: ['priority'] aliases: [ priority ]
multiple: multiple:
description: description:
- Whether there are more than one records with similar C(name). - Whether there are more than one records with similar C(name) and C(record_type).
- Only allowed with C(record_type=A). - Only allowed for a few record types, e.g. C(record_type=A), C(record_type=NS) or C(record_type=MX).
- C(content) will not be updated as it is used as key to find the record. - C(content) will not be updated, instead it is used as a key to find existing records.
aliases: ['priority'] type: bool
default: no
state: state:
description: description:
- State of the record. - State of the record.
required: false default: present
default: 'present' choices: [ present, absent ]
choices: [ 'present', 'absent' ]
extends_documentation_fragment: exoscale extends_documentation_fragment: exoscale
''' '''
@ -95,23 +95,25 @@ EXAMPLES = '''
record_type: CNAME record_type: CNAME
content: web-vm-1 content: web-vm-1
- name: Create or update a MX record - name: Create another MX record
local_action: local_action:
module: exo_dns_record module: exo_dns_record
domain: example.com domain: example.com
record_type: MX record_type: MX
content: mx1.example.com content: mx1.example.com
prio: 10 prio: 10
multiple: yes
- name: Delete a MX record - name: Delete one MX record out of multiple
local_action: local_action:
module: exo_dns_record module: exo_dns_record
domain: example.com domain: example.com
record_type: MX record_type: MX
content: mx1.example.com content: mx1.example.com
multiple: yes
state: absent state: absent
- name: Remove a record - name: Remove a single A record
local_action: local_action:
module: exo_dns_record module: exo_dns_record
name: www name: www
@ -223,12 +225,7 @@ class ExoDnsRecord(ExoDns):
self.multiple = self.module.params.get('multiple') self.multiple = self.module.params.get('multiple')
self.record_type = self.module.params.get('record_type') self.record_type = self.module.params.get('record_type')
if self.multiple and self.record_type != 'A':
self.module.fail_json(msg="Multiple is only usable with record_type A")
self.content = self.module.params.get('content') self.content = self.module.params.get('content')
if self.content and self.record_type != 'TXT':
self.content = self.content.lower()
def _create_record(self, record): def _create_record(self, record):
self.result['changed'] = True self.result['changed'] = True
@ -265,31 +262,26 @@ class ExoDnsRecord(ExoDns):
domain = self.module.params.get('domain') domain = self.module.params.get('domain')
records = self.api_query("/domains/%s/records" % domain, "GET") records = self.api_query("/domains/%s/records" % domain, "GET")
record = None result = {}
for r in records: for r in records:
found_record = None
if r['record']['record_type'] == self.record_type:
r_name = r['record']['name'].lower()
r_content = r['record']['content'].lower()
# there are multiple A records but we found an exact match if r['record']['record_type'] != self.record_type:
if self.multiple and self.name == r_name and self.content == r_content: continue
record = r
break
# We do not expect to found more then one record with that content r_name = r['record']['name'].lower()
if not self.multiple and not self.name and self.content == r_content: r_content = r['record']['content']
found_record = r
# We do not expect to found more then one record with that name if r_name == self.name:
elif not self.multiple and self.name and self.name == r_name: if not self.multiple:
found_record = r if result:
self.module.fail_json(msg="More than one record with record_type=%s and name=%s params. "
"Use multiple=yes for more than one record." % (self.record_type, self.name))
else:
result = r
elif r_content == self.content:
return r
if record and found_record: return result
self.module.fail_json(msg="More than one record with your params. Use multiple=yes for more than one A record.")
if found_record:
record = found_record
return record
def present_record(self): def present_record(self):
record = self.get_record() record = self.get_record()
@ -332,11 +324,8 @@ def main():
argument_spec=argument_spec, argument_spec=argument_spec,
required_together=exo_dns_required_together(), required_together=exo_dns_required_together(),
required_if=[ required_if=[
['state', 'present', ['content']], ('state', 'present', ['content']),
['name', '', ['content']], ('multiple', True, ['content']),
],
required_one_of=[
['content', 'name'],
], ],
supports_check_mode=True, supports_check_mode=True,
) )

View file

@ -54,19 +54,6 @@
- result is failed - result is failed
- 'result.msg == "missing required arguments: domain"' - 'result.msg == "missing required arguments: domain"'
- name: test fail if missing required params
local_action:
module: exo_dns_record
domain: "{{ exo_dns_domain_name }}"
state: absent
register: result
ignore_errors: true
- name: verify results of test fail if missing required params
assert:
that:
- result is failed
- 'result.msg == "name is but the following are missing: content"'
- name: test fail if missing required params state=present - name: test fail if missing required params state=present
local_action: local_action:
module: exo_dns_record module: exo_dns_record
@ -78,21 +65,7 @@
assert: assert:
that: that:
- result is failed - result is failed
- 'result.msg == "state is present but the following are missing: content"' - 'result.msg == "state is present but all of the following are missing: content"'
- name: test fail if missing required params state=absent
local_action:
module: exo_dns_record
domain: "{{ exo_dns_domain_name }}"
name: ""
state: absent
register: result
ignore_errors: true
- name: verify results of test fail if missing required params state=absent
assert:
that:
- result is failed
- 'result.msg == "name is but the following are missing: content"'
- name: test create a record - name: test create a record
local_action: local_action: