Add support for passing parameters to the ext template (ext-params). Take advantage of disk-params, that don't seem to make much sense in this template (ExtStorage Providers are not predefined and we don't know their needs) and use them to pass the ext-params dynamically to the template.
ext-params are correlated with gnt-os-interface's os-params. All ext-params are exported to the ExtStorage Provider through it's environment, with variables prefixed with 'EXTP_' (similarly to the OS interface's 'OSP_' params). ext-params are passed via the --disk option. If the disk template is of type `ext', then any additional options passed to --disk and are not in IDISK_PARAMS are considered ext-params e.g.: gnt-instance add -t ext --disk=0:size=2G,param1=value1,param2=value2 Finally, we introduce a new IDISK_PARAM called IDISK_PROVIDER, that is mandatory for template `ext' and is used to select the desired ExtStorage Provider. This parameter is not a valid --disk option for any other template type. The IDISK_PROVIDER parameter becomes the first element of the disk's unique_id tuple e.g.: unique_id = ('sample_provider1', 'UUID.ext.diskX') Example selecting different ExtStorage Providers for each disk and passing different ext-params to them: -t ext --disk=0:size=2G,provider=sample_provider1,param1=value1 --disk=1:size=3G,provider=sample_provider2,param2=value2 Signed-off-by: Constantinos Venetsanopoulos <c...@grnet.gr> --- lib/bdev.py | 52 +++++++++++++++++++++++++++++++++++++++++----------- lib/cmdlib.py | 47 +++++++++++++++++++++++++++++++++++++++++++---- lib/constants.py | 9 ++++++++- lib/objects.py | 5 +++++ 4 files changed, 97 insertions(+), 16 deletions(-) diff --git a/lib/bdev.py b/lib/bdev.py index 69a7593..4c2b934 100644 --- a/lib/bdev.py +++ b/lib/bdev.py @@ -2802,6 +2802,7 @@ class ExtStorageDevice(BlockDev): raise ValueError("Invalid configuration data %s" % str(unique_id)) self.driver, self.vol_name = unique_id + self.ext_params = params self.major = self.minor = None self.Attach() @@ -2817,10 +2818,12 @@ class ExtStorageDevice(BlockDev): if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2: raise errors.ProgrammerError("Invalid configuration data %s" % str(unique_id)) + ext_params = params # Call the External Storage's create script, # to provision a new Volume inside the External Storage - _ExtStorageAction(constants.ES_ACTION_CREATE, unique_id, str(size)) + _ExtStorageAction(constants.ES_ACTION_CREATE, unique_id, + ext_params, str(size)) return ExtStorageDevice(unique_id, children, size, params) @@ -2837,7 +2840,8 @@ class ExtStorageDevice(BlockDev): # Call the External Storage's remove script, # to remove the Volume from the External Storage - _ExtStorageAction(constants.ES_ACTION_REMOVE, self.unique_id) + _ExtStorageAction(constants.ES_ACTION_REMOVE, self.unique_id, + self.ext_params) def Rename(self, new_id): """Rename this device. @@ -2857,7 +2861,7 @@ class ExtStorageDevice(BlockDev): # Call the External Storage's attach script, # to attach an existing Volume to a block device under /dev self.dev_path = _ExtStorageAction(constants.ES_ACTION_ATTACH, - self.unique_id) + self.unique_id, self.ext_params) try: st = os.stat(self.dev_path) @@ -2891,7 +2895,8 @@ class ExtStorageDevice(BlockDev): # Call the External Storage's detach script, # to detach an existing Volume from it's block device under /dev - _ExtStorageAction(constants.ES_ACTION_DETACH, self.unique_id) + _ExtStorageAction(constants.ES_ACTION_DETACH, self.unique_id, + self.ext_params) self.minor = None self.dev_path = None @@ -2932,7 +2937,7 @@ class ExtStorageDevice(BlockDev): # Call the External Storage's grow script, # to grow an existing Volume inside the External Storage _ExtStorageAction(constants.ES_ACTION_GROW, self.unique_id, - str(self.size), grow=str(new_size)) + self.ext_params, str(self.size), grow=str(new_size)) def SetInfo(self, text): """Update metadata with info text. @@ -2948,10 +2953,11 @@ class ExtStorageDevice(BlockDev): # Call the External Storage's setinfo script, # to set metadata for an existing Volume inside the External Storage _ExtStorageAction(constants.ES_ACTION_SETINFO, self.unique_id, - metadata=text) + self.ext_params, metadata=text) -def _ExtStorageAction(action, unique_id, size=None, grow=None, metadata=None): +def _ExtStorageAction(action, unique_id, ext_params, + size=None, grow=None, metadata=None): """Take an External Storage action. Take an External Storage action concerning or affecting @@ -2963,6 +2969,8 @@ def _ExtStorageAction(action, unique_id, size=None, grow=None, metadata=None): @type unique_id: tuple (driver, vol_name) @param unique_id: a tuple containing the type of ExtStorage (driver) and the Volume name + @type ext_params: dict + @type ext_params: ExtStorage parameters @type size: integer @param size: the size of the Volume in mebibytes @type grow: integer @@ -2980,7 +2988,8 @@ def _ExtStorageAction(action, unique_id, size=None, grow=None, metadata=None): _ThrowError("%s" % inst_es) # Create the basic environment for the driver's scripts - create_env = _ExtStorageEnvironment(unique_id, size, grow, metadata) + create_env = _ExtStorageEnvironment(unique_id, ext_params, size, + grow, metadata) # Do not use log file for action `attach' as we need # to get the output from RunResult @@ -3054,7 +3063,9 @@ def ExtStorageFromDisk(name, base_dir=None): # an optional one es_files = dict.fromkeys(constants.ES_SCRIPTS, True) - for filename in es_files: + es_files[constants.ES_PARAMETERS_FILE] = True + + for (filename, _) in es_files.items(): es_files[filename] = utils.PathJoin(es_dir, filename) try: @@ -3072,6 +3083,16 @@ def ExtStorageFromDisk(name, base_dir=None): return False, ("File '%s' under path '%s' is not executable" % (filename, es_dir)) + parameters = [] + if constants.ES_PARAMETERS_FILE in es_files: + parameters_file = es_files[constants.ES_PARAMETERS_FILE] + try: + parameters = utils.ReadFile(parameters_file).splitlines() + except EnvironmentError, err: + return False, ("Error while reading the EXT parameters file at %s: %s" % + (parameters_file, utils.ErrnoOrStr(err))) + parameters = [v.split(None, 1) for v in parameters] + es_obj = \ objects.ExtStorage(name=name, path=es_dir, create_script=es_files[constants.ES_SCRIPT_CREATE], @@ -3079,15 +3100,20 @@ def ExtStorageFromDisk(name, base_dir=None): grow_script=es_files[constants.ES_SCRIPT_GROW], attach_script=es_files[constants.ES_SCRIPT_ATTACH], detach_script=es_files[constants.ES_SCRIPT_DETACH], - setinfo_script=es_files[constants.ES_SCRIPT_SETINFO]) + setinfo_script=es_files[constants.ES_SCRIPT_SETINFO], + verify_script=es_files[constants.ES_SCRIPT_VERIFY], + supported_parameters=parameters) return True, es_obj -def _ExtStorageEnvironment(unique_id, size=None, grow=None, metadata=None): +def _ExtStorageEnvironment(unique_id, ext_params, + size=None, grow=None, metadata=None): """Calculate the environment for an External Storage script. @type unique_id: tuple (driver, vol_name) @param unique_id: ExtStorage pool and name of the Volume + @type ext_params: dict + @param ext_params: the EXT parameters @type size: string @param size: size of the Volume (in mebibytes) @type grow: string @@ -3103,6 +3129,10 @@ def _ExtStorageEnvironment(unique_id, size=None, grow=None, metadata=None): result = {} result["VOL_NAME"] = vol_name + # EXT params + for pname, pvalue in ext_params.items(): + result["EXTP_%s" % pname.upper()] = str(pvalue) + if size is not None: result["VOL_SIZE"] = size diff --git a/lib/cmdlib.py b/lib/cmdlib.py index ea36f86..167c014 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -7317,6 +7317,7 @@ class LUInstanceRecreateDisks(LogicalUnit): # TODO: Implement support changing VG while recreating constants.IDISK_VG, constants.IDISK_METAVG, + constants.IDISK_PROVIDER, ])) def _RunAllocator(self): @@ -9206,13 +9207,26 @@ def _GenerateDiskTemplate( elif template_name == constants.DT_RBD: logical_id_fn = lambda idx, _, disk: ("rbd", names[idx]) elif template_name == constants.DT_EXT: - logical_id_fn = lambda idx, _, disk: ("ext", names[idx]) + def logical_id_fn(idx, _, disk): + provider = disk.get(constants.IDISK_PROVIDER, None) + if provider is None: + raise errors.ProgrammerError("Disk template is %s, but '%s' is" + " not found", constants.DT_EXT, + constants.IDISK_PROVIDER) + return (provider, names[idx]) else: raise errors.ProgrammerError("Unknown disk template '%s'" % template_name) dev_type = _DISK_TEMPLATE_DEVICE_TYPE[template_name] for idx, disk in enumerate(disk_info): + params = {} + # Only for the Ext template add disk_info to params + if template_name == constants.DT_EXT: + params[constants.IDISK_PROVIDER] = disk[constants.IDISK_PROVIDER] + for key in disk: + if key not in constants.IDISK_PARAMS: + params[key] = disk[key] disk_index = idx + base_index size = disk[constants.IDISK_SIZE] feedback_fn("* disk %s, size %s" % @@ -9221,7 +9235,7 @@ def _GenerateDiskTemplate( logical_id=logical_id_fn(idx, disk_index, disk), iv_name="disk/%d" % disk_index, mode=disk[constants.IDISK_MODE], - params={})) + params=params)) return disks @@ -9671,7 +9685,7 @@ def _ComputeDisks(op, default_vg): @param op: The instance opcode @param default_vg: The default_vg to assume - @return: The computer disks + @return: The computed disks """ disks = [] @@ -9689,16 +9703,37 @@ def _ComputeDisks(op, default_vg): raise errors.OpPrereqError("Invalid disk size '%s'" % size, errors.ECODE_INVAL) + ext_provider = disk.get(constants.IDISK_PROVIDER, None) + if ext_provider and op.disk_template != constants.DT_EXT: + raise errors.OpPrereqError("The '%s' option is only valid for the %s" + " disk template, not %s" % + (constants.IDISK_PROVIDER, constants.DT_EXT, + op.disk_template), errors.ECODE_INVAL) + data_vg = disk.get(constants.IDISK_VG, default_vg) new_disk = { constants.IDISK_SIZE: size, constants.IDISK_MODE: mode, constants.IDISK_VG: data_vg, } + if constants.IDISK_METAVG in disk: new_disk[constants.IDISK_METAVG] = disk[constants.IDISK_METAVG] if constants.IDISK_ADOPT in disk: new_disk[constants.IDISK_ADOPT] = disk[constants.IDISK_ADOPT] + + # For extstorage, demand the `provider' option and add any + # additional parameters (ext-params) to the dict + if op.disk_template == constants.DT_EXT: + if ext_provider: + new_disk[constants.IDISK_PROVIDER] = ext_provider + for key in disk: + if key not in constants.IDISK_PARAMS: + new_disk[key] = disk[key] + else: + raise errors.OpPrereqError("Missing provider for template '%s'" % + constants.DT_EXT, errors.ECODE_INVAL) + disks.append(new_disk) return disks @@ -9755,7 +9790,8 @@ class LUInstanceCreate(LogicalUnit): # check disks. parameter names and consistent adopt/no-adopt strategy has_adopt = has_no_adopt = False for disk in self.op.disks: - utils.ForceDictType(disk, constants.IDISK_PARAMS_TYPES) + if self.op.disk_template != constants.DT_EXT: + utils.ForceDictType(disk, constants.IDISK_PARAMS_TYPES) if constants.IDISK_ADOPT in disk: has_adopt = True else: @@ -10546,6 +10582,9 @@ class LUInstanceCreate(LogicalUnit): _CheckNicsBridgesExist(self, self.nics, self.pnode.name) + #TODO: _CheckExtParams (remotely) + # Check parameters for extstorage + # memory check on primary node #TODO(dynmem): use MINMEM for checking if self.op.start: diff --git a/lib/constants.py b/lib/constants.py index 2ae80bb..872a8ef 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -635,6 +635,7 @@ ES_ACTION_GROW = "grow" ES_ACTION_ATTACH = "attach" ES_ACTION_DETACH = "detach" ES_ACTION_SETINFO = "setinfo" +ES_ACTION_VERIFY = "verify" ES_SCRIPT_CREATE = ES_ACTION_CREATE ES_SCRIPT_REMOVE = ES_ACTION_REMOVE @@ -642,15 +643,19 @@ ES_SCRIPT_GROW = ES_ACTION_GROW ES_SCRIPT_ATTACH = ES_ACTION_ATTACH ES_SCRIPT_DETACH = ES_ACTION_DETACH ES_SCRIPT_SETINFO = ES_ACTION_SETINFO +ES_SCRIPT_VERIFY = ES_ACTION_VERIFY ES_SCRIPTS = frozenset([ ES_SCRIPT_CREATE, ES_SCRIPT_REMOVE, ES_SCRIPT_GROW, ES_SCRIPT_ATTACH, ES_SCRIPT_DETACH, - ES_SCRIPT_SETINFO + ES_SCRIPT_SETINFO, + ES_SCRIPT_VERIFY ]) +ES_PARAMETERS_FILE = "parameters.list" + # ssh constants SSH = "ssh" SCP = "scp" @@ -1123,12 +1128,14 @@ IDISK_MODE = "mode" IDISK_ADOPT = "adopt" IDISK_VG = "vg" IDISK_METAVG = "metavg" +IDISK_PROVIDER = "provider" IDISK_PARAMS_TYPES = { IDISK_SIZE: VTYPE_SIZE, IDISK_MODE: VTYPE_STRING, IDISK_ADOPT: VTYPE_STRING, IDISK_VG: VTYPE_STRING, IDISK_METAVG: VTYPE_STRING, + IDISK_PROVIDER: VTYPE_STRING, } IDISK_PARAMS = frozenset(IDISK_PARAMS_TYPES.keys()) diff --git a/lib/objects.py b/lib/objects.py index 871045a..8ea14c6 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -909,6 +909,9 @@ class Disk(ConfigObject): constants.LDP_POOL: dt_params[constants.RBD_POOL], })) + elif disk_template == constants.DT_EXT: + result.append(constants.DISK_LD_DEFAULTS[constants.LD_EXT]) + return result @@ -1249,6 +1252,8 @@ class ExtStorage(ConfigObject): "attach_script", "detach_script", "setinfo_script", + "verify_script", + "supported_parameters", ] -- 1.7.10.4