mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Merge branch 'devel' into v2_final
Conflicts: lib/ansible/modules/core v2/ansible/modules/core v2/ansible/modules/extras
This commit is contained in:
commit
8f504dacdd
33 changed files with 1423 additions and 41 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -8,8 +8,9 @@ Major Changes:
|
|||
* template code now retains types for bools and Numbers instead of turning them into strings
|
||||
If you need the old behaviour, quote the value and it will get passed around as a string
|
||||
|
||||
Deprecated Modules:
|
||||
* ec2_ami_search, in favor of the new ec2_ami_find
|
||||
Deprecated Modules (new ones in parens):
|
||||
* ec2_ami_search (ec2_ami_find)
|
||||
* nova_compute (os_server)
|
||||
|
||||
New Modules:
|
||||
* find
|
||||
|
@ -22,12 +23,17 @@ New Modules:
|
|||
* cloudstack: cs_affinitygroup
|
||||
* cloudstack: cs_firewall
|
||||
* cloudstack: cs_iso
|
||||
* cloudstack: cs_instance
|
||||
* cloudstack: cs_sshkeypair
|
||||
* cloudstack: cs_securitygroup
|
||||
* cloudstack: cs_securitygroup_rule
|
||||
* cloudstack: cs_vmsnapshot
|
||||
* maven_artifact
|
||||
* openstack: os_server
|
||||
* openstack: os_server_facts
|
||||
* openstack: os_server_volume
|
||||
* openstack: os_subnet
|
||||
* openstack: os_volume
|
||||
* pushover
|
||||
* zabbix_host
|
||||
* zabbix_hostmacro
|
||||
|
@ -40,6 +46,7 @@ New Modules:
|
|||
* vmware_datacenter
|
||||
|
||||
New Inventory scripts:
|
||||
* cloudstack
|
||||
* fleetctl
|
||||
|
||||
Other Notable Changes:
|
||||
|
|
|
@ -301,12 +301,8 @@ Role dependencies can also be specified as a full path, just like top level role
|
|||
dependencies:
|
||||
- { role: '/path/to/common/roles/foo', x: 1 }
|
||||
|
||||
Role dependencies can also be installed from source control repos or tar files, using a comma separated format of path, an optional version (tag, commit, branch etc) and optional friendly role name (an attempt is made to derive a role name from the repo name or archive filename)::
|
||||
Role dependencies can also be installed from source control repos or tar files (via `galaxy`) using comma separated format of path, an optional version (tag, commit, branch etc) and optional friendly role name (an attempt is made to derive a role name from the repo name or archive filename). Both through the command line or via a requirements.yml passed to ansible-galaxy.
|
||||
|
||||
---
|
||||
dependencies:
|
||||
- { role: 'git+http://git.example.com/repos/role-foo,v1.1,foo' }
|
||||
- { role: '/path/to/tar/file.tgz,,friendly-name' }
|
||||
|
||||
Roles dependencies are always executed before the role that includes them, and are recursive. By default,
|
||||
roles can also only be added as a dependency once - if another role also lists it as a dependency it will
|
||||
|
|
|
@ -41,15 +41,22 @@ class AnsibleCloudStack:
|
|||
if not has_lib_cs:
|
||||
module.fail_json(msg="python library cs required: pip install cs")
|
||||
|
||||
self.result = {
|
||||
'changed': False,
|
||||
}
|
||||
|
||||
self.module = module
|
||||
self._connect()
|
||||
|
||||
self.project_id = None
|
||||
self.ip_address_id = None
|
||||
self.zone_id = None
|
||||
self.vm_id = None
|
||||
self.os_type_id = None
|
||||
self.domain = None
|
||||
self.account = None
|
||||
self.project = None
|
||||
self.ip_address = None
|
||||
self.zone = None
|
||||
self.vm = None
|
||||
self.os_type = None
|
||||
self.hypervisor = None
|
||||
self.capabilities = None
|
||||
|
||||
|
||||
def _connect(self):
|
||||
|
@ -68,27 +75,73 @@ class AnsibleCloudStack:
|
|||
else:
|
||||
self.cs = CloudStack(**read_config())
|
||||
|
||||
# TODO: rename to has_changed()
|
||||
def _has_changed(self, want_dict, current_dict, only_keys=None):
|
||||
for key, value in want_dict.iteritems():
|
||||
|
||||
# Optionally limit by a list of keys
|
||||
if only_keys and key not in only_keys:
|
||||
continue;
|
||||
|
||||
# Skip None values
|
||||
if value is None:
|
||||
continue;
|
||||
|
||||
if key in current_dict:
|
||||
|
||||
# API returns string for int in some cases, just to make sure
|
||||
if isinstance(value, int):
|
||||
current_dict[key] = int(current_dict[key])
|
||||
elif isinstance(value, str):
|
||||
current_dict[key] = str(current_dict[key])
|
||||
|
||||
# Only need to detect a singe change, not every item
|
||||
if value != current_dict[key]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _get_by_key(self, key=None, my_dict={}):
|
||||
if key:
|
||||
if key in my_dict:
|
||||
return my_dict[key]
|
||||
self.module.fail_json(msg="Something went wrong: %s not found" % key)
|
||||
return my_dict
|
||||
|
||||
|
||||
# TODO: for backward compatibility only, remove if not used anymore
|
||||
def get_project_id(self):
|
||||
if self.project_id:
|
||||
return self.project_id
|
||||
return self.get_project(key='id')
|
||||
|
||||
|
||||
def get_project(self, key=None):
|
||||
if self.project:
|
||||
return self._get_by_key(key, self.project)
|
||||
|
||||
project = self.module.params.get('project')
|
||||
if not project:
|
||||
return None
|
||||
|
||||
projects = self.cs.listProjects()
|
||||
args = {}
|
||||
args['listall'] = True
|
||||
args['account'] = self.get_account(key='name')
|
||||
args['domainid'] = self.get_domain(key='id')
|
||||
projects = self.cs.listProjects(**args)
|
||||
if projects:
|
||||
for p in projects['project']:
|
||||
if project in [ p['name'], p['displaytext'], p['id'] ]:
|
||||
self.project_id = p['id']
|
||||
return self.project_id
|
||||
self.project = p
|
||||
return self._get_by_key(key, self.project)
|
||||
self.module.fail_json(msg="project '%s' not found" % project)
|
||||
|
||||
|
||||
# TODO: for backward compatibility only, remove if not used anymore
|
||||
def get_ip_address_id(self):
|
||||
if self.ip_address_id:
|
||||
return self.ip_address_id
|
||||
return self.get_ip_address(key='id')
|
||||
|
||||
|
||||
def get_ip_address(self, key=None):
|
||||
if self.ip_address:
|
||||
return self._get_by_key(key, self.ip_address)
|
||||
|
||||
ip_address = self.module.params.get('ip_address')
|
||||
if not ip_address:
|
||||
|
@ -96,58 +149,78 @@ class AnsibleCloudStack:
|
|||
|
||||
args = {}
|
||||
args['ipaddress'] = ip_address
|
||||
args['projectid'] = self.get_project_id()
|
||||
args['account'] = self.get_account(key='name')
|
||||
args['domainid'] = self.get_domain(key='id')
|
||||
args['projectid'] = self.get_project(key='id')
|
||||
ip_addresses = self.cs.listPublicIpAddresses(**args)
|
||||
|
||||
if not ip_addresses:
|
||||
self.module.fail_json(msg="IP address '%s' not found" % args['ipaddress'])
|
||||
|
||||
self.ip_address_id = ip_addresses['publicipaddress'][0]['id']
|
||||
return self.ip_address_id
|
||||
self.ip_address = ip_addresses['publicipaddress'][0]
|
||||
return self._get_by_key(key, self.ip_address)
|
||||
|
||||
|
||||
# TODO: for backward compatibility only, remove if not used anymore
|
||||
def get_vm_id(self):
|
||||
if self.vm_id:
|
||||
return self.vm_id
|
||||
return self.get_vm(key='id')
|
||||
|
||||
|
||||
def get_vm(self, key=None):
|
||||
if self.vm:
|
||||
return self._get_by_key(key, self.vm)
|
||||
|
||||
vm = self.module.params.get('vm')
|
||||
if not vm:
|
||||
self.module.fail_json(msg="Virtual machine param 'vm' is required")
|
||||
|
||||
args = {}
|
||||
args['projectid'] = self.get_project_id()
|
||||
args['account'] = self.get_account(key='name')
|
||||
args['domainid'] = self.get_domain(key='id')
|
||||
args['projectid'] = self.get_project(key='id')
|
||||
args['zoneid'] = self.get_zone(key='id')
|
||||
vms = self.cs.listVirtualMachines(**args)
|
||||
if vms:
|
||||
for v in vms['virtualmachine']:
|
||||
if vm in [ v['displayname'], v['name'], v['id'] ]:
|
||||
self.vm_id = v['id']
|
||||
return self.vm_id
|
||||
if vm in [ v['name'], v['displayname'], v['id'] ]:
|
||||
self.vm = v
|
||||
return self._get_by_key(key, self.vm)
|
||||
self.module.fail_json(msg="Virtual machine '%s' not found" % vm)
|
||||
|
||||
|
||||
# TODO: for backward compatibility only, remove if not used anymore
|
||||
def get_zone_id(self):
|
||||
if self.zone_id:
|
||||
return self.zone_id
|
||||
return self.get_zone(key='id')
|
||||
|
||||
|
||||
def get_zone(self, key=None):
|
||||
if self.zone:
|
||||
return self._get_by_key(key, self.zone)
|
||||
|
||||
zone = self.module.params.get('zone')
|
||||
zones = self.cs.listZones()
|
||||
|
||||
# use the first zone if no zone param given
|
||||
if not zone:
|
||||
self.zone_id = zones['zone'][0]['id']
|
||||
return self.zone_id
|
||||
self.zone = zones['zone'][0]
|
||||
return self._get_by_key(key, self.zone)
|
||||
|
||||
if zones:
|
||||
for z in zones['zone']:
|
||||
if zone in [ z['name'], z['id'] ]:
|
||||
self.zone_id = z['id']
|
||||
return self.zone_id
|
||||
self.zone = z
|
||||
return self._get_by_key(key, self.zone)
|
||||
self.module.fail_json(msg="zone '%s' not found" % zone)
|
||||
|
||||
|
||||
# TODO: for backward compatibility only, remove if not used anymore
|
||||
def get_os_type_id(self):
|
||||
if self.os_type_id:
|
||||
return self.os_type_id
|
||||
return self.get_os_type(key='id')
|
||||
|
||||
|
||||
def get_os_type(self, key=None):
|
||||
if self.os_type:
|
||||
return self._get_by_key(key, self.zone)
|
||||
|
||||
os_type = self.module.params.get('os_type')
|
||||
if not os_type:
|
||||
|
@ -157,8 +230,8 @@ class AnsibleCloudStack:
|
|||
if os_types:
|
||||
for o in os_types['ostype']:
|
||||
if os_type in [ o['description'], o['id'] ]:
|
||||
self.os_type_id = o['id']
|
||||
return self.os_type_id
|
||||
self.os_type = o
|
||||
return self._get_by_key(key, self.os_type)
|
||||
self.module.fail_json(msg="OS type '%s' not found" % os_type)
|
||||
|
||||
|
||||
|
@ -181,6 +254,112 @@ class AnsibleCloudStack:
|
|||
self.module.fail_json(msg="Hypervisor '%s' not found" % hypervisor)
|
||||
|
||||
|
||||
def get_account(self, key=None):
|
||||
if self.account:
|
||||
return self._get_by_key(key, self.account)
|
||||
|
||||
account = self.module.params.get('account')
|
||||
if not account:
|
||||
return None
|
||||
|
||||
domain = self.module.params.get('domain')
|
||||
if not domain:
|
||||
self.module.fail_json(msg="Account must be specified with Domain")
|
||||
|
||||
args = {}
|
||||
args['name'] = account
|
||||
args['domainid'] = self.get_domain(key='id')
|
||||
args['listall'] = True
|
||||
accounts = self.cs.listAccounts(**args)
|
||||
if accounts:
|
||||
self.account = accounts['account'][0]
|
||||
return self._get_by_key(key, self.account)
|
||||
self.module.fail_json(msg="Account '%s' not found" % account)
|
||||
|
||||
|
||||
def get_domain(self, key=None):
|
||||
if self.domain:
|
||||
return self._get_by_key(key, self.domain)
|
||||
|
||||
domain = self.module.params.get('domain')
|
||||
if not domain:
|
||||
return None
|
||||
|
||||
args = {}
|
||||
args['name'] = domain
|
||||
args['listall'] = True
|
||||
domain = self.cs.listDomains(**args)
|
||||
if domains:
|
||||
self.domain = domains['domain'][0]
|
||||
return self._get_by_key(key, self.domain)
|
||||
self.module.fail_json(msg="Domain '%s' not found" % domain)
|
||||
|
||||
|
||||
def get_tags(self, resource=None):
|
||||
existing_tags = self.cs.listTags(resourceid=resource['id'])
|
||||
if existing_tags:
|
||||
return existing_tags['tag']
|
||||
return []
|
||||
|
||||
|
||||
def _delete_tags(self, resource, resource_type, tags):
|
||||
existing_tags = resource['tags']
|
||||
tags_to_delete = []
|
||||
for existing_tag in existing_tags:
|
||||
if existing_tag['key'] in tags:
|
||||
if existing_tag['value'] != tags[key]:
|
||||
tags_to_delete.append(existing_tag)
|
||||
else:
|
||||
tags_to_delete.append(existing_tag)
|
||||
if tags_to_delete:
|
||||
self.result['changed'] = True
|
||||
if not self.module.check_mode:
|
||||
args = {}
|
||||
args['resourceids'] = resource['id']
|
||||
args['resourcetype'] = resource_type
|
||||
args['tags'] = tags_to_delete
|
||||
self.cs.deleteTags(**args)
|
||||
|
||||
|
||||
def _create_tags(self, resource, resource_type, tags):
|
||||
tags_to_create = []
|
||||
for i, tag_entry in enumerate(tags):
|
||||
tag = {
|
||||
'key': tag_entry['key'],
|
||||
'value': tag_entry['value'],
|
||||
}
|
||||
tags_to_create.append(tag)
|
||||
if tags_to_create:
|
||||
self.result['changed'] = True
|
||||
if not self.module.check_mode:
|
||||
args = {}
|
||||
args['resourceids'] = resource['id']
|
||||
args['resourcetype'] = resource_type
|
||||
args['tags'] = tags_to_create
|
||||
self.cs.createTags(**args)
|
||||
|
||||
|
||||
def ensure_tags(self, resource, resource_type=None):
|
||||
if not resource_type or not resource:
|
||||
self.module.fail_json(msg="Error: Missing resource or resource_type for tags.")
|
||||
|
||||
if 'tags' in resource:
|
||||
tags = self.module.params.get('tags')
|
||||
if tags is not None:
|
||||
self._delete_tags(resource, resource_type, tags)
|
||||
self._create_tags(resource, resource_type, tags)
|
||||
resource['tags'] = self.get_tags(resource)
|
||||
return resource
|
||||
|
||||
|
||||
def get_capabilities(self, key=None):
|
||||
if self.capabilities:
|
||||
return self._get_by_key(key, self.capabilities)
|
||||
capabilities = self.cs.listCapabilities()
|
||||
self.capabilities = capabilities['capability']
|
||||
return self._get_by_key(key, self.capabilities)
|
||||
|
||||
# TODO: rename to poll_job()
|
||||
def _poll_job(self, job=None, key=None):
|
||||
if 'jobid' in job:
|
||||
while True:
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0341ddd35ed5ff477ad5de2488d947255ce86259
|
||||
Subproject commit 85c8a892c80b92730831d95fa654ef6d35b0eca0
|
|
@ -1 +1 @@
|
|||
Subproject commit 495ad450e53feb1cd26218dc68056cc34d1ea9ff
|
||||
Subproject commit 2690f096a47646cd17db135648def88afc40d92c
|
5
plugins/inventory/cloudstack.ini
Normal file
5
plugins/inventory/cloudstack.ini
Normal file
|
@ -0,0 +1,5 @@
|
|||
[cloudstack]
|
||||
#endpoint = https://api.exoscale.ch/compute
|
||||
endpoint = https://cloud.example.com/client/api
|
||||
key = cloudstack api key
|
||||
secret = cloudstack api secret
|
232
plugins/inventory/cloudstack.py
Executable file
232
plugins/inventory/cloudstack.py
Executable file
|
@ -0,0 +1,232 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2015, René Moser <mail@renemoser.net>
|
||||
#
|
||||
# This file is part of Ansible,
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
######################################################################
|
||||
|
||||
"""
|
||||
Ansible CloudStack external inventory script.
|
||||
=============================================
|
||||
|
||||
Generates Ansible inventory from CloudStack. Configuration is read from
|
||||
'cloudstack.ini'. If you need to pass the project, write a simple wrapper
|
||||
script, e.g. project_cloudstack.sh:
|
||||
|
||||
#!/bin/bash
|
||||
cloudstack.py --project <your_project> $@
|
||||
|
||||
|
||||
When run against a specific host, this script returns the following attributes
|
||||
based on the data obtained from CloudStack API:
|
||||
|
||||
"web01": {
|
||||
"cpu_number": 2,
|
||||
"nic": [
|
||||
{
|
||||
"ip": "10.102.76.98",
|
||||
"mac": "02:00:50:99:00:01",
|
||||
"type": "Isolated",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway": "10.102.76.1"
|
||||
},
|
||||
{
|
||||
"ip": "10.102.138.63",
|
||||
"mac": "06:b7:5a:00:14:84",
|
||||
"type": "Shared",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway": "10.102.138.1"
|
||||
}
|
||||
],
|
||||
"default_ip": "10.102.76.98",
|
||||
"zone": "ZUERICH",
|
||||
"created": "2014-07-02T07:53:50+0200",
|
||||
"hypervisor": "VMware",
|
||||
"memory": 2048,
|
||||
"state": "Running",
|
||||
"tags": [],
|
||||
"cpu_speed": 1800,
|
||||
"affinity_group": [],
|
||||
"service_offering": "Small",
|
||||
"cpu_used": "62%"
|
||||
}
|
||||
|
||||
|
||||
usage: cloudstack.py [--list] [--host HOST] [--project PROJECT]
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
try:
|
||||
import json
|
||||
except:
|
||||
import simplejson as json
|
||||
|
||||
|
||||
try:
|
||||
from cs import CloudStack, CloudStackException, read_config
|
||||
except ImportError:
|
||||
print >> sys.stderr, "Error: CloudStack library must be installed: pip install cs."
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class CloudStackInventory(object):
|
||||
def __init__(self):
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--host')
|
||||
parser.add_argument('--list', action='store_true')
|
||||
parser.add_argument('--project')
|
||||
|
||||
options = parser.parse_args()
|
||||
try:
|
||||
self.cs = CloudStack(**read_config())
|
||||
except CloudStackException, e:
|
||||
print >> sys.stderr, "Error: Could not connect to CloudStack API"
|
||||
|
||||
project_id = ''
|
||||
if options.project:
|
||||
project_id = self.get_project_id(options.project)
|
||||
|
||||
if options.host:
|
||||
data = self.get_host(options.host)
|
||||
print json.dumps(data, indent=2)
|
||||
|
||||
elif options.list:
|
||||
data = self.get_list()
|
||||
print json.dumps(data, indent=2)
|
||||
else:
|
||||
print >> sys.stderr, "usage: --list | --host <hostname> [--project <project>]"
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_project_id(self, project):
|
||||
projects = self.cs.listProjects()
|
||||
if projects:
|
||||
for p in projects['project']:
|
||||
if p['name'] == project or p['id'] == project:
|
||||
return p['id']
|
||||
print >> sys.stderr, "Error: Project %s not found." % project
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_host(self, name, project_id=''):
|
||||
hosts = self.cs.listVirtualMachines(projectid=project_id)
|
||||
data = {}
|
||||
if not hosts:
|
||||
return data
|
||||
for host in hosts['virtualmachine']:
|
||||
host_name = host['displayname']
|
||||
if name == host_name:
|
||||
data['zone'] = host['zonename']
|
||||
if 'group' in host:
|
||||
data['group'] = host['group']
|
||||
data['state'] = host['state']
|
||||
data['service_offering'] = host['serviceofferingname']
|
||||
data['affinity_group'] = host['affinitygroup']
|
||||
data['security_group'] = host['securitygroup']
|
||||
data['cpu_number'] = host['cpunumber']
|
||||
data['cpu_speed'] = host['cpuspeed']
|
||||
if 'cpuused' in host:
|
||||
data['cpu_used'] = host['cpuused']
|
||||
data['memory'] = host['memory']
|
||||
data['tags'] = host['tags']
|
||||
data['hypervisor'] = host['hypervisor']
|
||||
data['created'] = host['created']
|
||||
data['nic'] = []
|
||||
for nic in host['nic']:
|
||||
data['nic'].append({
|
||||
'ip': nic['ipaddress'],
|
||||
'mac': nic['macaddress'],
|
||||
'netmask': nic['netmask'],
|
||||
'gateway': nic['gateway'],
|
||||
'type': nic['type'],
|
||||
})
|
||||
if nic['isdefault']:
|
||||
data['default_ip'] = nic['ipaddress']
|
||||
break;
|
||||
return data
|
||||
|
||||
|
||||
def get_list(self, project_id=''):
|
||||
data = {
|
||||
'all': {
|
||||
'hosts': [],
|
||||
},
|
||||
'_meta': {
|
||||
'hostvars': {},
|
||||
},
|
||||
}
|
||||
|
||||
groups = self.cs.listInstanceGroups(projectid=project_id)
|
||||
if groups:
|
||||
for group in groups['instancegroup']:
|
||||
group_name = group['name']
|
||||
if group_name and not group_name in data:
|
||||
data[group_name] = {
|
||||
'hosts': []
|
||||
}
|
||||
|
||||
hosts = self.cs.listVirtualMachines(projectid=project_id)
|
||||
if not hosts:
|
||||
return data
|
||||
for host in hosts['virtualmachine']:
|
||||
host_name = host['displayname']
|
||||
data['all']['hosts'].append(host_name)
|
||||
data['_meta']['hostvars'][host_name] = {}
|
||||
data['_meta']['hostvars'][host_name]['zone'] = host['zonename']
|
||||
if 'group' in host:
|
||||
data['_meta']['hostvars'][host_name]['group'] = host['group']
|
||||
data['_meta']['hostvars'][host_name]['state'] = host['state']
|
||||
data['_meta']['hostvars'][host_name]['service_offering'] = host['serviceofferingname']
|
||||
data['_meta']['hostvars'][host_name]['affinity_group'] = host['affinitygroup']
|
||||
data['_meta']['hostvars'][host_name]['security_group'] = host['securitygroup']
|
||||
data['_meta']['hostvars'][host_name]['cpu_number'] = host['cpunumber']
|
||||
data['_meta']['hostvars'][host_name]['cpu_speed'] = host['cpuspeed']
|
||||
if 'cpuused' in host:
|
||||
data['_meta']['hostvars'][host_name]['cpu_used'] = host['cpuused']
|
||||
data['_meta']['hostvars'][host_name]['created'] = host['created']
|
||||
data['_meta']['hostvars'][host_name]['memory'] = host['memory']
|
||||
data['_meta']['hostvars'][host_name]['tags'] = host['tags']
|
||||
data['_meta']['hostvars'][host_name]['hypervisor'] = host['hypervisor']
|
||||
data['_meta']['hostvars'][host_name]['created'] = host['created']
|
||||
data['_meta']['hostvars'][host_name]['nic'] = []
|
||||
for nic in host['nic']:
|
||||
data['_meta']['hostvars'][host_name]['nic'].append({
|
||||
'ip': nic['ipaddress'],
|
||||
'mac': nic['macaddress'],
|
||||
'netmask': nic['netmask'],
|
||||
'gateway': nic['gateway'],
|
||||
'type': nic['type'],
|
||||
})
|
||||
if nic['isdefault']:
|
||||
data['_meta']['hostvars'][host_name]['default_ip'] = nic['ipaddress']
|
||||
|
||||
group_name = ''
|
||||
if 'group' in host:
|
||||
group_name = host['group']
|
||||
|
||||
if group_name and group_name in data:
|
||||
data[group_name]['hosts'].append(host_name)
|
||||
return data
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
CloudStackInventory()
|
|
@ -144,6 +144,11 @@ rackspace: $(CREDENTIALS_FILE)
|
|||
CLOUD_RESOURCE_PREFIX="$(CLOUD_RESOURCE_PREFIX)" make rackspace_cleanup ; \
|
||||
exit $$RC;
|
||||
|
||||
cloudstack:
|
||||
ansible-playbook cloudstack.yml -i $(INVENTORY) -e @$(VARS_FILE) -e "resource_prefix=$(CLOUD_RESOURCE_PREFIX)" -v $(TEST_FLAGS) ; \
|
||||
RC=$$? ; \
|
||||
exit $$RC;
|
||||
|
||||
$(CONSUL_RUNNING):
|
||||
|
||||
consul:
|
||||
|
|
13
test/integration/cloudstack.yml
Normal file
13
test/integration/cloudstack.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
gather_facts: no
|
||||
tags:
|
||||
- cloudstack
|
||||
roles:
|
||||
- { role: test_cs_sshkeypair, tags: test_cs_sshkeypair }
|
||||
- { role: test_cs_affinitygroup, tags: test_cs_affinitygroup }
|
||||
- { role: test_cs_securitygroup, tags: test_cs_securitygroup }
|
||||
- { role: test_cs_securitygroup_rule, tags: test_cs_securitygroup_rule }
|
||||
- { role: test_cs_instance, tags: test_cs_instance }
|
||||
- { role: test_cs_instancegroup, tags: test_cs_instancegroup }
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- test_cs_common
|
58
test/integration/roles/test_cs_affinitygroup/tasks/main.yml
Normal file
58
test/integration/roles/test_cs_affinitygroup/tasks/main.yml
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
- name: setup
|
||||
cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent
|
||||
register: ag
|
||||
- name: verify setup
|
||||
assert:
|
||||
that:
|
||||
- ag|success
|
||||
|
||||
- name: test fail if missing name
|
||||
action: cs_affinitygroup
|
||||
register: ag
|
||||
ignore_errors: true
|
||||
- name: verify results of fail if missing name
|
||||
assert:
|
||||
that:
|
||||
- ag|failed
|
||||
- ag.msg == "missing required arguments: name"
|
||||
|
||||
- name: test present affinity group
|
||||
cs_affinitygroup: name={{ cs_resource_prefix }}_ag
|
||||
register: ag
|
||||
- name: verify results of create affinity group
|
||||
assert:
|
||||
that:
|
||||
- ag|success
|
||||
- ag|changed
|
||||
- ag.name == "{{ cs_resource_prefix }}_ag"
|
||||
|
||||
- name: test present affinity group is idempotence
|
||||
cs_affinitygroup: name={{ cs_resource_prefix }}_ag
|
||||
register: ag
|
||||
- name: verify results present affinity group is idempotence
|
||||
assert:
|
||||
that:
|
||||
- ag|success
|
||||
- not ag|changed
|
||||
- ag.name == "{{ cs_resource_prefix }}_ag"
|
||||
|
||||
- name: test absent affinity group
|
||||
cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent
|
||||
register: ag
|
||||
- name: verify results of absent affinity group
|
||||
assert:
|
||||
that:
|
||||
- ag|success
|
||||
- ag|changed
|
||||
- ag.name == "{{ cs_resource_prefix }}_ag"
|
||||
|
||||
- name: test absent affinity group is idempotence
|
||||
cs_affinitygroup: name={{ cs_resource_prefix }}_ag state=absent
|
||||
register: ag
|
||||
- name: verify results of absent affinity group is idempotence
|
||||
assert:
|
||||
that:
|
||||
- ag|success
|
||||
- not ag|changed
|
||||
- ag.name is undefined
|
2
test/integration/roles/test_cs_common/defaults/main.yml
Normal file
2
test/integration/roles/test_cs_common/defaults/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
cs_resource_prefix: cloudstack
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
instance_number: 1
|
3
test/integration/roles/test_cs_instance/meta/main.yml
Normal file
3
test/integration/roles/test_cs_instance/meta/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- test_cs_common
|
23
test/integration/roles/test_cs_instance/tasks/absent.yml
Normal file
23
test/integration/roles/test_cs_instance/tasks/absent.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
- name: test destroy instance
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
state: absent
|
||||
register: instance
|
||||
- name: verify destroy instance
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- instance|changed
|
||||
- instance.state == "Destroyed"
|
||||
|
||||
- name: test destroy instance idempotence
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
state: absent
|
||||
register: instance
|
||||
- name: verify destroy instance idempotence
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
36
test/integration/roles/test_cs_instance/tasks/cleanup.yml
Normal file
36
test/integration/roles/test_cs_instance/tasks/cleanup.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
- name: cleanup ssh key
|
||||
cs_sshkeypair: name={{ cs_resource_prefix }}-sshkey state=absent
|
||||
register: sshkey
|
||||
- name: verify cleanup ssh key
|
||||
assert:
|
||||
that:
|
||||
- sshkey|success
|
||||
|
||||
- name: cleanup affinity group
|
||||
cs_affinitygroup: name={{ cs_resource_prefix }}-ag state=absent
|
||||
register: ag
|
||||
until: ag|success
|
||||
retries: 20
|
||||
delay: 5
|
||||
- name: verify cleanup affinity group
|
||||
assert:
|
||||
that:
|
||||
- ag|success
|
||||
|
||||
- name: cleanup security group ...take a while unless instance is expunged
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}-sg state=absent
|
||||
register: sg
|
||||
until: sg|success
|
||||
retries: 100
|
||||
delay: 10
|
||||
- name: verify cleanup security group
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
|
||||
# force expunge, only works with admin permissions
|
||||
- cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
state: expunged
|
||||
failed_when: false
|
11
test/integration/roles/test_cs_instance/tasks/main.yml
Normal file
11
test/integration/roles/test_cs_instance/tasks/main.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
- include: setup.yml
|
||||
tags: any
|
||||
- include: present.yml
|
||||
tags: test_cs_instance_present
|
||||
#- include: tags.yml
|
||||
# tags: test_cs_instance_tags
|
||||
- include: absent.yml
|
||||
tags: test_cs_instance_absent
|
||||
- include: cleanup.yml
|
||||
tags: test_cs_instance_cleanup
|
168
test/integration/roles/test_cs_instance/tasks/present.yml
Normal file
168
test/integration/roles/test_cs_instance/tasks/present.yml
Normal file
|
@ -0,0 +1,168 @@
|
|||
---
|
||||
- name: test create instance
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
template: Linux Debian 7 64-bit
|
||||
service_offering: Tiny
|
||||
affinity_group: "{{ cs_resource_prefix }}-ag"
|
||||
security_group: "{{ cs_resource_prefix }}-sg"
|
||||
ssh_key: "{{ cs_resource_prefix }}-sshkey"
|
||||
tags: []
|
||||
register: instance
|
||||
- name: verify create instance
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- instance|changed
|
||||
- instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.service_offering == "Tiny"
|
||||
- instance.state == "Running"
|
||||
- instance.ssh_key == "{{ cs_resource_prefix }}-sshkey"
|
||||
- not instance.tags
|
||||
|
||||
|
||||
- name: test create instance idempotence
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
template: Linux Debian 7 64-bit
|
||||
service_offering: Tiny
|
||||
affinity_group: "{{ cs_resource_prefix }}-ag"
|
||||
security_group: "{{ cs_resource_prefix }}-sg"
|
||||
ssh_key: "{{ cs_resource_prefix }}-sshkey"
|
||||
tags: []
|
||||
register: instance
|
||||
- name: verify create instance idempotence
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.service_offering == "Tiny"
|
||||
- instance.state == "Running"
|
||||
- instance.ssh_key == "{{ cs_resource_prefix }}-sshkey"
|
||||
- not instance.tags
|
||||
|
||||
|
||||
- name: test running instance not updated
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
service_offering: Micro
|
||||
register: instance
|
||||
- name: verify running instance not updated
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.service_offering == "Tiny"
|
||||
- instance.state == "Running"
|
||||
|
||||
|
||||
- name: test stopping instance
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
state: stopped
|
||||
register: instance
|
||||
- name: verify stopping instance
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- instance|changed
|
||||
- instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.service_offering == "Tiny"
|
||||
- instance.state == "Stopped"
|
||||
|
||||
|
||||
- name: test stopping instance idempotence
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
state: stopped
|
||||
register: instance
|
||||
- name: verify stopping instance idempotence
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.state == "Stopped"
|
||||
|
||||
|
||||
- name: test updating stopped instance
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
display_name: "{{ cs_resource_prefix }}-display-{{ instance_number }}"
|
||||
service_offering: Micro
|
||||
register: instance
|
||||
- name: verify updating stopped instance
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- instance|changed
|
||||
- instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
|
||||
- instance.service_offering == "Micro"
|
||||
- instance.state == "Stopped"
|
||||
|
||||
|
||||
- name: test starting instance
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
state: started
|
||||
register: instance
|
||||
- name: verify starting instance
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- instance|changed
|
||||
- instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.display_name == "{{ cs_resource_prefix }}-display-{{ instance_number }}"
|
||||
- instance.service_offering == "Micro"
|
||||
- instance.state == "Running"
|
||||
|
||||
|
||||
- name: test starting instance idempotence
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
state: started
|
||||
register: instance
|
||||
- name: verify starting instance idempotence
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.state == "Running"
|
||||
|
||||
- name: test force update running instance
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
service_offering: Tiny
|
||||
force: true
|
||||
register: instance
|
||||
- name: verify force update running instance
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- instance|changed
|
||||
- instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.service_offering == "Tiny"
|
||||
- instance.state == "Running"
|
||||
|
||||
- name: test force update running instance idempotence
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
service_offering: Tiny
|
||||
force: true
|
||||
register: instance
|
||||
- name: verify force update running instance idempotence
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.display_name == "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
- instance.service_offering == "Tiny"
|
||||
- instance.state == "Running"
|
32
test/integration/roles/test_cs_instance/tasks/setup.yml
Normal file
32
test/integration/roles/test_cs_instance/tasks/setup.yml
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
- name: setup ssh key
|
||||
cs_sshkeypair: name={{ cs_resource_prefix }}-sshkey
|
||||
register: sshkey
|
||||
- name: verify setup ssh key
|
||||
assert:
|
||||
that:
|
||||
- sshkey|success
|
||||
|
||||
- name: setup affinity group
|
||||
cs_affinitygroup: name={{ cs_resource_prefix }}-ag
|
||||
register: ag
|
||||
- name: verify setup affinity group
|
||||
assert:
|
||||
that:
|
||||
- ag|success
|
||||
|
||||
- name: setup security group
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}-sg
|
||||
register: sg
|
||||
- name: verify setup security group
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
|
||||
- name: setup instance to be absent
|
||||
cs_instance: name={{ cs_resource_prefix }}-vm-{{ instance_number }} state=absent
|
||||
register: instance
|
||||
- name: verify instance to be absent
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
82
test/integration/roles/test_cs_instance/tasks/tags.yml
Normal file
82
test/integration/roles/test_cs_instance/tasks/tags.yml
Normal file
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
- name: test add tags to instance
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
tags:
|
||||
- { key: "{{ cs_resource_prefix }}-tag1", value: "{{ cs_resource_prefix }}-value1" }
|
||||
- { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" }
|
||||
register: instance
|
||||
- name: verify add tags to instance
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- instance|changed
|
||||
- instance.tags|length == 2
|
||||
- instance.tags[0]['key'] == "{{ cs_resource_prefix }}-tag1"
|
||||
- instance.tags[1]['key'] == "{{ cs_resource_prefix }}-tag2"
|
||||
- instance.tags[0]['value'] == "{{ cs_resource_prefix }}-value1"
|
||||
- instance.tags[1]['value'] == "{{ cs_resource_prefix }}-value2"
|
||||
|
||||
|
||||
- name: test tags to instance idempotence
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
tags:
|
||||
- { key: "{{ cs_resource_prefix }}-tag1", value: "{{ cs_resource_prefix }}-value1" }
|
||||
- { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" }
|
||||
register: instance
|
||||
- name: verify tags to instance idempotence
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.tags|length == 2
|
||||
- instance.tags[0]['key'] == "{{ cs_resource_prefix }}-tag1"
|
||||
- instance.tags[1]['key'] == "{{ cs_resource_prefix }}-tag2"
|
||||
- instance.tags[0]['value'] == "{{ cs_resource_prefix }}-value1"
|
||||
- instance.tags[1]['value'] == "{{ cs_resource_prefix }}-value2"
|
||||
|
||||
- name: test change tags of instance
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
tags:
|
||||
- { key: "{{ cs_resource_prefix }}-tag2", value: "{{ cs_resource_prefix }}-value2" }
|
||||
- { key: "{{ cs_resource_prefix }}-tag3", value: "{{ cs_resource_prefix }}-value3" }
|
||||
register: instance
|
||||
- name: verify tags to instance idempotence
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.tags|length == 2
|
||||
- instance.tags[0]['key'] == "{{ cs_resource_prefix }}-tag1"
|
||||
- instance.tags[1]['key'] == "{{ cs_resource_prefix }}-tag3"
|
||||
- instance.tags[0]['value'] == "{{ cs_resource_prefix }}-value1"
|
||||
- instance.tags[1]['value'] == "{{ cs_resource_prefix }}-value3"
|
||||
|
||||
- name: test not touch tags of instance if no param tags
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
register: instance
|
||||
- name: verify not touch tags of instance if no param tags
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.tags|length == 2
|
||||
- instance.tags[0]['key'] == "{{ cs_resource_prefix }}-tag1"
|
||||
- instance.tags[1]['key'] == "{{ cs_resource_prefix }}-tag3"
|
||||
- instance.tags[0]['value'] == "{{ cs_resource_prefix }}-value1"
|
||||
- instance.tags[1]['value'] == "{{ cs_resource_prefix }}-value3"
|
||||
|
||||
- name: test remove tags
|
||||
cs_instance:
|
||||
name: "{{ cs_resource_prefix }}-vm-{{ instance_number }}"
|
||||
tags: []
|
||||
register: instance
|
||||
- name: verify remove tags
|
||||
assert:
|
||||
that:
|
||||
- instance|success
|
||||
- not instance|changed
|
||||
- instance.tags|length == 0
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- test_cs_common
|
58
test/integration/roles/test_cs_instancegroup/tasks/main.yml
Normal file
58
test/integration/roles/test_cs_instancegroup/tasks/main.yml
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
- name: setup
|
||||
cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent
|
||||
register: ig
|
||||
- name: verify setup
|
||||
assert:
|
||||
that:
|
||||
- ig|success
|
||||
|
||||
- name: test fail if missing name
|
||||
action: cs_instancegroup
|
||||
register: ig
|
||||
ignore_errors: true
|
||||
- name: verify results of fail if missing name
|
||||
assert:
|
||||
that:
|
||||
- ig|failed
|
||||
- ig.msg == "missing required arguments: name"
|
||||
|
||||
- name: test present instance group
|
||||
cs_instancegroup: name={{ cs_resource_prefix }}_ig
|
||||
register: ig
|
||||
- name: verify results of create instance group
|
||||
assert:
|
||||
that:
|
||||
- ig|success
|
||||
- ig|changed
|
||||
- ig.name == "{{ cs_resource_prefix }}_ig"
|
||||
|
||||
- name: test present instance group is idempotence
|
||||
cs_instancegroup: name={{ cs_resource_prefix }}_ig
|
||||
register: ig
|
||||
- name: verify results present instance group is idempotence
|
||||
assert:
|
||||
that:
|
||||
- ig|success
|
||||
- not ig|changed
|
||||
- ig.name == "{{ cs_resource_prefix }}_ig"
|
||||
|
||||
- name: test absent instance group
|
||||
cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent
|
||||
register: ig
|
||||
- name: verify results of absent instance group
|
||||
assert:
|
||||
that:
|
||||
- ig|success
|
||||
- ig|changed
|
||||
- ig.name == "{{ cs_resource_prefix }}_ig"
|
||||
|
||||
- name: test absent instance group is idempotence
|
||||
cs_instancegroup: name={{ cs_resource_prefix }}_ig state=absent
|
||||
register: ig
|
||||
- name: verify results of absent instance group is idempotence
|
||||
assert:
|
||||
that:
|
||||
- ig|success
|
||||
- not ig|changed
|
||||
- ig.name is undefined
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- test_cs_common
|
58
test/integration/roles/test_cs_securitygroup/tasks/main.yml
Normal file
58
test/integration/roles/test_cs_securitygroup/tasks/main.yml
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
- name: setup
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
|
||||
register: sg
|
||||
- name: verify setup
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
|
||||
- name: test fail if missing name
|
||||
action: cs_securitygroup
|
||||
register: sg
|
||||
ignore_errors: true
|
||||
- name: verify results of fail if missing name
|
||||
assert:
|
||||
that:
|
||||
- sg|failed
|
||||
- sg.msg == "missing required arguments: name"
|
||||
|
||||
- name: test present security group
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}_sg
|
||||
register: sg
|
||||
- name: verify results of create security group
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
- sg|changed
|
||||
- sg.name == "{{ cs_resource_prefix }}_sg"
|
||||
|
||||
- name: test present security group is idempotence
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}_sg
|
||||
register: sg
|
||||
- name: verify results present security group is idempotence
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
- not sg|changed
|
||||
- sg.name == "{{ cs_resource_prefix }}_sg"
|
||||
|
||||
- name: test absent security group
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
|
||||
register: sg
|
||||
- name: verify results of absent security group
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
- sg|changed
|
||||
- sg.name == "{{ cs_resource_prefix }}_sg"
|
||||
|
||||
- name: test absent security group is idempotence
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
|
||||
register: sg
|
||||
- name: verify results of absent security group is idempotence
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
- not sg|changed
|
||||
- sg.name is undefined
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- test_cs_common
|
|
@ -0,0 +1,105 @@
|
|||
- name: test remove http range rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
start_port: 8000
|
||||
end_port: 8888
|
||||
cidr: 1.2.3.4/32
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify create http range rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- sg_rule|changed
|
||||
- sg_rule.type == 'ingress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.protocol == 'tcp'
|
||||
- sg_rule.start_port == 8000
|
||||
- sg_rule.end_port == 8888
|
||||
- sg_rule.cidr == '1.2.3.4/32'
|
||||
|
||||
- name: test remove http range rule idempotence
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
start_port: 8000
|
||||
end_port: 8888
|
||||
cidr: 1.2.3.4/32
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify create http range rule idempotence
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- not sg_rule|changed
|
||||
|
||||
- name: test remove single port udp rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
port: 5353
|
||||
protocol: udp
|
||||
type: egress
|
||||
user_security_group: '{{ cs_resource_prefix }}_sg'
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify remove single port udp rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- sg_rule|changed
|
||||
- sg_rule.type == 'egress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.protocol == 'udp'
|
||||
- sg_rule.start_port == 5353
|
||||
- sg_rule.end_port == 5353
|
||||
- sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg'
|
||||
|
||||
- name: test remove single port udp rule idempotence
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
port: 5353
|
||||
protocol: udp
|
||||
type: egress
|
||||
user_security_group: '{{ cs_resource_prefix }}_sg'
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify remove single port udp rule idempotence
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- not sg_rule|changed
|
||||
|
||||
- name: test remove icmp rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
protocol: icmp
|
||||
type: ingress
|
||||
icmp_type: -1
|
||||
icmp_code: -1
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify icmp rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- sg_rule|changed
|
||||
- sg_rule.type == 'ingress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.cidr == '0.0.0.0/0'
|
||||
- sg_rule.protocol == 'icmp'
|
||||
- sg_rule.icmp_code == -1
|
||||
- sg_rule.icmp_type == -1
|
||||
|
||||
- name: test remove icmp rule idempotence
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
protocol: icmp
|
||||
type: ingress
|
||||
icmp_type: -1
|
||||
icmp_code: -1
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify icmp rule idempotence
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- not sg_rule|changed
|
|
@ -0,0 +1,7 @@
|
|||
- name: cleanup custom security group
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}_sg state=absent
|
||||
register: sg
|
||||
- name: verify setup
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
|
@ -0,0 +1,4 @@
|
|||
- include: setup.yml
|
||||
- include: present.yml
|
||||
- include: absent.yml
|
||||
- include: cleanup.yml
|
|
@ -0,0 +1,118 @@
|
|||
- name: test create http range rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
start_port: 8000
|
||||
end_port: 8888
|
||||
cidr: 1.2.3.4/32
|
||||
register: sg_rule
|
||||
- name: verify create http range rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- sg_rule|changed
|
||||
- sg_rule.type == 'ingress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.protocol == 'tcp'
|
||||
- sg_rule.start_port == 8000
|
||||
- sg_rule.end_port == 8888
|
||||
- sg_rule.cidr == '1.2.3.4/32'
|
||||
|
||||
- name: test create http range rule idempotence
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
start_port: 8000
|
||||
end_port: 8888
|
||||
cidr: 1.2.3.4/32
|
||||
register: sg_rule
|
||||
- name: verify create http range rule idempotence
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- not sg_rule|changed
|
||||
- sg_rule.type == 'ingress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.protocol == 'tcp'
|
||||
- sg_rule.start_port == 8000
|
||||
- sg_rule.end_port == 8888
|
||||
- sg_rule.cidr == '1.2.3.4/32'
|
||||
|
||||
- name: test create single port udp rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
port: 5353
|
||||
protocol: udp
|
||||
type: egress
|
||||
user_security_group: '{{ cs_resource_prefix }}_sg'
|
||||
register: sg_rule
|
||||
- name: verify create single port udp rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- sg_rule|changed
|
||||
- sg_rule.type == 'egress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.protocol == 'udp'
|
||||
- sg_rule.start_port == 5353
|
||||
- sg_rule.end_port == 5353
|
||||
- sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg'
|
||||
|
||||
|
||||
- name: test single port udp rule idempotence
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
port: 5353
|
||||
protocol: udp
|
||||
type: egress
|
||||
user_security_group: '{{ cs_resource_prefix }}_sg'
|
||||
register: sg_rule
|
||||
- name: verify single port udp rule idempotence
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- not sg_rule|changed
|
||||
- sg_rule.type == 'egress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.protocol == 'udp'
|
||||
- sg_rule.start_port == 5353
|
||||
- sg_rule.end_port == 5353
|
||||
- sg_rule.user_security_group == '{{ cs_resource_prefix }}_sg'
|
||||
|
||||
- name: test icmp rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
protocol: icmp
|
||||
type: ingress
|
||||
icmp_type: -1
|
||||
icmp_code: -1
|
||||
register: sg_rule
|
||||
- name: verify icmp rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- sg_rule|changed
|
||||
- sg_rule.type == 'ingress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.cidr == '0.0.0.0/0'
|
||||
- sg_rule.protocol == 'icmp'
|
||||
- sg_rule.icmp_code == -1
|
||||
- sg_rule.icmp_type == -1
|
||||
|
||||
- name: test icmp rule idempotence
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
protocol: icmp
|
||||
type: ingress
|
||||
icmp_type: -1
|
||||
icmp_code: -1
|
||||
register: sg_rule
|
||||
- name: verify icmp rule idempotence
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
- not sg_rule|changed
|
||||
- sg_rule.type == 'ingress'
|
||||
- sg_rule.security_group == 'default'
|
||||
- sg_rule.cidr == '0.0.0.0/0'
|
||||
- sg_rule.protocol == 'icmp'
|
||||
- sg_rule.icmp_code == -1
|
||||
- sg_rule.icmp_type == -1
|
|
@ -0,0 +1,56 @@
|
|||
- name: setup custom security group
|
||||
cs_securitygroup: name={{ cs_resource_prefix }}_sg
|
||||
register: sg
|
||||
- name: verify setup
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
|
||||
- name: setup default security group
|
||||
cs_securitygroup: name=default
|
||||
register: sg
|
||||
- name: verify setup
|
||||
assert:
|
||||
that:
|
||||
- sg|success
|
||||
|
||||
- name: setup remove icmp rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
protocol: icmp
|
||||
type: ingress
|
||||
icmp_type: -1
|
||||
icmp_code: -1
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify remove icmp rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
|
||||
- name: setup remove http range rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
start_port: 8000
|
||||
end_port: 8888
|
||||
cidr: 1.2.3.4/32
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify remove http range rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
||||
|
||||
- name: setup remove single port udp rule
|
||||
cs_securitygroup_rule:
|
||||
security_group: default
|
||||
port: 5353
|
||||
protocol: udp
|
||||
type: egress
|
||||
user_security_group: '{{ cs_resource_prefix }}-user-sg'
|
||||
state: absent
|
||||
register: sg_rule
|
||||
- name: verify remove single port udp rule
|
||||
assert:
|
||||
that:
|
||||
- sg_rule|success
|
3
test/integration/roles/test_cs_sshkeypair/meta/main.yml
Normal file
3
test/integration/roles/test_cs_sshkeypair/meta/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- test_cs_common
|
89
test/integration/roles/test_cs_sshkeypair/tasks/main.yml
Normal file
89
test/integration/roles/test_cs_sshkeypair/tasks/main.yml
Normal file
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
- name: setup cleanup
|
||||
cs_sshkeypair: name={{ cs_resource_prefix }}-sshkey state=absent
|
||||
|
||||
- name: test fail on missing name
|
||||
action: cs_sshkeypair
|
||||
ignore_errors: true
|
||||
register: sshkey
|
||||
- name: verify results of fail on missing name
|
||||
assert:
|
||||
that:
|
||||
- sshkey|failed
|
||||
- sshkey.msg == "missing required arguments: name"
|
||||
|
||||
- name: test ssh key creation
|
||||
cs_sshkeypair: name={{ cs_resource_prefix }}-sshkey
|
||||
register: sshkey
|
||||
- name: verify results of ssh key creation
|
||||
assert:
|
||||
that:
|
||||
- sshkey|success
|
||||
- sshkey|changed
|
||||
- sshkey.fingerprint is defined and sshkey.fingerprint != ""
|
||||
- sshkey.private_key is defined and sshkey.private_key != ""
|
||||
- sshkey.name == "{{ cs_resource_prefix }}-sshkey"
|
||||
|
||||
- name: test ssh key creation idempotence
|
||||
cs_sshkeypair: name={{ cs_resource_prefix }}-sshkey
|
||||
register: sshkey2
|
||||
- name: verify results of ssh key creation idempotence
|
||||
assert:
|
||||
that:
|
||||
- sshkey2|success
|
||||
- not sshkey2|changed
|
||||
- sshkey2.fingerprint is defined and sshkey2.fingerprint == sshkey.fingerprint
|
||||
- sshkey2.private_key is not defined
|
||||
- sshkey2.name == "{{ cs_resource_prefix }}-sshkey"
|
||||
|
||||
- name: test replace ssh public key
|
||||
cs_sshkeypair: |
|
||||
name={{ cs_resource_prefix }}-sshkey
|
||||
public_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
|
||||
register: sshkey3
|
||||
- name: verify results of replace ssh public key
|
||||
assert:
|
||||
that:
|
||||
- sshkey3|success
|
||||
- sshkey3|changed
|
||||
- sshkey3.fingerprint is defined and sshkey3.fingerprint != sshkey2.fingerprint
|
||||
- sshkey3.private_key is not defined
|
||||
- sshkey3.name == "{{ cs_resource_prefix }}-sshkey"
|
||||
|
||||
- name: test replace ssh public key idempotence
|
||||
cs_sshkeypair: |
|
||||
name={{ cs_resource_prefix }}-sshkey
|
||||
public_key="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
|
||||
register: sshkey4
|
||||
- name: verify results of ssh public key idempotence
|
||||
assert:
|
||||
that:
|
||||
- sshkey4|success
|
||||
- not sshkey4|changed
|
||||
- sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
|
||||
- sshkey4.private_key is not defined
|
||||
- sshkey4.name == "{{ cs_resource_prefix }}-sshkey"
|
||||
|
||||
- name: test ssh key absent
|
||||
cs_sshkeypair: name={{ cs_resource_prefix }}-sshkey state=absent
|
||||
register: sshkey5
|
||||
- name: verify result of key absent
|
||||
assert:
|
||||
that:
|
||||
- sshkey5|success
|
||||
- sshkey5|changed
|
||||
- sshkey5.fingerprint is defined and sshkey5.fingerprint == sshkey3.fingerprint
|
||||
- sshkey5.private_key is not defined
|
||||
- sshkey5.name == "{{ cs_resource_prefix }}-sshkey"
|
||||
|
||||
- name: test ssh key absent idempotence
|
||||
cs_sshkeypair: name={{ cs_resource_prefix }}-sshkey state=absent
|
||||
register: sshkey6
|
||||
- name: verify result of ssh key absent idempotence
|
||||
assert:
|
||||
that:
|
||||
- sshkey6|success
|
||||
- not sshkey6|changed
|
||||
- sshkey6.fingerprint is not defined
|
||||
- sshkey6.private_key is not defined
|
||||
- sshkey6.name is not defined
|
|
@ -355,4 +355,22 @@
|
|||
that:
|
||||
- "result.stat.checksum == '73b271c2cc1cef5663713bc0f00444b4bf9f4543'"
|
||||
|
||||
- name: insert a line into the quoted file with many double quotation strings
|
||||
lineinfile: dest={{output_dir}}/test_quoting.txt line="\"quote\" and \"unquote\""
|
||||
register: result
|
||||
|
||||
- name: assert that the quoted file was changed
|
||||
assert:
|
||||
that:
|
||||
- result.changed
|
||||
|
||||
- name: stat the quote test file
|
||||
stat: path={{output_dir}}/test_quoting.txt
|
||||
register: result
|
||||
|
||||
- name: assert test checksum matches after backref line was replaced
|
||||
assert:
|
||||
that:
|
||||
- "result.stat.checksum == 'b10ab2a3c3b6492680c8d0b1d6f35aa6b8f9e731'"
|
||||
|
||||
###################################################################
|
||||
|
|
Loading…
Reference in a new issue