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
def _validate(task): """Validate the prerequisites for virtual media based deploy. This method validates whether the 'driver_info' property of the supplied node contains the required information for this driver. :param task: a TaskManager instance containing the node to act on. :raises: InvalidParameterValue if any parameters are incorrect :raises: MissingParameterValue if some mandatory information is missing on the node """ node = task.node ilo_common.parse_driver_info(node) if 'ilo_deploy_iso' not in node.driver_info: raise exception.MissingParameterValue(_( "Missing 'ilo_deploy_iso' parameter in node's 'driver_info'.")) deploy_iso = node.driver_info['ilo_deploy_iso'] if not service_utils.is_glance_image(deploy_iso): try: image_service.HttpImageService().validate_href(deploy_iso) except exception.ImageRefValidationFailed: raise exception.InvalidParameterValue(_( "Virtual media deploy accepts only Glance images or " "HTTP(S) as driver_info['ilo_deploy_iso']. Either '%s' " "is not a glance UUID or not a valid HTTP(S) URL or " "the given URL is not reachable.") % deploy_iso)
def validate(self, task): """Validate the deployment information for the task's node. :param task: a TaskManager instance containing the node to act on. :raises: InvalidParameterValue, if some information is invalid. :raises: MissingParameterValue if 'kernel_id' and 'ramdisk_id' are missing in the Glance image or 'kernel' and 'ramdisk' not provided in instance_info for non-Glance image. """ node = task.node boot_option = deploy_utils.get_boot_option(node) boot_iso = node.instance_info.get('ilo_boot_iso') if (boot_option == "ramdisk" and boot_iso): if not service_utils.is_glance_image(boot_iso): try: image_service.HttpImageService().validate_href(boot_iso) except exception.ImageRefValidationFailed: with excutils.save_and_reraise_exception(): LOG.error("Virtual media deploy with 'ramdisk' " "boot_option accepts only Glance images or " "HTTP(S) URLs as " "instance_info['ilo_boot_iso']. Either %s " "is not a valid HTTP(S) URL or is not " "reachable.", boot_iso) return _validate_driver_info(task) if not task.driver.storage.should_write_image(task): return else: _validate_instance_image_info(task)
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
def _download_http_based_fw_to(self, target_file): """HTTP based firmware file downloader It downloads the file (url) to temporary location (file location). Original firmware file location (url) is expected in the format "http://.." :param target_file: destination file for downloading the original firmware file. :raises: ImageDownloadFailed, on failure to download the original file. """ src_file = self.parsed_url.geturl() with open(target_file, 'wb') as fd: image_service.HttpImageService().download(src_file, fd)
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})
def validate(self, task): """Validate the deployment information for the task's node. This method validates whether the 'driver_info' and/or 'instance_info' properties of the task's node contains the required information for this interface to function. :param task: A TaskManager instance containing the node to act on. :raises: InvalidParameterValue on malformed parameter(s) :raises: MissingParameterValue on missing parameter(s) """ node = task.node boot_option = deploy_utils.get_boot_option(node) try: boot_mode = ilo_common.get_current_boot_mode(task.node) except exception.IloOperationError: error = _("Validation for 'ilo-uefi-https' boot interface failed. " "Could not determine current boot mode for node " "%(node)s.") % node.uuid raise exception.InvalidParameterValue(error) if boot_mode.lower() != 'uefi': error = _("Validation for 'ilo-uefi-https' boot interface failed. " "The node is required to be in 'UEFI' boot mode.") raise exception.InvalidParameterValue(error) boot_iso = node.instance_info.get('ilo_boot_iso') if (boot_option == "ramdisk" and boot_iso): if not service_utils.is_glance_image(boot_iso): try: image_service.HttpImageService().validate_href(boot_iso) except exception.ImageRefValidationFailed: with excutils.save_and_reraise_exception(): LOG.error("UEFI-HTTPS boot with 'ramdisk' " "boot_option accepts only Glance images or " "HTTPS URLs as " "instance_info['ilo_boot_iso']. Either %s " "is not a valid HTTPS URL or is not " "reachable.", boot_iso) return self._validate_driver_info(task) if task.driver.storage.should_write_image(task): self._validate_instance_image_info(task)
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
def _get_boot_iso(task, root_uuid): """This method returns a boot ISO to boot the node. It chooses one of the three options in the order as below: 1. Does nothing if 'ilo_boot_iso' is present in node's instance_info and 'boot_iso_created_in_web_server' is not set in 'driver_internal_info'. 2. Image deployed has a meta-property 'boot_iso' in Glance. This should refer to the UUID of the boot_iso which exists in Glance. 3. Generates a boot ISO on the fly using kernel and ramdisk mentioned in the image deployed. It uploads the generated boot ISO to Swift. :param task: a TaskManager instance containing the node to act on. :param root_uuid: the uuid of the root partition. :returns: boot ISO URL. Should be either of below: * A Swift object - It should be of format 'swift:<object-name>'. It is assumed that the image object is present in CONF.ilo.swift_ilo_container; * A Glance image - It should be format 'glance://<glance-image-uuid>' or just <glance-image-uuid>; * An HTTP URL. On error finding the boot iso, it returns None. :raises: MissingParameterValue, if any of the required parameters are missing in the node's driver_info or instance_info. :raises: InvalidParameterValue, if any of the parameters have invalid value in the node's driver_info or instance_info. :raises: SwiftOperationError, if operation with Swift fails. :raises: ImageCreationFailed, if creation of boot ISO failed. :raises: exception.ImageRefValidationFailed if ilo_boot_iso is not HTTP(S) URL. """ LOG.debug("Trying to get a boot ISO to boot the baremetal node") # Option 1 - Check if user has provided ilo_boot_iso in node's # instance_info driver_internal_info = task.node.driver_internal_info boot_iso_created_in_web_server = ( driver_internal_info.get('boot_iso_created_in_web_server')) if (task.node.instance_info.get('ilo_boot_iso') and not boot_iso_created_in_web_server): LOG.debug("Using ilo_boot_iso provided in node's instance_info") boot_iso = task.node.instance_info['ilo_boot_iso'] if not service_utils.is_glance_image(boot_iso): try: image_service.HttpImageService().validate_href(boot_iso) except exception.ImageRefValidationFailed: with excutils.save_and_reraise_exception(): LOG.error("Virtual media deploy accepts only Glance " "images or HTTP(S) URLs as " "instance_info['ilo_boot_iso']. Either %s " "is not a valid HTTP(S) URL or is " "not reachable.", boot_iso) return task.node.instance_info['ilo_boot_iso'] # Option 2 - Check if user has provided a boot_iso in Glance. If boot_iso # is a supported non-glance href execution will proceed to option 3. deploy_info = _parse_deploy_info(task.node) image_href = deploy_info['image_source'] image_properties = ( images.get_image_properties( task.context, image_href, ['boot_iso', 'kernel_id', 'ramdisk_id'])) boot_iso_uuid = image_properties.get('boot_iso') kernel_href = (task.node.instance_info.get('kernel') or image_properties.get('kernel_id')) ramdisk_href = (task.node.instance_info.get('ramdisk') or image_properties.get('ramdisk_id')) if boot_iso_uuid: LOG.debug("Found boot_iso %s in Glance", boot_iso_uuid) return boot_iso_uuid if not kernel_href or not ramdisk_href: LOG.error("Unable to find kernel or ramdisk for " "image %(image)s to generate boot ISO for %(node)s", {'image': image_href, 'node': task.node.uuid}) return # NOTE(rameshg87): Functionality to share the boot ISOs created for # similar instances (instances with same deployed image) is # not implemented as of now. Creation/Deletion of such a shared boot ISO # will require synchronisation across conductor nodes for the shared boot # ISO. Such a synchronisation mechanism doesn't exist in ironic as of now. # Option 3 - Create boot_iso from kernel/ramdisk, upload to Swift # or web server and provide its name. deploy_iso_uuid = deploy_info['ilo_deploy_iso'] boot_mode = boot_mode_utils.get_boot_mode_for_deploy(task.node) boot_iso_object_name = _get_boot_iso_object_name(task.node) kernel_params = "" if deploy_utils.get_boot_option(task.node) == "ramdisk": i_info = task.node.instance_info kernel_params = "root=/dev/ram0 text " kernel_params += i_info.get("ramdisk_kernel_arguments", "") else: kernel_params = CONF.pxe.pxe_append_params with tempfile.NamedTemporaryFile(dir=CONF.tempdir) as fileobj: boot_iso_tmp_file = fileobj.name images.create_boot_iso(task.context, boot_iso_tmp_file, kernel_href, ramdisk_href, deploy_iso_uuid, root_uuid, kernel_params, boot_mode) if CONF.ilo.use_web_server_for_images: boot_iso_url = ( ilo_common.copy_image_to_web_server(boot_iso_tmp_file, boot_iso_object_name)) driver_internal_info = task.node.driver_internal_info driver_internal_info['boot_iso_created_in_web_server'] = True task.node.driver_internal_info = driver_internal_info task.node.save() LOG.debug("Created boot_iso %(boot_iso)s for node %(node)s", {'boot_iso': boot_iso_url, 'node': task.node.uuid}) return boot_iso_url else: container = CONF.ilo.swift_ilo_container swift_api = swift.SwiftAPI() swift_api.create_object(container, boot_iso_object_name, boot_iso_tmp_file) LOG.debug("Created boot_iso %s in Swift", boot_iso_object_name) return 'swift:%s' % boot_iso_object_name
def _get_boot_iso(task, root_uuid): """This method returns a boot ISO to boot the node. It chooses one of the three options in the order as below: 1. Does nothing if 'ilo_boot_iso' is present in node's instance_info and 'boot_iso_created_in_web_server' is not set in 'driver_internal_info'. 2. Image deployed has a meta-property 'boot_iso' in Glance. This should refer to the UUID of the boot_iso which exists in Glance. 3. Generates a boot ISO on the fly using kernel and ramdisk mentioned in the image deployed. It uploads the generated boot ISO to Swift. :param task: a TaskManager instance containing the node to act on. :param root_uuid: the uuid of the root partition. :returns: boot ISO URL. Should be either of below: * A Swift object - It should be of format 'swift:<object-name>'. It is assumed that the image object is present in CONF.ilo.swift_ilo_container; * A Glance image - It should be format 'glance://<glance-image-uuid>' or just <glance-image-uuid>; * An HTTP URL. On error finding the boot iso, it returns None. :raises: MissingParameterValue, if any of the required parameters are missing in the node's driver_info or instance_info. :raises: InvalidParameterValue, if any of the parameters have invalid value in the node's driver_info or instance_info. :raises: SwiftOperationError, if operation with Swift fails. :raises: ImageCreationFailed, if creation of boot ISO failed. :raises: exception.ImageRefValidationFailed if ilo_boot_iso is not HTTP(S) URL. """ LOG.debug("Trying to get a boot ISO to boot the baremetal node") # Option 1 - Check if user has provided ilo_boot_iso in node's # instance_info driver_internal_info = task.node.driver_internal_info boot_iso_created_in_web_server = ( driver_internal_info.get('boot_iso_created_in_web_server')) if (task.node.instance_info.get('ilo_boot_iso') and not boot_iso_created_in_web_server): LOG.debug("Using ilo_boot_iso provided in node's instance_info") boot_iso = task.node.instance_info['ilo_boot_iso'] if not service_utils.is_glance_image(boot_iso): try: image_service.HttpImageService().validate_href(boot_iso) except exception.ImageRefValidationFailed: with excutils.save_and_reraise_exception(): LOG.error( "Virtual media deploy accepts only Glance " "images or HTTP(S) URLs as " "instance_info['ilo_boot_iso']. Either %s " "is not a valid HTTP(S) URL or is " "not reachable.", boot_iso) return task.node.instance_info['ilo_boot_iso'] # Option 2 - Check if user has provided a boot_iso in Glance. If boot_iso # is a supported non-glance href execution will proceed to option 3. deploy_info = _parse_deploy_info(task.node) image_href = deploy_info['image_source'] image_properties = (images.get_image_properties( task.context, image_href, ['boot_iso', 'kernel_id', 'ramdisk_id'])) boot_iso_uuid = image_properties.get('boot_iso') kernel_href = (task.node.instance_info.get('kernel') or image_properties.get('kernel_id')) ramdisk_href = (task.node.instance_info.get('ramdisk') or image_properties.get('ramdisk_id')) if boot_iso_uuid: LOG.debug("Found boot_iso %s in Glance", boot_iso_uuid) return boot_iso_uuid # NOTE(rameshg87): Functionality to share the boot ISOs created for # similar instances (instances with same deployed image) is # not implemented as of now. Creation/Deletion of such a shared boot ISO # will require synchronisation across conductor nodes for the shared boot # ISO. Such a synchronisation mechanism doesn't exist in ironic as of now. # Option 3 - Create boot_iso from kernel/ramdisk, upload to Swift # or web server and provide its name. deploy_iso_uuid = deploy_info['ilo_deploy_iso'] use_web_server = CONF.ilo.use_web_server_for_images container = CONF.ilo.swift_ilo_container return virtual_media_base.prepare_iso_image( task, kernel_href, ramdisk_href, deploy_iso_href=deploy_iso_uuid, root_uuid=root_uuid, use_web_server=use_web_server, container=container)
def setUp(self): super(HttpImageServiceTestCase, self).setUp() self.service = image_service.HttpImageService() self.href = 'https://127.0.0.1:12345/fedora.qcow2'