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:
Michael DeHaan 2014-03-14 15:01:07 -04:00
parent e9f6496582
commit 6b43e6cd50

View file

@ -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()