def create_commissioning_script_set( self, node, scripts=None, script_input=None, enlisting=False, ): """Create a new commissioning ScriptSet with ScriptResults ScriptResults will be created for all builtin commissioning scripts. Optionally a list of user scripts and tags can be given to create ScriptResults for. If None all user scripts will be assumed. Scripts may also have paramaters passed to them. """ if node.is_controller: # Controllers can only run the builtin scripts for them. scripts = [ script["name"] for script in NODE_INFO_SCRIPTS.values() if script["run_on_controller"] ] elif enlisting: if Config.objects.get_config("enlist_commissioning"): scripts = list(NODE_INFO_SCRIPTS.keys()) + ["enlisting"] else: scripts = ["bmc-config"] elif not scripts: # No user selected scripts, select all scripts below. pass elif "none" in scripts: # Don't add any scripts besides the ones that come with MAAS. scripts = list(NODE_INFO_SCRIPTS.keys()) else: scripts = list(NODE_INFO_SCRIPTS.keys()) + scripts script_set = self.create( node=node, result_type=RESULT_TYPE.COMMISSIONING, power_state_before_transition=node.power_state, requested_scripts=scripts if scripts else [], ) if not scripts: # If the user hasn't selected any commissioning Scripts select # all by default excluding for_hardware scripts. qs = Script.objects.filter( script_type=SCRIPT_TYPE.COMMISSIONING, for_hardware=[]).exclude(tags__contains=["noauto"]) for script in qs: script_set.add_pending_script(script, script_input) else: self._add_user_selected_scripts(script_set, scripts, script_input) self._clean_old(node, RESULT_TYPE.COMMISSIONING, script_set) return script_set
def refresh(system_id, consumer_key, token_key, token_secret, maas_url=None): """Run all builtin commissioning scripts and report results to region.""" maaslog.info("Refreshing rack controller hardware information.") if maas_url is None: maas_url = 'http://127.0.0.1:5240/MAAS' url = "%s/metadata/%s/" % (maas_url, MD_VERSION) creds = { 'consumer_key': consumer_key, 'token_key': token_key, 'token_secret': token_secret, 'consumer_secret': '', } scripts = { name: config for name, config in NODE_INFO_SCRIPTS.items() if config['run_on_controller'] } with tempfile.TemporaryDirectory(prefix='maas-commission-') as tmpdir: failed_scripts = runscripts(scripts, url, creds, tmpdir=tmpdir) if len(failed_scripts) == 0: signal_wrapper(url, creds, 'OK', 'Finished refreshing %s' % system_id) else: signal_wrapper(url, creds, 'FAILED', 'Failed refreshing %s' % system_id)
def create_commissioning_script_set(self, node, scripts=None, script_input=None): """Create a new commissioning ScriptSet with ScriptResults ScriptResults will be created for all builtin commissioning scripts. Optionally a list of user scripts and tags can be given to create ScriptResults for. If None all user scripts will be assumed. Scripts may also have paramaters passed to them. """ # Avoid circular dependencies. from metadataserver.models import ScriptResult if scripts is None: scripts = [] else: scripts = [str(i) for i in scripts] script_set = self.create( node=node, result_type=RESULT_TYPE.COMMISSIONING, power_state_before_transition=node.power_state, requested_scripts=scripts, ) # Add all builtin commissioning scripts. for script_name, data in NODE_INFO_SCRIPTS.items(): if node.is_controller and not data["run_on_controller"]: continue ScriptResult.objects.create( script_set=script_set, status=SCRIPT_STATUS.PENDING, script_name=script_name, ) if node.is_controller: # MAAS doesn't run custom commissioning scripts during controller # refresh. return script_set elif not scripts: # If the user hasn't selected any commissioning Scripts select # all by default excluding for_hardware scripts. qs = Script.objects.filter( script_type=SCRIPT_TYPE.COMMISSIONING, for_hardware=[]).exclude(tags__contains=["noauto"]) for script in qs: script_set.add_pending_script(script, script_input) elif "none" in scripts: # Don't add any scripts besides the ones that come with MAAS but # do perform cleanup below. pass else: self._add_user_selected_scripts(script_set, scripts, script_input) self._clean_old(node, RESULT_TYPE.COMMISSIONING, script_set) return script_set
def load_builtin_scripts(): for script in BUILTIN_SCRIPTS: if script.inject_file: with open(script.inject_path, "r") as f: script.substitutes["inject_file"] = f.read() script_content = tempita.Template.from_filename(script.script_path, encoding="utf-8") script_content = script_content.substitute({ "name": script.name, **script.substitutes }) form = None try: script_in_db = Script.objects.get(name=script.name) except Script.DoesNotExist: form = ScriptForm( data={ "script": script_content, "comment": f"Created by maas-{get_maas_version()}", }) else: if script_in_db.script.data != script_content: # Don't add back old versions of a script. This prevents two # connected regions with different versions of a script from # fighting with eachother. for vtf in script_in_db.script.previous_versions(): if vtf.data == script_content: # Don't update anything if we detect we have an old # version of the builtin scripts break else: form = ScriptForm( instance=script_in_db, data={ "script": script_content, "comment": f"Updated by maas-{get_maas_version()}", }, edit_default=True, ) if form is not None: # Form validation should never fail as these are the scripts # which ship with MAAS. If they ever do this will be cause by # unit tests. assert ( form.is_valid() ), f"Builtin script {script.name} caused these errors: {form.errors}" script_in_db = form.save(commit=False) if NODE_INFO_SCRIPTS.get(script.name, {}).get("run_on_controller"): script_in_db.add_tag("deploy-info") else: script_in_db.remove_tag("deploy-info") script_in_db.default = True script_in_db.save()
def create_commissioning_script_set(self, node, scripts=[], input={}): """Create a new commissioning ScriptSet with ScriptResults ScriptResults will be created for all builtin commissioning scripts. Optionally a list of user scripts and tags can be given to create ScriptResults for. If None all user scripts will be assumed. Scripts may also have paramaters passed to them. """ # Avoid circular dependencies. from metadataserver.models import ScriptResult script_set = self.create( node=node, result_type=RESULT_TYPE.COMMISSIONING, power_state_before_transition=node.power_state) self._clean_old(node, RESULT_TYPE.COMMISSIONING, script_set) for script_name, data in NODE_INFO_SCRIPTS.items(): if node.is_controller and not data['run_on_controller']: continue ScriptResult.objects.create(script_set=script_set, status=SCRIPT_STATUS.PENDING, script_name=script_name) # MAAS doesn't run custom commissioning scripts during controller # refresh. if node.is_controller: return script_set if scripts == []: qs = Script.objects.filter(script_type=SCRIPT_TYPE.COMMISSIONING) else: ids = [ int(id) for id in scripts if isinstance(id, int) or id.isdigit() ] qs = Script.objects.filter( Q(name__in=scripts) | Q(tags__overlap=scripts) | Q(id__in=ids), script_type=SCRIPT_TYPE.COMMISSIONING) for script in qs: form = ParametersForm(data=input.get(script.name, {}), script=script, node=node) if not form.is_valid(): script_set.delete() raise ValidationError(form.errors) for param in form.cleaned_data['input']: ScriptResult.objects.create(script_set=script_set, status=SCRIPT_STATUS.PENDING, script=script, script_name=script.name, parameters=param) return script_set
def refresh( system_id, consumer_key, token_key, token_secret, maas_url=None, post_process_hook=None, ): """Run all builtin commissioning scripts and report results to region.""" maaslog.info("Refreshing rack controller hardware information.") if maas_url is None: maas_url = "http://127.0.0.1:5240/MAAS" url = "%s/metadata/%s/" % (maas_url, MD_VERSION) creds = { "consumer_key": consumer_key, "token_key": token_key, "token_secret": token_secret, "consumer_secret": "", } scripts = { name: config for name, config in NODE_INFO_SCRIPTS.items() if config["run_on_controller"] } with tempfile.TemporaryDirectory(prefix="maas-commission-") as tmpdir: failed_scripts = runscripts( scripts, url, creds, tmpdir=tmpdir, post_process_hook=post_process_hook, ) if len(failed_scripts) == 0: signal_wrapper(url, creds, "OK", "Finished refreshing %s" % system_id) else: signal_wrapper( url, creds, "FAILED", "Failed refreshing %s" % system_id )
def test_create_commissioning_script_set_for_controller(self): for _ in range(3): factory.make_Script(script_type=SCRIPT_TYPE.COMMISSIONING) node = factory.make_Node(node_type=random.choice([ NODE_TYPE.RACK_CONTROLLER, NODE_TYPE.REGION_CONTROLLER, NODE_TYPE.REGION_AND_RACK_CONTROLLER ]), ) script_set = ScriptSet.objects.create_commissioning_script_set(node) expected_scripts = [ script_name for script_name, data in NODE_INFO_SCRIPTS.items() if data['run_on_controller'] ] self.assertItemsEqual( expected_scripts, [script_result.name for script_result in script_set]) self.assertEquals(RESULT_TYPE.COMMISSIONING, script_set.result_type) self.assertEquals(node.power_state, script_set.power_state_before_transition)