def mount(self, req, body): """mount iso to vm """ context = req.environ['nova.context'] context.can(ics_vm_pl.BASE_POLICY_NAME) vmid = body['vmid'] isoid = body['isoid'] if not self._get_ics_session(): raise webob.exc.HTTPServerError(explanation="ics connect failed !") image = self._validate_image(context, isoid) if image.get('disk_format')!= 'iso' and image.get('disk_format')!= 'ISO' : explanation = _("diskformat must be iso.") raise webob.exc.HTTPPreconditionFailed(explanation=explanation) self._validate_vm(context, vmid) # do ics-vm mount iso LOG.info("begin to mount iso to ics_vm : %s", vmid) try: task_info = self._ics_manager.vm.attach_cdrom(vm_id=vmid, isoid=isoid) except Exception as e: # do something LOG.error("mount iso to ics_vm exception : " + e.message) raise webob.exc.HTTPServerError(explanation=e.message) LOG.info("end to mount iso to ics_vm : %s", vmid) state = task_info['state'] if state == 'FINISHED': res = {'success': True} else: res = {'success': False} return dict(vmMount=res)
def _sync_glance_image_to_lxd(client, context, image_ref): """Sync an image from glance to LXD image store. The image from glance can't go directly into the LXD image store, as LXD needs some extra metadata connected to it. The image is stored in the LXD image store with an alias to the image_ref. This way, it will only copy over once. """ lock_path = os.path.join(CONF.instances_path, 'locks') with lockutils.lock( lock_path, external=True, lock_file_prefix='lxd-image-{}'.format(image_ref)): try: image_file = tempfile.mkstemp()[1] manifest_file = tempfile.mkstemp()[1] image = IMAGE_API.get(context, image_ref) if image.get('disk_format') not in ACCEPTABLE_IMAGE_FORMATS: raise exception.ImageUnacceptable( image_id=image_ref, reason=_('Bad image format')) IMAGE_API.download(context, image_ref, dest_path=image_file) metadata = { 'architecture': image.get( 'hw_architecture', obj_fields.Architecture.from_host()), 'creation_date': int(os.stat(image_file).st_ctime)} metadata_yaml = json.dumps( metadata, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False).encode('utf-8') + b"\n" tarball = tarfile.open(manifest_file, "w:gz") tarinfo = tarfile.TarInfo(name='metadata.yaml') tarinfo.size = len(metadata_yaml) tarball.addfile(tarinfo, io.BytesIO(metadata_yaml)) tarball.close() with open(manifest_file, 'rb') as manifest: with open(image_file, 'rb') as image: image = client.images.create( image.read(), metadata=manifest.read(), wait=True) image.add_alias(image_ref, '') finally: os.unlink(image_file) os.unlink(manifest_file)
def select_image(self, context, image, host_hypervisor, instance, request_spec, filter_properties): """ Select the final image from a image list which come from the image_template properties of original image. It's a template id where the other images can be found. image: the original image passed to nova boot host_hypervisor: hypervisor type of host instance: instance object request_spec: request specification filter_properties: """ img_properties = image.get('properties', {}) if img_properties and img_properties.get('image_template'): LOG.info("Start to select a new image ...") base_images = img_properties.get('image_template').split(',') #base_image = self.select_all_related_img(context, image_uuids) for img_uuid in base_images: img_info = self.image_api.get(context, img_uuid) LOG.debug('img_info: {0}'.format(img_info)) if img_info.get('properties', {}): image_hv_type = img_info['properties'].get( 'hypervisor_type') if image_hv_type and image_hv_type.lower( ) in host_hypervisor.lower(): return self.update_properties(img_info, instance, request_spec, filter_properties) return image, instance, request_spec
def update_properties(self, image, instance, request_spec, filter_properties): instance = self.update_instance_image_info(image, instance, filter_properties) request_spec['instance_properties']['image_ref'] = image.get('id') request_spec['instance_properties'][ 'system_metadata'] = instance.system_metadata request_spec['image'] = image return image, instance, request_spec
def index(self, req, image_id): context = req.environ['nova.context'] try: image = self._image_service.show(context, image_id) except (exception.NotFound, exception.InvalidImageRef): explanation = _("Image not found.") raise webob.exc.HTTPNotFound(explanation=explanation) image_properties = image.get('properties', None) if image_properties: managed_disk = image_properties.get('managed_disk', False) return self._return_dict(image_id, managed_disk)
def update_instance_image_info(image, instance, filter_properties): instance.image_ref = image.get('id') from nova import utils as nova_utils system_metadata = nova_utils.get_system_metadata_from_image( image, filter_properties.get('instance_type')) keys = instance.system_metadata.keys() for item in keys: if item.startswith('image_'): del instance.system_metadata[item] instance.system_metadata.update(system_metadata) instance.system_metadata.setdefault('image_base_image_ref', instance['image_ref']) return instance
def remove_invalid_hosts(self, images, hosts): valid_host = [] for host in hosts: for image in images: img_hy_type = image.get('properties', {}).get('hypervisor_type') host_hv_type = host.obj.hypervisor_type.lower() if host_hv_type == 'ironic': host_hv_type = 'baremetal' if not img_hy_type or (img_hy_type and img_hy_type.lower() not in host_hv_type): continue valid_host.append(host) LOG.debug('valid host: {0}'.format(valid_host)) return valid_host
def _image_to_xml_detailed(self, xml_doc, image): image_node = xml_doc.createElement('image') self._add_image_attributes(image_node, image) if 'server' in image: server_node = self._create_server_node(xml_doc, image['server']) image_node.appendChild(server_node) metadata = image.get('metadata', {}).items() if len(metadata) > 0: metadata_node = self._create_metadata_node(xml_doc, metadata) image_node.appendChild(metadata_node) link_nodes = self._create_link_nodes(xml_doc, image['links']) for link_node in link_nodes: image_node.appendChild(link_node) return image_node
def _get_metadata(self, context, image_id, image=None): if not image: image = self.image_service.show(context, image_id) metadata = image.get('properties', {}) return metadata
def check_is_bool(image, key): val = image.get('deleted') if not isinstance(val, bool): self.fail('image\'s "%s" attribute wasn\'t ' 'a bool: %r' % (key, val))
def build_instances(self, context, instances, image, filter_properties, admin_password, injected_files, requested_networks, security_groups, block_device_mapping=None, legacy_bdm=True): # TODO(ndipanov): Remove block_device_mapping and legacy_bdm in version # 2.0 of the RPC API. # TODO(danms): Remove this in version 2.0 of the RPC API if (requested_networks and not isinstance(requested_networks, objects.NetworkRequestList)): requested_networks = objects.NetworkRequestList(objects=[ objects.NetworkRequest.from_tuple(t) for t in requested_networks ]) # TODO(melwitt): Remove this in version 2.0 of the RPC API flavor = filter_properties.get('instance_type') if flavor and not isinstance(flavor, objects.Flavor): # Code downstream may expect extra_specs to be populated since it # is receiving an object, so lookup the flavor to ensure this. flavor = objects.Flavor.get_by_id(context, flavor['id']) filter_properties = dict(filter_properties, instance_type=flavor) request_spec = {} try: # check retry policy. Rather ugly use of instances[0]... # but if we've exceeded max retries... then we really only # have a single instance. scheduler_utils.populate_retry(filter_properties, instances[0].uuid) request_spec = scheduler_utils.build_request_spec( context, image, instances) hosts = self._schedule_instances(context, request_spec, filter_properties) except Exception as exc: updates = {'vm_state': vm_states.ERROR, 'task_state': None} for instance in instances: self._set_vm_state_and_notify(context, instance.uuid, 'build_instances', updates, exc, request_spec) self._cleanup_allocated_networks(context, instance, requested_networks) return host_hypervisor = '' hosts_info = [] reselect_flag = self.need_select_image(request_spec) if reselect_flag: # Normal user need promoted privilege to search db elevated = context.elevated() hosts_info = db.compute_node_get_all(elevated) LOG.debug("hosts_info: {0}".format(hosts_info)) for (instance, host) in six.moves.zip(instances, hosts): if reselect_flag: for hi in hosts_info: if hi.get('service') and hi['service'].get( 'host') == host['host']: host_hypervisor = hi.get('hypervisor_type') LOG.debug( 'host_hypervisor: {0}'.format(host_hypervisor)) break image, instance, request_spec = self.select_image( context, image, host_hypervisor, instance, request_spec, filter_properties) LOG.debug("Final image: {0}".format(image.get('id'))) try: instance.save() instance.refresh() except (exception.InstanceNotFound, exception.InstanceInfoCacheNotFound): LOG.debug('Instance deleted during build', instance=instance) continue local_filter_props = copy.deepcopy(filter_properties) scheduler_utils.populate_filter_properties(local_filter_props, host) # The block_device_mapping passed from the api doesn't contain # instance specific information bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) self.compute_rpcapi.build_and_run_instance( context, instance=instance, host=host['host'], image=image, request_spec=request_spec, filter_properties=local_filter_props, admin_password=admin_password, injected_files=injected_files, requested_networks=requested_networks, security_groups=security_groups, block_device_mapping=bdms, node=host['nodename'], limits=host['limits'])
def notify(self, context, message, priority, retry=False): ctxt = self._deserialize_context(context) event_type = message.get('event_type') if event_type in CONF.wiki_eventtype_blacklist: return if event_type not in CONF.wiki_eventtype_whitelist: LOG.debug("Ignoring message type %s" % event_type) return LOG.debug("Handling message type %s" % event_type) payload = message['payload'] instance = payload['instance_id'] instance_name = payload['display_name'] project_id = payload['tenant_id'] if project_id in CONF.wiki_project_blacklist: LOG.debug("Ignoring project %s" % project_id) return template_param_dict = {} for field in self.RawTemplateFields: template_param_dict[field] = payload[field] template_param_dict['username'] = payload['user_id'] fqdn = "%s.%s.%s" % (instance_name, project_id, CONF.wiki_instance_dns_domain) resource_name = fqdn if event_type == 'compute.instance.delete.end': # No need to gather up instance info, just delete the page self.page_editor.edit_page("", resource_name, True) return inst = objects.Instance.get_by_uuid(ctxt, instance) simple_id = inst['id'] ec2_id = 'i-%08x' % simple_id template_param_dict['cpu_count'] = inst['vcpus'] template_param_dict['disk_gb_current'] = inst['ephemeral_gb'] template_param_dict['host'] = inst['host'] template_param_dict['reservation_id'] = inst['reservation_id'] template_param_dict['availability_zone'] = inst['availability_zone'] template_param_dict['original_host'] = inst['launched_on'] template_param_dict['fqdn'] = fqdn template_param_dict['ec2_id'] = ec2_id template_param_dict['project_name'] = project_id template_param_dict['region'] = CONF.wiki_instance_region ips = [] floating_ips = [] try: nw_info = network.API().get_instance_nw_info(ctxt, inst) ip_objs = nw_info.fixed_ips() floating_ip_objs = nw_info.floating_ips() ips = [ip['address'] for ip in ip_objs] floating_ips = [ip['address'] for ip in floating_ip_objs] except exception.FixedIpNotFoundForInstance: ips = [] floating_ips = [] template_param_dict['private_ip'] = ','.join(ips) template_param_dict['public_ip'] = ','.join(floating_ips) sec_groups = inst['security_groups'] grps = [grp['name'] for grp in sec_groups] template_param_dict['security_group'] = ','.join(grps) if inst['image_ref']: try: image = self._image_service.show(ctxt, inst['image_ref']) image_name = image.get('name', inst['image_ref']) template_param_dict['image_name'] = image_name except (TypeError, exception.ImageNotAuthorized): template_param_dict['image_name'] = inst['image_ref'] else: template_param_dict['image_name'] = 'tbd' fields_string = "" for key in template_param_dict: fields_string += "\n|%s=%s" % (key, template_param_dict[key]) self.page_editor.edit_page(fields_string, resource_name, False)
def _sync_glance_image_to_lxd(client, context, image_ref): """Sync an image from glance to LXD image store. The image from glance can't go directly into the LXD image store, as LXD needs some extra metadata connected to it. The image is stored in the LXD image store with an alias to the image_ref. This way, it will only copy over once. """ lock_path = os.path.join(CONF.instances_path, 'locks') with lockutils.lock( lock_path, external=True, lock_file_prefix='lxd-image-{}'.format(image_ref)): # NOTE(jamespage): Re-query by image_ref to ensure # that another process did not # sneak infront of this one and create # the same image already. try: client.images.get_by_alias(image_ref) return except lxd_exceptions.LXDAPIException as e: if e.response.status_code != 404: raise try: image_file = tempfile.mkstemp()[1] manifest_file = tempfile.mkstemp()[1] image = IMAGE_API.get(context, image_ref) if image.get('disk_format') not in ACCEPTABLE_IMAGE_FORMATS: raise exception.ImageUnacceptable( image_id=image_ref, reason=_('Bad image format')) IMAGE_API.download(context, image_ref, dest_path=image_file) # It is possible that LXD already have the same image # but NOT aliased as result of previous publish/export operation # (snapshot from openstack). # In that case attempt to add it again # (implicitly via instance launch from affected image) will produce # LXD error - "Image with same fingerprint already exists". # Error does not have unique identifier to handle it we calculate # fingerprint of image as LXD do it and check if LXD already have # image with such fingerprint. # If any we will add alias to this image and will not re-import it def add_alias(): def lxdimage_fingerprint(): def sha256_file(): sha256 = hashlib.sha256() with closing(open(image_file, 'rb')) as f: for block in iter(lambda: f.read(65536), b''): sha256.update(block) return sha256.hexdigest() return sha256_file() fingerprint = lxdimage_fingerprint() if client.images.exists(fingerprint): LOG.info( 'Image with fingerprint %(fingerprint)s already exists' 'but not accessible by alias %(alias)s, add alias', {'fingerprint': fingerprint, 'alias': image_ref}) lxdimage = client.images.get(fingerprint) lxdimage.add_alias(image_ref, '') return True return False if add_alias(): return # up2date LXD publish/export operations produce images which # already contains /rootfs and metdata.yaml in exported file. # We should not pass metdata explicitly in that case as imported # image will be unusable bacause LXD will think that it containts # rootfs and will not extract embedded /rootfs properly. # Try to detect if image content already has metadata and not pass # explicit metadata in that case def imagefile_has_metadata(image_file): try: with closing(tarfile.TarFile.open( name=image_file, mode='r:*')) as tf: try: tf.getmember('metadata.yaml') return True except KeyError: pass except tarfile.ReadError: pass return False if imagefile_has_metadata(image_file): LOG.info('Image %(alias)s already has metadata, ' 'skipping metadata injection...', {'alias': image_ref}) with open(image_file, 'rb') as image: image = client.images.create(image.read(), wait=True) else: metadata = { 'architecture': image.get( 'hw_architecture', obj_fields.Architecture.from_host()), 'creation_date': int(os.stat(image_file).st_ctime)} metadata_yaml = json.dumps( metadata, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False).encode('utf-8') + b"\n" tarball = tarfile.open(manifest_file, "w:gz") tarinfo = tarfile.TarInfo(name='metadata.yaml') tarinfo.size = len(metadata_yaml) tarball.addfile(tarinfo, io.BytesIO(metadata_yaml)) tarball.close() with open(manifest_file, 'rb') as manifest: with open(image_file, 'rb') as image: image = client.images.create( image.read(), metadata=manifest.read(), wait=True) image.add_alias(image_ref, '') finally: os.unlink(image_file) os.unlink(manifest_file)
def notify(self, ctxt, message): event_type = message.get('event_type') if event_type in CONF.wiki_eventtype_blacklist: return if event_type not in CONF.wiki_eventtype_whitelist: LOG.debug("Ignoring message type %s" % event_type) return payload = message['payload'] instance = payload['instance_id'] instance_name = payload['display_name'] template_param_dict = {} for field in self.RawTemplateFields: template_param_dict[field] = payload[field] tenant_id = payload['tenant_id'] if (CONF.wiki_use_keystone and self._keystone_login(tenant_id, ctxt)): tenant_obj = self.tenant_manager[tenant_id].get(tenant_id) user_obj = self.user_manager[tenant_id].get(payload['user_id']) tenant_name = tenant_obj.name user_name = user_obj.name template_param_dict['tenant'] = tenant_name template_param_dict['username'] = user_name inst = self.conductor_api.instance_get_by_uuid(ctxt, payload['instance_id']) simple_id = inst['id'] ec2_id = 'i-%08x' % simple_id if CONF.wiki_instance_dns_domain: fqdn = "%s.%s" % (instance_name, CONF.wiki_instance_dns_domain) resourceName = "%s.%s" % (ec2_id, CONF.wiki_instance_dns_domain) else: fqdn = instance_name resourceName = ec2_id template_param_dict['cpu_count'] = inst['vcpus'] template_param_dict['disk_gb_current'] = inst['ephemeral_gb'] template_param_dict['host'] = inst['host'] template_param_dict['reservation_id'] = inst['reservation_id'] template_param_dict['availability_zone'] = inst['availability_zone'] template_param_dict['original_host'] = inst['launched_on'] template_param_dict['fqdn'] = fqdn template_param_dict['ec2_id'] = ec2_id template_param_dict['project_name'] = inst['project_id'] template_param_dict['region'] = CONF.wiki_instance_region ips = [] floating_ips = [] try: nw_info = network.API().get_instance_nw_info(ctxt, inst) ip_objs = nw_info.fixed_ips() floating_ip_objs = nw_info.floating_ips() ips = [ip['address'] for ip in ip_objs] floating_ips = [ip['address'] for ip in floating_ip_objs] except exception.FixedIpNotFoundForInstance: ips = [] floating_ips = [] template_param_dict['private_ip'] = ','.join(ips) template_param_dict['public_ip'] = ','.join(floating_ips) sec_groups = self.conductor_api.security_group_get_by_instance( ctxt, inst) grps = [grp['name'] for grp in sec_groups] template_param_dict['security_group'] = ','.join(grps) image = self._image_service.show(ctxt, inst['image_ref']) image_name = image.get('name', inst['image_ref']) template_param_dict['image_name'] = image_name fields_string = "" for key in template_param_dict: fields_string += "\n|%s=%s" % (key, template_param_dict[key]) clear_page = False if event_type == 'compute.instance.delete.start': page_string = ("\n%s\nThis instance has been deleted.\n%s\n" % (begin_comment, end_comment)) clear_page = True else: page_string = "%s\n{{InstanceStatus%s}}\n%s" % ( begin_comment, fields_string, end_comment) self._wiki_login() pagename = "%s%s" % (CONF.wiki_page_prefix, resourceName) LOG.debug("wikistatus: Writing instance info" " to page http://%s/wiki/%s" % (self.host, pagename)) page = self.site.Pages[pagename] try: pText = page.edit() if clear_page: newText = page_string else: start_replace_index = pText.find(begin_comment) if start_replace_index == -1: # Just stick new text at the top. newText = "%s\n%s" % (page_string, pText) else: # Replace content between comment tags. end_replace_index = pText.find(end_comment, start_replace_index) if end_replace_index == -1: end_replace_index = (start_replace_index + len(begin_comment)) else: end_replace_index += len(end_comment) newText = "%s%s%s" % (pText[:start_replace_index], page_string, pText[end_replace_index:]) page.save(newText, "Auto update of instance info.") except (mwclient.errors.InsufficientPermission, mwclient.errors.LoginError): LOG.debug("Failed to update wiki page..." " trying to re-login next time.") self._wiki_logged_in = False
def notify(self, ctxt, message): event_type = message.get('event_type') if event_type in FLAGS.wiki_eventtype_blacklist: return if event_type not in FLAGS.wiki_eventtype_whitelist: LOG.debug("Ignoring message type %s" % event_type) return payload = message['payload'] instance = payload['instance_id'] instance_name = payload['display_name'] pagename = "%s%s" % (FLAGS.wiki_page_prefix, instance_name) LOG.debug("wikistatus: Writing instance info" " to page http://%s/wiki/%s" % (self.host, pagename)) if event_type == 'compute.instance.delete.end': page_string = _("This instance has been deleted.") else: template_param_dict = {} for field in self.RawTemplateFields: template_param_dict[field] = payload[field] tenant_id = payload['tenant_id'] if (FLAGS.wiki_use_keystone and self._keystone_login(tenant_id, ctxt)): tenant_obj = self.tenant_manager[tenant_id].get(tenant_id) user_obj = self.user_manager[tenant_id].get(payload['user_id']) tenant_name = tenant_obj.name user_name = user_obj.name template_param_dict['tenant'] = tenant_name template_param_dict['username'] = user_name inst = db.instance_get_by_uuid(ctxt, payload['instance_id']) simple_id = inst.id template_param_dict['cpu_count'] = inst.vcpus template_param_dict['disk_gb_current'] = inst.ephemeral_gb template_param_dict['host'] = inst.host template_param_dict['reservation_id'] = inst.reservation_id template_param_dict['availability_zone'] = inst.availability_zone template_param_dict['original_host'] = inst.launched_on template_param_dict['public_ip'] = inst.access_ip_v4 try: fixed_ips = db.fixed_ip_get_by_instance(ctxt, payload['instance_id']) except exception.FixedIpNotFoundForInstance: fixed_ips = [] ips = [ip.address for ip in fixed_ips] template_param_dict['private_ip'] = ','.join(ips) sec_groups = db.security_group_get_by_instance(ctxt, simple_id) grps = [grp.name for grp in sec_groups] template_param_dict['security_group'] = ','.join(grps) image = self._image_service.show(ctxt, inst.image_ref) image_name = image.get('name', inst.image_ref) template_param_dict['image_name'] = image_name fields_string = "" for key in template_param_dict: fields_string += "\n|%s=%s" % (key, template_param_dict[key]) page_string = "{{InstanceStatus%s}}" % fields_string self._wiki_login() page = self.site.Pages[pagename] try: page.edit() page.save(page_string, "Auto update of instance info.") except (mwclient.errors.InsufficientPermission, mwclient.errors.LoginError): LOG.debug("Failed to update wiki page..." " trying to re-login next time.") self._wiki_logged_in = False