summaryrefslogtreecommitdiff
path: root/ironic/common
diff options
context:
space:
mode:
Diffstat (limited to 'ironic/common')
-rw-r--r--ironic/common/exception.py4
-rw-r--r--ironic/common/keystone.py51
-rw-r--r--ironic/common/swift.py187
3 files changed, 235 insertions, 7 deletions
diff --git a/ironic/common/exception.py b/ironic/common/exception.py
index 735f1ce1c..aeec784dc 100644
--- a/ironic/common/exception.py
+++ b/ironic/common/exception.py
@@ -445,3 +445,7 @@ class InsufficientDiskSpace(IronicException):
class ImageCreationFailed(IronicException):
message = _('Creating %(image_type)s image failed: %(error)s')
+
+
+class SwiftOperationError(IronicException):
+ message = _("Swift operation '%(operation)s' failed: %(error)s")
diff --git a/ironic/common/keystone.py b/ironic/common/keystone.py
index c197c231a..8f785ac1c 100644
--- a/ironic/common/keystone.py
+++ b/ironic/common/keystone.py
@@ -23,24 +23,61 @@ from ironic.common import exception
CONF = cfg.CONF
+def _is_apiv3(auth_url, auth_version):
+ """Checks if V3 version of API is being used or not.
+
+ This method inspects auth_url and auth_version, and checks whether V3
+ version of the API is being used or not.
+
+ :param auth_url: a http or https url to be inspected(like
+ 'http://127.0.0.1:9898/').
+ :param auth_version: a string containing the version(like 'v2', 'v3.0')
+ :returns: True if V3 of the API is being used.
+ """
+ return auth_version == 'v3.0' or '/v3' in parse.urlparse(auth_url).path
+
+
+def get_keystone_url(auth_url, auth_version):
+ """Gives an http/https url to contact keystone.
+
+ Given an auth_url and auth_version, this method generates the url in
+ which keystone can be reached.
+
+ :param auth_url: a http or https url to be inspected(like
+ 'http://127.0.0.1:9898/').
+ :param auth_version: a string containing the version(like v2, v3.0, etc)
+ :returns: a string containing the keystone url
+ """
+ api_v3 = _is_apiv3(auth_url, auth_version)
+ api_version = 'v3' if api_v3 else 'v2.0'
+ # NOTE(lucasagomes): Get rid of the trailing '/' otherwise urljoin()
+ # fails to override the version in the URL
+ return parse.urljoin(auth_url.rstrip('/'), api_version)
+
+
def get_service_url(service_type='baremetal', endpoint_type='internal'):
- """Wrapper for get service url from keystone service catalog."""
+ """Wrapper for get service url from keystone service catalog.
+
+ Given a service_type and an endpoint_type, this method queries keystone
+ service catalog and provides the url for the desired endpoint.
+
+ :param service_type: the keystone service for which url is required.
+ :param endpoint_type: the type of endpoint for the service.
+ :returns: an http/https url for the desired endpoint.
+ """
auth_url = CONF.keystone_authtoken.auth_uri
if not auth_url:
raise exception.CatalogFailure(_('Keystone API endpoint is missing'))
- api_v3 = CONF.keystone_authtoken.auth_version == 'v3.0' or \
- 'v3' in parse.urlparse(auth_url).path
+ auth_version = CONF.keystone_authtoken.auth_version
+ api_v3 = _is_apiv3(auth_url, auth_version)
if api_v3:
from keystoneclient.v3 import client
else:
from keystoneclient.v2_0 import client
- api_version = 'v3' if api_v3 else 'v2.0'
- # NOTE(lucasagomes): Get rid of the trailing '/' otherwise urljoin()
- # fails to override the version in the URL
- auth_url = parse.urljoin(auth_url.rstrip('/'), api_version)
+ auth_url = get_keystone_url(auth_url, auth_version)
try:
ksclient = client.Client(username=CONF.keystone_authtoken.admin_user,
password=CONF.keystone_authtoken.admin_password,
diff --git a/ironic/common/swift.py b/ironic/common/swift.py
new file mode 100644
index 000000000..c5f0e9f8c
--- /dev/null
+++ b/ironic/common/swift.py
@@ -0,0 +1,187 @@
+#
+# Copyright 2014 OpenStack Foundation
+# All Rights Reserved
+#
+# 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.
+
+from oslo.config import cfg
+from six.moves.urllib import parse
+from swiftclient import client as swift_client
+from swiftclient import exceptions as swift_exceptions
+from swiftclient import utils as swift_utils
+
+from ironic.common import exception
+from ironic.common import keystone
+from ironic.openstack.common import log as logging
+
+swift_opts = [
+ cfg.IntOpt('swift_max_retries',
+ default=2,
+ help='Maximum number of times to retry a Swift request, '
+ 'before failing.')
+ ]
+
+
+CONF = cfg.CONF
+CONF.register_opts(swift_opts, group='swift')
+
+CONF.import_opt('admin_user', 'keystonemiddleware.auth_token',
+ group='keystone_authtoken')
+CONF.import_opt('admin_tenant_name', 'keystonemiddleware.auth_token',
+ group='keystone_authtoken')
+CONF.import_opt('admin_password', 'keystonemiddleware.auth_token',
+ group='keystone_authtoken')
+CONF.import_opt('auth_uri', 'keystonemiddleware.auth_token',
+ group='keystone_authtoken')
+CONF.import_opt('auth_version', 'keystonemiddleware.auth_token',
+ group='keystone_authtoken')
+CONF.import_opt('insecure', 'keystonemiddleware.auth_token',
+ group='keystone_authtoken')
+
+LOG = logging.getLogger(__name__)
+
+
+class SwiftAPI(object):
+ """API for communicating with Swift."""
+
+ def __init__(self,
+ user=CONF.keystone_authtoken.admin_user,
+ tenant_name=CONF.keystone_authtoken.admin_tenant_name,
+ key=CONF.keystone_authtoken.admin_password,
+ auth_url=CONF.keystone_authtoken.auth_uri,
+ auth_version=CONF.keystone_authtoken.auth_version):
+ """Constructor for creating a SwiftAPI object.
+
+ :param user: the name of the user for Swift account
+ :param tenant_name: the name of the tenant for Swift account
+ :param key: the 'password' or key to authenticate with
+ :param auth_url: the url for authentication
+ :param auth_version: the version of api to use for authentication
+ """
+ auth_url = keystone.get_keystone_url(auth_url, auth_version)
+ params = {'retries': CONF.swift.swift_max_retries,
+ 'insecure': CONF.keystone_authtoken.insecure,
+ 'user': user,
+ 'tenant_name': tenant_name,
+ 'key': key,
+ 'authurl': auth_url,
+ 'auth_version': auth_version}
+
+ self.connection = swift_client.Connection(**params)
+
+ def create_object(self, container, object, filename,
+ object_headers=None):
+ """Uploads a given file to Swift.
+
+ :param container: The name of the container for the object.
+ :param object: The name of the object in Swift
+ :param filename: The file to upload, as the object data
+ :param object_headers: the headers for the object to pass to Swift
+ :returns: The Swift UUID of the object
+ :raises: SwiftOperationError, if any operation with Swift fails.
+ """
+ try:
+ self.connection.put_container(container)
+ except swift_exceptions.ClientException as e:
+ operation = _("put container")
+ raise exception.SwiftOperationError(operation=operation, error=e)
+
+ with open(filename, "r") as fileobj:
+
+ try:
+ obj_uuid = self.connection.put_object(container,
+ object,
+ fileobj,
+ headers=object_headers)
+ except swift_exceptions.ClientException as e:
+ operation = _("put object")
+ raise exception.SwiftOperationError(operation=operation,
+ error=e)
+
+ return obj_uuid
+
+ def get_temp_url(self, container, object, timeout):
+ """Returns the temp url for the given Swift object.
+
+ :param container: The name of the container in which Swift object
+ is placed.
+ :param object: The name of the Swift object.
+ :param timeout: The timeout in seconds after which the generated url
+ should expire.
+ :returns: The temp url for the object.
+ :raises: SwiftOperationError, if any operation with Swift fails.
+ """
+ try:
+ account_info = self.connection.head_account()
+ except swift_exceptions.ClientException as e:
+ operation = _("head account")
+ raise exception.SwiftOperationError(operation=operation,
+ error=e)
+
+ storage_url, token = self.connection.get_auth()
+ parse_result = parse.urlparse(storage_url)
+ swift_object_path = '/'.join((parse_result.path, container, object))
+ temp_url_key = account_info['x-account-meta-temp-url-key']
+ url_path = swift_utils.generate_temp_url(swift_object_path, timeout,
+ temp_url_key, 'GET')
+ return parse.urlunparse((parse_result.scheme,
+ parse_result.netloc,
+ url_path,
+ None,
+ None,
+ None))
+
+ def delete_object(self, container, object):
+ """Deletes the given Swift object.
+
+ :param container: The name of the container in which Swift object
+ is placed.
+ :param object: The name of the object in Swift to be deleted.
+ :raises: SwiftOperationError, if operation with Swift fails.
+ """
+ try:
+ self.connection.delete_object(container, object)
+ except swift_exceptions.ClientException as e:
+ operation = _("delete object")
+ raise exception.SwiftOperationError(operation=operation, error=e)
+
+ def head_object(self, container, object):
+ """Retrieves the information about the given Swift object.
+
+ :param container: The name of the container in which Swift object
+ is placed.
+ :param object: The name of the object in Swift
+ :returns: The information about the object as returned by
+ Swift client's head_object call.
+ :raises: SwiftOperationError, if operation with Swift fails.
+ """
+ try:
+ return self.connection.head_object(container, object)
+ except swift_exceptions.ClientException as e:
+ operation = _("head object")
+ raise exception.SwiftOperationError(operation=operation, error=e)
+
+ def update_object_meta(self, container, object, object_headers):
+ """Update the metadata of a given Swift object.
+
+ :param container: The name of the container in which Swift object
+ is placed.
+ :param object: The name of the object in Swift
+ :param object_headers: the headers for the object to pass to Swift
+ :raises: SwiftOperationError, if operation with Swift fails.
+ """
+ try:
+ self.connection.post_object(container, object, object_headers)
+ except swift_exceptions.ClientException as e:
+ operation = _("post object")
+ raise exception.SwiftOperationError(operation=operation, error=e)