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)
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
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
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 })
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)
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)
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'}
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)
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}
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
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
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 })
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)
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
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']