summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/general/plugins/modules/memset_dns_reload.py
blob: 668c8c0bf3fbd081335360615725894a7702a3a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2018, Simon Weald <ansible@simonweald.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

DOCUMENTATION = '''
---
module: memset_dns_reload
author: "Simon Weald (@glitchcrab)"
short_description: Request reload of Memset's DNS infrastructure,
notes:
  - DNS reload requests are a best-effort service provided by Memset; these generally
    happen every 15 minutes by default, however you can request an immediate reload if
    later tasks rely on the records being created. An API key generated via the
    Memset customer control panel is required with the following minimum scope -
    C(dns.reload). If you wish to poll the job status to wait until the reload has
    completed, then C(job.status) is also required.
description:
  - Request a reload of Memset's DNS infrastructure, and optionally poll until it finishes.
extends_documentation_fragment:
  - community.general.attributes
attributes:
    check_mode:
        support: none
    diff_mode:
        support: none
options:
    api_key:
        required: true
        type: str
        description:
            - The API key obtained from the Memset control panel.
    poll:
        default: false
        type: bool
        description:
            - Boolean value, if set will poll the reload job's status and return
              when the job has completed (unless the 30 second timeout is reached first).
              If the timeout is reached then the task will not be marked as failed, but
              stderr will indicate that the polling failed.
'''

EXAMPLES = '''
- name: Submit DNS reload and poll
  community.general.memset_dns_reload:
    api_key: 5eb86c9196ab03919abcf03857163741
    poll: true
  delegate_to: localhost
'''

RETURN = '''
---
memset_api:
  description: Raw response from the Memset API.
  returned: always
  type: complex
  contains:
    error:
      description: Whether the job ended in error state.
      returned: always
      type: bool
      sample: true
    finished:
      description: Whether the job completed before the result was returned.
      returned: always
      type: bool
      sample: true
    id:
      description: Job ID.
      returned: always
      type: str
      sample: "c9cc8ad2a3e3fb8c63ed83c424928ef8"
    status:
      description: Job status.
      returned: always
      type: str
      sample: "DONE"
    type:
      description: Job type.
      returned: always
      type: str
      sample: "dns"
'''

from time import sleep

from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.memset import memset_api_call


def poll_reload_status(api_key=None, job_id=None, payload=None):
    '''
    We poll the `job.status` endpoint every 5 seconds up to a
    maximum of 6 times. This is a relatively arbitrary choice of
    timeout, however requests rarely take longer than 15 seconds
    to complete.
    '''
    memset_api, stderr, msg = None, None, None
    payload['id'] = job_id

    api_method = 'job.status'
    _has_failed, _msg, response = memset_api_call(api_key=api_key, api_method=api_method, payload=payload)

    while not response.json()['finished']:
        counter = 0
        while counter < 6:
            sleep(5)
            _has_failed, msg, response = memset_api_call(api_key=api_key, api_method=api_method, payload=payload)
            counter += 1
    if response.json()['error']:
        # the reload job was submitted but polling failed. Don't return this as an overall task failure.
        stderr = "Reload submitted successfully, but the Memset API returned a job error when attempting to poll the reload status."
    else:
        memset_api = response.json()
        msg = None

    return memset_api, msg, stderr


def reload_dns(args=None):
    '''
    DNS reloads are a single API call and therefore there's not much
    which can go wrong outside of auth errors.
    '''
    retvals, payload = dict(), dict()
    has_changed, has_failed = False, False
    memset_api, msg, stderr = None, None, None

    api_method = 'dns.reload'
    has_failed, msg, response = memset_api_call(api_key=args['api_key'], api_method=api_method)

    if has_failed:
        # this is the first time the API is called; incorrect credentials will
        # manifest themselves at this point so we need to ensure the user is
        # informed of the reason.
        retvals['failed'] = has_failed
        if response.status_code is not None:
            retvals['memset_api'] = response.json()
        else:
            retvals['stderr'] = response.stderr
        retvals['msg'] = msg
        return retvals

    # set changed to true if the reload request was accepted.
    has_changed = True
    memset_api = msg
    # empty msg var as we don't want to return the API's json response twice.
    msg = None

    if args['poll']:
        # hand off to the poll function.
        job_id = response.json()['id']
        memset_api, msg, stderr = poll_reload_status(api_key=args['api_key'], job_id=job_id, payload=payload)

    # assemble return variables.
    retvals['failed'] = has_failed
    retvals['changed'] = has_changed
    for val in ['msg', 'stderr', 'memset_api']:
        if val is not None:
            retvals[val] = eval(val)

    return retvals


def main():
    global module
    module = AnsibleModule(
        argument_spec=dict(
            api_key=dict(required=True, type='str', no_log=True),
            poll=dict(required=False, default=False, type='bool')
        ),
        supports_check_mode=False
    )

    # populate the dict with the user-provided vars.
    args = dict()
    for key, arg in module.params.items():
        args[key] = arg

    retvals = reload_dns(args)

    if retvals['failed']:
        module.fail_json(**retvals)
    else:
        module.exit_json(**retvals)


if __name__ == '__main__':
    main()