openstack-ansible/playbooks/library/glance
Ian Cordasco c1fdbab4de Upgrade the Keystone library to use v3
In order to enable and deploy federated Keystone, we need to use version
3 of the Keystone API and the v3 Keystone Client. This work begins that
transition by having a set of backwards compatible library commands.

Specifically, this commit updates the keystone library to use v3
Keystone Client and the usage of ensure_tenant in the os_keystone tasks
to use the v3 admin url.

In version 3 of Keystone's Endpoints (Catalog) API each endpoint only
has one URL and has separate interface types (public, internal, admin).
This change updates all uses of ensure_endpoint to structure the
endpoint data in a better way for the ensure_endpoint command in the
keystone module. As a result, some incidents where internalurl and
adminurl were swapped have been fixed.

Note:
In new deployments the endpoints will be created using the v3 API and
will therefore not be available via the v2 API. This will be a breaking
change to legacy CLI clients. The openstack CLI should be used instead.

DocImpact
Related-Bug: #1470635
Partially-implements: blueprint keystone-federation
Change-Id: I2cd4f505e850b4b113452abc25ee00d486b1637d
2015-07-13 19:41:44 -07:00

234 lines
7.3 KiB
Python

#!/usr/bin/env python
# Copyright 2014, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
DOCUMENTATION = """
---
module: glance
short_description:
- Basic module for interacting with openstack glance
description:
- Basic module for interacting with openstack glance
options:
command:
description:
- Operation for the module to perform. Currently available
choices:
- image-list
- image-create
openrc_path:
decription:
- Path to openrc file from which credentials and keystoneclient
- endpoint will be extracted
image_name:
description:
- Name of the image to create
image_url:
description:
- URL from which to download the image data
image_container_format:
description:
- container format that the image uses (bare)
image_disk_format:
description:
- disk format that the image uses
image_is_public:
description:
- Should the image be visible to all tenants?
choices:
- true (public)
- false (private)
api_version:
description:
- which version of the glance api to use
choices:
- 1
- 2
default: 1
insecure:
description:
- Explicitly allow client to perform "insecure" TLS
choices:
- false
- true
default: false
author: Hugh Saunders
"""
EXAMPLES = """
# Create an image
- name: Ensure cirros image
glance:
command: 'image-create'
openrc_path: /root/openrc
image_name: cirros
image_url: 'https://example-domain.com/cirros-0.3.2-source.tar.gz'
image_container_format: bare
image_disk_format: qcow2
image_is_public: True
# Get facts about existing images
- name: Get image facts
glance:
command: 'image-list'
openrc_path: /root/openrc
"""
import glanceclient.client as glclient
import keystoneclient.v3.client as ksclient
COMMAND_MAP = {'image-list': 'list_images',
'image-create': 'create_image'}
class ManageGlance(object):
def __init__(self, module):
self.state_change = False
self.glance = None
self.keystone = None
self.module = module
try:
self._keystone_authenticate()
self._init_glance()
except Exception as e:
self.module.fail_json(
err="Initialisation Error: %s" % e,
rc=2, msg=str(e))
def _parse_openrc(self):
"""Get credentials from an openrc file."""
openrc_path = self.module.params['openrc_path']
line_re = re.compile('^export (?P<key>OS_\w*)=(?P<value>[^\n]*)')
with open(openrc_path) as openrc:
matches = [line_re.match(l) for l in openrc]
return dict(
(g.groupdict()['key'], g.groupdict()['value'])
for g in matches if g
)
def _keystone_authenticate(self):
"""Authenticate with Keystone."""
openrc = self._parse_openrc()
insecure = self.module.params['insecure']
self.keystone = ksclient.Client(insecure=insecure,
username=openrc['OS_USERNAME'],
password=openrc['OS_PASSWORD'],
project_name=openrc['OS_PROJECT_NAME'],
auth_url=openrc['OS_AUTH_URL'])
def _init_glance(self):
"""Create glance client object using token and url from keystone."""
openrc = self._parse_openrc()
p = self.module.params
v = p['api_version']
ep = self.keystone.service_catalog.url_for(
service_type='image',
endpoint_type=openrc['OS_ENDPOINT_TYPE']
)
self.glance = glclient.Client(
endpoint='%s/v%s' % (ep, v),
token=self.keystone.get_token(self.keystone.session)
)
def route(self):
"""Run the command specified by the command parameter."""
getattr(self, COMMAND_MAP[self.module.params['command']])()
def _get_image_facts(self):
"""Helper function to format image list as a dictionary."""
p = self.module.params
v = p['api_version']
if v == '1':
return dict(
(i.name, i.to_dict()) for i in self.glance.images.list()
)
elif v == '2':
return dict(
(i.name, i) for i in self.glance.images.list()
)
def list_images(self):
"""Get information about available glance images.
Returns as a fact dictionary glance_images
"""
self.module.exit_json(
changed=self.state_change,
ansible_facts=dict(glance_images=self._get_image_facts()))
def create_image(self):
"""Create a glance image that references a remote url."""
p = self.module.params
v = p['api_version']
image_name = p['image_name']
image_opts = dict(
name=image_name,
disk_format=p['image_disk_format'],
container_format=p['image_container_format'],
copy_from=p['image_url']
)
if v == '1':
image_opts['is_public'] = p['image_is_public']
elif v == '2':
if p['image_is_public']:
vis = 'public'
else:
vis = 'private'
image_opts['visibility'] = vis
images = {i.name for i in self.glance.images.list()}
if image_name in images:
self.module.exit_json(
changed=self.state_change,
ansible_facts=dict(
glance_images=self._get_image_facts()
)
)
else:
self.glance.images.create(**image_opts)
self.state_change = True
self.module.exit_json(
changed=self.state_change,
ansible_facts=dict(
glance_images=self._get_image_facts()
)
)
def main():
module = AnsibleModule(
argument_spec=dict(
command=dict(required=True, choices=COMMAND_MAP.keys()),
openrc_path=dict(required=True),
image_name=dict(required=False),
image_url=dict(required=False),
image_container_format=dict(required=False),
image_disk_format=dict(required=False),
image_is_public=dict(required=False, choices=BOOLEANS),
api_version=dict(default='1', required=False, choices=['1', '2']),
insecure=dict(default=False, required=False,
choices=BOOLEANS + ['True', 'False'])
),
supports_check_mode=False
)
mg = ManageGlance(module)
mg.route()
from ansible.module_utils.basic import *
if __name__ == '__main__':
main()