def continue_deploy(self, task): task.process_event('resume') node = task.node image_source = node.instance_info.get('image_source') LOG.debug('Continuing deploy for node %(node)s with image %(img)s', { 'node': node.uuid, 'img': image_source }) image_info = { 'id': image_source.split('/')[-1], 'urls': [node.instance_info['image_url']], 'checksum': node.instance_info['image_checksum'], # NOTE(comstud): Older versions of ironic do not set # 'disk_format' nor 'container_format', so we use .get() # to maintain backwards compatibility in case code was # upgraded in the middle of a build request. 'disk_format': node.instance_info.get('image_disk_format'), 'container_format': node.instance_info.get('image_container_format'), 'stream_raw_images': CONF.agent.stream_raw_images, } if (node.instance_info.get('image_os_hash_algo') and node.instance_info.get('image_os_hash_value')): image_info['os_hash_algo'] = node.instance_info[ 'image_os_hash_algo'] image_info['os_hash_value'] = node.instance_info[ 'image_os_hash_value'] proxies = {} for scheme in ('http', 'https'): proxy_param = 'image_%s_proxy' % scheme proxy = node.driver_info.get(proxy_param) if proxy: proxies[scheme] = proxy if proxies: image_info['proxies'] = proxies no_proxy = node.driver_info.get('image_no_proxy') if no_proxy is not None: image_info['no_proxy'] = no_proxy image_info['node_uuid'] = node.uuid iwdi = node.driver_internal_info.get('is_whole_disk_image') if not iwdi: for label in PARTITION_IMAGE_LABELS: image_info[label] = node.instance_info.get(label) boot_option = deploy_utils.get_boot_option(node) image_info['deploy_boot_mode'] = ( boot_mode_utils.get_boot_mode(node)) image_info['boot_option'] = boot_option disk_label = deploy_utils.get_disk_label(node) if disk_label is not None: image_info['disk_label'] = disk_label # Tell the client to download and write the image with the given args self._client.prepare_image(node, image_info) task.process_event('wait')
def get_deploy_info(node, address, iqn, port=None, lun='1', conv_flags=None): """Returns the information required for doing iSCSI deploy in a dictionary. :param node: ironic node object :param address: iSCSI address :param iqn: iSCSI iqn for the target disk :param port: iSCSI port, defaults to one specified in the configuration :param lun: iSCSI lun, defaults to '1' :param conv_flags: flag that will modify the behaviour of the image copy to disk. :raises: MissingParameterValue, if some required parameters were not passed. :raises: InvalidParameterValue, if any of the parameters have invalid value. """ i_info = deploy_utils.parse_instance_info(node) params = { 'address': address, 'port': port or CONF.iscsi.portal_port, 'iqn': iqn, 'lun': lun, 'image_path': deploy_utils._get_image_file_path(node.uuid), 'node_uuid': node.uuid} is_whole_disk_image = node.driver_internal_info['is_whole_disk_image'] if not is_whole_disk_image: params.update({'root_mb': i_info['root_mb'], 'swap_mb': i_info['swap_mb'], 'ephemeral_mb': i_info['ephemeral_mb'], 'preserve_ephemeral': i_info['preserve_ephemeral'], 'boot_option': deploy_utils.get_boot_option(node), 'boot_mode': _get_boot_mode(node), 'cpu_arch': node.properties.get('cpu_arch')}) # Append disk label if specified disk_label = deploy_utils.get_disk_label(node) if disk_label is not None: params['disk_label'] = disk_label missing = [key for key in params if params[key] is None] if missing: raise exception.MissingParameterValue( _("Parameters %s were not passed to ironic" " for deploy.") % missing) # configdrive is nullable params['configdrive'] = i_info.get('configdrive') if is_whole_disk_image: return params if conv_flags: params['conv_flags'] = conv_flags # ephemeral_format is nullable params['ephemeral_format'] = i_info.get('ephemeral_format') return params
def _parse_partitioning_info(node): info = node.instance_info i_info = {} partitions = [] i_info['label'] = deploy_utils.get_disk_label(node) or 'msdos' # prepend 1MiB bios_grub partition for GPT so that grub(2) installs if i_info['label'] == 'gpt': bios_partition = {'name': 'bios', 'size': 1, 'unit': 'MiB', 'flags': {'bios_grub': 'yes'}} partitions.append(bios_partition) ephemeral_mb = info['ephemeral_mb'] if ephemeral_mb: i_info['ephemeral_format'] = info['ephemeral_format'] ephemeral_partition = {'name': 'ephemeral', 'size': ephemeral_mb, 'unit': 'MiB', 'format': i_info['ephemeral_format']} partitions.append(ephemeral_partition) i_info['preserve_ephemeral'] = ( 'yes' if info['preserve_ephemeral'] else 'no') swap_mb = info['swap_mb'] if swap_mb: swap_partition = {'name': 'swap', 'size': swap_mb, 'unit': 'MiB', 'format': 'linux-swap'} partitions.append(swap_partition) # pre-create partition for configdrive configdrive = info.get('configdrive') if configdrive: configdrive_partition = {'name': 'configdrive', 'size': 64, 'unit': 'MiB', 'format': 'fat32'} partitions.append(configdrive_partition) # NOTE(pas-ha) make the root partition last so that # e.g. cloud-init can grow it on first start root_partition = {'name': 'root', 'size': info['root_mb'], 'unit': 'MiB'} if i_info['label'] == 'msdos': root_partition['flags'] = {'boot': 'yes'} partitions.append(root_partition) i_info['partitions'] = partitions return {'partition_info': i_info}
def get_deploy_info(node, **kwargs): """Returns the information required for doing iSCSI deploy in a dictionary. :param node: ironic node object :param kwargs: the keyword args passed from the conductor node. :raises: MissingParameterValue, if some required parameters were not passed. :raises: InvalidParameterValue, if any of the parameters have invalid value. """ deploy_key = kwargs.get('key') i_info = deploy_utils.parse_instance_info(node) if i_info['deploy_key'] != deploy_key: raise exception.InvalidParameterValue(_("Deploy key does not match")) params = { 'address': kwargs.get('address'), 'port': kwargs.get('port', CONF.iscsi.portal_port), 'iqn': kwargs.get('iqn'), 'lun': kwargs.get('lun', '1'), 'image_path': _get_image_file_path(node.uuid), 'node_uuid': node.uuid } is_whole_disk_image = node.driver_internal_info['is_whole_disk_image'] if not is_whole_disk_image: params.update({ 'root_mb': 1024 * int(i_info['root_gb']), 'swap_mb': int(i_info['swap_mb']), 'ephemeral_mb': 1024 * int(i_info['ephemeral_gb']), 'preserve_ephemeral': i_info['preserve_ephemeral'], 'boot_option': deploy_utils.get_boot_option(node), 'boot_mode': _get_boot_mode(node) }) # Append disk label if specified disk_label = deploy_utils.get_disk_label(node) if disk_label is not None: params['disk_label'] = disk_label missing = [key for key in params if params[key] is None] if missing: raise exception.MissingParameterValue( _("Parameters %s were not passed to ironic" " for deploy.") % missing) if is_whole_disk_image: return params # configdrive and ephemeral_format are nullable params['ephemeral_format'] = i_info.get('ephemeral_format') params['configdrive'] = i_info.get('configdrive') return params
def continue_deploy(self, task): task.process_event('resume') node = task.node image_source = node.instance_info.get('image_source') LOG.debug('Continuing deploy for node %(node)s with image %(img)s', {'node': node.uuid, 'img': image_source}) image_info = { 'id': image_source.split('/')[-1], 'urls': [node.instance_info['image_url']], 'checksum': node.instance_info['image_checksum'], # NOTE(comstud): Older versions of ironic do not set # 'disk_format' nor 'container_format', so we use .get() # to maintain backwards compatibility in case code was # upgraded in the middle of a build request. 'disk_format': node.instance_info.get('image_disk_format'), 'container_format': node.instance_info.get( 'image_container_format'), 'stream_raw_images': CONF.agent.stream_raw_images, } proxies = {} for scheme in ('http', 'https'): proxy_param = 'image_%s_proxy' % scheme proxy = node.driver_info.get(proxy_param) if proxy: proxies[scheme] = proxy if proxies: image_info['proxies'] = proxies no_proxy = node.driver_info.get('image_no_proxy') if no_proxy is not None: image_info['no_proxy'] = no_proxy image_info['node_uuid'] = node.uuid iwdi = node.driver_internal_info.get('is_whole_disk_image') if not iwdi: for label in PARTITION_IMAGE_LABELS: image_info[label] = node.instance_info.get(label) boot_option = deploy_utils.get_boot_option(node) boot_mode = deploy_utils.get_boot_mode_for_deploy(node) if boot_mode: image_info['deploy_boot_mode'] = boot_mode else: image_info['deploy_boot_mode'] = 'bios' image_info['boot_option'] = boot_option disk_label = deploy_utils.get_disk_label(node) if disk_label is not None: image_info['disk_label'] = disk_label # Tell the client to download and write the image with the given args self._client.prepare_image(node, image_info) task.process_event('wait')
def get_deploy_info(node, address, iqn, port=None, lun='1'): """Returns the information required for doing iSCSI deploy in a dictionary. :param node: ironic node object :param address: iSCSI address :param iqn: iSCSI iqn for the target disk :param port: iSCSI port, defaults to one specified in the configuration :param lun: iSCSI lun, defaults to '1' :raises: MissingParameterValue, if some required parameters were not passed. :raises: InvalidParameterValue, if any of the parameters have invalid value. """ i_info = deploy_utils.parse_instance_info(node) params = { 'address': address, 'port': port or CONF.iscsi.portal_port, 'iqn': iqn, 'lun': lun, 'image_path': _get_image_file_path(node.uuid), 'node_uuid': node.uuid} is_whole_disk_image = node.driver_internal_info['is_whole_disk_image'] if not is_whole_disk_image: params.update({'root_mb': i_info['root_mb'], 'swap_mb': i_info['swap_mb'], 'ephemeral_mb': i_info['ephemeral_mb'], 'preserve_ephemeral': i_info['preserve_ephemeral'], 'boot_option': deploy_utils.get_boot_option(node), 'boot_mode': _get_boot_mode(node)}) # Append disk label if specified disk_label = deploy_utils.get_disk_label(node) if disk_label is not None: params['disk_label'] = disk_label missing = [key for key in params if params[key] is None] if missing: raise exception.MissingParameterValue( _("Parameters %s were not passed to ironic" " for deploy.") % missing) # configdrive is nullable params['configdrive'] = i_info.get('configdrive') if is_whole_disk_image: return params # ephemeral_format is nullable params['ephemeral_format'] = i_info.get('ephemeral_format') return params
def _parse_partitioning_info(node): info = node.instance_info i_info = {'label': deploy_utils.get_disk_label(node) or 'msdos'} is_gpt = i_info['label'] == 'gpt' unit = 'MiB' partitions = {} def add_partition(name, start, end): partitions[name] = { 'number': len(partitions) + 1, 'part_start': '%i%s' % (start, unit), 'part_end': '%i%s' % (end, unit) } if is_gpt: partitions[name]['name'] = name end = 1 if is_gpt: # prepend 1MiB bios_grub partition for GPT so that grub(2) installs start, end = end, end + 1 add_partition('bios', start, end) partitions['bios']['flags'] = ['bios_grub'] ephemeral_mb = info['ephemeral_mb'] if ephemeral_mb: start, end = end, end + ephemeral_mb add_partition('ephemeral', start, end) i_info['ephemeral_format'] = info['ephemeral_format'] i_info['preserve_ephemeral'] = ('yes' if info['preserve_ephemeral'] else 'no') swap_mb = info['swap_mb'] if swap_mb: start, end = end, end + swap_mb add_partition('swap', start, end) configdrive = info.get('configdrive') if configdrive: # pre-create 64MiB partition for configdrive start, end = end, end + 64 add_partition('configdrive', start, end) # NOTE(pas-ha) make the root partition last so that # e.g. cloud-init can grow it on first start start, end = end, end + info['root_mb'] add_partition('root', start, end) if not is_gpt: partitions['root']['flags'] = ['boot'] i_info['partitions'] = partitions return {'partition_info': i_info}
def get_deploy_info(node, **kwargs): """Returns the information required for doing iSCSI deploy in a dictionary. :param node: ironic node object :param kwargs: the keyword args passed from the conductor node. :raises: MissingParameterValue, if some required parameters were not passed. :raises: InvalidParameterValue, if any of the parameters have invalid value. """ deploy_key = kwargs.get('key') i_info = parse_instance_info(node) if i_info['deploy_key'] != deploy_key: raise exception.InvalidParameterValue(_("Deploy key does not match")) params = { 'address': kwargs.get('address'), 'port': kwargs.get('port', '3260'), 'iqn': kwargs.get('iqn'), 'lun': kwargs.get('lun', '1'), 'image_path': _get_image_file_path(node.uuid), 'node_uuid': node.uuid} is_whole_disk_image = node.driver_internal_info['is_whole_disk_image'] if not is_whole_disk_image: params.update({'root_mb': 1024 * int(i_info['root_gb']), 'swap_mb': int(i_info['swap_mb']), 'ephemeral_mb': 1024 * int(i_info['ephemeral_gb']), 'preserve_ephemeral': i_info['preserve_ephemeral'], 'boot_option': deploy_utils.get_boot_option(node), 'boot_mode': _get_boot_mode(node)}) # Append disk label if specified disk_label = deploy_utils.get_disk_label(node) if disk_label is not None: params['disk_label'] = disk_label missing = [key for key in params if params[key] is None] if missing: raise exception.MissingParameterValue( _("Parameters %s were not passed to ironic" " for deploy.") % missing) if is_whole_disk_image: return params # configdrive and ephemeral_format are nullable params['ephemeral_format'] = i_info.get('ephemeral_format') params['configdrive'] = i_info.get('configdrive') return params
def _parse_partitioning_info(node): info = node.instance_info i_info = {'label': deploy_utils.get_disk_label(node) or 'msdos'} is_gpt = i_info['label'] == 'gpt' unit = 'MiB' partitions = {} def add_partition(name, start, end): partitions[name] = {'number': len(partitions) + 1, 'part_start': '%i%s' % (start, unit), 'part_end': '%i%s' % (end, unit)} if is_gpt: partitions[name]['name'] = name end = 1 if is_gpt: # prepend 1MiB bios_grub partition for GPT so that grub(2) installs start, end = end, end + 1 add_partition('bios', start, end) partitions['bios']['flags'] = ['bios_grub'] ephemeral_mb = info['ephemeral_mb'] if ephemeral_mb: start, end = end, end + ephemeral_mb add_partition('ephemeral', start, end) i_info['ephemeral_format'] = info['ephemeral_format'] i_info['preserve_ephemeral'] = ( 'yes' if info['preserve_ephemeral'] else 'no') swap_mb = info['swap_mb'] if swap_mb: start, end = end, end + swap_mb add_partition('swap', start, end) configdrive = info.get('configdrive') if configdrive: # pre-create 64MiB partition for configdrive start, end = end, end + 64 add_partition('configdrive', start, end) # NOTE(pas-ha) make the root partition last so that # e.g. cloud-init can grow it on first start start, end = end, end + info['root_mb'] add_partition('root', start, end) if not is_gpt: partitions['root']['flags'] = ['boot'] i_info['partitions'] = partitions return {'partition_info': i_info}
def write_image(self, task): if not task.driver.storage.should_write_image(task): return node = task.node image_source = node.instance_info.get('image_source') LOG.debug('Continuing deploy for node %(node)s with image %(img)s', { 'node': node.uuid, 'img': image_source }) image_info = { 'id': image_source.split('/')[-1], 'urls': [node.instance_info['image_url']], # NOTE(comstud): Older versions of ironic do not set # 'disk_format' nor 'container_format', so we use .get() # to maintain backwards compatibility in case code was # upgraded in the middle of a build request. 'disk_format': node.instance_info.get('image_disk_format'), 'container_format': node.instance_info.get('image_container_format'), 'stream_raw_images': CONF.agent.stream_raw_images, } if node.instance_info.get('image_checksum'): image_info['checksum'] = node.instance_info['image_checksum'] if (node.instance_info.get('image_os_hash_algo') and node.instance_info.get('image_os_hash_value')): image_info['os_hash_algo'] = node.instance_info[ 'image_os_hash_algo'] image_info['os_hash_value'] = node.instance_info[ 'image_os_hash_value'] proxies = {} for scheme in ('http', 'https'): proxy_param = 'image_%s_proxy' % scheme proxy = node.driver_info.get(proxy_param) if proxy: proxies[scheme] = proxy if proxies: image_info['proxies'] = proxies no_proxy = node.driver_info.get('image_no_proxy') if no_proxy is not None: image_info['no_proxy'] = no_proxy image_info['node_uuid'] = node.uuid iwdi = node.driver_internal_info.get('is_whole_disk_image') if not iwdi: for label in PARTITION_IMAGE_LABELS: image_info[label] = node.instance_info.get(label) boot_option = deploy_utils.get_boot_option(node) image_info['deploy_boot_mode'] = ( boot_mode_utils.get_boot_mode(node)) image_info['boot_option'] = boot_option disk_label = deploy_utils.get_disk_label(node) if disk_label is not None: image_info['disk_label'] = disk_label has_write_image = agent_base.find_step(task, 'deploy', 'deploy', 'write_image') is not None if not has_write_image: LOG.warning( 'The agent on node %s does not have the deploy ' 'step deploy.write_image, using the deprecated ' 'synchronous fall-back', task.node.uuid) if self.has_decomposed_deploy_steps and has_write_image: configdrive = node.instance_info.get('configdrive') # Now switch into the corresponding in-band deploy step and let the # result be polled normally. new_step = { 'interface': 'deploy', 'step': 'write_image', 'args': { 'image_info': image_info, 'configdrive': configdrive } } return agent_base.execute_step(task, new_step, 'deploy', client=self._client) else: # TODO(dtantsur): remove in W command = self._client.prepare_image(node, image_info, wait=True) if command['command_status'] == 'FAILED': # TODO(jimrollenhagen) power off if using neutron dhcp to # align with pxe driver? msg = (_('node %(node)s command status errored: %(error)s') % { 'node': node.uuid, 'error': command['command_error'] }) LOG.error(msg) deploy_utils.set_failed_state(task, msg)
def write_image(self, task): if not task.driver.storage.should_write_image(task): return node = task.node image_source = node.instance_info.get('image_source') LOG.debug('Continuing deploy for node %(node)s with image %(img)s', { 'node': node.uuid, 'img': image_source }) image_info = { 'id': image_source.split('/')[-1], 'urls': [node.instance_info['image_url']], # NOTE(comstud): Older versions of ironic do not set # 'disk_format' nor 'container_format', so we use .get() # to maintain backwards compatibility in case code was # upgraded in the middle of a build request. 'disk_format': node.instance_info.get('image_disk_format'), 'container_format': node.instance_info.get('image_container_format'), 'stream_raw_images': CONF.agent.stream_raw_images, } if node.instance_info.get('image_checksum'): image_info['checksum'] = node.instance_info['image_checksum'] if (node.instance_info.get('image_os_hash_algo') and node.instance_info.get('image_os_hash_value')): image_info['os_hash_algo'] = node.instance_info[ 'image_os_hash_algo'] image_info['os_hash_value'] = node.instance_info[ 'image_os_hash_value'] proxies = {} for scheme in ('http', 'https'): proxy_param = 'image_%s_proxy' % scheme proxy = node.driver_info.get(proxy_param) if proxy: proxies[scheme] = proxy if proxies: image_info['proxies'] = proxies no_proxy = node.driver_info.get('image_no_proxy') if no_proxy is not None: image_info['no_proxy'] = no_proxy image_info['node_uuid'] = node.uuid iwdi = node.driver_internal_info.get('is_whole_disk_image') if not iwdi: for label in PARTITION_IMAGE_LABELS: image_info[label] = node.instance_info.get(label) boot_option = deploy_utils.get_boot_option(node) image_info['deploy_boot_mode'] = ( boot_mode_utils.get_boot_mode(node)) image_info['boot_option'] = boot_option disk_label = deploy_utils.get_disk_label(node) if disk_label is not None: image_info['disk_label'] = disk_label configdrive = manager_utils.get_configdrive_image(node) if configdrive: # FIXME(dtantsur): remove this duplication once IPA is ready: # https://review.opendev.org/c/openstack/ironic-python-agent/+/790471 image_info['configdrive'] = configdrive # Now switch into the corresponding in-band deploy step and let the # result be polled normally. new_step = { 'interface': 'deploy', 'step': 'write_image', 'args': { 'image_info': image_info, 'configdrive': configdrive } } return agent_base.execute_step(task, new_step, 'deploy', client=self._client)