~andreserl/maas/refactor_debconf_selections_preseed

« back to all changes in this revision

Viewing changes to src/metadataserver/models/scriptset.py

  • Committer: LaMont Jones
  • Date: 2017-02-17 14:23:04 UTC
  • mfrom: (5747 maas)
  • mto: This revision was merged to the branch mainline in revision 5748.
  • Revision ID: lamont@canonical.com-20170217142304-djxqtuvefc1sdfnb
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
from django.core.exceptions import ObjectDoesNotExist
9
9
from django.db.models import (
10
10
    CASCADE,
 
11
    CharField,
11
12
    DateTimeField,
12
13
    ForeignKey,
13
14
    IntegerField,
14
15
    Manager,
15
16
    Model,
16
 
)
 
17
    Q,
 
18
)
 
19
from maasserver.enum import (
 
20
    POWER_STATE,
 
21
    POWER_STATE_CHOICES,
 
22
)
 
23
from maasserver.exceptions import NoScriptsFound
 
24
from maasserver.models import Config
17
25
from maasserver.models.cleansave import CleanSave
18
26
from maasserver.preseed import CURTIN_INSTALL_LOG
19
27
from metadataserver import DefaultMeta
29
37
 
30
38
class ScriptSetManager(Manager):
31
39
 
32
 
    def create_commissioning_script_set(self, node):
 
40
    def _clean_old(self, node, result_type, new_script_set):
 
41
        # Gather the list of existing script results of the given type for this
 
42
        # node.
 
43
        script_sets = self.filter(node=node, result_type=result_type)
 
44
        # Exclude the newly created script_set so we don't try to remove it.
 
45
        # This can happen when multiple script_sets have last_ping = None.
 
46
        script_sets = script_sets.exclude(id=new_script_set.id)
 
47
        # Sort by last_ping in reverse order so we only remove older entrees.
 
48
        script_sets = script_sets.order_by('last_ping').reverse()
 
49
        config_var = {
 
50
            RESULT_TYPE.COMMISSIONING: 'max_node_commissioning_results',
 
51
            RESULT_TYPE.TESTING: 'max_node_testing_results',
 
52
            RESULT_TYPE.INSTALLATION: 'max_node_installation_results',
 
53
        }
 
54
        script_set_limit = Config.objects.get_config(config_var[result_type])
 
55
        # Remove one from the script_set_limit to account for the newly created
 
56
        # script_set.
 
57
        script_set_limit -= 1
 
58
        if script_sets.count() > script_set_limit:
 
59
            for script_set in script_sets[script_set_limit:]:
 
60
                script_set.delete()
 
61
 
 
62
    def create_commissioning_script_set(self, node, scripts=[]):
33
63
        """Create a new commissioning ScriptSet with ScriptResults
34
64
 
35
 
        ScriptResults will be created for all builtin commissioning scripts
36
 
        and custom commissioning scripts if the node is not a controller.
 
65
        ScriptResults will be created for all builtin commissioning scripts.
 
66
        Optionally a list of user scripts and tags can be given to create
 
67
        ScriptResults for. If None all user scripts will be assumed.
37
68
        """
38
69
        # Avoid circular dependencies.
39
70
        from metadataserver.models import ScriptResult
40
71
 
41
72
        script_set = self.create(
42
 
            node=node, result_type=RESULT_TYPE.COMMISSIONING)
 
73
            node=node, result_type=RESULT_TYPE.COMMISSIONING,
 
74
            power_state_before_transition=node.power_state)
 
75
        self._clean_old(node, RESULT_TYPE.COMMISSIONING, script_set)
43
76
 
44
77
        for script_name, data in NODE_INFO_SCRIPTS.items():
45
78
            if node.is_controller and not data['run_on_controller']:
53
86
        if node.is_controller:
54
87
            return script_set
55
88
 
56
 
        for script in Script.objects.filter(
57
 
                script_type=SCRIPT_TYPE.COMMISSIONING):
 
89
        if scripts == []:
 
90
            qs = Script.objects.filter(
 
91
                script_type=SCRIPT_TYPE.COMMISSIONING)
 
92
        else:
 
93
            qs = Script.objects.filter(
 
94
                Q(name__in=scripts) | Q(tags__overlap=scripts),
 
95
                script_type=SCRIPT_TYPE.COMMISSIONING)
 
96
        for script in qs:
58
97
            ScriptResult.objects.create(
59
98
                script_set=script_set, status=SCRIPT_STATUS.PENDING,
60
 
                script=script, script_version=script.script)
 
99
                script=script)
61
100
 
62
101
        return script_set
63
102
 
64
 
    def create_testing_script_set(self, node):
65
 
        """Create a new testing ScriptSet with ScriptResults."""
 
103
    def create_testing_script_set(self, node, scripts=[]):
 
104
        """Create a new testing ScriptSet with ScriptResults.
 
105
 
 
106
        Optionally a list of user scripts and tags can be given to create
 
107
        ScriptResults for. If None all Scripts tagged 'commissioning' will be
 
108
        assumed."""
66
109
        # Avoid circular dependencies.
67
110
        from metadataserver.models import ScriptResult
68
111
 
69
 
        script_set = self.create(node=node, result_type=RESULT_TYPE.TESTING)
70
 
 
71
 
        for script in Script.objects.filter(script_type=SCRIPT_TYPE.TESTING):
 
112
        if scripts == []:
 
113
            scripts.append('commissioning')
 
114
 
 
115
        qs = Script.objects.filter(
 
116
            Q(name__in=scripts) | Q(tags__overlap=scripts),
 
117
            script_type=SCRIPT_TYPE.TESTING)
 
118
 
 
119
        # A ScriptSet should never be empty. If an empty script set is set as a
 
120
        # node's current_testing_script_set the UI will show an empty table and
 
121
        # the node-results API will not output any test results.
 
122
        if not qs.exists():
 
123
            raise NoScriptsFound()
 
124
 
 
125
        script_set = self.create(
 
126
            node=node, result_type=RESULT_TYPE.TESTING,
 
127
            power_state_before_transition=node.power_state)
 
128
 
 
129
        for script in qs:
72
130
            ScriptResult.objects.create(
73
131
                script_set=script_set, status=SCRIPT_STATUS.PENDING,
74
 
                script=script, script_version=script.script)
 
132
                script=script)
75
133
 
 
134
        self._clean_old(node, RESULT_TYPE.TESTING, script_set)
76
135
        return script_set
77
136
 
78
137
    def create_installation_script_set(self, node):
81
140
        from metadataserver.models import ScriptResult
82
141
 
83
142
        script_set = self.create(
84
 
            node=node, result_type=RESULT_TYPE.INSTALLATION)
 
143
            node=node, result_type=RESULT_TYPE.INSTALLATION,
 
144
            power_state_before_transition=node.power_state)
 
145
 
85
146
        # Curtin uploads the installation log using the full path we specify in
86
147
        # the preseed.
87
148
        ScriptResult.objects.create(
88
149
            script_set=script_set, status=SCRIPT_STATUS.PENDING,
89
150
            script_name=CURTIN_INSTALL_LOG)
 
151
 
 
152
        self._clean_old(node, RESULT_TYPE.INSTALLATION, script_set)
90
153
        return script_set
91
154
 
92
155
 
105
168
        choices=RESULT_TYPE_CHOICES, editable=False,
106
169
        default=RESULT_TYPE.COMMISSIONING)
107
170
 
 
171
    power_state_before_transition = CharField(
 
172
        max_length=10, null=False, blank=False,
 
173
        choices=POWER_STATE_CHOICES, default=POWER_STATE.UNKNOWN,
 
174
        editable=False)
 
175
 
108
176
    def __str__(self):
109
177
        return "%s/%s" % (
110
178
            self.node.system_id, RESULT_TYPE_CHOICES[self.result_type][1])