Add GCE guide and retool a bit to show the add_host interactions, improvements/upgrades are welcome.
Had to shoot the recently merged nova_group module in the head temporarily as it contained a dict comprehension, which means it can't work on all the platforms and was also breaking docs builds on CentOS. Will engage with list about that shortly.
This commit is contained in:
parent
e9f6496582
commit
6b43e6cd50
1 changed files with 0 additions and 343 deletions
343
cloud/nova_group
343
cloud/nova_group
|
@ -1,343 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, John Dewey <john@dewey.ws>
|
||||
#
|
||||
# This module 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.
|
||||
#
|
||||
# This software 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 this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import locale
|
||||
import os
|
||||
import six
|
||||
|
||||
try:
|
||||
from novaclient.openstack.common import uuidutils
|
||||
from novaclient.openstack.common import strutils
|
||||
from novaclient.v1_1 import client
|
||||
from novaclient.v1_1 import security_groups
|
||||
from novaclient.v1_1 import security_group_rules
|
||||
from novaclient import exceptions
|
||||
except ImportError:
|
||||
print("failed=True msg='novaclient is required for this module to work'")
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: security_group
|
||||
version_added: "1.6"
|
||||
short_description: Maintain nova security groups.
|
||||
description:
|
||||
- Manage nova security groups using the python-novaclient library.
|
||||
options:
|
||||
|
||||
login_username:
|
||||
description:
|
||||
- Login username to authenticate to keystone. If not set then the value of the OS_USERNAME environment variable is used.
|
||||
required: false
|
||||
default: None
|
||||
login_password:
|
||||
description:
|
||||
- Password of login user. If not set then the value of the OS_PASSWORD environment variable is used.
|
||||
required: false
|
||||
default: None
|
||||
login_tenant_name:
|
||||
description:
|
||||
- The tenant name of the login user. If not set then the value of the OS_TENANT_NAME environment variable is used.
|
||||
required: false
|
||||
default: None
|
||||
auth_url:
|
||||
description:
|
||||
- The keystone url for authentication. If not set then the value of the OS_AUTH_URL environment variable is used.
|
||||
required: false
|
||||
default: None
|
||||
region_name:
|
||||
description:
|
||||
- Name of the region.
|
||||
required: false
|
||||
default: None
|
||||
name:
|
||||
description:
|
||||
- Name of the security group.
|
||||
required: true
|
||||
description:
|
||||
description:
|
||||
- Description of the security group.
|
||||
required: true
|
||||
rules:
|
||||
description:
|
||||
- List of firewall rules to enforce in this group (see example).
|
||||
Must specify either an IPv4 'cidr' address or 'group' UUID.
|
||||
required: true
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the resource.
|
||||
choices: ['present', 'absent']
|
||||
required: false
|
||||
default: 'present'
|
||||
|
||||
requirements: ["novaclient"]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: create example group and rules
|
||||
local_action:
|
||||
module: security_group
|
||||
name: example
|
||||
description: an example nova group
|
||||
rules:
|
||||
- ip_protocol: tcp
|
||||
from_port: 80
|
||||
to_port: 80
|
||||
cidr: 0.0.0.0/0
|
||||
- ip_protocol: tcp
|
||||
from_port: 3306
|
||||
to_port: 3306
|
||||
group: "{{ group_uuid }}"
|
||||
- ip_protocol: icmp
|
||||
from_port: -1
|
||||
to_port: -1
|
||||
cidr: 0.0.0.0/0
|
||||
|
||||
- name: delete rule from example group
|
||||
local_action:
|
||||
module: security_group
|
||||
name: example
|
||||
description: an example nova group
|
||||
rules:
|
||||
- ip_protocol: tcp
|
||||
from_port: 80
|
||||
to_port: 80
|
||||
cidr: 0.0.0.0/0
|
||||
- ip_protocol: icmp
|
||||
from_port: -1
|
||||
to_port: -1
|
||||
cidr: 0.0.0.0/0
|
||||
state: absent
|
||||
'''
|
||||
|
||||
class NovaGroup(object):
|
||||
def __init__(self, client):
|
||||
self._sg = security_groups.SecurityGroupManager(client)
|
||||
|
||||
# Taken from novaclient/v1_1/shell.py.
|
||||
def _get_secgroup(self, secgroup):
|
||||
# Check secgroup is an UUID
|
||||
if uuidutils.is_uuid_like(strutils.safe_encode(secgroup)):
|
||||
try:
|
||||
sg = self._sg.get(secgroup)
|
||||
return sg
|
||||
except exceptions.NotFound:
|
||||
return False
|
||||
|
||||
# Check secgroup as a name
|
||||
for s in self._sg.list():
|
||||
encoding = (locale.getpreferredencoding() or
|
||||
sys.stdin.encoding or
|
||||
'UTF-8')
|
||||
if not six.PY3:
|
||||
s.name = s.name.encode(encoding)
|
||||
if secgroup == s.name:
|
||||
return s
|
||||
return False
|
||||
|
||||
|
||||
class SecurityGroup(NovaGroup):
|
||||
def __init__(self, client, module):
|
||||
super(SecurityGroup, self).__init__(client)
|
||||
self._module = module
|
||||
self._name = module.params.get('name')
|
||||
self._description = module.params.get('description')
|
||||
|
||||
def get(self):
|
||||
return self._get_secgroup(self._name)
|
||||
|
||||
def create(self):
|
||||
return self._sg.create(self._name, self._description)
|
||||
|
||||
def delete(self):
|
||||
return self._sg.delete(self._name)
|
||||
|
||||
|
||||
class SecurityGroupRule(NovaGroup):
|
||||
def __init__(self, client, module):
|
||||
super(SecurityGroupRule, self).__init__(client)
|
||||
self._module = module
|
||||
self._name = module.params.get('name')
|
||||
self._rules = module.params.get('rules')
|
||||
self._validate_rules()
|
||||
self._sgr = security_group_rules.SecurityGroupRuleManager(client)
|
||||
self._secgroup = self._get_secgroup(self._name)
|
||||
self._current_rules = self._lookup_dict(self._secgroup.rules)
|
||||
|
||||
def _concat_security_group_rule(self, rule):
|
||||
"""
|
||||
Normalize the given rule into a string in the format of:
|
||||
protocol-from_port-to_port-group
|
||||
The `group` needs a bit of massaging.
|
||||
1. If an empty dict -- return None.
|
||||
2. If a dict -- lookup group UUID (novaclient only returns the name).
|
||||
3. Return `group` from rules dict.
|
||||
|
||||
:param rule: A novaclient SecurityGroupRule object.
|
||||
"""
|
||||
group = rule.get('group')
|
||||
# Oddly novaclient occasionaly returns None as {}.
|
||||
if group is not None and not any(group):
|
||||
group = None
|
||||
elif type(group) == dict:
|
||||
g = group.get('name')
|
||||
group = self._get_secgroup(g)
|
||||
r = "%s-%s-%s-%s" % (rule.get('ip_protocol'),
|
||||
rule.get('from_port'),
|
||||
rule.get('to_port'),
|
||||
group)
|
||||
return r
|
||||
|
||||
def _lookup_dict(self, rules):
|
||||
"""
|
||||
Populate a dict with current rules.
|
||||
|
||||
:param rule: A novaclient SecurityGroupRule object.
|
||||
"""
|
||||
return {self._concat_security_group_rule(rule): rule for rule in rules}
|
||||
|
||||
def _get_rule(self, rule):
|
||||
"""
|
||||
Return rule when found and False when not.
|
||||
|
||||
:param rule: A novaclient SecurityGroupRule object.
|
||||
"""
|
||||
r = self._concat_security_group_rule(rule)
|
||||
if r in self._current_rules:
|
||||
return self._current_rules[r]
|
||||
|
||||
def _validate_rules(self):
|
||||
for rule in self._rules:
|
||||
if 'group' in rule and 'cidr' in rule:
|
||||
self._module.fail_json(msg="Specify group OR cidr")
|
||||
|
||||
def create(self):
|
||||
changed = False
|
||||
filtered = [rule for rule in self._rules
|
||||
if rule.get('state') != 'absent']
|
||||
for rule in filtered:
|
||||
if not self._get_rule(rule):
|
||||
if 'cidr' in rule:
|
||||
self._sgr.create(self._secgroup.id,
|
||||
rule.get('ip_protocol'),
|
||||
rule.get('from_port'),
|
||||
rule.get('to_port'),
|
||||
cidr=rule.get('cidr'))
|
||||
changed = True
|
||||
if 'group' in rule:
|
||||
self._sgr.create(self._secgroup.id,
|
||||
rule.get('ip_protocol'),
|
||||
rule.get('from_port'),
|
||||
rule.get('to_port'),
|
||||
group_id=rule.get('group'))
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
def delete(self):
|
||||
changed = False
|
||||
filtered = [rule for rule in self._rules
|
||||
if rule.get('state') == 'absent']
|
||||
for rule in filtered:
|
||||
r = self._get_rule(rule)
|
||||
if r:
|
||||
self._sgr.delete(r.get('id'))
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
def update(self):
|
||||
changed = False
|
||||
if self.create():
|
||||
changed = True
|
||||
if self.delete():
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
name=dict(required=True),
|
||||
description=dict(required=True),
|
||||
rules=dict(),
|
||||
login_username=dict(),
|
||||
login_password=dict(no_log=True),
|
||||
login_tenant_name=dict(),
|
||||
auth_url= dict(),
|
||||
region_name=dict(default=None),
|
||||
state = dict(default='present', choices=['present', 'absent']),
|
||||
),
|
||||
supports_check_mode=False,
|
||||
)
|
||||
login_username = module.params.get('login_username')
|
||||
login_password = module.params.get('login_password')
|
||||
login_tenant_name = module.params.get('login_tenant_name')
|
||||
auth_url = module.params.get('auth_url')
|
||||
|
||||
# allow stackrc environment variables to be used if ansible vars aren't set
|
||||
if not login_username and 'OS_USERNAME' in os.environ:
|
||||
login_username = os.environ['OS_USERNAME']
|
||||
|
||||
if not login_password and 'OS_PASSWORD' in os.environ:
|
||||
login_password = os.environ['OS_PASSWORD']
|
||||
|
||||
if not login_tenant_name and 'OS_TENANT_NAME' in os.environ:
|
||||
login_tenant_name = os.environ['OS_TENANT_NAME']
|
||||
|
||||
if not auth_url and 'OS_AUTH_URL' in os.environ:
|
||||
auth_url = os.environ['OS_AUTH_URL']
|
||||
|
||||
nova = client.Client(login_username,
|
||||
login_password,
|
||||
login_tenant_name,
|
||||
auth_url,
|
||||
service_type='compute')
|
||||
try:
|
||||
nova.authenticate()
|
||||
except exceptions.Unauthorized as e:
|
||||
module.fail_json(msg="Invalid OpenStack Nova credentials.: %s" % e.message)
|
||||
except exceptions.AuthorizationFailure as e:
|
||||
module.fail_json(msg="Unable to authorize user: %s" % e.message)
|
||||
|
||||
rules = module.params.get('rules')
|
||||
state = module.params.get('state')
|
||||
security_group = SecurityGroup(nova, module)
|
||||
|
||||
changed = False
|
||||
group_id = None
|
||||
group = security_group.get()
|
||||
if group:
|
||||
group_id = group.id
|
||||
if state == 'absent':
|
||||
security_group.delete()
|
||||
changed = True
|
||||
elif state == 'present':
|
||||
group = security_group.create()
|
||||
changed = True
|
||||
group_id = group.id
|
||||
|
||||
if rules is not None:
|
||||
security_group_rules = SecurityGroupRule(nova, module)
|
||||
if security_group_rules.update():
|
||||
changed = True
|
||||
|
||||
module.exit_json(changed=changed, group_id=group_id)
|
||||
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
main()
|
Loading…
Reference in a new issue