Add explicit coverage of required_together (#72107)
* Add explicit coverage of required_together * ci_complete ci_coverage * Remove incidental_hcloud_server * Remove hcloud from shippable matrix * ci_complete ci_coverage
This commit is contained in:
parent
7f1c32f5ce
commit
460ba041c8
8 changed files with 16 additions and 1143 deletions
|
@ -143,7 +143,6 @@ matrix:
|
|||
- env: T=i/cs//1
|
||||
- env: T=i/tower//1
|
||||
- env: T=i/cloud//1
|
||||
- env: T=i/hcloud//1
|
||||
|
||||
branches:
|
||||
except:
|
||||
|
|
|
@ -50,6 +50,8 @@ def main():
|
|||
'default': [],
|
||||
},
|
||||
'needed_param': {},
|
||||
'required_together_one': {},
|
||||
'required_together_two': {},
|
||||
},
|
||||
required_if=(
|
||||
('state', 'present', ('path', 'content'), True),
|
||||
|
@ -57,6 +59,9 @@ def main():
|
|||
mutually_exclusive=(
|
||||
('path', 'content'),
|
||||
),
|
||||
required_together=(
|
||||
('required_together_one', 'required_together_two'),
|
||||
),
|
||||
)
|
||||
|
||||
module.fail_on_missing_params(module.params['fail_on_missing_params'])
|
||||
|
|
|
@ -112,6 +112,15 @@
|
|||
register: argspec_fail_on_missing_params_bad
|
||||
ignore_errors: true
|
||||
|
||||
- argspec:
|
||||
required_together_one: foo
|
||||
required_together_two: bar
|
||||
|
||||
- argspec:
|
||||
required_together_one: foo
|
||||
register: argspec_fail_required_together
|
||||
ignore_errors: true
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- argspec_required_if_fail is failed
|
||||
|
@ -144,3 +153,5 @@
|
|||
- argspec_bad_json is failed
|
||||
|
||||
- argspec_fail_on_missing_params_bad is failed
|
||||
|
||||
- argspec_fail_required_together is failed
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
cloud/hcloud
|
||||
shippable/hcloud/incidental
|
|
@ -1,5 +0,0 @@
|
|||
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
---
|
||||
hcloud_prefix: "tests"
|
||||
hcloud_server_name: "{{hcloud_prefix}}-integration"
|
|
@ -1,517 +0,0 @@
|
|||
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
---
|
||||
- name: setup
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: verify setup
|
||||
assert:
|
||||
that:
|
||||
- result is success
|
||||
- name: test missing required parameters on create server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
- name: verify fail test missing required parameters on create server
|
||||
assert:
|
||||
that:
|
||||
- result is failed
|
||||
- 'result.msg == "missing required arguments: server_type, image"'
|
||||
|
||||
- name: test create server with check mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
server_type: cx11
|
||||
image: ubuntu-18.04
|
||||
state: present
|
||||
register: result
|
||||
check_mode: yes
|
||||
- name: test create server server
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: test create server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name}}"
|
||||
server_type: cx11
|
||||
image: ubuntu-18.04
|
||||
state: started
|
||||
register: main_server
|
||||
- name: verify create server
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
|
||||
- main_server.hcloud_server.server_type == "cx11"
|
||||
- main_server.hcloud_server.status == "running"
|
||||
- main_server.root_password != ""
|
||||
|
||||
- name: test create server idempotence
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: started
|
||||
register: result
|
||||
- name: verify create server idempotence
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
|
||||
- name: test stop server with check mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: stopped
|
||||
register: result
|
||||
check_mode: yes
|
||||
- name: verify stop server with check mode
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.hcloud_server.status == "running"
|
||||
|
||||
- name: test stop server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: stopped
|
||||
register: result
|
||||
- name: verify stop server
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.hcloud_server.status == "off"
|
||||
|
||||
- name: test start server with check mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: started
|
||||
register: result
|
||||
check_mode: true
|
||||
- name: verify start server with check mode
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: test start server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: started
|
||||
register: result
|
||||
- name: verify start server
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.hcloud_server.status == "running"
|
||||
|
||||
- name: test start server idempotence
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: started
|
||||
register: result
|
||||
- name: verify start server idempotence
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.hcloud_server.status == "running"
|
||||
|
||||
- name: test stop server by its id
|
||||
hcloud_server:
|
||||
id: "{{ main_server.hcloud_server.id }}"
|
||||
state: stopped
|
||||
register: result
|
||||
- name: verify stop server by its id
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.hcloud_server.status == "off"
|
||||
|
||||
- name: test resize server running without force
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
server_type: "cx21"
|
||||
state: present
|
||||
register: result
|
||||
check_mode: true
|
||||
- name: verify test resize server running without force
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.hcloud_server.server_type == "cx11"
|
||||
|
||||
- name: test resize server with check mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
server_type: "cx21"
|
||||
state: stopped
|
||||
register: result
|
||||
check_mode: true
|
||||
- name: verify resize server with check mode
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: test enable backups with check mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
backups: true
|
||||
state: stopped
|
||||
register: result
|
||||
check_mode: true
|
||||
- name: verify enable backups with check mode
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
|
||||
- name: test enable backups
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
backups: true
|
||||
state: stopped
|
||||
register: result
|
||||
- name: verify enable backups
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.hcloud_server.backup_window != ""
|
||||
|
||||
- name: test enable backups idempotence
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
backups: true
|
||||
state: stopped
|
||||
register: result
|
||||
- name: verify enable backups idempotence
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.hcloud_server.backup_window != ""
|
||||
|
||||
- name: test rebuild server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
image: ubuntu-18.04
|
||||
state: rebuild
|
||||
register: result_after_test
|
||||
- name: verify rebuild server
|
||||
assert:
|
||||
that:
|
||||
- result_after_test is changed
|
||||
- result.hcloud_server.id == result_after_test.hcloud_server.id
|
||||
|
||||
- name: test rebuild server with check mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
image: ubuntu-18.04
|
||||
state: rebuild
|
||||
register: result_after_test
|
||||
check_mode: true
|
||||
- name: verify rebuild server with check mode
|
||||
assert:
|
||||
that:
|
||||
- result_after_test is changed
|
||||
|
||||
- name: test update server protection booth protection arguments are required
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
delete_protection: true
|
||||
state: present
|
||||
register: result_after_test
|
||||
ignore_errors: true
|
||||
- name: verify update server protection booth protection arguments are required
|
||||
assert:
|
||||
that:
|
||||
- result_after_test is failed
|
||||
- 'result_after_test.msg == "parameters are required together: delete_protection, rebuild_protection"'
|
||||
|
||||
- name: test update server protection fails if they are not the same
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
delete_protection: true
|
||||
rebuild_protection: false
|
||||
state: present
|
||||
register: result_after_test
|
||||
ignore_errors: true
|
||||
- name: verify update server protection fails if they are not the same
|
||||
assert:
|
||||
that:
|
||||
- result_after_test is failed
|
||||
|
||||
- name: test update server protection
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
delete_protection: true
|
||||
rebuild_protection: true
|
||||
state: present
|
||||
register: result_after_test
|
||||
ignore_errors: true
|
||||
- name: verify update server protection
|
||||
assert:
|
||||
that:
|
||||
- result_after_test is changed
|
||||
- result_after_test.hcloud_server.delete_protection is sameas true
|
||||
- result_after_test.hcloud_server.rebuild_protection is sameas true
|
||||
|
||||
- name: test server without protection set to be idempotent
|
||||
hcloud_server:
|
||||
name: "{{hcloud_server_name}}"
|
||||
register: result_after_test
|
||||
- name: verify test server without protection set to be idempotent
|
||||
assert:
|
||||
that:
|
||||
- result_after_test is not changed
|
||||
- result_after_test.hcloud_server.delete_protection is sameas true
|
||||
- result_after_test.hcloud_server.rebuild_protection is sameas true
|
||||
|
||||
- name: test delete server fails if it is protected
|
||||
hcloud_server:
|
||||
name: "{{hcloud_server_name}}"
|
||||
state: absent
|
||||
ignore_errors: yes
|
||||
register: result
|
||||
- name: verify delete server fails if it is protected
|
||||
assert:
|
||||
that:
|
||||
- result is failed
|
||||
- 'result.msg == "server deletion is protected"'
|
||||
|
||||
- name: test rebuild server fails if it is protected
|
||||
hcloud_server:
|
||||
name: "{{hcloud_server_name}}"
|
||||
image: ubuntu-18.04
|
||||
state: rebuild
|
||||
ignore_errors: yes
|
||||
register: result
|
||||
- name: verify rebuild server fails if it is protected
|
||||
assert:
|
||||
that:
|
||||
- result is failed
|
||||
- 'result.msg == "server rebuild is protected"'
|
||||
|
||||
- name: test remove server protection
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
delete_protection: false
|
||||
rebuild_protection: false
|
||||
state: present
|
||||
register: result_after_test
|
||||
ignore_errors: true
|
||||
- name: verify remove server protection
|
||||
assert:
|
||||
that:
|
||||
- result_after_test is changed
|
||||
- result_after_test.hcloud_server.delete_protection is sameas false
|
||||
- result_after_test.hcloud_server.rebuild_protection is sameas false
|
||||
|
||||
- name: absent server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: verify absent server
|
||||
assert:
|
||||
that:
|
||||
- result is success
|
||||
|
||||
- name: test create server with ssh key
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name}}"
|
||||
server_type: cx11
|
||||
image: "ubuntu-18.04"
|
||||
ssh_keys:
|
||||
- ci@ansible.hetzner.cloud
|
||||
state: started
|
||||
register: main_server
|
||||
- name: verify create server with ssh key
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
|
||||
- main_server.hcloud_server.server_type == "cx11"
|
||||
- main_server.hcloud_server.status == "running"
|
||||
- main_server.root_password != ""
|
||||
|
||||
- name: absent server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: verify absent server
|
||||
assert:
|
||||
that:
|
||||
- result is success
|
||||
|
||||
- name: test create server with rescue_mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name}}"
|
||||
server_type: cx11
|
||||
image: "ubuntu-18.04"
|
||||
ssh_keys:
|
||||
- ci@ansible.hetzner.cloud
|
||||
rescue_mode: "linux64"
|
||||
state: started
|
||||
register: main_server
|
||||
- name: verify create server with rescue_mode
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
|
||||
- main_server.hcloud_server.server_type == "cx11"
|
||||
- main_server.hcloud_server.status == "running"
|
||||
- main_server.root_password != ""
|
||||
- main_server.hcloud_server.rescue_enabled is sameas true
|
||||
|
||||
- name: absent server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: verify absent server
|
||||
assert:
|
||||
that:
|
||||
- result is success
|
||||
|
||||
- name: setup server
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name}}"
|
||||
server_type: cx11
|
||||
image: ubuntu-18.04
|
||||
state: started
|
||||
register: main_server
|
||||
- name: verify setup server
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
|
||||
- main_server.hcloud_server.server_type == "cx11"
|
||||
- main_server.hcloud_server.status == "running"
|
||||
- main_server.root_password != ""
|
||||
|
||||
- name: test activate rescue mode with check_mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
rescue_mode: "linux64"
|
||||
ssh_keys:
|
||||
- ci@ansible.hetzner.cloud
|
||||
state: present
|
||||
register: main_server
|
||||
check_mode: true
|
||||
- name: verify activate rescue mode
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
|
||||
- name: test activate rescue mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
rescue_mode: "linux64"
|
||||
ssh_keys:
|
||||
- ci@ansible.hetzner.cloud
|
||||
state: present
|
||||
register: main_server
|
||||
- name: verify activate rescue mode
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.rescue_enabled is sameas true
|
||||
|
||||
- name: test disable rescue mode
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
ssh_keys:
|
||||
- ci@ansible.hetzner.cloud
|
||||
state: present
|
||||
register: main_server
|
||||
- name: verify activate rescue mode
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.rescue_enabled is sameas false
|
||||
|
||||
- name: test activate rescue mode without ssh keys
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
rescue_mode: "linux64"
|
||||
state: present
|
||||
register: main_server
|
||||
- name: verify activate rescue mode without ssh keys
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.rescue_enabled is sameas true
|
||||
|
||||
- name: cleanup
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: verify cleanup
|
||||
assert:
|
||||
that:
|
||||
- result is success
|
||||
|
||||
- name: test create server with labels
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name}}"
|
||||
server_type: cx11
|
||||
image: "ubuntu-18.04"
|
||||
ssh_keys:
|
||||
- ci@ansible.hetzner.cloud
|
||||
labels:
|
||||
key: value
|
||||
mylabel: "val123"
|
||||
state: started
|
||||
register: main_server
|
||||
- name: verify create server with labels
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.labels.key == "value"
|
||||
- main_server.hcloud_server.labels.mylabel == "val123"
|
||||
|
||||
- name: test update server with labels
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name}}"
|
||||
server_type: cx11
|
||||
image: "ubuntu-18.04"
|
||||
ssh_keys:
|
||||
- ci@ansible.hetzner.cloud
|
||||
labels:
|
||||
key: other
|
||||
mylabel: "val123"
|
||||
state: started
|
||||
register: main_server
|
||||
- name: verify update server with labels
|
||||
assert:
|
||||
that:
|
||||
- main_server is changed
|
||||
- main_server.hcloud_server.labels.key == "other"
|
||||
- main_server.hcloud_server.labels.mylabel == "val123"
|
||||
|
||||
- name: test update server with labels in other order
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name}}"
|
||||
server_type: cx11
|
||||
image: "ubuntu-18.04"
|
||||
ssh_keys:
|
||||
- ci@ansible.hetzner.cloud
|
||||
labels:
|
||||
mylabel: "val123"
|
||||
key: other
|
||||
state: started
|
||||
register: main_server
|
||||
- name: verify update server with labels in other order
|
||||
assert:
|
||||
that:
|
||||
- main_server is not changed
|
||||
|
||||
- name: cleanup with labels
|
||||
hcloud_server:
|
||||
name: "{{ hcloud_server_name }}"
|
||||
state: absent
|
||||
register: result
|
||||
- name: verify cleanup
|
||||
assert:
|
||||
that:
|
||||
- result is success
|
|
@ -1,63 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
|
||||
|
||||
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.module_utils.ansible_release import __version__
|
||||
from ansible.module_utils.basic import env_fallback, missing_required_lib
|
||||
|
||||
try:
|
||||
import hcloud
|
||||
|
||||
HAS_HCLOUD = True
|
||||
except ImportError:
|
||||
HAS_HCLOUD = False
|
||||
|
||||
|
||||
class Hcloud(object):
|
||||
def __init__(self, module, represent):
|
||||
self.module = module
|
||||
self.represent = represent
|
||||
self.result = {"changed": False, self.represent: None}
|
||||
if not HAS_HCLOUD:
|
||||
module.fail_json(msg=missing_required_lib("hcloud-python"))
|
||||
self._build_client()
|
||||
|
||||
def _build_client(self):
|
||||
self.client = hcloud.Client(
|
||||
token=self.module.params["api_token"],
|
||||
api_endpoint=self.module.params["endpoint"],
|
||||
application_name="ansible-module",
|
||||
application_version=__version__,
|
||||
)
|
||||
|
||||
def _mark_as_changed(self):
|
||||
self.result["changed"] = True
|
||||
|
||||
@staticmethod
|
||||
def base_module_arguments():
|
||||
return {
|
||||
"api_token": {
|
||||
"type": "str",
|
||||
"required": True,
|
||||
"fallback": (env_fallback, ["HCLOUD_TOKEN"]),
|
||||
"no_log": True,
|
||||
},
|
||||
"endpoint": {"type": "str", "default": "https://api.hetzner.cloud/v1"},
|
||||
}
|
||||
|
||||
def _prepare_result(self):
|
||||
"""Prepare the result for every module
|
||||
|
||||
:return: dict
|
||||
"""
|
||||
return {}
|
||||
|
||||
def get_result(self):
|
||||
if getattr(self, self.represent) is not None:
|
||||
self.result[self.represent] = self._prepare_result()
|
||||
return self.result
|
|
@ -1,555 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
"metadata_version": "1.1",
|
||||
"status": ["preview"],
|
||||
"supported_by": "community",
|
||||
}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: hcloud_server
|
||||
|
||||
short_description: Create and manage cloud servers on the Hetzner Cloud.
|
||||
|
||||
version_added: "2.8"
|
||||
|
||||
description:
|
||||
- Create, update and manage cloud servers on the Hetzner Cloud.
|
||||
|
||||
author:
|
||||
- Lukas Kaemmerling (@LKaemmerling)
|
||||
|
||||
options:
|
||||
id:
|
||||
description:
|
||||
- The ID of the Hetzner Cloud server to manage.
|
||||
- Only required if no server I(name) is given
|
||||
type: int
|
||||
name:
|
||||
description:
|
||||
- The Name of the Hetzner Cloud server to manage.
|
||||
- Only required if no server I(id) is given or a server does not exists.
|
||||
type: str
|
||||
server_type:
|
||||
description:
|
||||
- The Server Type of the Hetzner Cloud server to manage.
|
||||
- Required if server does not exists.
|
||||
type: str
|
||||
ssh_keys:
|
||||
description:
|
||||
- List of SSH key names
|
||||
- The key names correspond to the SSH keys configured for your
|
||||
Hetzner Cloud account access.
|
||||
type: list
|
||||
volumes:
|
||||
description:
|
||||
- List of Volumes IDs that should be attached to the server on server creation.
|
||||
type: list
|
||||
image:
|
||||
description:
|
||||
- Image the server should be created from.
|
||||
- Required if server does not exists.
|
||||
type: str
|
||||
location:
|
||||
description:
|
||||
- Location of Server.
|
||||
- Required if no I(datacenter) is given and server does not exists.
|
||||
type: str
|
||||
datacenter:
|
||||
description:
|
||||
- Datacenter of Server.
|
||||
- Required of no I(location) is given and server does not exists.
|
||||
type: str
|
||||
backups:
|
||||
description:
|
||||
- Enable or disable Backups for the given Server.
|
||||
type: bool
|
||||
default: no
|
||||
upgrade_disk:
|
||||
description:
|
||||
- Resize the disk size, when resizing a server.
|
||||
- If you want to downgrade the server later, this value should be False.
|
||||
type: bool
|
||||
default: no
|
||||
force_upgrade:
|
||||
description:
|
||||
- Force the upgrade of the server.
|
||||
- Power off the server if it is running on upgrade.
|
||||
type: bool
|
||||
default: no
|
||||
user_data:
|
||||
description:
|
||||
- User Data to be passed to the server on creation.
|
||||
- Only used if server does not exists.
|
||||
type: str
|
||||
rescue_mode:
|
||||
description:
|
||||
- Add the Hetzner rescue system type you want the server to be booted into.
|
||||
type: str
|
||||
version_added: 2.9
|
||||
labels:
|
||||
description:
|
||||
- User-defined labels (key-value pairs).
|
||||
type: dict
|
||||
delete_protection:
|
||||
description:
|
||||
- Protect the Server for deletion.
|
||||
- Needs to be the same as I(rebuild_protection).
|
||||
type: bool
|
||||
version_added: "2.10"
|
||||
rebuild_protection:
|
||||
description:
|
||||
- Protect the Server for rebuild.
|
||||
- Needs to be the same as I(delete_protection).
|
||||
type: bool
|
||||
version_added: "2.10"
|
||||
state:
|
||||
description:
|
||||
- State of the server.
|
||||
default: present
|
||||
choices: [ absent, present, restarted, started, stopped, rebuild ]
|
||||
type: str
|
||||
extends_documentation_fragment: hcloud
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Create a basic server
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
server_type: cx11
|
||||
image: ubuntu-18.04
|
||||
state: present
|
||||
|
||||
- name: Create a basic server with ssh key
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
server_type: cx11
|
||||
image: ubuntu-18.04
|
||||
location: fsn1
|
||||
ssh_keys:
|
||||
- me@myorganisation
|
||||
state: present
|
||||
|
||||
- name: Resize an existing server
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
server_type: cx21
|
||||
upgrade_disk: yes
|
||||
state: present
|
||||
|
||||
- name: Ensure the server is absent (remove if needed)
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
state: absent
|
||||
|
||||
- name: Ensure the server is started
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
state: started
|
||||
|
||||
- name: Ensure the server is stopped
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
state: stopped
|
||||
|
||||
- name: Ensure the server is restarted
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
state: restarted
|
||||
|
||||
- name: Ensure the server is will be booted in rescue mode and therefore restarted
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
rescue_mode: linux64
|
||||
state: restarted
|
||||
|
||||
- name: Ensure the server is rebuild
|
||||
hcloud_server:
|
||||
name: my-server
|
||||
image: ubuntu-18.04
|
||||
state: rebuild
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
hcloud_server:
|
||||
description: The server instance
|
||||
returned: Always
|
||||
type: complex
|
||||
contains:
|
||||
id:
|
||||
description: Numeric identifier of the server
|
||||
returned: always
|
||||
type: int
|
||||
sample: 1937415
|
||||
name:
|
||||
description: Name of the server
|
||||
returned: always
|
||||
type: str
|
||||
sample: my-server
|
||||
status:
|
||||
description: Status of the server
|
||||
returned: always
|
||||
type: str
|
||||
sample: running
|
||||
server_type:
|
||||
description: Name of the server type of the server
|
||||
returned: always
|
||||
type: str
|
||||
sample: cx11
|
||||
ipv4_address:
|
||||
description: Public IPv4 address of the server
|
||||
returned: always
|
||||
type: str
|
||||
sample: 116.203.104.109
|
||||
ipv6:
|
||||
description: IPv6 network of the server
|
||||
returned: always
|
||||
type: str
|
||||
sample: 2a01:4f8:1c1c:c140::/64
|
||||
location:
|
||||
description: Name of the location of the server
|
||||
returned: always
|
||||
type: str
|
||||
sample: fsn1
|
||||
datacenter:
|
||||
description: Name of the datacenter of the server
|
||||
returned: always
|
||||
type: str
|
||||
sample: fsn1-dc14
|
||||
rescue_enabled:
|
||||
description: True if rescue mode is enabled, Server will then boot into rescue system on next reboot
|
||||
returned: always
|
||||
type: bool
|
||||
sample: false
|
||||
backup_window:
|
||||
description: Time window (UTC) in which the backup will run, or null if the backups are not enabled
|
||||
returned: always
|
||||
type: bool
|
||||
sample: 22-02
|
||||
labels:
|
||||
description: User-defined labels (key-value pairs)
|
||||
returned: always
|
||||
type: dict
|
||||
delete_protection:
|
||||
description: True if server is protected for deletion
|
||||
type: bool
|
||||
returned: always
|
||||
sample: false
|
||||
version_added: "2.10"
|
||||
rebuild_protection:
|
||||
description: True if server is protected for rebuild
|
||||
type: bool
|
||||
returned: always
|
||||
sample: false
|
||||
version_added: "2.10"
|
||||
"""
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_native
|
||||
from ansible.module_utils.hcloud import Hcloud
|
||||
|
||||
try:
|
||||
from hcloud.volumes.domain import Volume
|
||||
from hcloud.ssh_keys.domain import SSHKey
|
||||
from hcloud.servers.domain import Server
|
||||
from hcloud import APIException
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class AnsibleHcloudServer(Hcloud):
|
||||
def __init__(self, module):
|
||||
Hcloud.__init__(self, module, "hcloud_server")
|
||||
self.hcloud_server = None
|
||||
|
||||
def _prepare_result(self):
|
||||
image = None if self.hcloud_server.image is None else to_native(self.hcloud_server.image.name)
|
||||
return {
|
||||
"id": to_native(self.hcloud_server.id),
|
||||
"name": to_native(self.hcloud_server.name),
|
||||
"ipv4_address": to_native(self.hcloud_server.public_net.ipv4.ip),
|
||||
"ipv6": to_native(self.hcloud_server.public_net.ipv6.ip),
|
||||
"image": image,
|
||||
"server_type": to_native(self.hcloud_server.server_type.name),
|
||||
"datacenter": to_native(self.hcloud_server.datacenter.name),
|
||||
"location": to_native(self.hcloud_server.datacenter.location.name),
|
||||
"rescue_enabled": self.hcloud_server.rescue_enabled,
|
||||
"backup_window": to_native(self.hcloud_server.backup_window),
|
||||
"labels": self.hcloud_server.labels,
|
||||
"delete_protection": self.hcloud_server.protection["delete"],
|
||||
"rebuild_protection": self.hcloud_server.protection["rebuild"],
|
||||
"status": to_native(self.hcloud_server.status),
|
||||
}
|
||||
|
||||
def _get_server(self):
|
||||
try:
|
||||
if self.module.params.get("id") is not None:
|
||||
self.hcloud_server = self.client.servers.get_by_id(
|
||||
self.module.params.get("id")
|
||||
)
|
||||
else:
|
||||
self.hcloud_server = self.client.servers.get_by_name(
|
||||
self.module.params.get("name")
|
||||
)
|
||||
except APIException as e:
|
||||
self.module.fail_json(msg=e.message)
|
||||
|
||||
def _create_server(self):
|
||||
|
||||
self.module.fail_on_missing_params(
|
||||
required_params=["name", "server_type", "image"]
|
||||
)
|
||||
params = {
|
||||
"name": self.module.params.get("name"),
|
||||
"server_type": self.client.server_types.get_by_name(
|
||||
self.module.params.get("server_type")
|
||||
),
|
||||
"user_data": self.module.params.get("user_data"),
|
||||
"labels": self.module.params.get("labels"),
|
||||
}
|
||||
if self.client.images.get_by_name(self.module.params.get("image")) is not None:
|
||||
# When image name is not available look for id instead
|
||||
params["image"] = self.client.images.get_by_name(self.module.params.get("image"))
|
||||
else:
|
||||
params["image"] = self.client.images.get_by_id(self.module.params.get("image"))
|
||||
|
||||
if self.module.params.get("ssh_keys") is not None:
|
||||
params["ssh_keys"] = [
|
||||
SSHKey(name=ssh_key_name)
|
||||
for ssh_key_name in self.module.params.get("ssh_keys")
|
||||
]
|
||||
|
||||
if self.module.params.get("volumes") is not None:
|
||||
params["volumes"] = [
|
||||
Volume(id=volume_id) for volume_id in self.module.params.get("volumes")
|
||||
]
|
||||
|
||||
if self.module.params.get("location") is None and self.module.params.get("datacenter") is None:
|
||||
# When not given, the API will choose the location.
|
||||
params["location"] = None
|
||||
params["datacenter"] = None
|
||||
elif self.module.params.get("location") is not None and self.module.params.get("datacenter") is None:
|
||||
params["location"] = self.client.locations.get_by_name(
|
||||
self.module.params.get("location")
|
||||
)
|
||||
elif self.module.params.get("location") is None and self.module.params.get("datacenter") is not None:
|
||||
params["datacenter"] = self.client.datacenters.get_by_name(
|
||||
self.module.params.get("datacenter")
|
||||
)
|
||||
|
||||
if not self.module.check_mode:
|
||||
resp = self.client.servers.create(**params)
|
||||
self.result["root_password"] = resp.root_password
|
||||
resp.action.wait_until_finished(max_retries=1000)
|
||||
[action.wait_until_finished() for action in resp.next_actions]
|
||||
|
||||
rescue_mode = self.module.params.get("rescue_mode")
|
||||
if rescue_mode:
|
||||
self._get_server()
|
||||
self._set_rescue_mode(rescue_mode)
|
||||
|
||||
self._mark_as_changed()
|
||||
self._get_server()
|
||||
|
||||
def _update_server(self):
|
||||
try:
|
||||
rescue_mode = self.module.params.get("rescue_mode")
|
||||
if rescue_mode and self.hcloud_server.rescue_enabled is False:
|
||||
if not self.module.check_mode:
|
||||
self._set_rescue_mode(rescue_mode)
|
||||
self._mark_as_changed()
|
||||
elif not rescue_mode and self.hcloud_server.rescue_enabled is True:
|
||||
if not self.module.check_mode:
|
||||
self.hcloud_server.disable_rescue().wait_until_finished()
|
||||
self._mark_as_changed()
|
||||
|
||||
if self.module.params.get("backups") and self.hcloud_server.backup_window is None:
|
||||
if not self.module.check_mode:
|
||||
self.hcloud_server.enable_backup().wait_until_finished()
|
||||
self._mark_as_changed()
|
||||
elif not self.module.params.get("backups") and self.hcloud_server.backup_window is not None:
|
||||
if not self.module.check_mode:
|
||||
self.hcloud_server.disable_backup().wait_until_finished()
|
||||
self._mark_as_changed()
|
||||
|
||||
labels = self.module.params.get("labels")
|
||||
if labels is not None and labels != self.hcloud_server.labels:
|
||||
if not self.module.check_mode:
|
||||
self.hcloud_server.update(labels=labels)
|
||||
self._mark_as_changed()
|
||||
|
||||
server_type = self.module.params.get("server_type")
|
||||
if server_type is not None and self.hcloud_server.server_type.name != server_type:
|
||||
previous_server_status = self.hcloud_server.status
|
||||
state = self.module.params.get("state")
|
||||
if previous_server_status == Server.STATUS_RUNNING:
|
||||
if not self.module.check_mode:
|
||||
if self.module.params.get("force_upgrade") or state == "stopped":
|
||||
self.stop_server() # Only stopped server can be upgraded
|
||||
else:
|
||||
self.module.warn(
|
||||
"You can not upgrade a running instance %s. You need to stop the instance or use force_upgrade=yes."
|
||||
% self.hcloud_server.name
|
||||
)
|
||||
timeout = 100
|
||||
if self.module.params.get("upgrade_disk"):
|
||||
timeout = (
|
||||
1000
|
||||
) # When we upgrade the disk too the resize progress takes some more time.
|
||||
if not self.module.check_mode:
|
||||
self.hcloud_server.change_type(
|
||||
server_type=self.client.server_types.get_by_name(server_type),
|
||||
upgrade_disk=self.module.params.get("upgrade_disk"),
|
||||
).wait_until_finished(timeout)
|
||||
if state == "present" and previous_server_status == Server.STATUS_RUNNING or state == "started":
|
||||
self.start_server()
|
||||
|
||||
self._mark_as_changed()
|
||||
|
||||
delete_protection = self.module.params.get("delete_protection")
|
||||
rebuild_protection = self.module.params.get("rebuild_protection")
|
||||
if (delete_protection is not None and rebuild_protection is not None) and (
|
||||
delete_protection != self.hcloud_server.protection["delete"] or rebuild_protection !=
|
||||
self.hcloud_server.protection["rebuild"]):
|
||||
if not self.module.check_mode:
|
||||
self.hcloud_server.change_protection(delete=delete_protection,
|
||||
rebuild=rebuild_protection).wait_until_finished()
|
||||
self._mark_as_changed()
|
||||
self._get_server()
|
||||
except APIException as e:
|
||||
self.module.fail_json(msg=e.message)
|
||||
|
||||
def _set_rescue_mode(self, rescue_mode):
|
||||
if self.module.params.get("ssh_keys"):
|
||||
resp = self.hcloud_server.enable_rescue(type=rescue_mode,
|
||||
ssh_keys=[self.client.ssh_keys.get_by_name(ssh_key_name).id
|
||||
for
|
||||
ssh_key_name in
|
||||
self.module.params.get("ssh_keys")])
|
||||
else:
|
||||
resp = self.hcloud_server.enable_rescue(type=rescue_mode)
|
||||
resp.action.wait_until_finished()
|
||||
self.result["root_password"] = resp.root_password
|
||||
|
||||
def start_server(self):
|
||||
try:
|
||||
if self.hcloud_server.status != Server.STATUS_RUNNING:
|
||||
if not self.module.check_mode:
|
||||
self.client.servers.power_on(self.hcloud_server).wait_until_finished()
|
||||
self._mark_as_changed()
|
||||
self._get_server()
|
||||
except APIException as e:
|
||||
self.module.fail_json(msg=e.message)
|
||||
|
||||
def stop_server(self):
|
||||
try:
|
||||
if self.hcloud_server.status != Server.STATUS_OFF:
|
||||
if not self.module.check_mode:
|
||||
self.client.servers.power_off(self.hcloud_server).wait_until_finished()
|
||||
self._mark_as_changed()
|
||||
self._get_server()
|
||||
except APIException as e:
|
||||
self.module.fail_json(msg=e.message)
|
||||
|
||||
def rebuild_server(self):
|
||||
self.module.fail_on_missing_params(
|
||||
required_params=["image"]
|
||||
)
|
||||
try:
|
||||
if not self.module.check_mode:
|
||||
self.client.servers.rebuild(self.hcloud_server, self.client.images.get_by_name(
|
||||
self.module.params.get("image"))).wait_until_finished()
|
||||
self._mark_as_changed()
|
||||
|
||||
self._get_server()
|
||||
except APIException as e:
|
||||
self.module.fail_json(msg=e.message)
|
||||
|
||||
def present_server(self):
|
||||
self._get_server()
|
||||
if self.hcloud_server is None:
|
||||
self._create_server()
|
||||
else:
|
||||
self._update_server()
|
||||
|
||||
def delete_server(self):
|
||||
try:
|
||||
self._get_server()
|
||||
if self.hcloud_server is not None:
|
||||
if not self.module.check_mode:
|
||||
self.client.servers.delete(self.hcloud_server).wait_until_finished()
|
||||
self._mark_as_changed()
|
||||
self.hcloud_server = None
|
||||
except APIException as e:
|
||||
self.module.fail_json(msg=e.message)
|
||||
|
||||
@staticmethod
|
||||
def define_module():
|
||||
return AnsibleModule(
|
||||
argument_spec=dict(
|
||||
id={"type": "int"},
|
||||
name={"type": "str"},
|
||||
image={"type": "str"},
|
||||
server_type={"type": "str"},
|
||||
location={"type": "str"},
|
||||
datacenter={"type": "str"},
|
||||
user_data={"type": "str"},
|
||||
ssh_keys={"type": "list"},
|
||||
volumes={"type": "list"},
|
||||
labels={"type": "dict"},
|
||||
backups={"type": "bool", "default": False},
|
||||
upgrade_disk={"type": "bool", "default": False},
|
||||
force_upgrade={"type": "bool", "default": False},
|
||||
rescue_mode={"type": "str"},
|
||||
delete_protection={"type": "bool"},
|
||||
rebuild_protection={"type": "bool"},
|
||||
state={
|
||||
"choices": ["absent", "present", "restarted", "started", "stopped", "rebuild"],
|
||||
"default": "present",
|
||||
},
|
||||
**Hcloud.base_module_arguments()
|
||||
),
|
||||
required_one_of=[['id', 'name']],
|
||||
mutually_exclusive=[["location", "datacenter"]],
|
||||
required_together=[["delete_protection", "rebuild_protection"]],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleHcloudServer.define_module()
|
||||
|
||||
hcloud = AnsibleHcloudServer(module)
|
||||
state = module.params.get("state")
|
||||
if state == "absent":
|
||||
hcloud.delete_server()
|
||||
elif state == "present":
|
||||
hcloud.present_server()
|
||||
elif state == "started":
|
||||
hcloud.present_server()
|
||||
hcloud.start_server()
|
||||
elif state == "stopped":
|
||||
hcloud.present_server()
|
||||
hcloud.stop_server()
|
||||
elif state == "restarted":
|
||||
hcloud.present_server()
|
||||
hcloud.stop_server()
|
||||
hcloud.start_server()
|
||||
elif state == "rebuild":
|
||||
hcloud.present_server()
|
||||
hcloud.rebuild_server()
|
||||
|
||||
module.exit_json(**hcloud.get_result())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in a new issue