def test_download_with_retries(self):
        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 exception.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.Service(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)
Exemple #2
0
def _get_tftp_image_info(node, ctx):
    """Generate the paths for tftp files for this instance

    Raises IronicException if
    - instance does not contain kernel_id or ramdisk_id
    - deploy_kernel_id or deploy_ramdisk_id can not be read from
      driver_info and defaults are not set

    """
    d_info = _parse_deploy_info(node)
    image_info = {}

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

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

    for label in labels:
        if label not in i_info:
            continue
        image_info[label] = (i_info[label],
                             os.path.join(CONF.pxe.tftp_root, node.uuid,
                                          label))

    return image_info
Exemple #3
0
def _get_tftp_image_info(node, ctx):
    """Generate the paths for tftp files for this instance

    Raises IronicException if
    - instance does not contain kernel_id or ramdisk_id
    - deploy_kernel_id or deploy_ramdisk_id can not be read from
      driver_info and defaults are not set

    """
    #TODO(ghe): Called multiples times. Should we store image_info?
    d_info = _parse_driver_info(node)
    image_info = {
        'deploy_kernel': [None, None],
        'deploy_ramdisk': [None, None],
    }

    for label in image_info:
        image_info[label][0] = str(d_info[label]).split('/')[-1]
        image_info[label][1] = os.path.join(CONF.pxe.tftp_root, node.uuid,
                                            label)

    glance_service = service.Service(version=1, context=ctx)
    iproperties = glance_service.show(d_info['image_source'])['properties']
    for label in ('kernel', 'ramdisk'):
        image_info[label] = [None, None]
        image_info[label][0] = str(iproperties[label + '_id']).split('/')[-1]
        image_info[label][1] = os.path.join(CONF.pxe.tftp_root, node.uuid,
                                            label)

    return image_info
Exemple #4
0
def _validate_glance_image(ctx, driver_info):
    """Validate the image in Glance.

    Check if the image exist in Glance and if it contains the
    'kernel_id' and 'ramdisk_id' properties.

    :raises: InvalidParameterValue.
    """
    image_id = driver_info['image_source']
    try:
        glance_service = service.Service(version=1, context=ctx)
        image_props = glance_service.show(image_id)['properties']
    except (exception.GlanceConnectionFailed, exception.ImageNotAuthorized,
            exception.Invalid):
        raise exception.InvalidParameterValue(
            _("Failed to connect to Glance to get the properties "
              "of the image %s") % image_id)
    except exception.ImageNotFound:
        raise exception.InvalidParameterValue(
            _("Image %s not found in Glance") % image_id)

    missing_props = []
    for prop in ('kernel_id', 'ramdisk_id'):
        if not image_props.get(prop):
            missing_props.append(prop)

    if missing_props:
        props = ', '.join(missing_props)
        raise exception.InvalidParameterValue(
            _("Image %(image)s is missing the following properties: "
              "%(properties)s") % {
                  'image': image_id,
                  'properties': props
              })
Exemple #5
0
def fetch(context, image_href, path, image_service=None):
    # TODO(vish): Improve context handling and add owner and auth data
    #             when it is added to glance.  Right now there is no
    #             auth checking in glance, so we assume that access was
    #             checked before we got here.
    if not image_service:
        image_service = service.Service(version=1, context=context)

    with fileutils.remove_path_on_error(path):
        with open(path, "wb") as image_file:
            image_service.download(image_href, image_file)
Exemple #6
0
def get_glance_image_property(context, image_uuid, property):
    """Returns the value of a glance image property.

    :param context: context
    :param image_uuid: the UUID of the image in glance
    :param property: the property whose value is required.
    :returns: the value of the property if it exists, otherwise None.
    """
    glance_service = service.Service(version=1, context=context)
    iproperties = glance_service.show(image_uuid)['properties']
    return iproperties.get(property)
Exemple #7
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 API version 2 is required for getting direct_url of the image.
    glance_service = service.Service(version=2, 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)
    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 exception.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.Service(stub_client, 1, stub_context)
        image_id = 1  # doesn't matter
        writer = NullWriter()
        self.assertRaises(exception.ImageNotFound, stub_service.download,
                          image_id, writer)
 def setUp(self):
     super(TestGlanceSwiftTempURL, self).setUp()
     client = stubs.StubGlanceClient()
     self.context = context.RequestContext()
     self.service = service.Service(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()
     self.fake_image = {'id': '757274c4-2856-4bd2-bb20-9a4a231e187b'}
Exemple #10
0
    def prepare(self, task):
        """Prepare the deployment environment for this task's node.
        Get the image info from glance, config the mac for the xcat
        use ssh and iptables to disable dhcp on network node
        :param task: a TaskManager instance containing the node to act on.
        """
        # TODO(deva): optimize this if rerun on existing files
        d_info = _parse_deploy_info(task.node)
        i_info = task.node.instance_info
        image_id = d_info['image_source']
        try:
            glance_service = service.Service(version=1, context=task.context)
            image_name = glance_service.show(image_id)['name']
            i_info['image_name'] = image_name
        except (exception.GlanceConnectionFailed, exception.ImageNotAuthorized,
                exception.Invalid):
            LOG.warning(
                _("Failed to connect to Glance to get the properties "
                  "of the image %s") % image_id)

        node_mac_addresses = driver_utils.get_node_mac_addresses(task)
        vif_ports_info = xcat_neutron.get_ports_info_from_neutron(task)
        try:
            network_info = self._get_deploy_network_info(
                vif_ports_info, node_mac_addresses)
        except (xcat_exception.GetNetworkFixedIPFailure,
                xcat_exception.GetNetworkIdFailure):
            LOG.error(_("Failed to get network info"))
            return
        if not network_info:
            LOG.error(_("Failed to get network info"))
            return

        fixed_ip_address = network_info['fixed_ip_address']
        deploy_mac_address = network_info['mac_address']
        network_id = network_info['network_id']

        i_info['fixed_ip_address'] = fixed_ip_address
        i_info['network_id'] = network_id
        i_info['deploy_mac_address'] = deploy_mac_address

        # use iptables to drop the dhcp mac of baremetal machine
        self._ssh_append_dhcp_rule(CONF.xcat.network_node_ip,
                                   CONF.xcat.ssh_port, CONF.xcat.ssh_user,
                                   CONF.xcat.ssh_password, network_id,
                                   deploy_mac_address)
        self._chdef_node_mac_address(d_info, deploy_mac_address)
Exemple #11
0
def get_glance_image_properties(context, image_uuid, properties="all"):
    """Returns the values of several properties of a glance image

    :param context: context
    :param image_uuid: the UUID of the image in glance
    :param properties: the properties whose values are required.
        This argument is optional, default value is "all", so if not specified
        all properties will be returned.
    :returns: a dict of the values of the properties. A property not on the
        glance metadata will have a value of None.
    """
    glance_service = service.Service(version=1, context=context)
    iproperties = glance_service.show(image_uuid)['properties']

    if properties == "all":
        return iproperties

    return {p: iproperties.get(p) for p in properties}
Exemple #12
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.Service(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
Exemple #13
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
    """
    node = task.node
    instance_info = node.instance_info

    glance = image_service.Service(version=2, context=task.context)
    image_info = glance.show(instance_info['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']
    return instance_info
Exemple #14
0
def validate_glance_image_properties(ctx, deploy_info, properties):
    """Validate the image in Glance.

    Check if the image exist in Glance and if it contains the
    properties passed.

    :param ctx: security context
    :param deploy_info: the deploy_info to be validated
    :param properties: the list of image meta-properties to be validated.
    :raises: InvalidParameterValue if connection to glance failed or
        authorization for accessing image failed or if image doesn't exist.
    :raises: MissingParameterValue if the glance image doesn't contain
        the mentioned properties.
    """
    image_id = deploy_info['image_source']
    try:
        glance_service = service.Service(version=1, context=ctx)
        image_props = glance_service.show(image_id)['properties']
    except (exception.GlanceConnectionFailed, exception.ImageNotAuthorized,
            exception.Invalid):
        raise exception.InvalidParameterValue(
            _("Failed to connect to Glance to get the properties "
              "of the image %s") % image_id)
    except exception.ImageNotFound:
        raise exception.InvalidParameterValue(
            _("Image %s not found in Glance") % image_id)

    missing_props = []
    for prop in properties:
        if not image_props.get(prop):
            missing_props.append(prop)

    if missing_props:
        props = ', '.join(missing_props)
        raise exception.MissingParameterValue(
            _("Image %(image)s is missing the following properties: "
              "%(properties)s") % {
                  'image': image_id,
                  'properties': props
              })
Exemple #15
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, 'w')
            inf = open('/dev/urandom', 'r')
            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.Service(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)
Exemple #16
0
def _get_tftp_image_info(node, ctx):
    """Generate the paths for tftp files for this instance

    Raises IronicException if
    - instance does not contain kernel_id or ramdisk_id
    - deploy_kernel_id or deploy_ramdisk_id can not be read from
      driver_info and defaults are not set

    """
    d_info = _parse_driver_info(node)
    image_info = {
        'deploy_kernel': [None, None],
        'deploy_ramdisk': [None, None],
    }

    for label in image_info:
        image_info[label][0] = str(d_info[label]).split('/')[-1]
        image_info[label][1] = os.path.join(CONF.pxe.tftp_root, node.uuid,
                                            label)

    driver_info = node.driver_info
    labels = ('kernel', 'ramdisk')
    if not (driver_info.get('pxe_kernel') and driver_info.get('pxe_ramdisk')):
        glance_service = service.Service(version=1, context=ctx)
        iproperties = glance_service.show(d_info['image_source'])['properties']
        for label in labels:
            driver_info['pxe_' + label] = str(
                iproperties[label + '_id']).split('/')[-1]
        node.driver_info = driver_info
        node.save(ctx)

    for label in labels:
        image_info[label] = [None, None]
        image_info[label][0] = driver_info['pxe_' + label]
        image_info[label][1] = os.path.join(CONF.pxe.tftp_root, node.uuid,
                                            label)

    return image_info
Exemple #17
0
def download_size(context, image_href, image_service=None):
    if not image_service:
        image_service = service.Service(version=1, context=context)
    return image_service.show(image_href)['size']