def test_no_retry_on_success(self): fd, tmpfilename = tempfile.mkstemp() _, tmpfilename2 = tempfile.mkstemp() try: fp = os.fdopen(fd, 'w+') fp.write('''#!/bin/sh # If we've already run, bail out. grep -q foo "$1" && exit 1 # Mark that we've run before. echo foo > "$1" # Check that stdin gets passed correctly. grep foo ''') fp.close() os.chmod(tmpfilename, 0o755) try: utils.execute(tmpfilename, tmpfilename2, process_input=b'foo', attempts=2) except OSError as e: if e.errno == errno.EACCES: self.skipTest("Permissions error detected. " "Are you running with a noexec /tmp?") else: raise finally: os.unlink(tmpfilename) os.unlink(tmpfilename2)
def activate_bootloader(self, context, node, instance): """Configure Tilera boot loader for an instance Kernel and ramdisk images are downloaded by cache_tftp_images, and stored in /tftpboot/{uuid}/ This method writes the instances config file, and then creates symlinks for each MAC address in the instance. By default, the complete layout looks like this: /tftpboot/ ./{uuid}/ kernel ./fs_node_id/ """ (root_mb, swap_mb) = get_partition_sizes(instance) tilera_nfs_path = get_tilera_nfs_path(node['id']) image_file_path = get_image_file_path(instance) deployment_key = utils.random_alnum(32) db.bm_node_update(context, node['id'], {'deploy_key': deployment_key, 'image_path': image_file_path, 'pxe_config_path': tilera_nfs_path, 'root_mb': root_mb, 'swap_mb': swap_mb}) if os.path.exists(image_file_path) and \ os.path.exists(tilera_nfs_path): utils.execute('mount', '-o', 'loop', image_file_path, tilera_nfs_path, run_as_root=True)
def mkswap(dev, label='swap1'): """Execute mkswap on a device.""" utils.execute('mkswap', '-L', label, dev, run_as_root=True, check_exit_code=[0])
def _allow_iscsi_tgtadm(tid, address): utils.execute('tgtadm', '--lld', 'iscsi', '--mode', 'target', '--op', 'bind', '--tid', tid, '--initiator-address', address, run_as_root=True)
def _prepare_floppy_image(task, params): """Prepares the floppy image for passing the parameters. This method prepares a temporary vfat filesystem image, which contains the parameters to be passed to the ramdisk. Then it uploads the file NFS or CIFS server. :param task: a TaskManager instance containing the node to act on. :param params: a dictionary containing 'parameter name'->'value' mapping to be passed to the deploy ramdisk via the floppy image. :returns: floppy image filename :raises: ImageCreationFailed, if it failed while creating the floppy image. :raises: IRMCOperationError, if copying floppy image file failed. """ floppy_filename = _get_floppy_image_name(task.node) floppy_fullpathname = os.path.join( CONF.irmc.remote_image_share_root, floppy_filename) with tempfile.NamedTemporaryFile() as vfat_image_tmpfile_obj: images.create_vfat_image(vfat_image_tmpfile_obj.name, parameters=params) try: utils.execute('cp', vfat_image_tmpfile_obj.name, floppy_fullpathname, check_exit_code=[0]) except Exception as e: operation = _("Copying floppy image file") raise exception.IRMCOperationError( operation=operation, error=e) return floppy_filename
def convert_image(source, dest, out_format, run_as_root=False): """Convert image to other format.""" # NOTE(jlvillal): This function has been moved to ironic-lib. And is # planned to be deleted here. If need to modify this function, please also # do the same modification in ironic-lib cmd = ('qemu-img', 'convert', '-O', out_format, source, dest) utils.execute(*cmd, run_as_root=run_as_root)
def test_execute_get_root_helper(self): with mock.patch.object( processutils, 'execute', autospec=True) as execute_mock: helper = utils._get_root_helper() utils.execute('foo', run_as_root=True) execute_mock.assert_called_once_with('foo', run_as_root=True, root_helper=helper)
def test_execute_use_standard_locale_with_env_variables(self, execute_mock): utils.execute('foo', use_standard_locale=True, env_variables={'foo': 'bar'}) execute_mock.assert_called_once_with('foo', env_variables={'LC_ALL': 'C', 'foo': 'bar'})
def awake_amt_interface(node): """Wake up AMT interface. AMT interface goes to sleep after a period of time if the host is off. This method will ping AMT interface to wake it up. Because there is no guarantee that the AMT address in driver_info is correct, only ping the IP five times which is enough to wake it up. :param node: an Ironic node object. :raises: AMTConnectFailure if unable to connect to the server. """ awake_interval = CONF.amt.awake_interval if awake_interval == 0: return now = time.time() last_awake = AMT_AWAKE_CACHE.get(node.uuid, 0) if now - last_awake > awake_interval: cmd_args = ['ping', '-i', 0.2, '-c', 5, node.driver_info['amt_address']] try: utils.execute(*cmd_args) except processutils.ProcessExecutionError as err: LOG.error(_LE('Unable to awake AMT interface on node ' '%(node_id)s. Error: %(error)s'), {'node_id': node.uuid, 'error': err}) raise exception.AMTConnectFailure() else: LOG.debug(('Successfully awakened AMT interface on node ' '%(node_id)s.'), {'node_id': node.uuid}) AMT_AWAKE_CACHE[node.uuid] = now
def test_exec_ipmitool(self): pw_file = "/tmp/password_file" self.mox.StubOutWithMock(ipmi, "_make_password_file") self.mox.StubOutWithMock(utils, "execute") self.mox.StubOutWithMock(utils, "delete_if_exists") ipmi._make_password_file(self.ipmi.password).AndReturn(pw_file) args = [ "ipmitool", "-I", "lanplus", "-H", self.ipmi.address, "-U", self.ipmi.user, "-f", pw_file, "A", "B", "C", ] utils.execute(*args, attempts=3).AndReturn(("", "")) utils.delete_if_exists(pw_file).AndReturn(None) self.mox.ReplayAll() self.ipmi._exec_ipmitool("A B C") self.mox.VerifyAll()
def discovery(portal_address, portal_port): """Do iSCSI discovery on portal.""" utils.execute('iscsiadm', '-m', 'discovery', '-t', 'st', '-p', '%s:%s' % (portal_address, portal_port), run_as_root=True, check_exit_code=[0])
def _exec(self, *args): # NOTE(lucasagomes): utils.execute() is already a wrapper on top # of processutils.execute() which raises specific # exceptions. It also logs any failure so we don't # need to log it again here. utils.execute('parted', '-a', self._alignment, '-s', self._device, '--', 'unit', 'MiB', *args, check_exit_code=[0], run_as_root=True)
def stop_console(self): console_pid = _get_console_pid(self.node_id) if console_pid: # Allow exitcode 99 (RC_UNAUTHORIZED) utils.execute('kill', '-TERM', str(console_pid), run_as_root=True, check_exit_code=[0, 99]) utils.delete_if_exists(_get_console_pid_path(self.node_id))
def delete_iscsi(portal_address, portal_port, target_iqn): """Delete the iSCSI target.""" utils.execute('iscsiadm', '-m', 'node', '-p', '%s:%s' % (portal_address, portal_port), '-T', target_iqn, '-o', 'delete', run_as_root=True, check_exit_code=[0])
def create_isolinux_image_for_bios(output_file, kernel, ramdisk, kernel_params=None): """Creates an isolinux image on the specified file. Copies the provided kernel, ramdisk to a directory, generates the isolinux configuration file using the kernel parameters provided, and then generates a bootable ISO image. :param output_file: the path to the file where the iso image needs to be created. :param kernel: the kernel to use. :param ramdisk: the ramdisk to use. :param kernel_params: a list of strings(each element being a string like 'K=V' or 'K' or combination of them like 'K1=V1,K2,...') to be added as the kernel cmdline. :raises: ImageCreationFailed, if image creation failed while copying files or while running command to generate iso. """ ISOLINUX_BIN = "isolinux/isolinux.bin" ISOLINUX_CFG = "isolinux/isolinux.cfg" options = {"kernel": "/vmlinuz", "ramdisk": "/initrd"} with utils.tempdir() as tmpdir: files_info = {kernel: "vmlinuz", ramdisk: "initrd", CONF.isolinux_bin: ISOLINUX_BIN} try: _create_root_fs(tmpdir, files_info) except (OSError, IOError) as e: LOG.exception(_LE("Creating the filesystem root failed.")) raise exception.ImageCreationFailed(image_type="iso", error=e) cfg = _generate_cfg(kernel_params, CONF.isolinux_config_template, options) isolinux_cfg = os.path.join(tmpdir, ISOLINUX_CFG) utils.write_to_file(isolinux_cfg, cfg) try: utils.execute( "mkisofs", "-r", "-V", "VMEDIA_BOOT_ISO", "-cache-inodes", "-J", "-l", "-no-emul-boot", "-boot-load-size", "4", "-boot-info-table", "-b", ISOLINUX_BIN, "-o", output_file, tmpdir, ) except processutils.ProcessExecutionError as e: LOG.exception(_LE("Creating ISO image failed.")) raise exception.ImageCreationFailed(image_type="iso", error=e)
def logout_iscsi(portal_address, portal_port, target_iqn): """Logout from an iSCSI target.""" utils.execute('iscsiadm', '-m', 'node', '-p', '%s:%s' % (portal_address, portal_port), '-T', target_iqn, '--logout', run_as_root=True, check_exit_code=[0])
def dd(src, dst): """Execute dd from src to dst.""" utils.execute('dd', 'if=%s' % src, 'of=%s' % dst, 'bs=1M', 'oflag=direct', run_as_root=True, check_exit_code=[0])
def _iptables_set(self, node_ip, user_data): """Sets security setting (iptables:port) if needed. iptables -A INPUT -p tcp ! -s $IP --dport $PORT -j DROP /tftpboot/iptables_rule script sets iptables rule on the given node. """ rule_path = CONF.tftp_root + "/iptables_rule" if user_data is not None: open_ip = base64.b64decode(user_data) utils.execute(rule_path, node_ip, open_ip)
def force_iscsi_lun_update(target_iqn): """force iSCSI initiator to re-read luns.""" LOG.debug("Re-reading iSCSI luns.") utils.execute('iscsiadm', '-m', 'node', '-T', target_iqn, '-R', run_as_root=True, check_exit_code=[0])
def destroy_disk_metadata(dev, node_uuid): """Destroy metadata structures on node's disk. Ensure that node's disk appears to be blank without zeroing the entire drive. To do this we will zero: - the first 18KiB to clear MBR / GPT data - the last 18KiB to clear GPT and other metadata like: LVM, veritas, MDADM, DMRAID, ... """ # NOTE(NobodyCam): This is needed to work around bug: # https://bugs.launchpad.net/ironic/+bug/1317647 LOG.debug("Start destroy disk metadata for node %(node)s.", {"node": node_uuid}) try: utils.execute("dd", "if=/dev/zero", "of=%s" % dev, "bs=512", "count=36", run_as_root=True, check_exit_code=[0]) except processutils.ProcessExecutionError as err: with excutils.save_and_reraise_exception(): LOG.error( _LE("Failed to erase beginning of disk for node " "%(node)s. Command: %(command)s. Error: %(error)s."), {"node": node_uuid, "command": err.cmd, "error": err.stderr}, ) # now wipe the end of the disk. # get end of disk seek value try: block_sz = get_dev_block_size(dev) except processutils.ProcessExecutionError as err: with excutils.save_and_reraise_exception(): LOG.error( _LE("Failed to get disk block count for node %(node)s. " "Command: %(command)s. Error: %(error)s."), {"node": node_uuid, "command": err.cmd, "error": err.stderr}, ) else: seek_value = block_sz - 36 try: utils.execute( "dd", "if=/dev/zero", "of=%s" % dev, "bs=512", "count=36", "seek=%d" % seek_value, run_as_root=True, check_exit_code=[0], ) except processutils.ProcessExecutionError as err: with excutils.save_and_reraise_exception(): LOG.error( _LE( "Failed to erase the end of the disk on node " "%(node)s. Command: %(command)s. " "Error: %(error)s." ), {"node": node_uuid, "command": err.cmd, "error": err.stderr}, )
def login_iscsi(portal_address, portal_port, target_iqn): """Login to an iSCSI target.""" utils.execute('iscsiadm', '-m', 'node', '-p', '%s:%s' % (portal_address, portal_port), '-T', target_iqn, '--login', run_as_root=True, check_exit_code=[0]) # Ensure the login complete time.sleep(3)
def setUp(self): super(RealFilePartitioningTestCase, self).setUp() # NOTE(dtantsur): no parted utility on gate-ironic-python26 try: common_utils.execute('parted', '--version') except OSError as exc: self.skipTest('parted utility was not found: %s' % exc) self.file = tempfile.NamedTemporaryFile() self.addCleanup(lambda: self.file.close()) # NOTE(dtantsur): 20 MiB file with zeros common_utils.execute('dd', 'if=/dev/zero', 'of=%s' % self.file.name, 'bs=1', 'count=0', 'seek=20MiB')
def stop_shellinabox_console(node_uuid): """Close the serial console for a node.""" try: console_pid = _get_console_pid(node_uuid) except exception.NoConsolePid: LOG.warning(_("No console pid found for node %s" " while trying to stop shellinabox console.") % node_uuid) else: # Allow exitcode 99 (RC_UNAUTHORIZED) utils.execute("kill", str(console_pid), check_exit_code=[0, 99]) finally: utils.unlink_without_raise(_get_console_pid_file(node_uuid))
def make_partitions(dev, root_mb, swap_mb): """Create partitions for root and swap on a disk device.""" # Lead in with 1MB to allow room for the partition table itself, otherwise # the way sfdisk adjusts doesn't shift the partition up to compensate, and # we lose the space. # http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/raring/util-linux/ # raring/view/head:/fdisk/sfdisk.c#L1940 stdin_command = ('1,%d,83;\n,%d,82;\n0,0;\n0,0;\n' % (root_mb, swap_mb)) utils.execute('sfdisk', '-uM', dev, process_input=stdin_command, run_as_root=True, check_exit_code=[0]) # avoid "device is busy" time.sleep(3)
def discovery(portal_address, portal_port): """Do iSCSI discovery on portal.""" utils.execute( "iscsiadm", "-m", "discovery", "-t", "st", "-p", "%s:%s" % (portal_address, portal_port), run_as_root=True, check_exit_code=[0], )
def delete_iscsi(portal_address, portal_port, target_iqn): """Delete the iSCSI target.""" # Retry delete until it succeeds (exit code 0) or until there is # no longer a target to delete (exit code 21). utils.execute('iscsiadm', '-m', 'node', '-p', '%s:%s' % (portal_address, portal_port), '-T', target_iqn, '-o', 'delete', run_as_root=True, check_exit_code=[0, 21], attempts=5, delay_on_retry=True)
def logout_iscsi(portal_address, portal_port, target_iqn): """Logout from an iSCSI target.""" utils.execute( "iscsiadm", "-m", "node", "-p", "%s:%s" % (portal_address, portal_port), "-T", target_iqn, "--logout", run_as_root=True, check_exit_code=[0], )
def _create_iscsi_export_tgtadm(path, tid, iqn): utils.execute('tgtadm', '--lld', 'iscsi', '--mode', 'target', '--op', 'new', '--tid', tid, '--targetname', iqn, run_as_root=True) utils.execute('tgtadm', '--lld', 'iscsi', '--mode', 'logicalunit', '--op', 'new', '--tid', tid, '--lun', '1', '--backing-store', path, run_as_root=True)
def setUp(self): super(RealFilePartitioningTestCase, self).setUp() # NOTE(dtantsur): no parted utility on gate-ironic-python26 try: common_utils.execute('parted', '--version') except OSError as exc: self.skipTest('parted utility was not found: %s' % exc) self.file = tempfile.NamedTemporaryFile(delete=False) # NOTE(ifarkas): the file needs to be closed, so fuser won't report # any usage self.file.close() # NOTE(dtantsur): 20 MiB file with zeros common_utils.execute('dd', 'if=/dev/zero', 'of=%s' % self.file.name, 'bs=1', 'count=0', 'seek=20MiB')
def create_database(self): """Create database if required for this server.""" # FIXME(jlvillal) to work with Ironic raise Exception("Does not work") if self.needs_database: conf_dir = os.path.join(self.test_dir, 'etc') safe_mkdirs(conf_dir) conf_filepath = os.path.join(conf_dir, 'ironic-manage.conf') with open(conf_filepath, 'w') as conf_file: conf_file.write('[DEFAULT]\n') conf_file.write('sql_connection = %s' % self.sql_connection) conf_file.flush() ironic_db_env = 'IRONIC_DB_TEST_SQLITE_FILE' if ironic_db_env in os.environ: # use the empty db created and cached as a tempfile # instead of spending the time creating a new one db_location = os.environ[ironic_db_env] os.system('cp %s %s/tests.sqlite' % (db_location, self.test_dir)) else: # FIXME(jlvillal) what is the correct command???? cmd = ('%s -m ironic.cmd.manage --config-file %s db sync' % (sys.executable, conf_filepath)) utils.execute(cmd) # copy the clean db to a temp location so that it # can be reused for future tests (osf, db_location) = tempfile.mkstemp() os.close(osf) os.system('cp %s/tests.sqlite %s' % (self.test_dir, db_location)) os.environ[ironic_db_env] = db_location # cleanup the temp file when the test suite is # complete def _delete_cached_db(): try: os.remove(os.environ[ironic_db_env]) except Exception: # FIXME(jlvillal) We should log this raise NotImplementedError # logger.exception( # "Error cleaning up the file %s" % # os.environ[ironic_db_env]) atexit.register(_delete_cached_db)
def create_isolinux_image(output_file, kernel, ramdisk, kernel_params=None): """Creates an isolinux image on the specified file. Copies the provided kernel, ramdisk to a directory, generates the isolinux configuration file using the kernel parameters provided, and then generates a bootable ISO image. :param output_file: the path to the file where the iso image needs to be created. :param kernel: the kernel to use. :param ramdisk: the ramdisk to use. :param kernel_params: a list of strings(each element being a string like 'K=V' or 'K' or combination of them like 'K1=V1,K2,...') to be added as the kernel cmdline. :raises: ImageCreationFailed, if image creation failed while copying files or while running command to generate iso. """ ISOLINUX_BIN = 'isolinux/isolinux.bin' ISOLINUX_CFG = 'isolinux/isolinux.cfg' with utils.tempdir() as tmpdir: files_info = { kernel: 'vmlinuz', ramdisk: 'initrd', CONF.isolinux_bin: ISOLINUX_BIN, } try: _create_root_fs(tmpdir, files_info) except (OSError, IOError) as e: LOG.exception(_LE("Creating the filesystem root failed.")) raise exception.ImageCreationFailed(image_type='iso', error=e) cfg = _generate_isolinux_cfg(kernel_params) isolinux_cfg = os.path.join(tmpdir, ISOLINUX_CFG) utils.write_to_file(isolinux_cfg, cfg) try: utils.execute('mkisofs', '-r', '-V', "BOOT IMAGE", '-cache-inodes', '-J', '-l', '-no-emul-boot', '-boot-load-size', '4', '-boot-info-table', '-b', ISOLINUX_BIN, '-o', output_file, tmpdir) except processutils.ProcessExecutionError as e: LOG.exception(_LE("Creating ISO image failed.")) raise exception.ImageCreationFailed(image_type='iso', error=e)
def make_partitions(dev, root_mb, swap_mb): """Create partitions for root and swap on a disk device.""" # Lead in with 1MB to allow room for the partition table itself, otherwise # the way sfdisk adjusts doesn't shift the partition up to compensate, and # we lose the space. # http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/raring/util-linux/ # raring/view/head:/fdisk/sfdisk.c#L1940 stdin_command = ('1,%d,83;\n,%d,82;\n0,0;\n0,0;\n' % (root_mb, swap_mb)) utils.execute('sfdisk', '-uM', dev, process_input=stdin_command, run_as_root=True, attempts=3, check_exit_code=[0]) # avoid "device is busy" time.sleep(3)
def get_dev_block_size(dev): """Get the device size in 512 byte sectors.""" block_sz, cmderr = utils.execute('blockdev', '--getsz', dev, run_as_root=True, check_exit_code=[0]) return int(block_sz)
def _stop_console(node_uuid): """Close the serial console for a node Kills the console process and deletes the PID file. :param node_uuid: the UUID of the node :raises: NoConsolePid if no console PID was found :raises: processutils.ProcessExecutionError if unable to stop the process """ try: console_pid = _get_console_pid(node_uuid) # Allow exitcode 99 (RC_UNAUTHORIZED) utils.execute('kill', str(console_pid), check_exit_code=[0, 99]) finally: utils.unlink_without_raise(_get_console_pid_file(node_uuid))
def qemu_img_info(path): """Return an object containing the parsed output from qemu-img info.""" if not os.path.exists(path): return imageutils.QemuImgInfo() out, err = utils.execute('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path) return imageutils.QemuImgInfo(out)
def login_iscsi(portal_address, portal_port, target_iqn): """Login to an iSCSI target.""" utils.execute('iscsiadm', '-m', 'node', '-p', '%s:%s' % (portal_address, portal_port), '-T', target_iqn, '--login', run_as_root=True, check_exit_code=[0], attempts=5, delay_on_retry=True) # Ensure the login complete verify_iscsi_connection(target_iqn) # force iSCSI initiator to re-read luns force_iscsi_lun_update(target_iqn)
def _exec_ipmitool(driver_info, command): """Execute the ipmitool command. This uses the lanplus interface to communicate with the BMC device driver. :param driver_info: the ipmitool parameters for accessing a node. :param command: the ipmitool command to be executed. :returns: (stdout, stderr) from executing the command. :raises: PasswordFileFailedToCreate from creating or writing to the temporary file. :raises: processutils.ProcessExecutionError from executing the command. """ args = ['ipmitool', '-I', 'lanplus', '-H', driver_info['address'], '-L', driver_info['priv_level'] ] if driver_info['username']: args.append('-U') args.append(driver_info['username']) for name, option in BRIDGING_OPTIONS: if driver_info[name] is not None: args.append(option) args.append(driver_info[name]) # specify retry timing more precisely, if supported if _is_option_supported('timing'): num_tries = max( (CONF.ipmi.retry_timeout // CONF.ipmi.min_command_interval), 1) args.append('-R') args.append(str(num_tries)) args.append('-N') args.append(str(CONF.ipmi.min_command_interval)) # 'ipmitool' command will prompt password if there is no '-f' option, # we set it to '\0' to write a password file to support empty password with _make_password_file(driver_info['password'] or '\0') as pw_file: args.append('-f') args.append(pw_file) args.extend(command.split(" ")) # NOTE(deva): ensure that no communications are sent to a BMC more # often than once every min_command_interval seconds. time_till_next_poll = CONF.ipmi.min_command_interval - ( time.time() - LAST_CMD_TIME.get(driver_info['address'], 0)) if time_till_next_poll > 0: time.sleep(time_till_next_poll) try: out, err = utils.execute(*args) finally: LAST_CMD_TIME[driver_info['address']] = time.time() return out, err
def _show_tgtadm(): out, _ = utils.execute('tgtadm', '--lld', 'iscsi', '--mode', 'target', '--op', 'show', run_as_root=True) return out
def get_partition_table(device): """Get partitions information from given device. :param device: The device path. :returns: If a partition table is present. """ output = utils.execute('parted', '-s', '-m', device, 'print')[0] header = [line for line in output.split('\n') if line.strip()][1] match = _PARTED_PRINT_HEADER_RE.match(header) return match.groups()[0]
def qemu_img_info(path): """Return an object containing the parsed output from qemu-img info.""" # NOTE(jlvillal): This function has been moved to ironic-lib. And is # planned to be deleted here. If need to modify this function, please also # do the same modification in ironic-lib if not os.path.exists(path): return imageutils.QemuImgInfo() out, err = utils.execute('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path) return imageutils.QemuImgInfo(out)
def _exec_ipmitool(driver_info, command): args = [ 'ipmitool', '-I', 'lanplus', '-H', driver_info['address'], '-U', driver_info['username'], '-f' ] with _make_password_file(driver_info['password']) as pw_file: args.append(pw_file) args.extend(command.split(" ")) out, err = utils.execute(*args, attempts=3) LOG.debug(_("ipmitool stdout: '%(out)s', stderr: '%(err)s'"), locals()) return out, err
def block_uuid(dev): """Get UUID of a block device.""" out, _err = utils.execute('blkid', '-s', 'UUID', '-o', 'value', dev, run_as_root=True, check_exit_code=[0]) return out.strip()
def _send_signal(node_uuid, signum): """send a signal to the console server. Kills the console process and deletes the PID file. :param node_uuid: the UUID of the node :param signum: signal number to send :raises: NoConsolePid if no console PID was found :raises: processutils.ProcessExecutionError if unable to stop the process """ try: console_pid = _get_console_pid(node_uuid) # Allow exitcode 99 (RC_UNAUTHORIZED) utils.execute('kill', '-%s' % signum, str(console_pid), check_exit_code=[0, 99]) finally: pass
def _exec_pdutool(self, mode): """Changes power state of the given node. According to the mode (1-ON, 2-OFF, 3-REBOOT), power state can be changed. /tftpboot/pdu_mgr script handles power management of PDU (Power Distribution Unit). """ if mode == CONF.tile_pdu_status: try: utils.execute('ping', '-c1', self.address, check_exit_code=True) return CONF.tile_pdu_on except exception.ProcessExecutionError: return CONF.tile_pdu_off else: try: utils.execute(CONF.tile_pdu_mgr, CONF.tile_pdu_ip, mode) time.sleep(CONF.tile_power_wait) return mode except exception.ProcessExecutionError: LOG.exception(_("PDU failed"))
def test_no_retry_on_success(self): fd, tmpfilename = tempfile.mkstemp() _, tmpfilename2 = tempfile.mkstemp() try: fp = os.fdopen(fd, 'w+') fp.write('''#!/bin/sh # If we've already run, bail out. grep -q foo "$1" && exit 1 # Mark that we've run before. echo foo > "$1" # Check that stdin gets passed correctly. grep foo ''') fp.close() os.chmod(tmpfilename, 0o755) utils.execute(tmpfilename, tmpfilename2, process_input='foo', attempts=2) finally: os.unlink(tmpfilename) os.unlink(tmpfilename2)
def login_iscsi(portal_address, portal_port, target_iqn): """Login to an iSCSI target.""" utils.execute('iscsiadm', '-m', 'node', '-p', '%s:%s' % (utils.wrap_ipv6(portal_address), portal_port), '-T', target_iqn, '--login', run_as_root=True, check_exit_code=[0], attempts=5, delay_on_retry=True) error_occurred = False try: # Ensure the login complete verify_iscsi_connection(target_iqn) # force iSCSI initiator to re-read luns force_iscsi_lun_update(target_iqn) # ensure file system sees the block device check_file_system_for_iscsi_device(portal_address, portal_port, target_iqn) except (exception.InstanceDeployFailure, processutils.ProcessExecutionError) as e: with excutils.save_and_reraise_exception(): error_occurred = True LOG.error("Failed to login to an iSCSI target due to %s", e) finally: if error_occurred: try: logout_iscsi(portal_address, portal_port, target_iqn) delete_iscsi(portal_address, portal_port, target_iqn) except processutils.ProcessExecutionError as e: LOG.warning( "An error occurred when trying to cleanup " "failed ISCSI session error %s", e)
def _exec_ipmitool(self, command): args = [ 'ipmitool', '-I', 'lanplus', '-H', self.address, '-U', self.user, '-f' ] pwfile = _make_password_file(self.password) try: args.append(pwfile) args.extend(command.split(" ")) out, err = utils.execute(*args, attempts=3) LOG.debug(_("ipmitool stdout: '%(out)s', stderr: '%(err)s'"), locals()) return out, err finally: utils.delete_if_exists(pwfile)
def start_console(self): if not self.port: return args = [] args.append(CONF.terminal) if CONF.terminal_cert_dir: args.append("-c") args.append(CONF.terminal_cert_dir) else: args.append("-t") args.append("-p") args.append(str(self.port)) args.append("--background=%s" % _get_console_pid_path(self.node_id)) args.append("-s") try: pwfile = _make_password_file(self.password) ipmi_args = "/:%(uid)s:%(gid)s:HOME:ipmitool -H %(address)s" \ " -I lanplus -U %(user)s -f %(pwfile)s sol activate" \ % {'uid': os.getuid(), 'gid': os.getgid(), 'address': self.address, 'user': self.user, 'pwfile': pwfile, } args.append(ipmi_args) # Run shellinaboxd without pipes. Otherwise utils.execute() waits # infinitely since shellinaboxd does not close passed fds. x = ["'" + arg.replace("'", "'\\''") + "'" for arg in args] x.append('</dev/null') x.append('>/dev/null') x.append('2>&1') utils.execute(' '.join(x), shell=True) finally: utils.delete_if_exists(pwfile)
def deactivate_bootloader(self, context, node, instance): """Delete Tilera bootloader images and config.""" try: db.bm_node_update(context, node['id'], {'deploy_key': None, 'image_path': None, 'pxe_config_path': None, 'root_mb': 0, 'swap_mb': 0}) except exception.NodeNotFound: pass tilera_nfs_path = get_tilera_nfs_path(node['id']) if os.path.ismount(tilera_nfs_path): utils.execute('rpc.mountd', run_as_root=True) utils.execute('umount', '-f', tilera_nfs_path, run_as_root=True) try: image_info = get_tftp_image_info(instance) except exception.NovaException: pass else: for label in image_info.keys(): (uuid, path) = image_info[label] utils.unlink_without_raise(path) try: self._collect_mac_addresses(context, node) except db_exc.DBError: pass if os.path.exists(os.path.join(CONF.tftp_root, instance['uuid'])): utils.rmtree_without_raise( os.path.join(CONF.tftp_root, instance['uuid']))
def test_mkfs(self): self.mox.StubOutWithMock(utils, 'execute') utils.execute('mkfs', '-t', 'ext4', '-F', '/my/block/dev') utils.execute('mkfs', '-t', 'msdos', '/my/msdos/block/dev') utils.execute('mkswap', '/my/swap/block/dev') self.mox.ReplayAll() utils.mkfs('ext4', '/my/block/dev') utils.mkfs('msdos', '/my/msdos/block/dev') utils.mkfs('swap', '/my/swap/block/dev')
def _delete_iscsi_export_tgtadm(tid): try: utils.execute('tgtadm', '--lld', 'iscsi', '--mode', 'logicalunit', '--op', 'delete', '--tid', tid, '--lun', '1', run_as_root=True) except exception.ProcessExecutionError: pass try: utils.execute('tgtadm', '--lld', 'iscsi', '--mode', 'target', '--op', 'delete', '--tid', tid, run_as_root=True) except exception.ProcessExecutionError: pass # Check if the tid is deleted, that is, check the tid no longer exists. # If the tid dose not exist, tgtadm returns with exit_code 22. # utils.execute() can check the exit_code if check_exit_code parameter is # passed. But, regardless of whether check_exit_code contains 0 or not, # if the exit_code is 0, the function dose not report errors. So we have to # catch a ProcessExecutionError and test its exit_code is 22. try: utils.execute('tgtadm', '--lld', 'iscsi', '--mode', 'target', '--op', 'show', '--tid', tid, run_as_root=True) except exception.ProcessExecutionError as e: if e.exit_code == 22: # OK, the tid is deleted return raise raise exception.NovaException( _('baremetal driver was unable to delete tid %s') % tid)
def _run_playbook(node, name, extra_vars, key, tags=None, notags=None): """Execute ansible-playbook.""" root = _get_playbooks_path(node) playbook = os.path.join(root, name) inventory = os.path.join(root, 'inventory') ironic_vars = {'ironic': extra_vars} python_interpreter = _get_python_interpreter(node) if python_interpreter: ironic_vars['ansible_python_interpreter'] = python_interpreter args = [ CONF.ansible.ansible_playbook_script, playbook, '-i', inventory, '-e', json.dumps(ironic_vars), ] if CONF.ansible.config_file_path: env = ['env', 'ANSIBLE_CONFIG=%s' % CONF.ansible.config_file_path] args = env + args if tags: args.append('--tags=%s' % ','.join(tags)) if notags: args.append('--skip-tags=%s' % ','.join(notags)) if key: args.append('--private-key=%s' % key) verbosity = CONF.ansible.verbosity if verbosity is None and CONF.debug: verbosity = 4 if verbosity: args.append('-' + 'v' * verbosity) if CONF.ansible.ansible_extra_args: args.extend(shlex.split(CONF.ansible.ansible_extra_args)) try: out, err = utils.execute(*args) return out, err except processutils.ProcessExecutionError as e: raise exception.InstanceDeployFailure(reason=e)
def exec_xcatcmd(driver_info, command, args): """ excute xcat cmd """ cmd = [command, driver_info['xcat_node']] cmd.extend(args.split(" ")) # NOTE: ensure that no communications are excuted more # often than once every min_command_interval seconds. time_till_next_poll = CONF.ipmi.min_command_interval - ( time.time() - LAST_CMD_TIME.get(driver_info['xcat_node'], 0)) if time_till_next_poll > 0: time.sleep(time_till_next_poll) try: out, err = utils.execute(*cmd) if err: raise xcat_exception.xCATCmdFailure(cmd=cmd, node=driver_info['xcat_node'], args=args) finally: LAST_CMD_TIME[driver_info['xcat_node']] = time.time() return out, err
def get_disk_identifier(dev): """Get the disk identifier from the disk being exposed by the ramdisk. This disk identifier is appended to the pxe config which will then be used by chain.c32 to detect the correct disk to chainload. This is helpful in deployments to nodes with multiple disks. http://www.syslinux.org/wiki/index.php/Comboot/chain.c32#mbr: :param dev: Path for the already populated disk device. :returns The Disk Identifier. """ disk_identifier = utils.execute('hexdump', '-s', '440', '-n', '4', '-e', '''\"0x%08x\"''', dev, run_as_root=True, check_exit_code=[0], attempts=5, delay_on_retry=True) return disk_identifier[0]
def get_ics_console_log(node_uuid): """Get the content of a console log of a node (ironic console server). :param node_uuid: the UUID of the node :raises: ConsoleError if unable to stop the console process """ log_file = _get_console_log_file(node_uuid) args = ["tail", "-n", "100", log_file] try: LOG.debug('Running subprocess: %s', ' '.join(args)) stdout, stderr = utils.execute(*args) except (OSError, ValueError) as e: error = _("%(exec_error)s\n" "Command: %(command)s") % { 'exec_error': str(e), 'command': ' '.join(args) } LOG.warning(error) raise exception.ConsoleSubprocessFailed(error=error) return stdout
def verify_iscsi_connection(target_iqn): """Verify iscsi connection.""" LOG.debug("Checking for iSCSI target to become active.") for attempt in range(CONF.deploy.iscsi_verify_attempts): out, _err = utils.execute('iscsiadm', '-m', 'node', '-S', run_as_root=True, check_exit_code=[0]) if target_iqn in out: break time.sleep(1) LOG.debug("iSCSI connection not active. Rechecking. Attempt " "%(attempt)d out of %(total)d", {"attempt": attempt, "total": CONF.deploy.iscsi_verify_attempts}) else: msg = _("Max attempts to verify a iSCSI connection is active reached " "and the connection didn't become active.") LOG.error(msg) raise exception.InstanceDeployFailure(msg)
def verify_iscsi_connection(target_iqn): """Verify iscsi connection.""" LOG.debug("Checking for iSCSI target to become active.") total_checks = CONF.iscsi.verify_attempts for attempt in range(total_checks): out, _err = utils.execute('iscsiadm', '-m', 'node', '-S', run_as_root=True, check_exit_code=[0]) if target_iqn in out: break time.sleep(1) LOG.debug("iSCSI connection not active. Rechecking. Attempt " "%(attempt)d out of %(total)d", {"attempt": attempt + 1, "total": total_checks}) else: msg = _("iSCSI connection did not become active after attempting to " "verify %d times.") % total_checks LOG.error(msg) raise exception.InstanceDeployFailure(msg)
def _run_playbook(name, extra_vars, key, tags=None, notags=None): """Execute ansible-playbook.""" playbook = os.path.join(CONF.ansible.playbooks_path, name) args = [ CONF.ansible.ansible_playbook_script, playbook, '-i', INVENTORY_FILE, '-e', json.dumps(extra_vars), ] if CONF.ansible.config_file_path: env = ['env', 'ANSIBLE_CONFIG=%s' % CONF.ansible.config_file_path] args = env + args if tags: args.append('--tags=%s' % ','.join(tags)) if notags: args.append('--skip-tags=%s' % ','.join(notags)) if key: args.append('--private-key=%s' % key) verbosity = CONF.ansible.verbosity if verbosity is None and CONF.debug: verbosity = 4 if verbosity: args.append('-' + 'v' * verbosity) if CONF.ansible.ansible_extra_args: args.extend(shlex.split(CONF.ansible.ansible_extra_args)) try: out, err = utils.execute(*args) return out, err except processutils.ProcessExecutionError as e: raise exception.InstanceDeployFailure(reason=e)
def _check_option_support(options): """Checks if the specific ipmitool options are supported on host. This method updates the module-level variables indicating whether an option is supported so that it is accessible by any driver interface class in this module. It is intended to be called from the __init__ method of such classes only. :param options: list of ipmitool options to be checked :raises: OSError """ for opt in options: if _is_option_supported(opt) is None: try: cmd = ipmitool_command_options[opt] out, err = utils.execute(*cmd) except processutils.ProcessExecutionError: # the local ipmitool does not support the command. _is_option_supported(opt, False) else: # looks like ipmitool supports the command. _is_option_supported(opt, True)