From d26f4d1184b02566fc71b5fd6b86dbc7044043f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Ole=C5=9B?= Date: Mon, 1 Jun 2015 00:34:33 +0000 Subject: [PATCH] Keystone related resources --- example.py | 29 +- library/keystone_service.py | 311 ++++++++++++++++++ resources/keystone_role/actions/remove.yml | 5 + resources/keystone_role/actions/run.yml | 5 + resources/keystone_role/meta.yaml | 33 ++ resources/keystone_service/meta.yaml | 2 +- .../actions/remove.yaml | 1 + .../actions/run.yaml | 19 ++ resources/keystone_service_endpoint/meta.yaml | 49 +++ resources/keystone_tenant/actions/remove.yml | 5 + resources/keystone_tenant/actions/run.yml | 5 + resources/keystone_tenant/meta.yaml | 27 ++ resources/keystone_user/actions/remove.yml | 3 +- resources/keystone_user/actions/run.yml | 3 +- resources/keystone_user/meta.yaml | 5 +- 15 files changed, 492 insertions(+), 10 deletions(-) create mode 100644 library/keystone_service.py create mode 100644 resources/keystone_role/actions/remove.yml create mode 100644 resources/keystone_role/actions/run.yml create mode 100644 resources/keystone_role/meta.yaml create mode 100644 resources/keystone_service_endpoint/actions/remove.yaml create mode 100644 resources/keystone_service_endpoint/actions/run.yaml create mode 100644 resources/keystone_service_endpoint/meta.yaml create mode 100644 resources/keystone_tenant/actions/remove.yml create mode 100644 resources/keystone_tenant/actions/run.yml create mode 100644 resources/keystone_tenant/meta.yaml diff --git a/example.py b/example.py index 5dd392bc..036be505 100644 --- a/example.py +++ b/example.py @@ -41,6 +41,11 @@ def deploy(): haproxy_config = resource.create('haproxy_config', 'resources/haproxy', {'ip': '', 'ssh_key': '', 'ssh_user': '', 'configs_names':[], 'configs_ports':[], 'listen_ports':[], 'configs':[], 'config_dir': ''}) haproxy_service = resource.create('haproxy_service', 'resources/docker_container/', {'image': 'tutum/haproxy', 'ports': [], 'host_binds': [], 'volume_binds':[], 'ip': '', 'ssh_key': '', 'ssh_user': ''}) + admin_tenant = resource.create('admin_tenant', 'resources/keystone_tenant', {'keystone_host': '', 'keystone_port':'', 'login_user': 'admin', 'admin_token':'', 'tenant_name' : 'admin', 'ip': '', 'ssh_user': '', 'ssh_key': ''}) + admin_user = resource.create('admin_user', 'resources/keystone_user', {'keystone_host': '', 'keystone_port':'', 'login_user': 'admin', 'admin_token':'', 'tenant_name' : '', 'user_name': 'admin', 'user_password':'admin', 'ip': '', 'ssh_user': '', 'ssh_key': ''}) + admin_role = resource.create('admin_role', 'resources/keystone_role', {'keystone_host': '', 'keystone_port':'', 'login_user': 'admin', 'admin_token':'', 'tenant_name' : '', 'user_name': '', 'role_name': 'admin', 'ip': '', 'ssh_user': '', 'ssh_key': ''}) + keystone_service_endpoint = resource.create('keystone_service_endpoint', 'resources/keystone_service_endpoint/', {'ip':'', 'ssh_key' : '', 'ssh_user':'', 'admin_port':'', 'admin_token':'', 'adminurl':'http://{{ip}}:{{admin_port}}/v2.0', 'internalurl':'http://{{ip}}:{{port}}/v2.0', 'publicurl':'http://{{ip}}:{{port}}/v2.0', 'description':'OpenStack Identity Service', 'keystone_host':'', 'keystone_port':'', 'name':'keystone', 'port':'', 'type':'identity'}) + #### # connections @@ -81,6 +86,15 @@ def deploy(): signals.connect(node2, haproxy_service) signals.connect(haproxy_config, haproxy_service, {'listen_ports': 'ports', 'config_dir': 'host_binds'}) + #keystone configuration + signals.connect(keystone_config1, admin_tenant) + signals.connect(keystone_service1, admin_tenant, {'admin_port': 'keystone_port', 'ip': 'keystone_host'}) + signals.connect(admin_tenant, admin_user) + signals.connect(admin_user, admin_role) + signals.connect(keystone_config1, keystone_service_endpoint) + signals.connect(keystone_service1, keystone_service_endpoint, {'ip': 'keystone_host','admin_port':'admin_port', 'port':'port'}) + signals.connect(keystone_service1, keystone_service_endpoint, {'admin_port': 'keystone_port'}) + has_errors = False for r in [node1, @@ -94,7 +108,11 @@ def deploy(): keystone_service2, haproxy_keystone_config, haproxy_config, - haproxy_service]: + haproxy_service, + admin_tenant, + admin_user, + admin_role, + keystone_service_endpoint]: errors = validation.validate_resource(r) if errors: has_errors = True @@ -115,7 +133,12 @@ def deploy(): actions.resource_action(keystone_service2, 'run') actions.resource_action(haproxy_config, 'run') actions.resource_action(haproxy_service, 'run') + time.sleep(10) #TODO fix haproxy to wait until it's ready + actions.resource_action(admin_tenant, 'run') + actions.resource_action(admin_user, 'run') + actions.resource_action(admin_role, 'run') + actions.resource_action(keystone_service_endpoint, 'run') # test working configuration requests.get('http://%s:%s' % (keystone_service1.args['ip'].value, keystone_service1.args['port'].value)) @@ -132,6 +155,10 @@ def undeploy(): resources = map(resource.wrap_resource, db.get_list('resource')) resources = {r.name: r for r in resources} + actions.resource_action(resources['keystone_service_endpoint'], 'remove') + actions.resource_action(resources['admin_role'], 'remove') + actions.resource_action(resources['admin_user'], 'remove') + actions.resource_action(resources['admin_tenant'], 'remove') actions.resource_action(resources['haproxy_service'], 'remove') actions.resource_action(resources['haproxy_config'], 'remove') actions.resource_action(resources['keystone_service2'], 'remove') diff --git a/library/keystone_service.py b/library/keystone_service.py new file mode 100644 index 00000000..f1278673 --- /dev/null +++ b/library/keystone_service.py @@ -0,0 +1,311 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copied from: https://github.com/openstack-ansible/openstack-ansible-modules/blob/master/keystone_service + +DOCUMENTATION = ''' +--- +module: keystone_service +short_description: Manage OpenStack Identity (keystone) service endpoints +options: + name: + description: + - name of service (e.g., keystone) + required: yes + type: + description: + - type of service (e.g., identity) + required: yes + description: + description: + - description of service (e.g., Identity Service) + required: yes + public_url: + description: + - public url of service. + - 'Alias: I(url)' + - 'Alias: I(publicurl)' + required: yes + internal_url: + description: + - internal url of service. + - 'Alias: I(internalurl)' + required: no + default: value of public_url + admin_url: + description: + - admin url of service. + - 'Alias: I(adminurl)' + required: no + default: value of public_url + insecure: + description: + - allow use of self-signed SSL certificates + required: no + choices: [ "yes", "no" ] + region: + description: + - region of service + required: yes + state: + description: + - Indicate desired state of the resource + choices: ['present', 'absent'] + default: present + + + +requirements: [ python-keystoneclient ] +author: Lorin Hochstein +''' + +EXAMPLES = ''' +examples: +keystone_service: > + name=keystone + type=identity + description="Keystone Identity Service" + publicurl=http://192.168.206.130:5000/v2.0 + internalurl=http://192.168.206.130:5000/v2.0 + adminurl=http://192.168.206.130:35357/v2.0 + +keystone_service: > + name=glance + type=image + description="Glance Identity Service" + url=http://192.168.206.130:9292 + +''' + +try: + from keystoneclient.v2_0 import client +except ImportError: + keystoneclient_found = False +else: + keystoneclient_found = True + +import traceback + + +def authenticate(endpoint, token, login_user, login_password, tenant_name, + insecure): + """Return a keystone client object""" + + if token: + return client.Client(endpoint=endpoint, token=token, insecure=insecure) + else: + return client.Client(auth_url=endpoint, username=login_user, + password=login_password, tenant_name=tenant_name, + insecure=insecure) + +def get_service(keystone, name): + """ Retrieve a service by name """ + services = [x for x in keystone.services.list() if x.name == name] + count = len(services) + if count == 0: + raise KeyError("No keystone services with name %s" % name) + elif count > 1: + raise ValueError("%d services with name %s" % (count, name)) + else: + return services[0] + + +def get_endpoint(keystone, name): + """ Retrieve a service endpoint by name """ + service = get_service(keystone, name) + endpoints = [x for x in keystone.endpoints.list() + if x.service_id == service.id] + count = len(endpoints) + if count == 0: + raise KeyError("No keystone endpoints with service name %s" % name) + elif count > 1: + raise ValueError("%d endpoints with service name %s" % (count, name)) + else: + return endpoints[0] + + +def ensure_service_present(keystone, name, service_type, description, + check_mode): + """ Ensure the service is present and has the right values + + Returns a pair, where the first element is a boolean that indicates + a state change, and the second element is the service uuid, or None + if running in check mode""" + service = None + try: + service = get_service(keystone, name) + except: + # Service doesn't exist yet, we'll need to create one + pass + else: + # See if it matches exactly + if service.name == name and \ + service.type == service_type and \ + service.description == description: + + # Same, no changes needed + return (False, service.id) + + # At this point, we know we will need to make a change + if check_mode: + return (True, None) + + if service is None: + service = keystone.services.create(name=name, + service_type=service_type, + description=description) + return (True, service.id) + else: + msg = "keystone v2 API doesn't support updating services" + raise ValueError(msg) + + +def ensure_endpoint_present(keystone, name, public_url, internal_url, + admin_url, region, check_mode): + """ Ensure the service endpoint is present and have the right values + + Assumes the service object has already been created at this point""" + + service = get_service(keystone, name) + endpoint = None + try: + endpoint = get_endpoint(keystone, name) + except: + # Endpoint doesn't exist yet, we'll need to create one + pass + else: + # See if it matches + if endpoint.publicurl == public_url and \ + endpoint.adminurl == admin_url and \ + endpoint.internalurl == internal_url and \ + endpoint.region == region: + + # Same, no changes needed + return (False, endpoint.id) + + # At this point, we know we will need to make a change + if check_mode: + return (True, None) + + if endpoint is None: + endpoint = keystone.endpoints.create(region=region, + service_id=service.id, + publicurl=public_url, + adminurl=admin_url, + internalurl=internal_url) + return (True, endpoint.id) + else: + msg = "keystone v2 API doesn't support updating endpoints" + raise ValueError(msg) + + +def ensure_service_absent(keystone, name, check_mode): + """ Ensure the service is absent""" + + raise NotImplementedError() + +def ensure_endpoint_absent(keystone, name, check_mode): + """ Ensure the service endpoint """ + raise NotImplementedError() + + +def dispatch(keystone, name, service_type, description, public_url, + internal_url, admin_url, region, state, check_mode): + + if state == 'present': + (service_changed, service_id) = ensure_service_present(keystone, + name, + service_type, + description, + check_mode) + + (endpoint_changed, endpoint_id) = ensure_endpoint_present( + keystone, + name, + public_url, + internal_url, + admin_url, + region, + check_mode) + return dict(changed=service_changed or endpoint_changed, + service_id=service_id, + endpoint_id=endpoint_id) + elif state == 'absent': + endpoint_changed = ensure_endpoint_absent(keystone, name, check_mode) + service_changed = ensure_service_absent(keystone, name, check_mode) + return dict(changed=service_changed or endpoint_changed) + else: + raise ValueError("Code should never reach here") + + + +def main(): + + module = AnsibleModule( + argument_spec=dict( + name=dict(required=True), + type=dict(required=True), + description=dict(required=False), + public_url=dict(required=True, aliases=['url', 'publicurl']), + internal_url=dict(required=False, aliases=['internalurl']), + admin_url=dict(required=False, aliases=['adminurl']), + region=dict(required=True), + state=dict(default='present', choices=['present', 'absent']), + endpoint=dict(required=False, + default="http://127.0.0.1:35357/v2.0", + aliases=['auth_url']), + token=dict(required=False), + insecure=dict(required=False, default=False, choices=BOOLEANS), + + login_user=dict(required=False), + login_password=dict(required=False), + tenant_name=dict(required=False, aliases=['tenant']) + ), + supports_check_mode=True, + mutually_exclusive=[['token', 'login_user'], + ['token', 'login_password'], + ['token', 'tenant_name']] + ) + + endpoint = module.params['endpoint'] + token = module.params['token'] + login_user = module.params['login_user'] + login_password = module.params['login_password'] + tenant_name = module.params['tenant_name'] + insecure = module.boolean(module.params['insecure']) + name = module.params['name'] + service_type = module.params['type'] + description = module.params['description'] + public_url = module.params['public_url'] + internal_url = module.params['internal_url'] + if internal_url is None: + internal_url = public_url + admin_url = module.params['admin_url'] + if admin_url is None: + admin_url = public_url + region = module.params['region'] + state = module.params['state'] + + keystone = authenticate(endpoint, token, login_user, login_password, + tenant_name, insecure) + check_mode = module.check_mode + + try: + d = dispatch(keystone, name, service_type, description, + public_url, internal_url, admin_url, region, state, + check_mode) + except Exception: + if check_mode: + # If we have a failure in check mode + module.exit_json(changed=True, + msg="exception: %s" % traceback.format_exc()) + else: + module.fail_json(msg=traceback.format_exc()) + else: + module.exit_json(**d) + + +# this is magic, see lib/ansible/module_common.py +#<> +if __name__ == '__main__': + main() diff --git a/resources/keystone_role/actions/remove.yml b/resources/keystone_role/actions/remove.yml new file mode 100644 index 00000000..386d38ea --- /dev/null +++ b/resources/keystone_role/actions/remove.yml @@ -0,0 +1,5 @@ +- hosts: [{{ ip }}] + sudo: yes + tasks: + - name: keystone role + keystone_user: endpoint=http://{{keystone_host}}:{{keystone_port}}/v2.0/ token={{admin_token}} user={{user_name}} tenant={{tenant_name}} role={{role_name}} state=absent diff --git a/resources/keystone_role/actions/run.yml b/resources/keystone_role/actions/run.yml new file mode 100644 index 00000000..88960081 --- /dev/null +++ b/resources/keystone_role/actions/run.yml @@ -0,0 +1,5 @@ +- hosts: [{{ ip }}] + sudo: yes + tasks: + - name: keystone role + keystone_user: endpoint=http://{{keystone_host}}:{{keystone_port}}/v2.0/ token={{admin_token}} user={{user_name}} tenant={{tenant_name}} role={{role_name}} state=present diff --git a/resources/keystone_role/meta.yaml b/resources/keystone_role/meta.yaml new file mode 100644 index 00000000..1d8fe6ce --- /dev/null +++ b/resources/keystone_role/meta.yaml @@ -0,0 +1,33 @@ +id: keystone_user +handler: ansible +version: 1.0.0 +input: + keystone_host: + schema: str! + value: + keystone_port: + schema: int! + value: + admin_token: + schema: str! + value: + user_name: + schema: str! + value: + tenant_name: + schema: str! + value: + role_name: + schema: str! + value: + ip: + schema: str! + value: + ssh_key: + schema: str! + value: + ssh_user: + schema: str! + value: + +tags: [resource/keystone_user, resources/keystone] diff --git a/resources/keystone_service/meta.yaml b/resources/keystone_service/meta.yaml index be5b3892..746c2d69 100644 --- a/resources/keystone_service/meta.yaml +++ b/resources/keystone_service/meta.yaml @@ -4,7 +4,7 @@ version: 1.0.0 input: image: schema: str! - value: kollaglue/centos-rdo-keystone + value: kollaglue/centos-rdo-j-keystone config_dir: schema: str! value: /etc/solar/keystone diff --git a/resources/keystone_service_endpoint/actions/remove.yaml b/resources/keystone_service_endpoint/actions/remove.yaml new file mode 100644 index 00000000..b15fe775 --- /dev/null +++ b/resources/keystone_service_endpoint/actions/remove.yaml @@ -0,0 +1 @@ +#todo diff --git a/resources/keystone_service_endpoint/actions/run.yaml b/resources/keystone_service_endpoint/actions/run.yaml new file mode 100644 index 00000000..6fe788a8 --- /dev/null +++ b/resources/keystone_service_endpoint/actions/run.yaml @@ -0,0 +1,19 @@ +- hosts: [{{ ip }}] + sudo: yes + vars: + ip: {{ip}} + port: {{port}} + admin_port: {{admin_port}} + tasks: + - name: keystone service and endpoint + keystone_service: + token: {{admin_token}} + name: {{name}} + type: {{type}} + description: {{description}} + publicurl: {{publicurl}} + internalurl: {{internalurl}} + adminurl: {{adminurl}} + region: "RegionOne" + state: present + endpoint: http://{{keystone_host}}:{{keystone_port}}/v2.0/ diff --git a/resources/keystone_service_endpoint/meta.yaml b/resources/keystone_service_endpoint/meta.yaml new file mode 100644 index 00000000..ce0b740f --- /dev/null +++ b/resources/keystone_service_endpoint/meta.yaml @@ -0,0 +1,49 @@ +id: keystone_user +handler: ansible +version: 1.0.0 +input: + keystone_host: + schema: str! + value: + keystone_port: + schema: int! + value: + admin_token: + schema: str! + value: + port: + schema: int! + value: + admin_port: + schema: int! + value: + name: + schema: str! + value: + type: + schema: str! + value: + description: + schema: str! + value: + publicurl: + schema: str! + value: + internalurl: + schema: str! + value: + adminurl: + schema: str! + value: + ip: + schema: str! + value: + ssh_key: + schema: str! + value: + ssh_user: + schema: str! + value: + +tags: [resource/keystone_tenant, resources/keystone] + diff --git a/resources/keystone_tenant/actions/remove.yml b/resources/keystone_tenant/actions/remove.yml new file mode 100644 index 00000000..b19a2fc3 --- /dev/null +++ b/resources/keystone_tenant/actions/remove.yml @@ -0,0 +1,5 @@ +- hosts: [{{ ip }}] + sudo: yes + tasks: + - name: keystone tenant + keystone_user: endpoint=http://{{keystone_host}}:{{keystone_port}}/v2.0/ token={{admin_token}} tenant={{tenant_name}} state=absent diff --git a/resources/keystone_tenant/actions/run.yml b/resources/keystone_tenant/actions/run.yml new file mode 100644 index 00000000..5122a7d8 --- /dev/null +++ b/resources/keystone_tenant/actions/run.yml @@ -0,0 +1,5 @@ +- hosts: [{{ ip }}] + sudo: yes + tasks: + - name: keystone tenant + keystone_user: endpoint=http://{{keystone_host}}:{{keystone_port}}/v2.0/ token={{admin_token}} tenant={{tenant_name}} state=present diff --git a/resources/keystone_tenant/meta.yaml b/resources/keystone_tenant/meta.yaml new file mode 100644 index 00000000..ac7e6d6f --- /dev/null +++ b/resources/keystone_tenant/meta.yaml @@ -0,0 +1,27 @@ +id: keystone_user +handler: ansible +version: 1.0.0 +input: + keystone_host: + schema: str! + value: + keystone_port: + schema: int! + value: + admin_token: + schema: str! + value: + tenant_name: + schema: str! + value: + ip: + schema: str! + value: + ssh_key: + schema: str! + value: + ssh_user: + schema: str! + value: + +tags: [resource/keystone_tenant, resources/keystone] diff --git a/resources/keystone_user/actions/remove.yml b/resources/keystone_user/actions/remove.yml index 492749ef..a56289db 100644 --- a/resources/keystone_user/actions/remove.yml +++ b/resources/keystone_user/actions/remove.yml @@ -2,5 +2,4 @@ sudo: yes tasks: - name: keystone user - - keystone_user: endpoint=http://{keystone_host}}:{{keystone_port}}/v2.0/ user={{user_name}} tenant={{tenant_name}} state=absent - - keystone_user: endpoint=http://{keystone_host}}:{{keystone_port}}/v2.0/ tenant={{tenant_name}} state=absent + keystone_user: endpoint=http://{{keystone_host}}:{{keystone_port}}/v2.0/ token={{admin_token}} user={{user_name}} password={{user_password}} tenant={{tenant_name}} state=absent diff --git a/resources/keystone_user/actions/run.yml b/resources/keystone_user/actions/run.yml index 1a7a5469..113d01b1 100644 --- a/resources/keystone_user/actions/run.yml +++ b/resources/keystone_user/actions/run.yml @@ -2,5 +2,4 @@ sudo: yes tasks: - name: keystone user - - keystone_user: endpoint=http://{keystone_host}}:{{keystone_port}}/v2.0/ tenant={{tenant_name}} state=present - - keystone_user: endpoint=http://{keystone_host}}:{{keystone_port}}/v2.0/ user={{user_name}} password={{user_password}} tenant={{tenant_name}} state=present + keystone_user: endpoint=http://{{keystone_host}}:{{keystone_port}}/v2.0/ token={{admin_token}} user={{user_name}} password={{user_password}} tenant={{tenant_name}} state=present diff --git a/resources/keystone_user/meta.yaml b/resources/keystone_user/meta.yaml index 971469f6..edaa75d6 100644 --- a/resources/keystone_user/meta.yaml +++ b/resources/keystone_user/meta.yaml @@ -8,10 +8,7 @@ input: keystone_port: schema: int! value: - login_user: - schema: str! - value: - login_token: + admin_token: schema: str! value: user_name: