def test_input_url_defaults_empty_with_no_input(self): script = factory.make_Script(parameters={"url": {"type": "url"}}) form = ParametersForm(data={}, script=script, node=factory.make_Node()) self.assertTrue(form.is_valid(), form.errors) self.assertDictEqual({}, form.cleaned_data["input"][0])
def test_validates_parameters_is_dict(self): form = ParametersForm(data=[factory.make_name() for _ in range(3)]) self.assertFalse(form.is_valid()) self.assertDictEqual({"parameters": ["Must be a dictionary"]}, form.errors)
def is_valid(self): valid = super().is_valid() if valid and self.instance.default and not self.edit_default: for field in self.Meta.fields: if field in ["tags", "timeout"]: continue if field in self.data: set_form_error( self, field, "Not allowed to change on default scripts.", ) valid = False name = self.data.get("name") # none is used to tell the API to not run testing_scripts during # commissioning. if name is not None and name.lower() == "none": set_form_error(self, "name", '"none" is a reserved name.') valid = False # The name can't be a digit as MAAS allows scripts to be selected by # id. if name is not None and name.isdigit(): set_form_error(self, "name", "Cannot be a number.") valid = False if name is not None and pipes.quote(name) != name: set_form_error( self, "name", "Name '%s' contains disallowed characters, e.g. space or quotes." % name, ) valid = False # If comment and script exist __init__ combines both fields into a dict # to pass to VersionedTextFileField. if "comment" in self.data: set_form_error( self, "comment", '"comment" may only be used when specifying a "script" ' "as well.", ) valid = False if "script" in self.data: if not self._validate_results(self.instance.results): valid = False if "parameters" in self.data: params_form = ParametersForm(data=self.data.get("parameters")) if not params_form.is_valid(): valid = False if (not valid and self.instance.script_id is not None and self.initial.get("script") != self.instance.script_id and self.instance.script.id is not None): # If form validation failed cleanup any new VersionedTextFile # created by the VersionedTextFileField. self.instance.script.delete() return valid
def test__validates_unsupported_parameter_types_if_not_required(self): unsupported_type = factory.make_name("unsupported") form = ParametersForm( data={"storage": {"type": unsupported_type, "required": False}} ) self.assertTrue(form.is_valid())
def regenerate(self, storage=True, network=True): """Regenerate any ScriptResult which has a storage parameter. Deletes and recreates ScriptResults for any ScriptResult which has a storage parameter. Used after commissioning has completed when there are tests to be run. """ # Avoid circular dependencies. from metadataserver.models import ScriptResult regenerate_scripts = {} for script_result in (self.scriptresult_set.filter( status=SCRIPT_STATUS.PENDING).exclude(parameters={}).defer( "stdout", "stderr", "output", "result")): # If there are multiple storage devices or interface on the system # for every script which contains a storage or interface type # parameter there will be one ScriptResult per device. If we # already know a script must be regenearted it can be deleted as # the device the ScriptResult is for may no longer exist. # Regeneratation below will generate ScriptResults for each # existing storage or interface device. if script_result.script in regenerate_scripts: script_result.delete() continue # Check if the ScriptResult contains any storage or interface type # parameter. If so remove the value of the storage or interface # parameter only and add it to the list of Scripts which must be # regenearted. for param_name, param in script_result.parameters.items(): if (storage and param["type"] == "storage") or ( network and param["type"] == "interface"): # Remove the storage or interface parameter as the storage # device or interface may no longer exist. The # ParametersForm will set the default value(all). script_result.parameters.pop(param_name) # Only preserve the value of the parameter as that is what # the form will validate. regenerate_scripts[script_result.script] = { key: value["value"] for key, value in script_result.parameters.items() } script_result.delete() break for script, params in regenerate_scripts.items(): form = ParametersForm(data=params, script=script, node=self.node) if not form.is_valid(): err_msg = ( "Removing Script %s from ScriptSet due to regeneration " "error - %s" % (script.name, dict(form.errors))) logger.error(err_msg) Event.objects.create_node_event( system_id=self.node.system_id, event_type=EVENT_TYPES.SCRIPT_RESULT_ERROR, event_description=err_msg, ) continue for i in form.cleaned_data["input"]: ScriptResult.objects.create( script_set=self, status=SCRIPT_STATUS.PENDING, script=script, script_name=script.name, parameters=i, )