~lutostag/ubuntu/utopic/maas/1.5.2+packagefix

« back to all changes in this revision

Viewing changes to src/maasserver/power_parameters.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez, Graham Binns, Andres Rodriguez, Julian Edwards, Seth Arnold
  • Date: 2014-02-15 12:08:23 UTC
  • mfrom: (1.2.22)
  • Revision ID: package-import@ubuntu.com-20140215120823-kew2lqrw5qgww721
Tags: 1.5+bzr1948-0ubuntu1
* New upstream release.

[ Graham Binns ]
* debian/control: Depends on python-jsonschema.

[ Andres Rodriguez ]
* debian/maas-region-controller-min.posinst: Make txlongpoll.yaml only
  readable by the app and not world readeable.
* debian/patches/02-pserv-config.patch: Refreshed.

[ Julian Edwards ]
* debian/extras/maas-cli renamed to debian/extras/maas, and introduce
  a deprecation warning in favour of using maas over maas-cli.
* debian/extras/maas renamed to debian/extras/maas-region-admin
* debian/maas-cli.install: install debian/extras/maas
* debian/maas-dns.postinst: Invoke maas-region-admin instead of maas
* debian/maas-region-controller-min.install: install maas-region-admin
  instead of maas
* debian/maas-region-controller.postinst: Invoke maas-region-admin instead
  of maas
* debian/maas-cli.links: Link from maas to maas-cli for backward compat.

[ Seth Arnold ]
* debian/maas-region-controller-min.postinst: Make sure txlongpoll.yaml
  gets correct permissions on upgrade (LP: #1254034)

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
 
34
34
 
35
35
from django import forms
 
36
from jsonschema import validate
36
37
from maasserver.config_forms import DictCharField
37
38
from maasserver.fields import MACAddressFormField
38
39
from provisioningserver.enum import (
40
41
    IPMI_DRIVER_CHOICES,
41
42
    )
42
43
 
43
 
# FIXME: These should come from a hardware driver.
44
 
POWER_TYPE_PARAMETERS = {
45
 
    # Empty type, for the case where nothing is entered in the form yet.
46
 
    '': DictCharField(
47
 
        [], required=False, skip_check=True),
48
 
    'ether_wake': DictCharField(
49
 
        [
50
 
            ('mac_address',
51
 
             MACAddressFormField(label="MAC Address", required=False)),
52
 
        ],
53
 
        required=False,
54
 
        skip_check=True),
55
 
    'virsh': DictCharField(
56
 
        [
57
 
            ('power_address',
58
 
             forms.CharField(label="Address", required=False)),
59
 
            ('power_id',
60
 
             forms.CharField(label="Power ID", required=False)),
61
 
        ],
62
 
        required=False,
63
 
        skip_check=True),
64
 
    'fence_cdu': DictCharField(
65
 
        [
66
 
            ('power_id',
67
 
             forms.CharField(label="Power ID", required=False)),
68
 
            ('power_address',
69
 
             forms.CharField(label="IP Address or Hostname", required=False)),
70
 
            ('power_user',
71
 
             forms.CharField(label="Username", required=False)),
72
 
            ('power_pass',
73
 
             forms.CharField(label="Password", required=False)),
74
 
        ],
75
 
        required=False,
76
 
        skip_check=True),
77
 
    'ipmi': DictCharField(
78
 
        [
79
 
            ('power_driver',
80
 
             forms.ChoiceField(
81
 
                 label="Driver", required=False,
82
 
                 choices=IPMI_DRIVER_CHOICES,
83
 
                 initial=IPMI_DRIVER.DEFAULT)),
84
 
            ('power_address',
85
 
             forms.CharField(label="IP Address or Hostname", required=False)),
86
 
            ('power_user',
87
 
             forms.CharField(label="Username", required=False)),
88
 
            ('power_pass',
89
 
             forms.CharField(label="Password", required=False)),
90
 
        ],
91
 
        required=False,
92
 
        skip_check=True),
93
 
    'moonshot': DictCharField(
94
 
        [
95
 
            ('power_address',
96
 
             forms.CharField(
97
 
                 label="IP Address or Hostname", required=False)),
98
 
            ('power_user',
99
 
             forms.CharField(label="Username", required=False)),
100
 
            ('power_pass',
101
 
             forms.CharField(label="Password", required=False)),
102
 
            ('power_hwaddress',
103
 
             forms.CharField(label="Hardware Address", required=False)),
104
 
        ],
105
 
        required=False,
106
 
        skip_check=True),
107
 
    'sm15k': DictCharField(
108
 
        [
109
 
            ('power_address',
110
 
             forms.CharField(
111
 
                 label="IP Address or Hostname", required=False)),
112
 
            ('power_user',
113
 
             forms.CharField(label="Username", required=False)),
114
 
            ('power_pass',
115
 
             forms.CharField(label="Password", required=False)),
116
 
            ('system_id',
117
 
             forms.CharField(label="System ID", required=False)),
118
 
        ],
119
 
        required=False,
120
 
        skip_check=True),
121
 
    'amt': DictCharField(
122
 
        [
123
 
            ('power_address',
124
 
             forms.CharField(
125
 
                 label="IP Address or Hostname", required=False)),
126
 
            ('power_pass',
127
 
             forms.CharField(label="Password", required=False)),
128
 
        ],
129
 
        required=False,
130
 
        skip_check=True),
131
 
}
 
44
 
 
45
# Represent the Django choices format as JSON; an array of 2-item
 
46
# arrays.
 
47
CHOICE_FIELD_SCHEMA = {
 
48
    'type': 'array',
 
49
    'items': {
 
50
        'title': "Power type paramter field choice",
 
51
        'type': 'array',
 
52
        'minItems': 2,
 
53
        'maxItems': 2,
 
54
        'uniqueItems': True,
 
55
        'items': {
 
56
            'type': 'string',
 
57
        }
 
58
    },
 
59
}
 
60
 
 
61
 
 
62
POWER_TYPE_PARAMETER_FIELD_SCHEMA = {
 
63
    'title': "Power type parameter field",
 
64
    'type': 'object',
 
65
    'properties': {
 
66
        'name': {
 
67
            'type': 'string',
 
68
        },
 
69
        'field_type': {
 
70
            'type': 'string',
 
71
        },
 
72
        'label': {
 
73
            'type': 'string',
 
74
        },
 
75
        'required': {
 
76
            'type': 'boolean',
 
77
        },
 
78
        'choices': CHOICE_FIELD_SCHEMA,
 
79
        'default': {
 
80
            'type': 'string',
 
81
        },
 
82
    },
 
83
    'required': ['field_type', 'label', 'required'],
 
84
}
 
85
 
 
86
 
 
87
# A basic JSON schema for what power type parameters should look like.
 
88
JSON_POWER_TYPE_PARAMETERS_SCHEMA = {
 
89
    'title': "Power parameters set",
 
90
    'type': 'array',
 
91
    'items': {
 
92
        'title': "Power type parameters",
 
93
        'type': 'object',
 
94
        'properties': {
 
95
            'fields': {
 
96
                'type': 'array',
 
97
                'items': POWER_TYPE_PARAMETER_FIELD_SCHEMA,
 
98
            },
 
99
        },
 
100
        'required': ['fields'],
 
101
    },
 
102
}
 
103
 
 
104
 
 
105
def make_json_field(
 
106
        name, label, field_type=None, choices=None, default=None,
 
107
        required=False):
 
108
    """Helper function for building a JSON power type parameters field.
 
109
 
 
110
    :param name: The name of the field.
 
111
    :type name: string
 
112
    :param label: The label to be presented to the user for this field.
 
113
    :type label: string
 
114
    :param field_type: The type of field to create. Can be one of
 
115
        (string, choice, mac_address). Defaults to string.
 
116
    :type field_type: string.
 
117
    :param choices: The collection of choices to present to the user.
 
118
        Needs to be structured as a list of lists, otherwise
 
119
        make_json_field() will raise a ValidationError.
 
120
    :type list:
 
121
    :param default: The default value for the field.
 
122
    :type default: string
 
123
    :param required: Whether or not a value for the field is required.
 
124
    :type required: boolean
 
125
    """
 
126
    if field_type not in ('string', 'mac_address', 'choice'):
 
127
        field_type = 'string'
 
128
    if choices is None:
 
129
        choices = []
 
130
    validate(choices, CHOICE_FIELD_SCHEMA)
 
131
    if default is None:
 
132
        default = ""
 
133
    field = {
 
134
        'name': name,
 
135
        'label': label,
 
136
        'required': required,
 
137
        'field_type': field_type,
 
138
        'choices': choices,
 
139
        'default': default,
 
140
    }
 
141
    return field
 
142
 
 
143
 
 
144
# FIXME this should all be produced by hardware drivers, not defined statically
 
145
# like this.
 
146
JSON_POWER_TYPE_PARAMETERS = [
 
147
    {
 
148
        'name': 'ether_wake',
 
149
        'fields': [
 
150
            make_json_field(
 
151
                'mac_address', "MAC Address", field_type='mac_address'),
 
152
        ],
 
153
    },
 
154
    {
 
155
        'name': 'virsh',
 
156
        'fields': [
 
157
            make_json_field('power_address', "Power address"),
 
158
            make_json_field('power_id', "Power ID"),
 
159
        ],
 
160
    },
 
161
    {
 
162
        'name': 'fence_cdu',
 
163
        'fields': [
 
164
            make_json_field('power_address', "Power address"),
 
165
            make_json_field('power_id', "Power ID"),
 
166
            make_json_field('power_user', "Power user"),
 
167
            make_json_field('power_pass', "Power password"),
 
168
        ],
 
169
    },
 
170
    {
 
171
        'name': 'ipmi',
 
172
        'fields': [
 
173
            make_json_field(
 
174
                'power_driver', "Power driver", field_type='choice',
 
175
                choices=IPMI_DRIVER_CHOICES, default=IPMI_DRIVER.DEFAULT),
 
176
            make_json_field('power_address', "Power address"),
 
177
            make_json_field('power_user', "Power user"),
 
178
            make_json_field('power_pass', "Power password"),
 
179
        ],
 
180
    },
 
181
    {
 
182
        'name': 'moonshot',
 
183
        'fields': [
 
184
            make_json_field('power_address', "Power address"),
 
185
            make_json_field('power_user', "Power user"),
 
186
            make_json_field('power_pass', "Power password"),
 
187
            make_json_field('power_hwaddress', "Power hardware address"),
 
188
        ],
 
189
    },
 
190
    {
 
191
        'name': 'sm15k',
 
192
        'fields': [
 
193
            make_json_field('system_id', "System ID"),
 
194
            make_json_field('power_address', "Power address"),
 
195
            make_json_field('power_user', "Power user"),
 
196
            make_json_field('power_pass', "Power password"),
 
197
        ],
 
198
    },
 
199
    {
 
200
        'name': 'amt',
 
201
        'fields': [
 
202
            make_json_field(
 
203
                'mac_address', "MAC Address", field_type='mac_address'),
 
204
            make_json_field('power_pass', "Power password"),
 
205
        ],
 
206
    },
 
207
]
 
208
 
 
209
 
 
210
FIELD_TYPE_MAPPINGS = {
 
211
    'string': forms.CharField,
 
212
    'mac_address': MACAddressFormField,
 
213
    'choice': forms.ChoiceField,
 
214
}
 
215
 
 
216
 
 
217
def make_form_field(json_field):
 
218
    """Build a Django form field based on the JSON spec.
 
219
 
 
220
    :param json_field: The JSON-specified field to convert into a valid
 
221
        Djangoism.
 
222
    :type json_field: dict
 
223
    :return: The correct Django form field for the field type, as
 
224
        specified in FIELD_TYPE_MAPPINGS.
 
225
    """
 
226
    field_class = FIELD_TYPE_MAPPINGS.get(
 
227
        json_field['field_type'], forms.CharField)
 
228
    if json_field['field_type'] == 'choice':
 
229
        extra_parameters = {
 
230
            'choices': json_field['choices'],
 
231
            'initial': json_field['default'],
 
232
            }
 
233
    else:
 
234
        extra_parameters = {}
 
235
    form_field = field_class(
 
236
        label=json_field['label'], required=json_field['required'],
 
237
        **extra_parameters)
 
238
    return form_field
 
239
 
 
240
 
 
241
def get_power_type_parameters_from_json(json_power_type_parameters):
 
242
    """Return power type parameters.
 
243
 
 
244
    :param json_power_type_parameters: Power type parameters expressed
 
245
        as a JSON string or as set of JSONSchema-verifiable objects.
 
246
        Will be validated using jsonschema.validate().
 
247
    :type json_power_type_parameters: JSON string or iterable.
 
248
    :return: A dict of power parameters for all power types, indexed by
 
249
        power type name.
 
250
    """
 
251
    validate(json_power_type_parameters, JSON_POWER_TYPE_PARAMETERS_SCHEMA)
 
252
    power_parameters = {
 
253
        # Empty type, for the case where nothing is entered in the form yet.
 
254
        '': DictCharField(
 
255
            [], required=False, skip_check=True),
 
256
    }
 
257
    for power_type in json_power_type_parameters:
 
258
        fields = []
 
259
        for json_field in power_type['fields']:
 
260
            fields.append((
 
261
                json_field['name'], make_form_field(json_field)))
 
262
        params = DictCharField(fields, required=False, skip_check=True)
 
263
        power_parameters[power_type['name']] = params
 
264
    return power_parameters
 
265
 
 
266
 
 
267
# We do this once because there's no point re-parsing the JSON every
 
268
# time we need to look up the power type parameters code.
 
269
POWER_TYPE_PARAMETERS = get_power_type_parameters_from_json(
 
270
    JSON_POWER_TYPE_PARAMETERS)