Example #1
0
def _publish_image(image_file, object_name):
    """Make image file downloadable.

    Depending on ironic settings, pushes given file into Swift or copies
    it over to local HTTP server's document root and returns publicly
    accessible URL leading to the given file.

    :param image_file: path to file to publish
    :param object_name: name of the published file
    :return: a URL to download published file
    """

    if CONF.redfish.use_swift:
        container = CONF.redfish.swift_container
        timeout = CONF.redfish.swift_object_expiry_timeout

        object_headers = {'X-Delete-After': str(timeout)}

        swift_api = swift.SwiftAPI()

        swift_api.create_object(container,
                                object_name,
                                image_file,
                                object_headers=object_headers)

        image_url = swift_api.get_temp_url(container, object_name, timeout)

    else:
        public_dir = os.path.join(CONF.deploy.http_root, IMAGE_SUBDIR)

        if not os.path.exists(public_dir):
            os.mkdir(public_dir, 0o755)

        published_file = os.path.join(public_dir, object_name)

        try:
            os.link(image_file, published_file)
            os.chmod(image_file, CONF.redfish.file_permission)

        except OSError as exc:
            LOG.debug(
                "Could not hardlink image file %(image)s to public "
                "location %(public)s (will copy it over): "
                "%(error)s", {
                    'image': image_file,
                    'public': published_file,
                    'error': exc
                })

            shutil.copyfile(image_file, published_file)
            os.chmod(published_file, CONF.redfish.file_permission)

        image_url = os.path.join(CONF.deploy.http_url, IMAGE_SUBDIR,
                                 object_name)

    image_url = _append_filename_param(image_url, os.path.basename(image_file))

    return image_url
Example #2
0
def _prepare_floppy_image(task, params):
    """Prepares the floppy image for passing the parameters.

    This method prepares a temporary vfat filesystem image. Then it adds
    two files into the image - one containing the authentication token and
    the other containing the parameters to be passed to the ramdisk. Then it
    uploads the file to Swift in 'swift_ilo_container', setting it to
    auto-expire after 'swift_object_expiry_timeout' seconds. Then it returns
    the temp url for the Swift object.

    :param task: a TaskManager instance containing the node to act on.
    :param params: a dictionary containing 'parameter name'->'value' mapping
        to be passed to the deploy ramdisk via the floppy image.
    :raises: ImageCreationFailed, if it failed while creating the floppy image.
    :raises: SwiftOperationError, if any operation with Swift fails.
    :returns: the Swift temp url for the floppy image.
    """
    with tempfile.NamedTemporaryFile() as vfat_image_tmpfile_obj:

        files_info = {}
        token_tmpfile_obj = None
        vfat_image_tmpfile = vfat_image_tmpfile_obj.name

        # If auth_strategy is noauth, then no need to write token into
        # the image file.
        if task.context.auth_token:
            token_tmpfile_obj = tempfile.NamedTemporaryFile()
            token_tmpfile = token_tmpfile_obj.name
            utils.write_to_file(token_tmpfile, task.context.auth_token)
            files_info[token_tmpfile] = 'token'

        try:
            images.create_vfat_image(vfat_image_tmpfile,
                                     files_info=files_info,
                                     parameters=params)
        finally:
            if token_tmpfile_obj:
                token_tmpfile_obj.close()

        container = CONF.ilo.swift_ilo_container
        object_name = _get_floppy_image_name(task.node)
        timeout = CONF.ilo.swift_object_expiry_timeout

        object_headers = {'X-Delete-After': timeout}
        swift_api = swift.SwiftAPI()
        swift_api.create_object(container,
                                object_name,
                                vfat_image_tmpfile,
                                object_headers=object_headers)
        temp_url = swift_api.get_temp_url(container, object_name, timeout)

        LOG.debug(
            "Uploaded floppy image %(object_name)s to %(container)s "
            "for deployment.", {
                'object_name': object_name,
                'container': container
            })
        return temp_url
Example #3
0
 def test_head_object(self, connection_mock):
     swiftapi = swift.SwiftAPI()
     connection_obj_mock = connection_mock.return_value
     expected_head_result = {'a': 'b'}
     connection_obj_mock.head_object.return_value = expected_head_result
     actual_head_result = swiftapi.head_object('container', 'object')
     connection_obj_mock.head_object.assert_called_once_with(
         'container', 'object')
     self.assertEqual(expected_head_result, actual_head_result)
Example #4
0
 def test_delete_object_exc(self, connection_mock):
     swiftapi = swift.SwiftAPI()
     exc = swift_exception.ClientException("Operation error")
     connection_obj_mock = connection_mock.return_value
     connection_obj_mock.delete_object.side_effect = exc
     self.assertRaises(exception.SwiftOperationError,
                       swiftapi.delete_object, 'container', 'object')
     connection_obj_mock.delete_object.assert_called_once_with(
         'container', 'object')
Example #5
0
 def test_delete_object_exc_resource_not_found(self, connection_mock):
     swiftapi = swift.SwiftAPI()
     exc = swift_exception.ClientException(
         "Resource not found", http_status=http_client.NOT_FOUND)
     connection_obj_mock = connection_mock.return_value
     connection_obj_mock.delete_object.side_effect = exc
     self.assertRaises(exception.SwiftObjectNotFoundError,
                       swiftapi.delete_object, 'container', 'object')
     connection_obj_mock.delete_object.assert_called_once_with(
         'container', 'object')
Example #6
0
 def test___init__(self, connection_mock):
     swift.SwiftAPI()
     params = {'retries': 2,
               'insecure': 0,
               'user': '******',
               'tenant_name': 'tenant',
               'key': 'password',
               'authurl': 'http://authurl/v2.0',
               'auth_version': '2'}
     connection_mock.assert_called_once_with(**params)
Example #7
0
 def test_create_object_create_container_fails(self, open_mock,
                                               connection_mock):
     swiftapi = swift.SwiftAPI()
     connection_obj_mock = connection_mock.return_value
     connection_obj_mock.put_container.side_effect = self.swift_exception
     self.assertRaises(exception.SwiftOperationError,
                       swiftapi.create_object, 'container', 'object',
                       'some-file-location')
     connection_obj_mock.put_container.assert_called_once_with('container')
     self.assertFalse(connection_obj_mock.put_object.called)
Example #8
0
    def _prepare_floppy_image(cls, task, params=None):
        """Prepares the floppy image for passing the parameters.

        This method prepares a temporary VFAT filesystem image and adds
        a file into the image which contains parameters to be passed to
        the ramdisk. Then this method uploads built image to Swift
        '[redfish]swift_container', setting it to auto expire after
        '[redfish]swift_object_expiry_timeout' seconds. Finally, a
        temporary Swift URL is returned addressing Swift object just
        created.

        :param task: a TaskManager instance containing the node to act on.
        :param params: a dictionary containing 'parameter name'->'value'
            mapping to be passed to deploy or rescue image via floppy image.
        :raises: ImageCreationFailed, if it failed while creating the floppy
            image.
        :raises: SwiftOperationError, if any operation with Swift fails.
        :returns: image URL for the floppy image.
        """
        object_name = cls._get_floppy_image_name(task.node)

        container = CONF.redfish.swift_container
        timeout = CONF.redfish.swift_object_expiry_timeout

        object_headers = {'X-Delete-After': str(timeout)}
        swift_api = swift.SwiftAPI()

        LOG.debug("Trying to create floppy image for node "
                  "%(node)s", {'node': task.node.uuid})

        with tempfile.NamedTemporaryFile(
                dir=CONF.tempdir, suffix='.img') as vfat_image_tmpfile_obj:

            vfat_image_tmpfile = vfat_image_tmpfile_obj.name
            images.create_vfat_image(vfat_image_tmpfile, parameters=params)

            swift_api.create_object(container,
                                    object_name,
                                    vfat_image_tmpfile,
                                    object_headers=object_headers)

        image_url = swift_api.get_temp_url(container, object_name, timeout)

        image_url = cls._append_filename_param(image_url, 'bootme.img')

        LOG.debug(
            "Created floppy image %(name)s in Swift for node %(node)s, "
            "exposed as temporary URL "
            "%(url)s", {
                'node': task.node.uuid,
                'name': object_name,
                'url': image_url
            })

        return image_url
Example #9
0
 def test___init__(self, connection_mock, keystone_mock):
     """Check if client is properly initialized with swift"""
     self.config(group='swift',
                 endpoint_override='http://example.com/objects')
     swift.SwiftAPI()
     connection_mock.assert_called_once_with(
         retries=2,
         session=keystone_mock.return_value,
         timeout=42,
         insecure=True,
         cert='spam',
         cert_key='ham',
         os_options={'object_storage_url': 'http://example.com/objects'})
Example #10
0
 def test_get_temp_url(self, gen_temp_url_mock, connection_mock,
                       keystone_mock):
     swiftapi = swift.SwiftAPI()
     connection_obj_mock = connection_mock.return_value
     connection_obj_mock.url = 'http://host/v1/AUTH_tenant_id'
     head_ret_val = {'x-account-meta-temp-url-key': 'secretkey'}
     connection_obj_mock.head_account.return_value = head_ret_val
     gen_temp_url_mock.return_value = 'temp-url-path'
     temp_url_returned = swiftapi.get_temp_url('container', 'object', 10)
     connection_obj_mock.head_account.assert_called_once_with()
     object_path_expected = '/v1/AUTH_tenant_id/container/object'
     gen_temp_url_mock.assert_called_once_with(object_path_expected, 10,
                                               'secretkey', 'GET')
     self.assertEqual('http://host/temp-url-path', temp_url_returned)
Example #11
0
def _clean_up_boot_iso_for_instance(node):
    """Deletes the boot ISO created in Swift for the instance.

    :param node: an ironic node object.
    """
    swift_api = swift.SwiftAPI()
    container = CONF.ilo.swift_ilo_container
    boot_iso_object_name = _get_boot_iso_object_name(node)
    try:
        swift_api.delete_object(container, boot_iso_object_name)
    except exception.SwiftOperationError as e:
        LOG.exception(_LE("Failed to clean up boot ISO for %(node)s."
                          "Error: %(error)s."),
                      {'node': node.uuid, 'error': e})
Example #12
0
 def test_create_object_put_object_fails(self, open_mock, connection_mock):
     swiftapi = swift.SwiftAPI()
     mock_file_handle = mock.MagicMock(spec=file)
     mock_file_handle.__enter__.return_value = 'file-object'
     open_mock.return_value = mock_file_handle
     connection_obj_mock = connection_mock.return_value
     connection_obj_mock.head_account.side_effect = None
     connection_obj_mock.put_object.side_effect = self.swift_exception
     self.assertRaises(exception.SwiftOperationError,
                       swiftapi.create_object, 'container',
                       'object', 'some-file-location')
     connection_obj_mock.put_container.assert_called_once_with('container')
     connection_obj_mock.put_object.assert_called_once_with('container',
             'object', 'file-object', headers=None)
Example #13
0
def _store_configdrive(node, configdrive):
    """Handle the storage of the config drive.

    If configured, the config drive data are uploaded to a swift endpoint.
    The Node's instance_info is updated to include either the temporary
    Swift URL from the upload, or if no upload, the actual config drive data.

    :param node: an Ironic node object.
    :param configdrive: A gzipped and base64 encoded configdrive.
    :raises: SwiftOperationError if an error occur when uploading the
             config drive to the swift endpoint.
    :raises: ConfigInvalid if required keystone authorization credentials
             with swift are missing.


    """
    if CONF.deploy.configdrive_use_object_store:
        # Don't store the JSON source in swift.
        if isinstance(configdrive, dict):
            configdrive = utils.build_configdrive(node, configdrive)

        # NOTE(lucasagomes): No reason to use a different timeout than
        # the one used for deploying the node
        timeout = (
            CONF.conductor.configdrive_swift_temp_url_duration
            or CONF.conductor.deploy_callback_timeout
            # The documented default in ironic.conf.conductor
            or 1800)
        container = CONF.conductor.configdrive_swift_container
        object_name = _get_configdrive_obj_name(node)

        object_headers = {'X-Delete-After': str(timeout)}

        with tempfile.NamedTemporaryFile(dir=CONF.tempdir,
                                         mode="wt") as fileobj:
            fileobj.write(configdrive)
            fileobj.flush()

            swift_api = swift.SwiftAPI()
            swift_api.create_object(container,
                                    object_name,
                                    fileobj.name,
                                    object_headers=object_headers)
            configdrive = swift_api.get_temp_url(container, object_name,
                                                 timeout)

    i_info = node.instance_info
    i_info['configdrive'] = configdrive
    node.instance_info = i_info
    node.save()
Example #14
0
 def test___init__(self, connection_mock, keystone_mock):
     sess = mock.Mock()
     sess.get_endpoint.return_value = 'http://swift:8080'
     sess.get_token.return_value = 'fake_token'
     sess.verify = '/path/to/ca/file'
     keystone_mock.return_value = sess
     swift.SwiftAPI()
     params = {
         'retries': 2,
         'preauthurl': 'http://swift:8080',
         'preauthtoken': 'fake_token',
         'insecure': False,
         'cacert': '/path/to/ca/file'
     }
     connection_mock.assert_called_once_with(**params)
Example #15
0
    def test_create_object(self, open_mock, connection_mock, keystone_mock):
        swiftapi = swift.SwiftAPI()
        connection_obj_mock = connection_mock.return_value
        mock_file_handle = mock.MagicMock(spec=io.BytesIO)
        mock_file_handle.__enter__.return_value = 'file-object'
        open_mock.return_value = mock_file_handle

        connection_obj_mock.put_object.return_value = 'object-uuid'

        object_uuid = swiftapi.create_object('container', 'object',
                                             'some-file-location')

        connection_obj_mock.put_container.assert_called_once_with('container')
        connection_obj_mock.put_object.assert_called_once_with(
            'container', 'object', 'file-object', headers=None)
        self.assertEqual('object-uuid', object_uuid)
Example #16
0
def _prepare_floppy_image(task, params):
    """Prepares the floppy image for passing the parameters.

    This method prepares a temporary vfat filesystem image. Then it adds
    a file into the image which contains the parameters to be passed to
    the ramdisk. After adding the parameters, it then uploads the file either
    to Swift in 'swift_ilo_container', setting it to auto-expire after
    'swift_object_expiry_timeout' seconds or in web server. Then it returns
    the temp url for the Swift object or the http url for the uploaded floppy
    image depending upon value of CONF.ilo.use_web_server_for_images.

    :param task: a TaskManager instance containing the node to act on.
    :param params: a dictionary containing 'parameter name'->'value' mapping
        to be passed to the deploy ramdisk via the floppy image.
    :raises: ImageCreationFailed, if it failed while creating the floppy image.
    :raises: SwiftOperationError, if any operation with Swift fails.
    :returns: the Swift temp url for the floppy image.
    """
    with tempfile.NamedTemporaryFile(
            dir=CONF.tempdir) as vfat_image_tmpfile_obj:

        vfat_image_tmpfile = vfat_image_tmpfile_obj.name
        images.create_vfat_image(vfat_image_tmpfile, parameters=params)
        object_name = _get_floppy_image_name(task.node)
        if CONF.ilo.use_web_server_for_images:
            image_url = copy_image_to_web_server(vfat_image_tmpfile,
                                                 object_name)
            return image_url
        else:
            container = CONF.ilo.swift_ilo_container
            timeout = CONF.ilo.swift_object_expiry_timeout

            object_headers = {'X-Delete-After': timeout}
            swift_api = swift.SwiftAPI()
            swift_api.create_object(container,
                                    object_name,
                                    vfat_image_tmpfile,
                                    object_headers=object_headers)
            temp_url = swift_api.get_temp_url(container, object_name, timeout)

            LOG.debug(
                "Uploaded floppy image %(object_name)s to %(container)s "
                "for deployment.", {
                    'object_name': object_name,
                    'container': container
                })
            return temp_url
Example #17
0
def get_swift_url(parsed_url):
    """Gets swift temp url.

    It generates a temp url for the swift based firmware url to the target
    file. Expecting url as swift://containername/objectname.

    :param parsed_url: Parsed url object.
    :raises: SwiftOperationError, on failure to get url from swift.
    """
    # Extract container name
    container = parsed_url.netloc
    # Extract the object name from the path of the form:
    #    ``/objectname`` OR
    #    ``/pseudo-folder/objectname``
    # stripping the leading '/' character.
    objectname = parsed_url.path.lstrip('/')
    timeout = CONF.ilo.swift_object_expiry_timeout
    # Generate temp url using swift API
    return swift.SwiftAPI().get_temp_url(container, objectname, timeout)
Example #18
0
def setup_vmedia_for_boot(task, boot_iso, parameters=None):
    """Sets up the node to boot from the given ISO image.

    This method attaches the given boot_iso on the node and passes
    the required parameters to it via virtual floppy image.

    :param task: a TaskManager instance containing the node to act on.
    :param boot_iso: a bootable ISO image to attach to. Should be either
                     of below:

                     * A Swift object - It should be of format
                       ``swift:<object-name>``.
                       It is assumed that the image object is present in
                       CONF.ilo.swift_ilo_container;
                     * A Glance image - It should be format
                       ``glance://<glance-image-uuid>``
                       or just ``<glance-image-uuid>``;
                     * An HTTP URL.
    :param parameters: the parameters to pass in the virtual floppy image
                       in a dictionary.  This is optional.
    :raises: ImageCreationFailed, if it failed while creating the floppy image.
    :raises: SwiftOperationError, if any operation with Swift fails.
    :raises: IloOperationError, if attaching virtual media failed.
    """
    LOG.info("Setting up node %s to boot from virtual media",
             task.node.uuid)
    if parameters:
        floppy_image_temp_url = _prepare_floppy_image(task, parameters)
        attach_vmedia(task.node, 'FLOPPY', floppy_image_temp_url)

    boot_iso_url = None
    parsed_ref = urlparse.urlparse(boot_iso)
    if parsed_ref.scheme == 'swift':
        swift_api = swift.SwiftAPI()
        container = CONF.ilo.swift_ilo_container
        object_name = parsed_ref.path
        timeout = CONF.ilo.swift_object_expiry_timeout
        boot_iso_url = swift_api.get_temp_url(
            container, object_name, timeout)
    elif service_utils.is_glance_image(boot_iso):
        boot_iso_url = (
            images.get_temp_url_for_glance_image(task.context, boot_iso))
    attach_vmedia(task.node, 'CDROM', boot_iso_url or boot_iso)
Example #19
0
def _clean_up_boot_iso_for_instance(node):
    """Deletes the boot ISO if it was created in Swift for the instance.

    :param node: an ironic node object.
    """
    ilo_boot_iso = node.instance_info.get('ilo_boot_iso')
    if not (ilo_boot_iso and ilo_boot_iso.startswith('swift')):
        return
    swift_api = swift.SwiftAPI()
    container = CONF.ilo.swift_ilo_container
    boot_iso_object_name = _get_boot_iso_object_name(node)
    try:
        swift_api.delete_object(container, boot_iso_object_name)
    except exception.SwiftOperationError as e:
        LOG.exception(
            _LE("Failed to clean up boot ISO for %(node)s."
                "Error: %(error)s."), {
                    'node': node.uuid,
                    'error': e
                })
Example #20
0
def _download_swift_based_fw_to(self, target_file):
    """Swift based firmware file downloader

    It generates a temp url for the swift based firmware url and then downloads
    the firmware file via http based downloader to the target file.
    Expecting url as swift://containername/objectname
    :param target_file: destination file for downloading the original firmware
                        file.
    :raises: SwiftOperationError, on failure to download from swift.
    :raises: ImageDownloadFailed, on failure to download the original file.
    """
    # Extract container name and object name
    container = self.parsed_url.netloc
    objectname = os.path.basename(self.parsed_url.path)
    timeout = CONF.ilo.swift_object_expiry_timeout
    # Generate temp url using swift API
    tempurl = swift.SwiftAPI().get_temp_url(container, objectname, timeout)
    # set the parsed_url attribute to the newly created tempurl from swift and
    # delegate the dowloading job to the http_based downloader
    self.parsed_url = urlparse.urlparse(tempurl)
    _download_http_based_fw_to(self, target_file)
Example #21
0
def setup_vmedia_for_boot(task, boot_iso, parameters=None):
    """Sets up the node to boot from the given ISO image.

    This method attaches the given boot_iso on the node and passes
    the required parameters to it via virtual floppy image.

    :param task: a TaskManager instance containing the node to act on.
    :param boot_iso: a bootable ISO image to attach to.  The boot iso
        should be present in either Glance or in Swift. If present in
        Glance, it should be of format 'glance:<glance-image-uuid>'.
        If present in Swift, it should be of format 'swift:<object-name>'.
        It is assumed that object is present in CONF.ilo.swift_ilo_container.
    :param parameters: the parameters to pass in the virtual floppy image
        in a dictionary.  This is optional.
    :raises: ImageCreationFailed, if it failed while creating the floppy image.
    :raises: SwiftOperationError, if any operation with Swift fails.
    :raises: IloOperationError, if attaching virtual media failed.
    """
    LOG.info(_LI("Setting up node %s to boot from virtual media"),
             task.node.uuid)

    if parameters:
        floppy_image_temp_url = _prepare_floppy_image(task, parameters)
        attach_vmedia(task.node, 'FLOPPY', floppy_image_temp_url)

    boot_iso_temp_url = None
    scheme, boot_iso_ref = boot_iso.split(':')
    if scheme == 'swift':
        swift_api = swift.SwiftAPI()
        container = CONF.ilo.swift_ilo_container
        object_name = boot_iso_ref
        timeout = CONF.ilo.swift_object_expiry_timeout
        boot_iso_temp_url = swift_api.get_temp_url(container, object_name,
                timeout)
    elif scheme == 'glance':
        glance_uuid = boot_iso_ref
        boot_iso_temp_url = images.get_temp_url_for_glance_image(task.context,
                glance_uuid)

    attach_vmedia(task.node, 'CDROM', boot_iso_temp_url)
Example #22
0
def store_ramdisk_logs(node, logs, label=None):
    """Store the ramdisk logs.

    This method stores the ramdisk logs according to the configured
    storage backend.

    :param node: A node object.
    :param logs: A gzipped and base64 encoded string containing the
                 logs archive.
    :param label: A string to label the log file such as a clean step name.
    :raises: OSError if the directory to save the logs cannot be created.
    :raises: IOError when the logs can't be saved to the local file system.
    :raises: SwiftOperationError, if any operation with Swift fails.

    """
    logs_file_name = get_ramdisk_logs_file_name(node, label=label)
    data = base64.decode_as_bytes(logs)

    if CONF.agent.deploy_logs_storage_backend == 'local':
        if not os.path.exists(CONF.agent.deploy_logs_local_path):
            os.makedirs(CONF.agent.deploy_logs_local_path)

        log_path = os.path.join(CONF.agent.deploy_logs_local_path,
                                logs_file_name)
        with open(log_path, 'wb') as f:
            f.write(data)

    elif CONF.agent.deploy_logs_storage_backend == 'swift':
        with tempfile.NamedTemporaryFile(dir=CONF.tempdir) as f:
            f.write(data)
            f.flush()

            # convert days to seconds
            timeout = CONF.agent.deploy_logs_swift_days_to_expire * 86400
            object_headers = {'X-Delete-After': str(timeout)}
            swift_api = swift.SwiftAPI()
            swift_api.create_object(CONF.agent.deploy_logs_swift_container,
                                    logs_file_name,
                                    f.name,
                                    object_headers=object_headers)
Example #23
0
def remove_image_from_swift(object_name, associated_with=None):
    """Removes the given image from swift.

    This method removes the given image name from swift. It deletes the
    image if it exists in CONF.ilo.swift_ilo_container

    :param object_name: The name of the object which needs to be removed
                        from swift.
    :param associated_with: string to depict the component/operation this
                            object is associated to.
    """
    container = CONF.ilo.swift_ilo_container
    try:
        swift_api = swift.SwiftAPI()
        swift_api.delete_object(container, object_name)
    except exception.SwiftObjectNotFoundError as e:
        LOG.warning(
            _LW("Temporary object %(associated_with_msg)s"
                "was already deleted from Swift. Error: %(err)s"), {
                    'associated_with_msg':
                    ("associated with %s " %
                     associated_with if associated_with else ""),
                    'err':
                    e
                })
    except exception.SwiftOperationError as e:
        LOG.exception(
            _LE("Error while deleting temporary swift object %(object_name)s "
                "%(associated_with_msg)s from %(container)s. Error: %(err)s"),
            {
                'object_name':
                object_name,
                'container':
                container,
                'associated_with_msg':
                ("associated with %s" %
                 associated_with if associated_with else ""),
                'err':
                e
            })
Example #24
0
    def test___init___radosgw(self, connection_mock, swift_session_mock):
        """Check if client is properly initialized with radosgw"""

        auth_url = 'http://1.2.3.4'
        username = '******'
        password = '******'
        CONF.set_override('object_store_endpoint_type', 'radosgw',
                          group='deploy')
        opts = [cfg.StrOpt('auth_url'), cfg.StrOpt('username'),
                cfg.StrOpt('password')]
        CONF.register_opts(opts, group='swift')

        CONF.set_override('auth_url', auth_url, group='swift')
        CONF.set_override('username', username, group='swift')
        CONF.set_override('password', password, group='swift')

        swift.SwiftAPI()
        params = {'authurl': auth_url,
                  'user': username,
                  'key': password}
        connection_mock.assert_called_once_with(**params)
        self.assertFalse(swift_session_mock.called)
Example #25
0
    def _delete_from_swift(task, container, object_name):
        LOG.debug(
            "Cleaning up image %(name)s from Swift container "
            "%(container)s for node "
            "%(node)s", {
                'node': task.node.uuid,
                'name': object_name,
                'container': container
            })

        swift_api = swift.SwiftAPI()

        try:
            swift_api.delete_object(container, object_name)

        except exception.SwiftOperationError as e:
            LOG.warning(
                "Failed to clean up image %(image)s for node "
                "%(node)s. Error: %(error)s.", {
                    'node': task.node.uuid,
                    'image': object_name,
                    'error': e
                })
Example #26
0
def _clean_up_boot_iso_for_instance(node):
    """Deletes the boot ISO if it was created for the instance.

    :param node: an ironic node object.
    """
    boot_iso_object_name = virtual_media_base.get_iso_image_name(node)

    if CONF.ilo.use_web_server_for_images:
        boot_iso_path = os.path.join(CONF.deploy.http_root,
                                     boot_iso_object_name)
        ironic_utils.unlink_without_raise(boot_iso_path)
    else:
        swift_api = swift.SwiftAPI()
        container = CONF.ilo.swift_ilo_container
        try:
            swift_api.delete_object(container, boot_iso_object_name)
        except exception.SwiftOperationError as e:
            LOG.exception(
                "Failed to clean up boot ISO for node "
                "%(node)s. Error: %(error)s.", {
                    'node': node.uuid,
                    'error': e
                })
Example #27
0
def cleanup_vmedia_boot(task):
    """Cleans a node after a virtual media boot.

    This method cleans up a node after a virtual media boot. It deletes the
    floppy image if it exists in CONF.ilo.swift_ilo_container. It also
    ejects both virtual media cdrom and virtual media floppy.

    :param task: a TaskManager instance containing the node to act on.
    """
    LOG.debug("Cleaning up node %s after virtual media boot", task.node.uuid)

    container = CONF.ilo.swift_ilo_container
    object_name = _get_floppy_image_name(task.node)
    try:
        swift_api = swift.SwiftAPI()
        swift_api.delete_object(container, object_name)
    except exception.SwiftOperationError as e:
        LOG.exception(
            _LE("Error while deleting %(object_name)s from "
                "%(container)s. Error: %(error)s"), {
                    'object_name': object_name,
                    'container': container,
                    'error': e
                })

    ilo_object = get_ilo_object(task.node)
    for device in ('FLOPPY', 'CDROM'):
        try:
            ilo_object.eject_virtual_media(device)
        except ilo_error.IloError as ilo_exception:
            LOG.exception(
                _LE("Error while ejecting virtual media %(device)s "
                    "from node %(uuid)s. Error: %(error)s"), {
                        'device': device,
                        'uuid': task.node.uuid,
                        'error': ilo_exception
                    })
Example #28
0
    def unpublish_image(self, object_name):
        """Withdraw the image previously made downloadable.

        Depending on ironic settings, removes previously published file
        from where it has been published - Swift or local HTTP server's
        document root.

        :param object_name: name of the published file (optional)
        """
        if self._is_swift_enabled():
            container = self._container

            swift_api = swift.SwiftAPI()

            LOG.debug(
                "Cleaning up image %(name)s from Swift container "
                "%(container)s", {
                    'name': object_name,
                    'container': container
                })

            try:
                swift_api.delete_object(container, object_name)

            except exception.SwiftOperationError as exc:
                LOG.warning(
                    "Failed to clean up image %(image)s. Error: "
                    "%(error)s.", {
                        'image': object_name,
                        'error': exc
                    })

        else:
            published_file = os.path.join(CONF.deploy.http_root,
                                          self._image_subdir, object_name)

            ironic_utils.unlink_without_raise(published_file)
Example #29
0
def _clean_up_boot_iso_for_instance(node):
    """Deletes the boot ISO if it was created for the instance.

    :param node: an ironic node object.
    """
    ilo_boot_iso = node.instance_info.get('ilo_boot_iso')
    if not ilo_boot_iso:
        return
    if ilo_boot_iso.startswith('swift'):
        swift_api = swift.SwiftAPI()
        container = CONF.ilo.swift_ilo_container
        boot_iso_object_name = _get_boot_iso_object_name(node)
        try:
            swift_api.delete_object(container, boot_iso_object_name)
        except exception.SwiftOperationError as e:
            LOG.exception("Failed to clean up boot ISO for node "
                          "%(node)s. Error: %(error)s.",
                          {'node': node.uuid, 'error': e})
    elif CONF.ilo.use_web_server_for_images:
        result = urlparse.urlparse(ilo_boot_iso)
        ilo_boot_iso_name = os.path.basename(result.path)
        boot_iso_path = os.path.join(
            CONF.deploy.http_root, ilo_boot_iso_name)
        ironic_utils.unlink_without_raise(boot_iso_path)
Example #30
0
def _get_boot_iso(task, root_uuid):
    """This method returns a boot ISO to boot the node.

    It chooses one of the three options in the order as below:
    1. Does nothing if 'ilo_boot_iso' is present in node's instance_info and
       'boot_iso_created_in_web_server' is not set in 'driver_internal_info'.
    2. Image deployed has a meta-property 'boot_iso' in Glance. This should
       refer to the UUID of the boot_iso which exists in Glance.
    3. Generates a boot ISO on the fly using kernel and ramdisk mentioned in
       the image deployed. It uploads the generated boot ISO to Swift.

    :param task: a TaskManager instance containing the node to act on.
    :param root_uuid: the uuid of the root partition.
    :returns: boot ISO URL. Should be either of below:
        * A Swift object - It should be of format 'swift:<object-name>'. It is
          assumed that the image object is present in
          CONF.ilo.swift_ilo_container;
        * A Glance image - It should be format 'glance://<glance-image-uuid>'
          or just <glance-image-uuid>;
        * An HTTP URL.
        On error finding the boot iso, it returns None.
    :raises: MissingParameterValue, if any of the required parameters are
        missing in the node's driver_info or instance_info.
    :raises: InvalidParameterValue, if any of the parameters have invalid
        value in the node's driver_info or instance_info.
    :raises: SwiftOperationError, if operation with Swift fails.
    :raises: ImageCreationFailed, if creation of boot ISO failed.
    :raises: exception.ImageRefValidationFailed if ilo_boot_iso is not
        HTTP(S) URL.
    """
    LOG.debug("Trying to get a boot ISO to boot the baremetal node")

    # Option 1 - Check if user has provided ilo_boot_iso in node's
    # instance_info
    driver_internal_info = task.node.driver_internal_info
    boot_iso_created_in_web_server = (
        driver_internal_info.get('boot_iso_created_in_web_server'))

    if (task.node.instance_info.get('ilo_boot_iso')
            and not boot_iso_created_in_web_server):
        LOG.debug("Using ilo_boot_iso provided in node's instance_info")
        boot_iso = task.node.instance_info['ilo_boot_iso']
        if not service_utils.is_glance_image(boot_iso):
            try:
                image_service.HttpImageService().validate_href(boot_iso)
            except exception.ImageRefValidationFailed:
                with excutils.save_and_reraise_exception():
                    LOG.error("Virtual media deploy accepts only Glance "
                              "images or HTTP(S) URLs as "
                              "instance_info['ilo_boot_iso']. Either %s "
                              "is not a valid HTTP(S) URL or is "
                              "not reachable.", boot_iso)

        return task.node.instance_info['ilo_boot_iso']

    # Option 2 - Check if user has provided a boot_iso in Glance. If boot_iso
    # is a supported non-glance href execution will proceed to option 3.
    deploy_info = _parse_deploy_info(task.node)

    image_href = deploy_info['image_source']
    image_properties = (
        images.get_image_properties(
            task.context, image_href, ['boot_iso', 'kernel_id', 'ramdisk_id']))

    boot_iso_uuid = image_properties.get('boot_iso')
    kernel_href = (task.node.instance_info.get('kernel')
                   or image_properties.get('kernel_id'))
    ramdisk_href = (task.node.instance_info.get('ramdisk')
                    or image_properties.get('ramdisk_id'))

    if boot_iso_uuid:
        LOG.debug("Found boot_iso %s in Glance", boot_iso_uuid)
        return boot_iso_uuid

    if not kernel_href or not ramdisk_href:
        LOG.error("Unable to find kernel or ramdisk for "
                  "image %(image)s to generate boot ISO for %(node)s",
                  {'image': image_href, 'node': task.node.uuid})
        return

    # NOTE(rameshg87): Functionality to share the boot ISOs created for
    # similar instances (instances with same deployed image) is
    # not implemented as of now. Creation/Deletion of such a shared boot ISO
    # will require synchronisation across conductor nodes for the shared boot
    # ISO.  Such a synchronisation mechanism doesn't exist in ironic as of now.

    # Option 3 - Create boot_iso from kernel/ramdisk, upload to Swift
    # or web server and provide its name.
    deploy_iso_uuid = deploy_info['ilo_deploy_iso']
    boot_mode = boot_mode_utils.get_boot_mode_for_deploy(task.node)
    boot_iso_object_name = _get_boot_iso_object_name(task.node)
    kernel_params = ""
    if deploy_utils.get_boot_option(task.node) == "ramdisk":
        i_info = task.node.instance_info
        kernel_params = "root=/dev/ram0 text "
        kernel_params += i_info.get("ramdisk_kernel_arguments", "")
    else:
        kernel_params = CONF.pxe.pxe_append_params
    with tempfile.NamedTemporaryFile(dir=CONF.tempdir) as fileobj:
        boot_iso_tmp_file = fileobj.name
        images.create_boot_iso(task.context, boot_iso_tmp_file,
                               kernel_href, ramdisk_href,
                               deploy_iso_uuid, root_uuid,
                               kernel_params, boot_mode)

        if CONF.ilo.use_web_server_for_images:
            boot_iso_url = (
                ilo_common.copy_image_to_web_server(boot_iso_tmp_file,
                                                    boot_iso_object_name))
            driver_internal_info = task.node.driver_internal_info
            driver_internal_info['boot_iso_created_in_web_server'] = True
            task.node.driver_internal_info = driver_internal_info
            task.node.save()
            LOG.debug("Created boot_iso %(boot_iso)s for node %(node)s",
                      {'boot_iso': boot_iso_url, 'node': task.node.uuid})
            return boot_iso_url
        else:
            container = CONF.ilo.swift_ilo_container
            swift_api = swift.SwiftAPI()
            swift_api.create_object(container, boot_iso_object_name,
                                    boot_iso_tmp_file)

            LOG.debug("Created boot_iso %s in Swift", boot_iso_object_name)
            return 'swift:%s' % boot_iso_object_name