summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/hrobot/plugins/modules/reset.py
blob: d367936e021bbb116e80fc3c943166912afad512 (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
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright (c) 2019 Felix Fontein <felix@fontein.de>
# 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 = r'''
---
module: reset
short_description: Reset a dedicated server
version_added: 1.2.0
author:
  - Felix Fontein (@felixfontein)
description:
  - Reset a dedicated server with a software or hardware reset, or by requesting a manual reset.
extends_documentation_fragment:
  - community.hrobot.robot
  - community.hrobot.attributes
  - community.hrobot.attributes.actiongroup_robot

attributes:
  action_group:
    version_added: 1.6.0
  check_mode:
    support: full
  diff_mode:
    support: none

options:
  server_number:
    description:
      - The server number of the server to reset.
    type: int
    required: true
  reset_type:
    description:
      - How to reset the server.
      - C(software) is a software reset. This should be similar to pressing Ctrl+Alt+Del on the keyboard.
      - C(power) is a hardware reset similar to pressing the Power button. An ACPI signal is sent, and if the
        server is configured correctly, this will trigger a regular shutdown.
      - C(hardware) is a hardware reset similar to pressing the Restart button. The power is cycled for the server.
      - C(manual) is a manual reset. This requests a technician to manually do the shutdown while looking at the
        screen output. B(Be careful) and only use this when really necessary!
      - Note that not every server supports every reset method!
    type: str
    required: true
    choices:
      - software
      - hardware
      - power
      - manual
'''

EXAMPLES = r'''
- name: Send ACPI signal to server to request controlled shutdown
  community.hrobot.reset:
    hetzner_user: foo
    hetzner_password: bar
    failover_ip: 1.2.3.4
    state: power

- name: Make sure that the server supports manual reset
  community.hrobot.reset:
    hetzner_user: foo
    hetzner_password: bar
    server_number: 1234
    reset_type: manual
  check_mode: true

- name: Request a manual reset (by a technican)
  community.hrobot.reset:
    hetzner_user: foo
    hetzner_password: bar
    server_number: 1234
    reset_type: manual
'''

RETURN = r''' # '''

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six.moves.urllib.parse import urlencode

from ansible_collections.community.hrobot.plugins.module_utils.robot import (
    BASE_URL,
    ROBOT_DEFAULT_ARGUMENT_SPEC,
    fetch_url_json,
)


def main():
    argument_spec = dict(
        server_number=dict(type='int', required=True),
        reset_type=dict(type='str', required=True, choices=['software', 'hardware', 'power', 'manual']),
    )
    argument_spec.update(ROBOT_DEFAULT_ARGUMENT_SPEC)
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )

    server_number = module.params['server_number']
    reset_type = {
        'software': 'sw',
        'hardware': 'hw',
        'power': 'power',
        'manual': 'man',
    }[module.params['reset_type']]

    if module.check_mode:
        url = "{0}/reset/{1}".format(BASE_URL, server_number)
        result, error = fetch_url_json(module, url, accept_errors=['SERVER_NOT_FOUND', 'RESET_NOT_AVAILABLE'])
        if not error and reset_type not in result['reset']['type']:
            module.fail_json(msg='The chosen reset method is not supported for this server')
    else:
        headers = {"Content-type": "application/x-www-form-urlencoded"}
        data = dict(
            type=reset_type,
        )
        url = "{0}/reset/{1}".format(BASE_URL, server_number)
        result, error = fetch_url_json(
            module,
            url,
            data=urlencode(data),
            headers=headers,
            method='POST',
            accept_errors=['INVALID_INPUT', 'SERVER_NOT_FOUND', 'RESET_NOT_AVAILABLE', 'RESET_MANUAL_ACTIVE', 'RESET_FAILED'],
        )
        if error and error == 'INVALID_INPUT':
            module.fail_json(msg='The chosen reset method is not supported for this server')
    if error:
        if error == 'SERVER_NOT_FOUND':
            module.fail_json(msg='This server does not exist, or you do not have access rights for it')
        if error == 'RESET_NOT_AVAILABLE':
            module.fail_json(msg='The server has no reset option available')
        if error == 'RESET_MANUAL_ACTIVE':
            module.fail_json(msg='A manual reset is already running')
        if error == 'RESET_FAILED':
            module.fail_json(msg='The reset failed due to an internal error at Hetzner')
        raise AssertionError('Unexpected error {0}'.format(error))  # pragma: no cover

    module.exit_json(changed=True)


if __name__ == '__main__':  # pragma: no cover
    main()  # pragma: no cover