def check_attach(self, context, volume, instance=None): # TODO(vish): abstract status checking? if volume["shareable"] == "true": if volume["status"] != "available" and volume["status"] != "in-use": msg = _("shareable volume's status must be" "'available' or 'in-use'") raise exception.InvalidVolume(reason=msg) if instance: for attachment in volume["attachments"]: if attachment["instance_uuid"] == instance["uuid"]: msg = _( "the shareable volume has already been attached" " to this instance and you cannot repeatedly attach" ) raise exception.InvalidVolume(reason=msg) else: if volume["status"] != "available": msg = _("status must be 'available'") raise exception.InvalidVolume(reason=msg) if volume["attach_status"] == "attached": msg = _("already attached") raise exception.InvalidVolume(reason=msg) if instance and not CONF.cinder.cross_az_attach: # NOTE(sorrison): If instance is on a host we match against it's AZ # else we check the intended AZ if instance.get("host"): instance_az = az.get_instance_availability_zone(context, instance) else: instance_az = instance["availability_zone"] if instance_az != volume["availability_zone"]: msg = _("Instance and volume not in same availability_zone") raise exception.InvalidVolume(reason=msg)
def test_get_instance_availability_zone_default_value(self): """Test get right availability zone by given an instance.""" fake_inst_id = 162 fake_inst = fakes.stub_instance(fake_inst_id, host=self.host) self.assertEqual(self.default_az, az.get_instance_availability_zone(self.context, fake_inst))
def check_attach(self, context, volume, instance=None): # TODO(vish): abstract status checking? if volume["status"] != "available": msg = _("volume '%(vol)s' status must be 'available'. Currently " "in '%(status)s'") % { "vol": volume["id"], "status": volume["status"], } raise exception.InvalidVolume(reason=msg) if volume["attach_status"] == "attached": msg = _("volume %s already attached") % volume["id"] raise exception.InvalidVolume(reason=msg) if instance and not CONF.cinder.cross_az_attach: instance_az = az.get_instance_availability_zone(context, instance) if instance_az != volume["availability_zone"]: msg = _( "Instance %(instance)s and volume %(vol)s are not in " "the same availability_zone. Instance is in " "%(ins_zone)s. Volume is in %(vol_zone)s" ) % { "instance": instance["id"], "vol": volume["id"], "ins_zone": instance_az, "vol_zone": volume["availability_zone"], } raise exception.InvalidVolume(reason=msg)
def _extend_server(self, context, server, instance): # NOTE(mriedem): The OS-EXT-AZ prefix should not be used for new # attributes after v2.1. They are only in v2.1 for backward compat # with v2.0. key = "%s:availability_zone" % PREFIX az = avail_zone.get_instance_availability_zone(context, instance) server[key] = az or ''
def test_get_instance_availability_zone_default_value(self): """Test get right availability zone by given an instance.""" fake_inst = objects.Instance(host=self.host, availability_zone=None) self.assertEqual(self.default_az, az.get_instance_availability_zone(self.context, fake_inst))
def check_attach(self, context, volume, instance=None): # TODO(vish): abstract status checking? if volume['status'] != "available": msg = _("volume '%(vol)s' status must be 'available'. Currently " "in '%(status)s'") % {'vol': volume['id'], 'status': volume['status']} raise exception.InvalidVolume(reason=msg) if volume['attach_status'] == "attached": msg = _("volume %s already attached") % volume['id'] raise exception.InvalidVolume(reason=msg) if instance and not CONF.cinder.cross_az_attach: # NOTE(sorrison): If instance is on a host we match against it's AZ # else we check the intended AZ if instance.get('host'): instance_az = az.get_instance_availability_zone( context, instance) else: instance_az = instance['availability_zone'] if instance_az != volume['availability_zone']: msg = _("Instance %(instance)s and volume %(vol)s are not in " "the same availability_zone. Instance is in " "%(ins_zone)s. Volume is in %(vol_zone)s") % { "instance": instance['id'], "vol": volume['id'], 'ins_zone': instance_az, 'vol_zone': volume['availability_zone']} raise exception.InvalidVolume(reason=msg)
def _extend_server(self, context, server, instance): key = "%s:availability_zone" % PREFIX az = avail_zone.get_instance_availability_zone(context, instance) if not az and instance.get("availability_zone"): # Likely hasn't reached a viable compute node yet so give back the # desired availability_zone that *may* exist in the instance # record itself. az = instance["availability_zone"] server[key] = az
def test_get_instance_availability_zone_from_aggregate(self): """Test get availability zone from aggregate by given an instance.""" host = "host170" service = self._create_service_with_topic("compute", host) self._add_to_aggregate(service, self.agg) fake_inst_id = 174 fake_inst = fakes.stub_instance(fake_inst_id, host=host) self.assertEqual(self.availability_zone, az.get_instance_availability_zone(self.context, fake_inst))
def test_get_instance_availability_zone_cache_differs(self, cache_get): host = 'host170' service = self._create_service_with_topic('compute', host) self._add_to_aggregate(service, self.agg) cache_get.return_value = self.default_az fake_inst = objects.Instance(host=host, availability_zone=self.availability_zone) self.assertEqual( self.availability_zone, az.get_instance_availability_zone(self.context, fake_inst))
def test_get_instance_availability_zone_from_aggregate(self): """Test get availability zone from aggregate by given an instance.""" host = 'host170' service = self._create_service_with_topic('compute', host) self._add_to_aggregate(service, self.agg) fake_inst = objects.Instance(host=host, availability_zone=self.availability_zone) self.assertEqual(self.availability_zone, az.get_instance_availability_zone(self.context, fake_inst))
def test_get_instance_availability_zone_no_host_set(self): """Test get availability zone from instance if host not set. This is testing the case in the compute API where the Instance object does not have the host attribute set because it's just the object that goes into the BuildRequest, it wasn't actually pulled from the DB. The instance in this case doesn't actually get inserted into the DB until it reaches conductor. So the host attribute may not be set but we expect availability_zone always will in the API because of _validate_and_build_base_options setting a default value which goes into the object. """ fake_inst = objects.Instance(availability_zone='inst-az') result = az.get_instance_availability_zone(self.context, fake_inst) self.assertEqual('inst-az', result)
def check_availability_zone(self, context, volume, instance=None): """Ensure that the availability zone is the same.""" # TODO(walter-boring): move this check to Cinder as part of # the reserve call. if instance and not CONF.cinder.cross_az_attach: instance_az = az.get_instance_availability_zone(context, instance) if instance_az != volume['availability_zone']: msg = _("Instance %(instance)s and volume %(vol)s are not in " "the same availability_zone. Instance is in " "%(ins_zone)s. Volume is in %(vol_zone)s") % { "instance": instance['id'], "vol": volume['id'], 'ins_zone': instance_az, 'vol_zone': volume['availability_zone']} raise exception.InvalidVolume(reason=msg)
def check_attach(self, context, volume, instance=None): # TODO(vish): abstract status checking? if volume['status'] != "available": msg = _("status must be 'available'") raise exception.InvalidVolume(reason=msg) if volume['attach_status'] == "attached": msg = _("already attached") raise exception.InvalidVolume(reason=msg) if instance and not CONF.cinder.cross_az_attach: # NOTE(sorrison): If instance is on a host we match against it's AZ # else we check the intended AZ if instance.get('host'): instance_az = az.get_instance_availability_zone( context, instance) else: instance_az = instance['availability_zone'] if instance_az != volume['availability_zone']: msg = _("Instance and volume not in same availability_zone") raise exception.InvalidVolume(reason=msg)
def show(self, request, instance, extend_address=True, show_extra_specs=None, show_AZ=True, show_config_drive=True, show_extended_attr=None, show_host_status=None, show_keypair=True, show_srv_usg=True): """Detailed view of a single instance.""" ip_v4 = instance.get('access_ip_v4') ip_v6 = instance.get('access_ip_v6') if show_extra_specs is None: # detail will pre-calculate this for us. If we're doing show, # then figure it out here. show_extra_specs = False if api_version_request.is_supported(request, min_version='2.47'): context = request.environ['nova.context'] show_extra_specs = context.can(fes_policies.POLICY_ROOT % 'index', fatal=False) server = { "server": { "id": instance["uuid"], "name": instance["display_name"], "status": self._get_vm_status(instance), "tenant_id": instance.get("project_id") or "", "user_id": instance.get("user_id") or "", "metadata": self._get_metadata(instance), "hostId": self._get_host_id(instance), "image": self._get_image(request, instance), "flavor": self._get_flavor(request, instance, show_extra_specs), "created": utils.isotime(instance["created_at"]), "updated": utils.isotime(instance["updated_at"]), "addresses": self._get_addresses(request, instance, extend_address), "accessIPv4": str(ip_v4) if ip_v4 is not None else '', "accessIPv6": str(ip_v6) if ip_v6 is not None else '', "links": self._get_links(request, instance["uuid"], self._collection_name), # NOTE(sdague): historically this was the # os-disk-config extension, but now that extensions # are gone, we merge these attributes here. "OS-DCF:diskConfig": ('AUTO' if instance.get('auto_disk_config') else 'MANUAL'), }, } if server["server"]["status"] in self._fault_statuses: _inst_fault = self._get_fault(request, instance) if _inst_fault: server['server']['fault'] = _inst_fault if server["server"]["status"] in self._progress_statuses: server["server"]["progress"] = instance.get("progress", 0) context = request.environ['nova.context'] if show_AZ: az = avail_zone.get_instance_availability_zone(context, instance) # NOTE(mriedem): The OS-EXT-AZ prefix should not be used for new # attributes after v2.1. They are only in v2.1 for backward compat # with v2.0. server["server"]["OS-EXT-AZ:availability_zone"] = az or '' if show_config_drive: server["server"]["config_drive"] = instance["config_drive"] if show_keypair: server["server"]["key_name"] = instance["key_name"] if show_srv_usg: for k in ['launched_at', 'terminated_at']: key = "OS-SRV-USG:" + k # NOTE(danms): Historically, this timestamp has been generated # merely by grabbing str(datetime) of a TZ-naive object. The # only way we can keep that with instance objects is to strip # the tzinfo from the stamp and str() it. server["server"][key] = (instance[k].replace( tzinfo=None) if instance[k] else None) if show_extended_attr is None: show_extended_attr = context.can(esa_policies.BASE_POLICY_NAME, fatal=False) if show_extended_attr: server["server"][ "OS-EXT-SRV-ATTR:hypervisor_hostname"] = instance.node properties = ['host', 'name'] if api_version_request.is_supported(request, min_version='2.3'): # NOTE(mriedem): These will use the OS-EXT-SRV-ATTR prefix # below and that's OK for microversion 2.3 which is being # compatible with v2.0 for the ec2 API split out from Nova. # After this, however, new microversions should not be using # the OS-EXT-SRV-ATTR prefix. properties += [ 'reservation_id', 'launch_index', 'hostname', 'kernel_id', 'ramdisk_id', 'root_device_name', 'user_data' ] for attr in properties: if attr == 'name': key = "OS-EXT-SRV-ATTR:instance_%s" % attr else: # NOTE(mriedem): Nothing after microversion 2.3 should use # the OS-EXT-SRV-ATTR prefix for the attribute key name. key = "OS-EXT-SRV-ATTR:%s" % attr server["server"][key] = instance[attr] if (api_version_request.is_supported(request, min_version='2.16')): if show_host_status is None: show_host_status = context.can(servers_policies.SERVERS % 'show:host_status', fatal=False) if show_host_status: host_status = self.compute_api.get_instance_host_status( instance) server["server"]['host_status'] = host_status if api_version_request.is_supported(request, min_version="2.9"): server["server"]["locked"] = (True if instance["locked_by"] else False) if api_version_request.is_supported(request, min_version="2.19"): server["server"]["description"] = instance.get( "display_description") if api_version_request.is_supported(request, min_version="2.26"): server["server"]["tags"] = [t.tag for t in instance.tags] if api_version_request.is_supported(request, min_version="2.63"): trusted_certs = None if instance.trusted_certs: trusted_certs = instance.trusted_certs.ids server["server"]["trusted_image_certificates"] = trusted_certs return server
def test_get_instance_availability_zone_no_host(self): """Test get availability zone from instance if host is None.""" fake_inst = objects.Instance(host=None, availability_zone='inst-az') result = az.get_instance_availability_zone(self.context, fake_inst) self.assertEqual('inst-az', result)
def __init__(self, instance, address=None, content=None, extra_md=None, network_info=None, vd_driver=None, network_metadata=None, request_context=None): """Creation of this object should basically cover all time consuming collection. Methods after that should not cause time delays due to network operations or lengthy cpu operations. The user should then get a single instance and make multiple method calls on it. """ if not content: content = [] ctxt = context.get_admin_context() # The default value of mimeType is set to MIME_TYPE_TEXT_PLAIN self.set_mimetype(MIME_TYPE_TEXT_PLAIN) self.instance = instance self.extra_md = extra_md self.availability_zone = az.get_instance_availability_zone(ctxt, instance) secgroup_api = openstack_driver.get_openstack_security_group_driver() self.security_groups = secgroup_api.get_instance_security_groups( ctxt, instance) self.mappings = _format_instance_mapping(ctxt, instance) if instance.user_data is not None: self.userdata_raw = base64.b64decode(instance.user_data) else: self.userdata_raw = None self.address = address # expose instance metadata. self.launch_metadata = utils.instance_meta(instance) self.password = password.extract_password(instance) self.uuid = instance.uuid self.content = {} self.files = [] # get network info, and the rendered network template if network_info is None: network_info = instance.info_cache.network_info # expose network metadata if network_metadata is None: self.network_metadata = netutils.get_network_metadata(network_info) else: self.network_metadata = network_metadata self.ip_info = \ ec2utils.get_ip_info_for_instance_from_nw_info(network_info) self.network_config = None cfg = netutils.get_injected_network_template(network_info) if cfg: key = "%04i" % len(self.content) self.content[key] = cfg self.network_config = {"name": "network_config", 'content_path': "/%s/%s" % (CONTENT_DIR, key)} # 'content' is passed in from the configdrive code in # nova/virt/libvirt/driver.py. That's how we get the injected files # (personalities) in. AFAIK they're not stored in the db at all, # so are not available later (web service metadata time). for (path, contents) in content: key = "%04i" % len(self.content) self.files.append({'path': path, 'content_path': "/%s/%s" % (CONTENT_DIR, key)}) self.content[key] = contents if vd_driver is None: vdclass = importutils.import_class(CONF.vendordata_driver) else: vdclass = vd_driver self.vddriver = vdclass(instance=instance, address=address, extra_md=extra_md, network_info=network_info) self.route_configuration = None # NOTE(mikal): the decision to not pass extra_md here like we # do to the StaticJSON driver is deliberate. extra_md will # contain the admin password for the instance, and we shouldn't # pass that to external services. self.vendordata_providers = { 'StaticJSON': vendordata_json.JsonFileVendorData( instance=instance, address=address, extra_md=extra_md, network_info=network_info), 'DynamicJSON': vendordata_dynamic.DynamicVendorData( instance=instance, address=address, network_info=network_info, context=request_context) }
def _extend_server(self, context, server, instance): key = "{0!s}:availability_zone".format(Extended_availability_zone.alias) az = avail_zone.get_instance_availability_zone(context, instance) server[key] = az or ''
def test_get_instance_availability_zone_no_host_no_az(self): """Test get availability zone if neither host nor az is set.""" fake_inst = objects.Instance(host=None, availability_zone=None) result = az.get_instance_availability_zone(self.context, fake_inst) self.assertIsNone(result)
def __init__(self, instance, address=None, content=None, extra_md=None, network_info=None, vd_driver=None, network_metadata=None, request_context=None): """Creation of this object should basically cover all time consuming collection. Methods after that should not cause time delays due to network operations or lengthy cpu operations. The user should then get a single instance and make multiple method calls on it. """ if not content: content = [] ctxt = context.get_admin_context() # The default value of mimeType is set to MIME_TYPE_TEXT_PLAIN self.set_mimetype(MIME_TYPE_TEXT_PLAIN) self.instance = instance self.extra_md = extra_md self.availability_zone = az.get_instance_availability_zone( ctxt, instance) secgroup_api = openstack_driver.get_openstack_security_group_driver() self.security_groups = secgroup_api.get_instance_security_groups( ctxt, instance) self.mappings = _format_instance_mapping(ctxt, instance) if instance.user_data is not None: self.userdata_raw = base64.decode_as_bytes(instance.user_data) else: self.userdata_raw = None self.address = address # expose instance metadata. self.launch_metadata = utils.instance_meta(instance) self.password = password.extract_password(instance) self.uuid = instance.uuid self.content = {} self.files = [] # get network info, and the rendered network template if network_info is None: network_info = instance.info_cache.network_info # expose network metadata if network_metadata is None: self.network_metadata = netutils.get_network_metadata(network_info) else: self.network_metadata = network_metadata self.ip_info = \ ec2utils.get_ip_info_for_instance_from_nw_info(network_info) self.network_config = None cfg = netutils.get_injected_network_template(network_info) if cfg: key = "%04i" % len(self.content) self.content[key] = cfg self.network_config = { "name": "network_config", 'content_path': "/%s/%s" % (CONTENT_DIR, key) } # 'content' is passed in from the configdrive code in # nova/virt/libvirt/driver.py. That's how we get the injected files # (personalities) in. AFAIK they're not stored in the db at all, # so are not available later (web service metadata time). for (path, contents) in content: key = "%04i" % len(self.content) self.files.append({ 'path': path, 'content_path': "/%s/%s" % (CONTENT_DIR, key) }) self.content[key] = contents if vd_driver is None: vdclass = importutils.import_class(CONF.vendordata_driver) else: vdclass = vd_driver self.vddriver = vdclass(instance=instance, address=address, extra_md=extra_md, network_info=network_info) self.route_configuration = None # NOTE(mikal): the decision to not pass extra_md here like we # do to the StaticJSON driver is deliberate. extra_md will # contain the admin password for the instance, and we shouldn't # pass that to external services. self.vendordata_providers = { 'StaticJSON': vendordata_json.JsonFileVendorData(instance=instance, address=address, extra_md=extra_md, network_info=network_info), 'DynamicJSON': vendordata_dynamic.DynamicVendorData(instance=instance, address=address, network_info=network_info, context=request_context) }
def __init__(self, instance, address=None, content=None, extra_md=None, conductor_api=None, network_info=None, vd_driver=None): """Creation of this object should basically cover all time consuming collection. Methods after that should not cause time delays due to network operations or lengthy cpu operations. The user should then get a single instance and make multiple method calls on it. """ if not content: content = [] ctxt = context.get_admin_context() # The default value of mimeType is set to MIME_TYPE_TEXT_PLAIN self.set_mimetype(MIME_TYPE_TEXT_PLAIN) self.instance = instance self.extra_md = extra_md if conductor_api: capi = conductor_api else: capi = conductor.API() self.availability_zone = az.get_instance_availability_zone(ctxt, instance) self.security_groups = objects.SecurityGroupList.get_by_instance( ctxt, instance) self.mappings = _format_instance_mapping(ctxt, instance) if instance.user_data is not None: self.userdata_raw = base64.b64decode(instance.user_data) else: self.userdata_raw = None self.ec2_ids = capi.get_ec2_ids(ctxt, obj_base.obj_to_primitive(instance)) self.address = address # expose instance metadata. self.launch_metadata = utils.instance_meta(instance) self.password = password.extract_password(instance) self.uuid = instance.uuid self.content = {} self.files = [] # get network info, and the rendered network template if network_info is None: network_info = instance.info_cache.network_info self.ip_info = \ ec2utils.get_ip_info_for_instance_from_nw_info(network_info) self.network_config = None cfg = netutils.get_injected_network_template(network_info) if cfg: key = "%04i" % len(self.content) self.content[key] = cfg self.network_config = {"name": "network_config", 'content_path': "/%s/%s" % (CONTENT_DIR, key)} # 'content' is passed in from the configdrive code in # nova/virt/libvirt/driver.py. That's how we get the injected files # (personalities) in. AFAIK they're not stored in the db at all, # so are not available later (web service metadata time). for (path, contents) in content: key = "%04i" % len(self.content) self.files.append({'path': path, 'content_path': "/%s/%s" % (CONTENT_DIR, key)}) self.content[key] = contents if vd_driver is None: vdclass = importutils.import_class(CONF.vendordata_driver) else: vdclass = vd_driver self.vddriver = vdclass(instance=instance, address=address, extra_md=extra_md, network_info=network_info) self.route_configuration = None
def _extend_server(self, context, server, instance): key = "%s:availability_zone" % Extended_availability_zone.alias az = avail_zone.get_instance_availability_zone(context, instance) server[key] = az or ''
def _extend_server(self, context, server, instance): key = "%s:availability_zone" % PREFIX az = avail_zone.get_instance_availability_zone(context, instance) server[key] = az or ''
def show(self, request, instance, extend_address=True, show_extra_specs=None, show_AZ=True, show_config_drive=True, show_extended_attr=None, show_host_status=None, show_keypair=True, show_srv_usg=True, show_sec_grp=True, show_extended_status=True, show_extended_volumes=True, bdms=None): """Detailed view of a single instance.""" ip_v4 = instance.get('access_ip_v4') ip_v6 = instance.get('access_ip_v6') if show_extra_specs is None: # detail will pre-calculate this for us. If we're doing show, # then figure it out here. show_extra_specs = False if api_version_request.is_supported(request, min_version='2.47'): context = request.environ['nova.context'] show_extra_specs = context.can( fes_policies.POLICY_ROOT % 'index', fatal=False) server = { "server": { "id": instance["uuid"], "name": instance["display_name"], "status": self._get_vm_status(instance), "tenant_id": instance.get("project_id") or "", "user_id": instance.get("user_id") or "", "metadata": self._get_metadata(instance), "hostId": self._get_host_id(instance), "image": self._get_image(request, instance), "flavor": self._get_flavor(request, instance, show_extra_specs), "created": utils.isotime(instance["created_at"]), "updated": utils.isotime(instance["updated_at"]), "addresses": self._get_addresses(request, instance, extend_address), "accessIPv4": str(ip_v4) if ip_v4 is not None else '', "accessIPv6": str(ip_v6) if ip_v6 is not None else '', "links": self._get_links(request, instance["uuid"], self._collection_name), # NOTE(sdague): historically this was the # os-disk-config extension, but now that extensions # are gone, we merge these attributes here. "OS-DCF:diskConfig": ( 'AUTO' if instance.get('auto_disk_config') else 'MANUAL'), }, } if server["server"]["status"] in self._fault_statuses: _inst_fault = self._get_fault(request, instance) if _inst_fault: server['server']['fault'] = _inst_fault if server["server"]["status"] in self._progress_statuses: server["server"]["progress"] = instance.get("progress", 0) context = request.environ['nova.context'] if show_AZ: az = avail_zone.get_instance_availability_zone(context, instance) # NOTE(mriedem): The OS-EXT-AZ prefix should not be used for new # attributes after v2.1. They are only in v2.1 for backward compat # with v2.0. server["server"]["OS-EXT-AZ:availability_zone"] = az or '' if show_config_drive: server["server"]["config_drive"] = instance["config_drive"] if show_keypair: server["server"]["key_name"] = instance["key_name"] if show_srv_usg: for k in ['launched_at', 'terminated_at']: key = "OS-SRV-USG:" + k # NOTE(danms): Historically, this timestamp has been generated # merely by grabbing str(datetime) of a TZ-naive object. The # only way we can keep that with instance objects is to strip # the tzinfo from the stamp and str() it. server["server"][key] = (instance[k].replace(tzinfo=None) if instance[k] else None) if show_sec_grp: self._add_security_grps(request, [server["server"]], [instance]) if show_extended_attr is None: show_extended_attr = context.can( esa_policies.BASE_POLICY_NAME, fatal=False) if show_extended_attr: properties = ['host', 'name', 'node'] if api_version_request.is_supported(request, min_version='2.3'): # NOTE(mriedem): These will use the OS-EXT-SRV-ATTR prefix # below and that's OK for microversion 2.3 which is being # compatible with v2.0 for the ec2 API split out from Nova. # After this, however, new microversions should not be using # the OS-EXT-SRV-ATTR prefix. properties += ['reservation_id', 'launch_index', 'hostname', 'kernel_id', 'ramdisk_id', 'root_device_name', 'user_data'] for attr in properties: if attr == 'name': key = "OS-EXT-SRV-ATTR:instance_%s" % attr elif attr == 'node': key = "OS-EXT-SRV-ATTR:hypervisor_hostname" else: # NOTE(mriedem): Nothing after microversion 2.3 should use # the OS-EXT-SRV-ATTR prefix for the attribute key name. key = "OS-EXT-SRV-ATTR:%s" % attr server["server"][key] = getattr(instance, attr) if show_extended_status: # NOTE(gmann): Removed 'locked_by' from extended status # to make it same as V2. If needed it can be added with # microversion. for state in ['task_state', 'vm_state', 'power_state']: # NOTE(mriedem): The OS-EXT-STS prefix should not be used for # new attributes after v2.1. They are only in v2.1 for backward # compat with v2.0. key = "%s:%s" % ('OS-EXT-STS', state) server["server"][key] = instance[state] if show_extended_volumes: # NOTE(mriedem): The os-extended-volumes prefix should not be used # for new attributes after v2.1. They are only in v2.1 for backward # compat with v2.0. add_delete_on_termination = api_version_request.is_supported( request, min_version='2.3') if bdms is None: bdms = objects.BlockDeviceMappingList.bdms_by_instance_uuid( context, [instance["uuid"]]) self._add_volumes_attachments(server["server"], bdms, add_delete_on_termination) if (api_version_request.is_supported(request, min_version='2.16')): if show_host_status is None: show_host_status = context.can( servers_policies.SERVERS % 'show:host_status', fatal=False) if show_host_status: host_status = self.compute_api.get_instance_host_status( instance) server["server"]['host_status'] = host_status if api_version_request.is_supported(request, min_version="2.9"): server["server"]["locked"] = (True if instance["locked_by"] else False) if api_version_request.is_supported(request, min_version="2.19"): server["server"]["description"] = instance.get( "display_description") if api_version_request.is_supported(request, min_version="2.26"): server["server"]["tags"] = [t.tag for t in instance.tags] if api_version_request.is_supported(request, min_version="2.63"): trusted_certs = None if instance.trusted_certs: trusted_certs = instance.trusted_certs.ids server["server"]["trusted_image_certificates"] = trusted_certs return server
def _extend_server(self, context, server, instance): key = "%s:availability_zone" % Extended_availability_zone.alias server[key] = availability_zones.get_instance_availability_zone( context, instance)
def __init__(self, instance, address=None, content=None, extra_md=None, conductor_api=None, network_info=None, vd_driver=None): """Creation of this object should basically cover all time consuming collection. Methods after that should not cause time delays due to network operations or lengthy cpu operations. The user should then get a single instance and make multiple method calls on it. """ if not content: content = [] ctxt = context.get_admin_context() # The default value of mimeType is set to MIME_TYPE_TEXT_PLAIN self.set_mimetype(MIME_TYPE_TEXT_PLAIN) self.instance = instance self.extra_md = extra_md if conductor_api: capi = conductor_api else: capi = conductor.API() self.availability_zone = az.get_instance_availability_zone( ctxt, instance) self.security_groups = objects.SecurityGroupList.get_by_instance( ctxt, instance) self.mappings = _format_instance_mapping(ctxt, instance) if instance.user_data is not None: self.userdata_raw = base64.b64decode(instance.user_data) else: self.userdata_raw = None self.ec2_ids = capi.get_ec2_ids(ctxt, obj_base.obj_to_primitive(instance)) self.address = address # expose instance metadata. self.launch_metadata = utils.instance_meta(instance) self.password = password.extract_password(instance) self.uuid = instance.uuid self.content = {} self.files = [] # get network info, and the rendered network template if network_info is None: network_info = instance.info_cache.network_info self.ip_info = \ ec2utils.get_ip_info_for_instance_from_nw_info(network_info) self.network_config = None cfg = netutils.get_injected_network_template(network_info) if cfg: key = "%04i" % len(self.content) self.content[key] = cfg self.network_config = { "name": "network_config", 'content_path': "/%s/%s" % (CONTENT_DIR, key) } # 'content' is passed in from the configdrive code in # nova/virt/libvirt/driver.py. That's how we get the injected files # (personalities) in. AFAIK they're not stored in the db at all, # so are not available later (web service metadata time). for (path, contents) in content: key = "%04i" % len(self.content) self.files.append({ 'path': path, 'content_path': "/%s/%s" % (CONTENT_DIR, key) }) self.content[key] = contents if vd_driver is None: vdclass = importutils.import_class(CONF.vendordata_driver) else: vdclass = vd_driver self.vddriver = vdclass(instance=instance, address=address, extra_md=extra_md, network_info=network_info) self.route_configuration = None
def show(self, request, instance, extend_address=True, show_extra_specs=None, show_AZ=True, show_config_drive=True, show_extended_attr=None, show_host_status=None, show_keypair=True, show_srv_usg=True, show_sec_grp=True, show_extended_status=True, show_extended_volumes=True, bdms=None, cell_down_support=False, show_server_groups=False): """Detailed view of a single instance.""" if show_extra_specs is None: # detail will pre-calculate this for us. If we're doing show, # then figure it out here. show_extra_specs = False if api_version_request.is_supported(request, min_version='2.47'): context = request.environ['nova.context'] show_extra_specs = context.can( fes_policies.POLICY_ROOT % 'index', fatal=False) if cell_down_support and 'display_name' not in instance: # NOTE(tssurya): If the microversion is >= 2.69, this boolean will # be true in which case we check if there are instances from down # cells (by checking if their objects have missing keys like # `display_name`) and return partial constructs based on the # information available from the nova_api database. return self._show_from_down_cell( request, instance, show_extra_specs, show_server_groups) ip_v4 = instance.get('access_ip_v4') ip_v6 = instance.get('access_ip_v6') server = { "server": { "id": instance["uuid"], "name": instance["display_name"], "status": self._get_vm_status(instance), "tenant_id": instance.get("project_id") or "", "user_id": instance.get("user_id") or "", "metadata": self._get_metadata(instance), "hostId": self._get_host_id(instance), "image": self._get_image(request, instance), "flavor": self._get_flavor(request, instance, show_extra_specs), "created": utils.isotime(instance["created_at"]), "updated": utils.isotime(instance["updated_at"]), "addresses": self._get_addresses(request, instance, extend_address), "accessIPv4": str(ip_v4) if ip_v4 is not None else '', "accessIPv6": str(ip_v6) if ip_v6 is not None else '', "links": self._get_links(request, instance["uuid"], self._collection_name), # NOTE(sdague): historically this was the # os-disk-config extension, but now that extensions # are gone, we merge these attributes here. "OS-DCF:diskConfig": ( 'AUTO' if instance.get('auto_disk_config') else 'MANUAL'), }, } if server["server"]["status"] in self._fault_statuses: _inst_fault = self._get_fault(request, instance) if _inst_fault: server['server']['fault'] = _inst_fault if server["server"]["status"] in self._progress_statuses: server["server"]["progress"] = instance.get("progress", 0) context = request.environ['nova.context'] if show_AZ: az = avail_zone.get_instance_availability_zone(context, instance) # NOTE(mriedem): The OS-EXT-AZ prefix should not be used for new # attributes after v2.1. They are only in v2.1 for backward compat # with v2.0. server["server"]["OS-EXT-AZ:availability_zone"] = az or '' if show_config_drive: server["server"]["config_drive"] = instance["config_drive"] if show_keypair: server["server"]["key_name"] = instance["key_name"] if show_srv_usg: for k in ['launched_at', 'terminated_at']: key = "OS-SRV-USG:" + k # NOTE(danms): Historically, this timestamp has been generated # merely by grabbing str(datetime) of a TZ-naive object. The # only way we can keep that with instance objects is to strip # the tzinfo from the stamp and str() it. server["server"][key] = (instance[k].replace(tzinfo=None) if instance[k] else None) if show_sec_grp: self._add_security_grps(request, [server["server"]], [instance]) if show_extended_attr is None: show_extended_attr = context.can( esa_policies.BASE_POLICY_NAME, fatal=False) if show_extended_attr: properties = ['host', 'name', 'node'] if api_version_request.is_supported(request, min_version='2.3'): # NOTE(mriedem): These will use the OS-EXT-SRV-ATTR prefix # below and that's OK for microversion 2.3 which is being # compatible with v2.0 for the ec2 API split out from Nova. # After this, however, new microversions should not be using # the OS-EXT-SRV-ATTR prefix. properties += ['reservation_id', 'launch_index', 'hostname', 'kernel_id', 'ramdisk_id', 'root_device_name', 'user_data'] for attr in properties: if attr == 'name': key = "OS-EXT-SRV-ATTR:instance_%s" % attr elif attr == 'node': key = "OS-EXT-SRV-ATTR:hypervisor_hostname" else: # NOTE(mriedem): Nothing after microversion 2.3 should use # the OS-EXT-SRV-ATTR prefix for the attribute key name. key = "OS-EXT-SRV-ATTR:%s" % attr server["server"][key] = getattr(instance, attr) if show_extended_status: # NOTE(gmann): Removed 'locked_by' from extended status # to make it same as V2. If needed it can be added with # microversion. for state in ['task_state', 'vm_state', 'power_state']: # NOTE(mriedem): The OS-EXT-STS prefix should not be used for # new attributes after v2.1. They are only in v2.1 for backward # compat with v2.0. key = "%s:%s" % ('OS-EXT-STS', state) server["server"][key] = instance[state] if show_extended_volumes: # NOTE(mriedem): The os-extended-volumes prefix should not be used # for new attributes after v2.1. They are only in v2.1 for backward # compat with v2.0. add_delete_on_termination = api_version_request.is_supported( request, min_version='2.3') if bdms is None: bdms = objects.BlockDeviceMappingList.bdms_by_instance_uuid( context, [instance["uuid"]]) self._add_volumes_attachments(server["server"], bdms, add_delete_on_termination) if (api_version_request.is_supported(request, min_version='2.16')): if show_host_status is None: show_host_status = context.can( servers_policies.SERVERS % 'show:host_status', fatal=False) if show_host_status: host_status = self.compute_api.get_instance_host_status( instance) server["server"]['host_status'] = host_status if api_version_request.is_supported(request, min_version="2.9"): server["server"]["locked"] = (True if instance["locked_by"] else False) if api_version_request.is_supported(request, min_version="2.73"): server["server"]["locked_reason"] = (instance.system_metadata.get( "locked_reason")) if api_version_request.is_supported(request, min_version="2.19"): server["server"]["description"] = instance.get( "display_description") if api_version_request.is_supported(request, min_version="2.26"): server["server"]["tags"] = [t.tag for t in instance.tags] if api_version_request.is_supported(request, min_version="2.63"): trusted_certs = None if instance.trusted_certs: trusted_certs = instance.trusted_certs.ids server["server"]["trusted_image_certificates"] = trusted_certs if show_server_groups: server['server']['server_groups'] = self._get_server_groups( context, instance) return server