def test_make_configdrive(self, mock_popen): fake_process = mock.Mock(returncode=0) fake_process.communicate.return_value = ('', '') mock_popen.return_value = fake_process with utils.tempdir() as dirname: utils.make_configdrive(dirname) mock_popen.assert_called_once_with(self.genisoimage_cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE) fake_process.communicate.assert_called_once_with()
def test_make_configdrive(self, mock_popen): fake_process = mock.Mock(returncode=0) fake_process.communicate.return_value = ('', '') mock_popen.return_value = fake_process with utils.tempdir() as dirname: utils.make_configdrive(dirname) mock_popen.assert_called_once_with(self.genisoimage_cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE) fake_process.communicate.assert_called_once_with()
def set_provision_state(self, node_uuid, state, configdrive=None, cleansteps=None): """Set the provision state for the node. :param node_uuid: The UUID or name of the node. :param state: The desired provision state. One of 'active', 'deleted', 'rebuild', 'inspect', 'provide', 'manage', 'clean', 'abort'. :param configdrive: A gzipped, base64-encoded configuration drive string OR the path to the configuration drive file OR the path to a directory containing the config drive files. In case it's a directory, a config drive will be generated from it. This is only valid when setting state to 'active'. :param cleansteps: The clean steps as a list of clean-step dictionaries; each dictionary should have keys 'interface' and 'step', and optional key 'args'. This must be specified (and is only valid) when setting provision-state to 'clean'. :raises: InvalidAttribute if there was an error with the clean steps :returns: The status of the request """ path = "%s/states/provision" % node_uuid body = {'target': state} if configdrive: if os.path.isfile(configdrive): with open(configdrive, 'rb') as f: configdrive = f.read() if os.path.isdir(configdrive): configdrive = utils.make_configdrive(configdrive) body['configdrive'] = configdrive elif cleansteps: body['clean_steps'] = cleansteps return self.update(path, body, http_method='PUT')
def set_provision_state(self, node_uuid, state, configdrive=None): path = "%s/states/provision" % node_uuid body = {'target': state} if configdrive: if os.path.isfile(configdrive): with open(configdrive, 'rb') as f: configdrive = f.read() if os.path.isdir(configdrive): configdrive = utils.make_configdrive(configdrive) body['configdrive'] = configdrive return self._update(self._path(path), body, method='PUT')
def set_provision_state(self, node_uuid, state, configdrive=None, cleansteps=None, rescue_password=None, os_ironic_api_version=None): """Set the provision state for the node. :param node_uuid: The UUID or name of the node. :param state: The desired provision state. One of 'active', 'deleted', 'rebuild', 'inspect', 'provide', 'manage', 'clean', 'abort', 'rescue', 'unrescue'. :param configdrive: A gzipped, base64-encoded configuration drive string OR the path to the configuration drive file OR the path to a directory containing the config drive files OR a dictionary to build config drive from. In case it's a directory, a config drive will be generated from it. In case it's a dictionary, a config drive will be generated on the server side (requires API version 1.56). This is only valid when setting state to 'active'. :param cleansteps: The clean steps as a list of clean-step dictionaries; each dictionary should have keys 'interface' and 'step', and optional key 'args'. This must be specified (and is only valid) when setting provision-state to 'clean'. :param rescue_password: A string to be used as the login password inside the rescue ramdisk once a node is rescued. This must be specified (and is only valid) when setting 'state' to 'rescue'. :param os_ironic_api_version: String version (e.g. "1.35") to use for the request. If not specified, the client's default is used. :raises: InvalidAttribute if there was an error with the clean steps :returns: The status of the request """ path = "%s/states/provision" % node_uuid body = {'target': state} if configdrive: if not isinstance(configdrive, dict): if os.path.isfile(configdrive): with open(configdrive, 'rb') as f: configdrive = f.read() if os.path.isdir(configdrive): configdrive = utils.make_configdrive(configdrive) body['configdrive'] = configdrive elif cleansteps: body['clean_steps'] = cleansteps elif rescue_password: body['rescue_password'] = rescue_password return self.update(path, body, http_method='PUT', os_ironic_api_version=os_ironic_api_version)
def set_provision_state(self, node_uuid, state, configdrive=None): path = "%s/states/provision" % node_uuid body = {'target': state} if configdrive: if os.path.isfile(configdrive): with open(configdrive, 'rb') as f: configdrive = f.read() if os.path.isdir(configdrive): configdrive = utils.make_configdrive(configdrive) body['configdrive'] = configdrive return self._update(self._path(path), body, method='PUT')
def create(self, repository, create_files=True): # Create a temp folder try: tmp_dir = tempfile.mkdtemp('_configdrive') tmp_dir_base = os.path.join(tmp_dir,'ec2', 'latest') os.makedirs(tmp_dir_base) if create_files: if not repository.exists(self.node_uuid + '/ec2/latest/'): repository.mkdir(self.node_uuid + '/ec2/latest') # user-data.json user_data_tmp_file = os.path.join(tmp_dir_base,'user-data') cfgdrive_user_json = json.dumps( self.user_data, indent=4, separators=(',', ': ')) with open(user_data_tmp_file, 'w') as outfile: outfile.write(cfgdrive_user_json) if create_files: repository.put( StringIO.StringIO(cfgdrive_user_json), self.node_uuid + '/ec2/latest/user-data') # meta-data.json meta_data_tmp_file = os.path.join(tmp_dir_base,'meta-data.json') cfgdrive_meta_json = json.dumps( self.meta_data, indent=4, separators=(',', ': ')) with open(meta_data_tmp_file, 'w') as outfile: outfile.write(cfgdrive_meta_json) if create_files: repository.put( StringIO.StringIO(cfgdrive_meta_json), self.node_uuid + '/ec2/latest/meta-data.json') # Create it using Ironic utils self.logger.debug("Creating configdrive volume") configdrive = utils.make_configdrive(tmp_dir) self.logger.debug("Uploading configdrive to repository") repository.put(StringIO.StringIO(configdrive), self.configdrive_id) except ironic_exception.ClientException as e: msg = "Error creating configdrive volume %s" % (e) self.logger.error(msg) raise ConfigdriveError(msg) except RepositoryError as e: msg = "Cannot save configdrive '%s' in the repository: %s" % (self.configdrive_id, e) self.logger.error(msg) raise ConfigdriveError(msg) except Exception as e: msg = "%s: %s" % (type(e).__name__, e) self.logger.error(msg) raise ConfigdriveError(msg) finally: if tmp_dir: shutil.rmtree(tmp_dir) self.logger.info("Configdrive created with id '%s' in the repository" % (self.configdrive_id)) return self.configdrive_id
def set_provision_state(self, node_uuid, state, configdrive=None, cleansteps=None, rescue_password=None, os_ironic_api_version=None): """Set the provision state for the node. :param node_uuid: The UUID or name of the node. :param state: The desired provision state. One of 'active', 'deleted', 'rebuild', 'inspect', 'provide', 'manage', 'clean', 'abort', 'rescue', 'unrescue'. :param configdrive: A gzipped, base64-encoded configuration drive string OR the path to the configuration drive file OR the path to a directory containing the config drive files OR a dictionary to build config drive from. In case it's a directory, a config drive will be generated from it. In case it's a dictionary, a config drive will be generated on the server side (requires API version 1.56). This is only valid when setting state to 'active'. :param cleansteps: The clean steps as a list of clean-step dictionaries; each dictionary should have keys 'interface' and 'step', and optional key 'args'. This must be specified (and is only valid) when setting provision-state to 'clean'. :param rescue_password: A string to be used as the login password inside the rescue ramdisk once a node is rescued. This must be specified (and is only valid) when setting 'state' to 'rescue'. :param os_ironic_api_version: String version (e.g. "1.35") to use for the request. If not specified, the client's default is used. :raises: InvalidAttribute if there was an error with the clean steps :returns: The status of the request """ path = "%s/states/provision" % node_uuid body = {'target': state} if configdrive: if not isinstance(configdrive, dict): if os.path.isfile(configdrive): with open(configdrive, 'rb') as f: configdrive = f.read() if os.path.isdir(configdrive): configdrive = utils.make_configdrive(configdrive) body['configdrive'] = configdrive elif cleansteps: body['clean_steps'] = cleansteps elif rescue_password: body['rescue_password'] = rescue_password return self.update(path, body, http_method='PUT', os_ironic_api_version=os_ironic_api_version)
def set_provision_state(self, node_uuid, state, configdrive=None, cleansteps=None): """Set the provision state for the node. :param node_uuid: The UUID or name of the node. :param state: The desired provision state. One of 'active', 'deleted', 'rebuild', 'inspect', 'provide', 'manage', 'clean', 'abort'. :param configdrive: A gzipped, base64-encoded configuration drive string OR the path to the configuration drive file OR the path to a directory containing the config drive files. In case it's a directory, a config drive will be generated from it. This is only valid when setting state to 'active'. :param cleansteps: The clean steps as a list of clean-step dictionaries; each dictionary should have keys 'interface' and 'step', and optional key 'args'. This must be specified (and is only valid) when setting provision-state to 'clean'. :raises: InvalidAttribute if there was an error with the clean steps :returns: The status of the request """ path = "%s/states/provision" % node_uuid body = {'target': state} if configdrive: if os.path.isfile(configdrive): with open(configdrive, 'rb') as f: configdrive = f.read() if os.path.isdir(configdrive): configdrive = utils.make_configdrive(configdrive) body['configdrive'] = configdrive elif cleansteps: body['clean_steps'] = cleansteps return self.update(path, body, http_method='PUT')