示例#1
0
 def setUp(self):
     super(TestSwiftTempUrlCache, self).setUp()
     client = stubs.StubGlanceClient()
     self.context = context.RequestContext()
     self.context.auth_token = 'fake'
     self.config(swift_temp_url_expected_download_start_delay=100,
                 group='glance')
     self.config(swift_temp_url_key='correcthorsebatterystaple',
                 group='glance')
     self.config(swift_endpoint_url='https://swift.example.com',
                 group='glance')
     self.config(swift_account='AUTH_a422b2-91f3-2f46-74b7-d7c9e8958f5d30',
                 group='glance')
     self.config(swift_api_version='v1',
                 group='glance')
     self.config(swift_container='glance',
                 group='glance')
     self.config(swift_temp_url_duration=1200,
                 group='glance')
     self.config(swift_temp_url_cache_enabled=True,
                 group='glance')
     self.config(swift_store_multiple_containers_seed=0,
                 group='glance')
     self.glance_service = service.GlanceImageService(client, version=2,
                                                      context=self.context)
示例#2
0
def build_instance_info_for_deploy(task):
    """Build instance_info necessary for deploying to a node."""
    node = task.node
    instance_info = node.instance_info

    image_source = instance_info['image_source']
    if service_utils.is_glance_image(image_source):
        glance = image_service.GlanceImageService(version=2,
                                                  context=task.context)
        image_info = glance.show(image_source)
        swift_temp_url = glance.swift_temp_url(image_info)
        LOG.debug('Got image info: %(info)s for node %(node)s.', {
            'info': image_info,
            'node': node.uuid
        })
        instance_info['image_url'] = swift_temp_url
        instance_info['image_checksum'] = image_info['checksum']
        instance_info['image_disk_format'] = image_info['disk_format']
    else:
        try:
            image_service.HttpImageService().validate_href(image_source)
        except exception.ImageRefValidationFailed:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _LE("Ansible deploy supports only HTTP(S) URLs as "
                        "instance_info['image_source']. Either %s "
                        "is not a valid HTTP(S) URL or "
                        "is not reachable."), image_source)
        instance_info['image_url'] = image_source

    return instance_info
示例#3
0
def _get_image_info(node, ctx):
    """Generate the paths for tftp files for this instance

    Raises IronicException if
    - instance does not contain kernel or ramdisk
    - deploy_kernel or deploy_ramdisk can not be read from
      driver_info and defaults are not set

    """
    d_info = _parse_deploy_info(node)
    image_info = {}
    root_dir = pxe_utils.get_root_dir()

    image_info.update(pxe_utils.get_deploy_kr_info(node.uuid, d_info))

    if node.driver_internal_info.get('is_whole_disk_image'):
        return image_info

    i_info = node.instance_info
    labels = ('kernel', 'ramdisk')
    if not (i_info.get('kernel') and i_info.get('ramdisk')):
        glance_service = service.GlanceImageService(version=1, context=ctx)
        iproperties = glance_service.show(d_info['image_source'])['properties']
        for label in labels:
            i_info[label] = str(iproperties[label + '_id'])
        node.instance_info = i_info
        node.save()

    for label in labels:
        image_info[label] = (i_info[label],
                             os.path.join(root_dir, node.uuid, label))

    return image_info
示例#4
0
    def test_download_with_retries(self, mock_sleep):
        tries = [0]

        class MyGlanceStubClient(stubs.StubGlanceClient):
            """A client that fails the first time, then succeeds."""
            def get(self, image_id):
                if tries[0] == 0:
                    tries[0] = 1
                    raise glance_exc.ServiceUnavailable('')
                else:
                    return {}

        stub_client = MyGlanceStubClient()
        stub_context = context.RequestContext(auth_token=True)
        stub_context.user_id = 'fake'
        stub_context.project_id = 'fake'
        stub_service = service.GlanceImageService(stub_client, 1, stub_context)
        image_id = 1  # doesn't matter
        writer = NullWriter()

        # When retries are disabled, we should get an exception
        self.config(glance_num_retries=0, group='glance')
        self.assertRaises(exception.GlanceConnectionFailed,
                          stub_service.download, image_id, writer)

        # Now lets enable retries. No exception should happen now.
        tries = [0]
        self.config(glance_num_retries=1, group='glance')
        stub_service.download(image_id, writer)
        self.assertTrue(mock_sleep.called)
示例#5
0
def build_instance_info_for_deploy(task):
    """Build instance_info necessary for deploying to a node.

    :param task: a TaskManager object containing the node
    :returns: a dictionary containing the properties to be updated
        in instance_info
    :raises: exception.ImageRefValidationFailed if image_source is not
        Glance href and is not HTTP(S) URL.
    """
    def validate_image_url(url, secret=False):
        """Validates image URL through the HEAD request.

        :param url: URL to be validated
        :param secret: if URL is secret (e.g. swift temp url),
            it will not be shown in logs.
        """
        try:
            image_service.HttpImageService().validate_href(url, secret)
        except exception.ImageRefValidationFailed as e:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE("Agent deploy supports only HTTP(S) URLs as "
                              "instance_info['image_source'] or swift "
                              "temporary URL. Either the specified URL is not "
                              "a valid HTTP(S) URL or is not reachable "
                              "for node %(node)s. Error: %(msg)s"),
                          {'node': node.uuid, 'msg': e})
    node = task.node
    instance_info = node.instance_info
    iwdi = node.driver_internal_info.get('is_whole_disk_image')
    image_source = instance_info['image_source']
    if service_utils.is_glance_image(image_source):
        glance = image_service.GlanceImageService(version=2,
                                                  context=task.context)
        image_info = glance.show(image_source)
        LOG.debug('Got image info: %(info)s for node %(node)s.',
                  {'info': image_info, 'node': node.uuid})
        swift_temp_url = glance.swift_temp_url(image_info)
        validate_image_url(swift_temp_url, secret=True)
        instance_info['image_url'] = swift_temp_url
        instance_info['image_checksum'] = image_info['checksum']
        instance_info['image_disk_format'] = image_info['disk_format']
        instance_info['image_container_format'] = (
            image_info['container_format'])
        instance_info['image_tags'] = image_info.get('tags', [])
        instance_info['image_properties'] = image_info['properties']

        if not iwdi:
            instance_info['kernel'] = image_info['properties']['kernel_id']
            instance_info['ramdisk'] = image_info['properties']['ramdisk_id']
    else:
        validate_image_url(image_source)
        instance_info['image_url'] = image_source

    if not iwdi:
        instance_info['image_type'] = 'partition'
        i_info = parse_instance_info(node)
        instance_info.update(i_info)
    else:
        instance_info['image_type'] = 'whole-disk-image'
    return instance_info
示例#6
0
 def setUp(self):
     super(TestGlanceImageService, self).setUp()
     self.client = stubs.StubGlanceClient()
     self.context = context.RequestContext(auth_token=True)
     self.context.user_id = 'fake'
     self.context.project_id = 'fake'
     self.service = service.GlanceImageService(self.client, self.context)
示例#7
0
def _get_instance_image_info(node, ctx):
    """Generate the paths for TFTP files for instance related images.

    This method generates the paths for instance kernel and
    instance ramdisk. This method also updates the node, so caller should
    already have a non-shared lock on the node.

    :param node: a node object
    :param ctx: context
    :returns: a dictionary whose keys are the names of the images (kernel,
        ramdisk) and values are the absolute paths of them. If it's a whole
        disk image, it returns an empty dictionary.
    """
    image_info = {}
    if node.driver_internal_info.get('is_whole_disk_image'):
        return image_info

    root_dir = pxe_utils.get_root_dir()
    i_info = node.instance_info
    labels = ('kernel', 'ramdisk')
    d_info = deploy_utils.get_image_instance_info(node)
    if not (i_info.get('kernel') and i_info.get('ramdisk')):
        glance_service = service.GlanceImageService(version=1, context=ctx)
        iproperties = glance_service.show(d_info['image_source'])['properties']
        for label in labels:
            i_info[label] = str(iproperties[label + '_id'])
        node.instance_info = i_info
        node.save()

    for label in labels:
        image_info[label] = (i_info[label],
                             os.path.join(root_dir, node.uuid, label))

    return image_info
示例#8
0
    def setUp(self):
        super(TestGlanceImageService, self).setUp()
        client = stubs.StubGlanceClient()
        self.context = context.RequestContext(auth_token=True)
        self.context.user_id = 'fake'
        self.context.project_id = 'fake'
        self.service = service.GlanceImageService(client, 1, self.context)

        self.config(glance_api_servers=['http://localhost'], group='glance')
        self.config(auth_strategy='keystone', group='glance')
示例#9
0
def get_temp_url_for_glance_image(context, image_uuid):
    """Returns the tmp url for a glance image.

    :param context: context
    :param image_uuid: the UUID of the image in glance
    :returns: the tmp url for the glance image.
    """
    glance_service = service.GlanceImageService(context=context)
    image_properties = glance_service.show(image_uuid)
    LOG.debug('Got image info: %(info)s for image %(image_uuid)s.',
              {'info': image_properties, 'image_uuid': image_uuid})
    return glance_service.swift_temp_url(image_properties)
示例#10
0
def build_instance_info_for_deploy(task):
    """Build instance_info necessary for deploying to a node.

    :param task: a TaskManager object containing the node
    :returns: a dictionary containing the properties to be updated
        in instance_info
    :raises: exception.ImageRefValidationFailed if image_source is not
        Glance href and is not HTTP(S) URL.
    """
    node = task.node
    instance_info = node.instance_info
    iwdi = node.driver_internal_info.get('is_whole_disk_image')
    image_source = instance_info['image_source']
    if service_utils.is_glance_image(image_source):
        glance = image_service.GlanceImageService(version=2,
                                                  context=task.context)
        image_info = glance.show(image_source)
        swift_temp_url = glance.swift_temp_url(image_info)
        LOG.debug('Got image info: %(info)s for node %(node)s.', {
            'info': image_info,
            'node': node.uuid
        })
        instance_info['image_url'] = swift_temp_url
        instance_info['image_checksum'] = image_info['checksum']
        instance_info['image_disk_format'] = image_info['disk_format']
        instance_info['image_container_format'] = (
            image_info['container_format'])
        instance_info['image_tags'] = image_info.get('tags', [])
        instance_info['image_properties'] = image_info['properties']

        if not iwdi:
            instance_info['kernel'] = image_info['properties']['kernel_id']
            instance_info['ramdisk'] = image_info['properties']['ramdisk_id']
    else:
        try:
            image_service.HttpImageService().validate_href(image_source)
        except exception.ImageRefValidationFailed:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    _LE("Agent deploy supports only HTTP(S) URLs as "
                        "instance_info['image_source']. Either %s "
                        "is not a valid HTTP(S) URL or "
                        "is not reachable."), image_source)
        instance_info['image_url'] = image_source

    if not iwdi:
        instance_info['image_type'] = 'partition'
        i_info = parse_instance_info(node)
        instance_info.update(i_info)
    else:
        instance_info['image_type'] = 'whole-disk-image'
    return instance_info
示例#11
0
def get_instance_image_info(task, ipxe_enabled=False):
    """Generate the paths for TFTP files for instance related images.

    This method generates the paths for instance kernel and
    instance ramdisk. This method also updates the node, so caller should
    already have a non-shared lock on the node.

    :param task: A TaskManager instance containing node and context.
    :param ipxe_enabled: Default false boolean to indicate if ipxe
                         is in use by the caller.
    :returns: a dictionary whose keys are the names of the images (kernel,
        ramdisk) and values are the absolute paths of them. If it's a whole
        disk image or node is configured for localboot,
        it returns an empty dictionary.
    """
    ctx = task.context
    node = task.node
    image_info = {}
    # NOTE(pas-ha) do not report image kernel and ramdisk for
    # local boot or whole disk images so that they are not cached
    if (node.driver_internal_info.get('is_whole_disk_image')
            or deploy_utils.get_boot_option(node) == 'local'):
        return image_info
    if ipxe_enabled:
        root_dir = get_ipxe_root_dir()
    else:
        root_dir = get_root_dir()
    i_info = node.instance_info
    if i_info.get('boot_iso'):
        image_info['boot_iso'] = (
            i_info['boot_iso'],
            os.path.join(root_dir, node.uuid, 'boot_iso'))

        return image_info

    labels = ('kernel', 'ramdisk')
    d_info = deploy_utils.get_image_instance_info(node)
    if not (i_info.get('kernel') and i_info.get('ramdisk')):
        glance_service = service.GlanceImageService(context=ctx)
        iproperties = glance_service.show(d_info['image_source'])['properties']
        for label in labels:
            i_info[label] = str(iproperties[label + '_id'])
        node.instance_info = i_info
        node.save()
    for label in labels:
        image_info[label] = (
            i_info[label],
            os.path.join(root_dir, node.uuid, label)
        )

    return image_info
示例#12
0
    def test_client_httpnotfound_converts_to_imagenotfound(self):
        class MyGlanceStubClient(stubs.StubGlanceClient):
            """A client that raises a HTTPNotFound exception."""
            def get(self, image_id):
                raise glance_exc.HTTPNotFound(image_id)

        stub_client = MyGlanceStubClient()
        stub_context = context.RequestContext(auth_token=True)
        stub_context.user_id = 'fake'
        stub_context.project_id = 'fake'
        stub_service = service.GlanceImageService(stub_client, 1, stub_context)
        image_id = 1  # doesn't matter
        writer = NullWriter()
        self.assertRaises(exception.ImageNotFound, stub_service.download,
                          image_id, writer)
示例#13
0
    def test_client_httpforbidden_converts_to_imagenotauthed(self):
        class MyGlanceStubClient(stubs.StubGlanceClient):
            """A client that raises a HTTPForbidden exception."""
            def get(self, image_id):
                raise glance_exc.HTTPForbidden(image_id)

        stub_client = MyGlanceStubClient()
        stub_context = context.RequestContext(auth_token=True)
        stub_context.user_id = 'fake'
        stub_context.project_id = 'fake'
        stub_service = service.GlanceImageService(stub_client, 1, stub_context)
        image_id = uuidutils.generate_uuid()
        writer = NullWriter()
        self.assertRaises(exception.ImageNotAuthorized, stub_service.download,
                          image_id, writer)
示例#14
0
 def setUp(self):
     super(TestGlanceSwiftTempURL, self).setUp()
     client = stubs.StubGlanceClient()
     self.context = context.RequestContext()
     self.context.auth_token = 'fake'
     self.service = service.GlanceImageService(client, 2, self.context)
     self.config(swift_temp_url_key='correcthorsebatterystaple',
                 group='glance')
     self.config(swift_endpoint_url='https://swift.example.com',
                 group='glance')
     self.config(swift_account='AUTH_a422b2-91f3-2f46-74b7-d7c9e8958f5d30',
                 group='glance')
     self.config(swift_api_version='v1', group='glance')
     self.config(swift_container='glance', group='glance')
     self.config(swift_temp_url_duration=1200, group='glance')
     self.config(swift_store_multiple_containers_seed=0, group='glance')
     self.fake_image = {'id': '757274c4-2856-4bd2-bb20-9a4a231e187b'}
示例#15
0
def _get_deploy_data(context, image_source):
    glance = image_service.GlanceImageService(version=2, context=context)
    image_props = glance.show(image_source).get('properties', {})
    LOG.debug('Image %s properties are: %s', image_source, image_props)
    try:
        disk_data = json.loads(image_props['fuel_disk_info'])
    except KeyError:
        raise exception.MissingParameterValue(
            _('Image %s does not contain '
              'disk layout data.') % image_source)
    except ValueError:
        raise exception.InvalidParameterValue(
            _('Invalid disk layout data for '
              'image %s') % image_source)
    data = FUEL_AGENT_PROVISION_TEMPLATE.copy()
    data['ks_meta']['pm_data']['ks_spaces'] = disk_data
    return data
示例#16
0
    def setUp(self):
        super(TestGlanceImageService, self).setUp()
        client = stubs.StubGlanceClient()
        self.context = context.RequestContext(auth_token=True)
        self.context.user_id = 'fake'
        self.context.project_id = 'fake'
        self.service = service.GlanceImageService(client, 1, self.context)

        self.config(glance_host='localhost', group='glance')
        try:
            self.config(auth_strategy='keystone', group='glance')
        except Exception:
            opts = [
                cfg.StrOpt('auth_strategy', default='keystone'),
            ]
            CONF.register_opts(opts)

        return
示例#17
0
 def setUp(self):
     super(CheckImageServiceTestCase, self).setUp()
     self.context = context.RequestContext(global_request_id='global')
     self.service = service.GlanceImageService(None, self.context)
     # NOTE(pas-ha) register keystoneauth dynamic options manually
     plugin = kaloading.get_plugin_loader('password')
     opts = kaloading.get_auth_plugin_conf_options(plugin)
     self.cfg_fixture.register_opts(opts, group='glance')
     self.config(auth_type='password',
                 auth_url='viking',
                 username='******',
                 password='******',
                 project_name='parrot',
                 service_type='image',
                 region_name='SomeRegion',
                 interface='internal',
                 group='glance')
     image_service._GLANCE_SESSION = None
示例#18
0
    def test_download_file_url(self, mock_getsize, mock_sendfile):
        # NOTE: only in v2 API
        class MyGlanceStubClient(stubs.StubGlanceClient):

            """A client that returns a file url."""

            s_tmpfname = '/whatever/source'

            def get(self, image_id):
                return type('GlanceTestDirectUrlMeta', (object,),
                            {'direct_url': 'file://%s' + self.s_tmpfname})

        stub_context = context.RequestContext(auth_token=True)
        stub_context.user_id = 'fake'
        stub_context.project_id = 'fake'
        stub_client = MyGlanceStubClient()

        stub_service = service.GlanceImageService(stub_client,
                                                  context=stub_context,
                                                  version=2)
        image_id = 1  # doesn't matter

        self.config(allowed_direct_url_schemes=['file'], group='glance')

        # patching open in base_image_service module namespace
        # to make call-spec assertions
        with mock.patch('ironic.common.glance_service.base_image_service.open',
                        new=mock.mock_open(), create=True) as mock_ironic_open:
            with open('/whatever/target', 'w') as mock_target_fd:
                stub_service.download(image_id, mock_target_fd)

        # assert the image data was neither read nor written
        # but rather sendfiled
        mock_ironic_open.assert_called_once_with(MyGlanceStubClient.s_tmpfname,
                                                 'r')
        mock_source_fd = mock_ironic_open()
        self.assertFalse(mock_source_fd.read.called)
        self.assertFalse(mock_target_fd.write.called)
        mock_sendfile.assert_called_once_with(
            mock_target_fd.fileno(),
            mock_source_fd.fileno(),
            0,
            mock_getsize(MyGlanceStubClient.s_tmpfname))
示例#19
0
    def test_download_file_url(self):
        # NOTE: only in v2 API
        class MyGlanceStubClient(stubs.StubGlanceClient):
            """A client that returns a file url."""

            (outfd, s_tmpfname) = tempfile.mkstemp(prefix='directURLsrc')
            outf = os.fdopen(outfd, 'wb')
            inf = open('/dev/urandom', 'rb')
            for i in range(10):
                _data = inf.read(1024)
                outf.write(_data)
            outf.close()

            def get(self, image_id):
                return type('GlanceTestDirectUrlMeta', (object, ),
                            {'direct_url': 'file://%s' + self.s_tmpfname})

        stub_context = context.RequestContext(auth_token=True)
        stub_context.user_id = 'fake'
        stub_context.project_id = 'fake'
        stub_client = MyGlanceStubClient()
        (outfd, tmpfname) = tempfile.mkstemp(prefix='directURLdst')
        writer = os.fdopen(outfd, 'w')

        stub_service = service.GlanceImageService(stub_client,
                                                  context=stub_context,
                                                  version=2)
        image_id = 1  # doesn't matter

        self.config(allowed_direct_url_schemes=['file'], group='glance')
        stub_service.download(image_id, writer)
        writer.close()

        # compare the two files
        rc = filecmp.cmp(tmpfname, stub_client.s_tmpfname)
        self.assertTrue(
            rc, "The file %s and %s should be the same" %
            (tmpfname, stub_client.s_tmpfname))
        os.remove(stub_client.s_tmpfname)
        os.remove(tmpfname)
示例#20
0
def _create_rootfs_link(task):
    """Create Swift temp url for deployment root FS."""
    rootfs = _get_boot_files(task.node)['deploy_squashfs']

    if service_utils.is_glance_image(rootfs):
        glance = image_service.GlanceImageService(version=2,
                                                  context=task.context)
        image_info = glance.show(rootfs)
        temp_url = glance.swift_temp_url(image_info)
        temp_url += '&filename=/root.squashfs'
        return temp_url

    try:
        image_service.HttpImageService().validate_href(rootfs)
    except exception.ImageRefValidationFailed:
        with excutils.save_and_reraise_exception():
            LOG.error(
                _LE("Agent deploy supports only HTTP URLs as "
                    "driver_info['deploy_squashfs']. Either %s "
                    "is not a valid HTTP URL or "
                    "is not reachable."), rootfs)
    return rootfs
示例#21
0
    def configure_local_boot(self, task, root_uuid=None,
                             efi_system_part_uuid=None,
                             prep_boot_part_uuid=None):
        """Helper method to configure local boot on the node.

        This method triggers bootloader installation on the node.
        On successful installation of bootloader, this method sets the
        node to boot from disk.

        :param task: a TaskManager object containing the node
        :param root_uuid: The UUID of the root partition. This is used
            for identifying the partition which contains the image deployed
            or None in case of whole disk images which we expect to already
            have a bootloader installed.
        :param efi_system_part_uuid: The UUID of the efi system partition.
            This is used only in uefi boot mode.
        :param prep_boot_part_uuid: The UUID of the PReP Boot partition.
            This is used only for booting ppc64* hardware.
        :raises: InstanceDeployFailure if bootloader installation failed or
            on encountering error while setting the boot device on the node.
        """
        node = task.node
        LOG.debug('Configuring local boot for node %s', node.uuid)

        # If the target RAID configuration is set to 'software' for the
        # 'controller', we need to trigger the installation of grub on
        # the holder disks of the desired Software RAID.
        internal_info = node.driver_internal_info
        raid_config = node.target_raid_config
        logical_disks = raid_config.get('logical_disks', [])
        software_raid = False
        for logical_disk in logical_disks:
            if logical_disk.get('controller') == 'software':
                LOG.debug('Node %s has a Software RAID configuration',
                          node.uuid)
                software_raid = True
                break

        # For software RAID try to get the UUID of the root fs from the
        # image's metadata (via Glance). Fall back to the driver internal
        # info in case it is not available (e.g. not set or there's no Glance).
        if software_raid:
            image_source = node.instance_info.get('image_source')
            try:
                context = task.context
                context.is_admin = True
                glance = image_service.GlanceImageService(
                    context=context)
                image_info = glance.show(image_source)
                image_properties = image_info.get('properties')
                root_uuid = image_properties['rootfs_uuid']
                LOG.debug('Got rootfs_uuid from Glance: %s', root_uuid)
            except Exception as e:
                LOG.warning('Could not get \'rootfs_uuid\' property for '
                            'image %(image)s from Glance: %(error)s.',
                            {'image': image_source, 'error': e})
                root_uuid = internal_info.get('root_uuid_or_disk_id')
                LOG.debug('Got rootfs_uuid from driver internal info: '
                          ' %s', root_uuid)

        whole_disk_image = internal_info.get('is_whole_disk_image')
        if software_raid or (root_uuid and not whole_disk_image):
            LOG.debug('Installing the bootloader for node %(node)s on '
                      'partition %(part)s, EFI system partition %(efi)s',
                      {'node': node.uuid, 'part': root_uuid,
                       'efi': efi_system_part_uuid})
            result = self._client.install_bootloader(
                node, root_uuid=root_uuid,
                efi_system_part_uuid=efi_system_part_uuid,
                prep_boot_part_uuid=prep_boot_part_uuid)
            if result['command_status'] == 'FAILED':
                msg = (_("Failed to install a bootloader when "
                         "deploying node %(node)s. Error: %(error)s") %
                       {'node': node.uuid,
                        'error': result['command_error']})
                log_and_raise_deployment_error(task, msg)

        try:
            persistent = True
            if node.driver_info.get('force_persistent_boot_device',
                                    'Default') == 'Never':
                persistent = False
            deploy_utils.try_set_boot_device(task, boot_devices.DISK,
                                             persistent=persistent)
        except Exception as e:
            msg = (_("Failed to change the boot device to %(boot_dev)s "
                     "when deploying node %(node)s. Error: %(error)s") %
                   {'boot_dev': boot_devices.DISK, 'node': node.uuid,
                    'error': e})
            log_and_raise_deployment_error(task, msg, exc=e)

        LOG.info('Local boot successfully configured for node %s', node.uuid)
示例#22
0
def build_instance_info_for_deploy(task):
    """Build instance_info necessary for deploying to a node.

    :param task: a TaskManager object containing the node
    :returns: a dictionary containing the properties to be updated
        in instance_info
    :raises: exception.ImageRefValidationFailed if image_source is not
        Glance href and is not HTTP(S) URL.
    """
    def validate_image_url(url, secret=False):
        """Validates image URL through the HEAD request.

        :param url: URL to be validated
        :param secret: if URL is secret (e.g. swift temp url),
            it will not be shown in logs.
        """
        try:
            image_service.HttpImageService().validate_href(url, secret)
        except exception.ImageRefValidationFailed as e:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    "Agent deploy supports only HTTP(S) URLs as "
                    "instance_info['image_source'] or swift "
                    "temporary URL. Either the specified URL is not "
                    "a valid HTTP(S) URL or is not reachable "
                    "for node %(node)s. Error: %(msg)s", {
                        'node': node.uuid,
                        'msg': e
                    })

    node = task.node
    instance_info = node.instance_info
    iwdi = node.driver_internal_info.get('is_whole_disk_image')
    image_source = instance_info['image_source']

    if service_utils.is_glance_image(image_source):
        glance = image_service.GlanceImageService(context=task.context)
        image_info = glance.show(image_source)
        LOG.debug('Got image info: %(info)s for node %(node)s.', {
            'info': image_info,
            'node': node.uuid
        })
        if CONF.agent.image_download_source == 'swift':
            swift_temp_url = glance.swift_temp_url(image_info)
            validate_image_url(swift_temp_url, secret=True)
            instance_info['image_url'] = swift_temp_url
            instance_info['image_checksum'] = image_info['checksum']
            instance_info['image_disk_format'] = image_info['disk_format']
            instance_info['image_os_hash_algo'] = image_info['os_hash_algo']
            instance_info['image_os_hash_value'] = image_info['os_hash_value']
        else:
            # Ironic cache and serve images from httpboot server
            force_raw = direct_deploy_should_convert_raw_image(node)
            _, image_path = cache_instance_image(task.context,
                                                 node,
                                                 force_raw=force_raw)
            if force_raw:
                instance_info['image_disk_format'] = 'raw'
                # Standard behavior is for image_checksum to be MD5,
                # so if the hash algorithm is None, then we will use
                # sha256.
                os_hash_algo = image_info.get('os_hash_algo')
                if os_hash_algo == 'md5':
                    LOG.debug(
                        'Checksum calculation for image %(image)s is '
                        'set to \'%(algo)s\', changing to \'sha256\'', {
                            'algo': os_hash_algo,
                            'image': image_path
                        })
                    os_hash_algo = 'sha256'
                LOG.debug(
                    'Recalculating checksum for image %(image)s due to '
                    'image conversion.', {'image': image_path})
                instance_info['image_checksum'] = None
                hash_value = compute_image_checksum(image_path, os_hash_algo)
                instance_info['image_os_hash_algo'] = os_hash_algo
                instance_info['image_os_hash_value'] = hash_value
            else:
                instance_info['image_checksum'] = image_info['checksum']
                instance_info['image_disk_format'] = image_info['disk_format']
                instance_info['image_os_hash_algo'] = image_info[
                    'os_hash_algo']
                instance_info['image_os_hash_value'] = image_info[
                    'os_hash_value']

            # Create symlink and update image url
            symlink_dir = _get_http_image_symlink_dir_path()
            fileutils.ensure_tree(symlink_dir)
            symlink_path = _get_http_image_symlink_file_path(node.uuid)
            utils.create_link_without_raise(image_path, symlink_path)
            base_url = CONF.deploy.http_url
            if base_url.endswith('/'):
                base_url = base_url[:-1]
            http_image_url = '/'.join(
                [base_url, CONF.deploy.http_image_subdir, node.uuid])
            validate_image_url(http_image_url, secret=True)
            instance_info['image_url'] = http_image_url

        instance_info['image_container_format'] = (
            image_info['container_format'])
        instance_info['image_tags'] = image_info.get('tags', [])
        instance_info['image_properties'] = image_info['properties']

        if not iwdi:
            instance_info['kernel'] = image_info['properties']['kernel_id']
            instance_info['ramdisk'] = image_info['properties']['ramdisk_id']
    else:
        validate_image_url(image_source)
        instance_info['image_url'] = image_source

    if not iwdi:
        instance_info['image_type'] = 'partition'
        i_info = parse_instance_info(node)
        instance_info.update(i_info)
    else:
        instance_info['image_type'] = 'whole-disk-image'
    return instance_info