Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cloudscale_server: implement param server_groups #54868

Merged
merged 4 commits into from
Apr 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
71 changes: 64 additions & 7 deletions lib/ansible/modules/cloud/cloudscale/cloudscale_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,15 @@
anti_affinity_with:
description:
- UUID of another server to create an anti-affinity group with.
- Mutually exclusive with I(server_groups).
- Deprecated, removed in version 2.11.
type: str
server_groups:
description:
- List of UUID or names of server groups.
- Mutually exclusive with I(anti_affinity_with).
type: list
version_added: '2.8'
user_data:
description:
- Cloud-init configuration (cloud-config) data to use for the server.
Expand All @@ -109,28 +117,29 @@
'''

EXAMPLES = '''
# Start a server (if it does not exist) and register the server details
# Create and start a server with an existing server group (shiny-group)
- name: Start cloudscale.ch server
cloudscale_server:
name: my-shiny-cloudscale-server
image: debian-8
flavor: flex-4
ssh_keys: ssh-rsa XXXXXXXXXX...XXXX ansible@cloudscale
server_groups: shiny-group
use_private_network: True
bulk_volume_size_gb: 100
api_token: xxxxxx
register: server1

# Start another server in anti-affinity to the first one
# Start another server in anti-affinity (server group shiny-group)
- name: Start second cloudscale.ch server
cloudscale_server:
name: my-other-shiny-server
image: ubuntu-16.04
flavor: flex-8
ssh_keys: ssh-rsa XXXXXXXXXXX ansible@cloudscale
anti_affinity_with: '{{ server1.uuid }}'
server_groups: shiny-group
api_token: xxxxxx


# Force to update the flavor of a running server
- name: Start cloudscale.ch server
cloudscale_server:
Expand Down Expand Up @@ -224,10 +233,18 @@
type: list
sample: ["ecdsa-sha2-nistp256 XXXXX", ... ]
anti_affinity_with:
description: List of servers in the same anti-affinity group
description:
- List of servers in the same anti-affinity group
- Deprecated, removed in version 2.11.
returned: success when not state == absent
type: str
type: list
sample: []
server_groups:
description: List of server groups
returned: success when not state == absent
type: list
sample: [ {"href": "https://api.cloudscale.ch/v1/server-groups/...", "uuid": "...", "name": "db-group"} ]
version_added: '2.8'
'''

from datetime import datetime, timedelta
Expand Down Expand Up @@ -378,12 +395,42 @@ def _update_param(self, param_key, server_info, requires_stop=False):

return server_info

def _get_server_group_ids(self):
server_group_params = self._module.params['server_groups']
if not server_group_params:
return None

matching_group_names = []
results = []
server_groups = self._get('server-groups')
for server_group in server_groups:
if server_group['uuid'] in server_group_params:
results.append(server_group['uuid'])
server_group_params.remove(server_group['uuid'])

elif server_group['name'] in server_group_params:
results.append(server_group['uuid'])
server_group_params.remove(server_group['name'])
resmo marked this conversation as resolved.
Show resolved Hide resolved
# Remember the names found
matching_group_names.append(server_group['name'])

# Names are not unique, verify if name already found in previous iterations
elif server_group['name'] in matching_group_names:
self._module.fail_json(msg="More than one server group with name exists: '%s'. "
"Use the 'uuid' parameter to identify the server group." % server_group['name'])

if server_group_params:
self._module.fail_json(msg="Server group name or UUID not found: %s" % ', '.join(server_group_params))

return results

def _create_server(self, server_info):
self._result['changed'] = True

data = deepcopy(self._module.params)
for i in ('uuid', 'state', 'force', 'api_timeout', 'api_token'):
del data[i]
data['server_groups'] = self._get_server_group_ids()

self._result['diff']['before'] = self._init_server_container()
self._result['diff']['after'] = deepcopy(data)
Expand All @@ -396,6 +443,14 @@ def _update_server(self, server_info):

previous_state = server_info.get('state')

# The API doesn't support to update server groups.
# Show a warning to the user if the desired state does not match.
desired_server_group_ids = self._get_server_group_ids()
if desired_server_group_ids is not None:
current_server_group_ids = [grp['uuid'] for grp in server_info['server_groups']]
if desired_server_group_ids != current_server_group_ids:
self._module.warn("Server groups can not be mutated, server needs redeployment to change groups.")

server_info = self._update_param('flavor', server_info, requires_stop=True)
server_info = self._update_param('name', server_info)

Expand Down Expand Up @@ -450,14 +505,16 @@ def main():
use_public_network=dict(type='bool', default=True),
use_private_network=dict(type='bool', default=False),
use_ipv6=dict(type='bool', default=True),
anti_affinity_with=dict(),
anti_affinity_with=dict(removed_in_version='2.11'),
server_groups=dict(type='list'),
user_data=dict(),
force=dict(type='bool', default=False)
))

module = AnsibleModule(
argument_spec=argument_spec,
required_one_of=(('name', 'uuid'),),
mutually_exclusive=(('anti_affinity_with', 'server_groups'),),
supports_check_mode=True,
)

Expand Down
53 changes: 53 additions & 0 deletions test/integration/targets/cloudscale_server/tasks/failures.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
- name: Fail missing params
cloudscale_server:
register: srv
ignore_errors: True
- name: 'VERIFY: Fail name and UUID'
assert:
that:
- srv is failed

- name: Fail unexisting server group
cloudscale_server:
name: '{{ cloudscale_resource_prefix }}-test-group'
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
password: '{{ cloudscale_test_password }}'
server_groups: '{{ cloudscale_resource_prefix }}-unexist-group'
ignore_errors: True
register: srv
- name: 'VERIFY: Fail unexisting server group'
assert:
that:
- srv is failed
- srv.msg.startswith('Server group name or UUID not found')

- name: Create two server groups with the same name
uri:
url: https://api.cloudscale.ch/v1/server-groups
method: POST
headers:
Authorization: 'Bearer {{ cloudscale_api_token }}'
body:
name: '{{ cloudscale_resource_prefix }}-duplicate'
type: anti-affinity
body_format: json
status_code: 201
register: duplicate
with_sequence: count=2

- name: Try to use server groups with identical name
cloudscale_server:
name: '{{ cloudscale_resource_prefix }}-test-group'
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
password: '{{ cloudscale_test_password }}'
server_groups: '{{ cloudscale_resource_prefix }}-duplicate'
ignore_errors: True
register: srv
- name: 'VERIFY: Fail unexisting server group'
assert:
that:
- srv is failed
- srv.msg.startswith('More than one server group with name exists')
4 changes: 4 additions & 0 deletions test/integration/targets/cloudscale_server/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
---
- block:
- import_tasks: failures.yml
- import_tasks: tests.yml
always:
- import_role:
name: cloudscale_common
tasks_from: cleanup_servers
- import_role:
name: cloudscale_common
tasks_from: cleanup_server_groups
43 changes: 39 additions & 4 deletions test/integration/targets/cloudscale_server/tasks/tests.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
---
- name: Setup server groups
cloudscale_server_group:
name: '{{ cloudscale_resource_prefix }}-group-{{ item }}'
type: anti-affinity
with_sequence: count=2

- name: Test create a running server in check mode
cloudscale_server:
name: '{{ cloudscale_resource_prefix }}-test'
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
ssh_keys: '{{ cloudscale_test_ssh_key }}'
server_groups: '{{ cloudscale_resource_prefix }}-group-1'
register: server
check_mode: yes
- name: Verify create a running server in check mode
Expand All @@ -19,25 +26,29 @@
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
ssh_keys: '{{ cloudscale_test_ssh_key }}'
server_groups: '{{ cloudscale_resource_prefix }}-group-1'
register: server
- name: Verify create a running server
assert:
that:
- server is changed
- server.state == 'running'
- server.server_groups.0.name == '{{ cloudscale_resource_prefix }}-group-1'

- name: Test create a running server idempotence
cloudscale_server:
name: '{{ cloudscale_resource_prefix }}-test'
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
ssh_keys: '{{ cloudscale_test_ssh_key }}'
server_groups: '{{ cloudscale_resource_prefix }}-group-1'
register: server
- name: Verify create a running server idempotence
assert:
that:
- server is not changed
- server.state == 'running'
- server.server_groups.0.name == '{{ cloudscale_resource_prefix }}-group-1'

- name: Test update flavor of a running server without force in check mode
cloudscale_server:
Expand All @@ -54,6 +65,7 @@
- server is not changed
- server.state == 'running'
- server.flavor.slug == '{{ cloudscale_test_flavor }}'
- server.server_groups.0.name == '{{ cloudscale_resource_prefix }}-group-1'

- name: Test update flavor of a running server without force
cloudscale_server:
Expand All @@ -69,6 +81,7 @@
- server is not changed
- server.state == 'running'
- server.flavor.slug == '{{ cloudscale_test_flavor }}'
- server.server_groups.0.name == '{{ cloudscale_resource_prefix }}-group-1'

- name: Test update flavor of a running server without force idempotence
cloudscale_server:
Expand All @@ -84,6 +97,7 @@
- server is not changed
- server.state == 'running'
- server.flavor.slug == '{{ cloudscale_test_flavor }}'
- server.server_groups.0.name == '{{ cloudscale_resource_prefix }}-group-1'

- name: Test update flavor and name of a running server without force in check mode
cloudscale_server:
Expand Down Expand Up @@ -196,7 +210,7 @@
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
ssh_keys: '{{ cloudscale_test_ssh_key }}'
anti_affinity_with: '{{ running_server_uuid }}'
server_groups: '{{ cloudscale_resource_prefix }}-group-1'
use_public_network: no
use_private_network: yes
state: stopped
Expand All @@ -214,7 +228,7 @@
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
ssh_keys: '{{ cloudscale_test_ssh_key }}'
anti_affinity_with: '{{ running_server_uuid }}'
server_groups: '{{ cloudscale_resource_prefix }}-group-1'
use_public_network: no
use_private_network: yes
state: stopped
Expand All @@ -226,14 +240,15 @@
- server_stopped.state == 'stopped'
- server_stopped.anti_affinity_with.0.uuid == running_server_uuid
- server_stopped.interfaces.0.type == 'private'
- server_stopped.server_groups.0.name == '{{ cloudscale_resource_prefix }}-group-1'

- name: Test create server stopped in anti affinity and private network only idempotence
cloudscale_server:
name: '{{ cloudscale_resource_prefix }}-test-stopped'
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
ssh_keys: '{{ cloudscale_test_ssh_key }}'
anti_affinity_with: '{{ running_server_uuid }}'
server_groups: '{{ cloudscale_resource_prefix }}-group-1'
use_public_network: no
use_private_network: yes
state: stopped
Expand All @@ -245,6 +260,27 @@
- server_stopped.state == 'stopped'
- server_stopped.anti_affinity_with.0.uuid == running_server_uuid
- server_stopped.interfaces.0.type == 'private'
- server_stopped.server_groups.0.name == '{{ cloudscale_resource_prefix }}-group-1'

- name: Test change server group not changed
cloudscale_server:
name: '{{ cloudscale_resource_prefix }}-test-stopped'
flavor: '{{ cloudscale_test_flavor }}'
image: '{{ cloudscale_test_image }}'
ssh_keys: '{{ cloudscale_test_ssh_key }}'
server_groups: '{{ cloudscale_resource_prefix }}-group-2'
use_public_network: no
use_private_network: yes
state: stopped
register: server_stopped
- name: Verify Test update server group not changed
assert:
that:
- server_stopped is not changed
- server_stopped.state == 'stopped'
- server_stopped.anti_affinity_with.0.uuid == running_server_uuid
- server_stopped.interfaces.0.type == 'private'
- server_stopped.server_groups.0.name == '{{ cloudscale_resource_prefix }}-group-1'

- name: Test create server with password in check mode
cloudscale_server:
Expand Down Expand Up @@ -371,7 +407,6 @@
- server.flavor.slug == '{{ cloudscale_test_flavor }}'
- server.name == '{{ cloudscale_resource_prefix }}-test'


- name: Test update a stopped server idempotence
cloudscale_server:
uuid: '{{ server.uuid }}'
Expand Down