This file is indexed.

/usr/lib/python2.7/dist-packages/maasserver/clusterrpc/power_parameters.py is in python-django-maas 1.5.4+bzr2294-0ubuntu1.2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# Copyright 2012-2014 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

"""Power parameters.  Each possible value of a Node's power_type field can
be associated with specific 'power parameters' wich will be used when
powering up or down the node in question.  These 'power parameters' will be
stored as a JSON object in the Node's power parameter field.  Even if we want
to allow arbitrary power parameters to be set using the API for maximum
flexibility, each value of power type is associated with a set of 'sensible'
power parameters.  That is used to validate data (but again, it is possible
to bypass that validation step and store arbitrary power parameters) and by
the UI to display the right power parameter fields that correspond to the
selected power_type.  The classes in this module are used to associate each
power type with a set of power parameters.

The power types are retrieved from the cluster controllers using the json
schema provisioningserver.power_schema.JSON_POWER_TYPE_SCHEMA.  To add new
parameters requires changes to hardware drivers that run in the cluster
controllers.
"""

from __future__ import (
    absolute_import,
    print_function,
    unicode_literals,
    )

str = None

__metaclass__ = type
__all__ = [
    'get_all_power_types_from_clusters',
    'get_power_type_choices',
    'get_power_type_parameters',
    ]


from django import forms
from jsonschema import validate
from maasserver.clusterrpc.utils import call_clusters
from maasserver.config_forms import DictCharField
from maasserver.fields import MACAddressFormField
from maasserver.utils.forms import compose_invalid_choice_text
from provisioningserver.power_schema import (
    JSON_POWER_TYPE_SCHEMA,
    POWER_TYPE_PARAMETER_FIELD_SCHEMA,
    )
from provisioningserver.rpc import cluster


FIELD_TYPE_MAPPINGS = {
    'string': forms.CharField,
    'mac_address': MACAddressFormField,
    'choice': forms.ChoiceField,
}


def make_form_field(json_field):
    """Build a Django form field based on the JSON spec.

    :param json_field: The JSON-specified field to convert into a valid
        Djangoism.
    :type json_field: dict
    :return: The correct Django form field for the field type, as
        specified in FIELD_TYPE_MAPPINGS.
    """
    field_class = FIELD_TYPE_MAPPINGS.get(
        json_field['field_type'], forms.CharField)
    if json_field['field_type'] == 'choice':
        invalid_choice_message = compose_invalid_choice_text(
            json_field['name'], json_field['choices'])
        extra_parameters = {
            'choices': json_field['choices'],
            'initial': json_field['default'],
            'error_messages': {
                'invalid_choice': invalid_choice_message},
            }
    else:
        extra_parameters = {}
    form_field = field_class(
        label=json_field['label'], required=json_field['required'],
        **extra_parameters)
    return form_field


def add_power_type_parameters(name, description, fields, parameters_set):
    """Add new power type parameters to the given parameters_set if it
    does not already exist.

    :param name: The name of the power type for which to add parameters.
    :type name: string
    :param description: A longer description of the power type. This
        will be displayed in the UI.
    :type description: string
    :param fields: The fields that make up the parameters for the power
        type. Will be validated against
        POWER_TYPE_PARAMETER_FIELD_SCHEMA.
    :type fields: list of `make_json_field` results.
    :param parameters_set: An existing list of power type parameters to
        mutate.
    :type parameters_set: list
    """
    for power_type in parameters_set:
        if name == power_type['name']:
            return
    field_set_schema = {
        'title': "Power type parameters field set schema",
        'type': 'array',
        'items': POWER_TYPE_PARAMETER_FIELD_SCHEMA,
    }
    validate(fields, field_set_schema)
    parameters_set.append(
        {'name': name, 'description': description, 'fields': fields})


def get_power_type_parameters_from_json(json_power_type_parameters):
    """Return power type parameters.

    :param json_power_type_parameters: Power type parameters expressed
        as a JSON string or as set of JSONSchema-verifiable objects.
        Will be validated using jsonschema.validate().
    :type json_power_type_parameters: JSON string or iterable.
    :return: A dict of power parameters for all power types, indexed by
        power type name.
    """
    validate(json_power_type_parameters, JSON_POWER_TYPE_SCHEMA)
    power_parameters = {
        # Empty type, for the case where nothing is entered in the form yet.
        '': DictCharField(
            [], required=False, skip_check=True),
    }
    for power_type in json_power_type_parameters:
        fields = []
        for json_field in power_type['fields']:
            fields.append((
                json_field['name'], make_form_field(json_field)))
        params = DictCharField(fields, required=False, skip_check=True)
        power_parameters[power_type['name']] = params
    return power_parameters


def get_power_type_parameters():
    return get_power_type_parameters_from_json(
        get_all_power_types_from_clusters())


def get_power_type_choices():
    """Mutate the power types returned from the cluster into a choices
    structure as used by Django.

    :return: list of (name, description) tuples
    """
    return [
        (power_type['name'], power_type['description'])
        for power_type in get_all_power_types_from_clusters()]


def get_power_types(nodegroups=None, ignore_errors=False):
    """Return the choice of mechanism to control a node's power.

    :param nodegroups: Restrict to power types on the supplied
        :class:`NodeGroup`s.
    :param ignore_errors: If comms errors are encountered talking to any
        clusters, ignore and carry on. This means partial data may be
        returned if other clusters are operational.

    :raises: :class:`ClusterUnavailable` if ignore_errors is False and a
        cluster controller is unavailable.

    :return: Dictionary mapping power type to its description.
    """
    types = dict()
    power_types = get_all_power_types_from_clusters(nodegroups, ignore_errors)
    for power_type in power_types:
        types[power_type['name']] = power_type['description']
    return types


def get_all_power_types_from_clusters(nodegroups=None, ignore_errors=True):
    """Query every cluster controller and obtain all known power types.

    :return: a list of power types matching the schema
        provisioningserver.power_schema.JSON_POWER_TYPE_PARAMETERS_SCHEMA
    """
    merged_types = []
    responses = call_clusters(
        cluster.DescribePowerTypes, nodegroups=nodegroups,
        ignore_errors=ignore_errors)
    for response in responses:
        power_types = response['power_types']
        for power_type in power_types:
            name = power_type['name']
            fields = power_type['fields']
            description = power_type['description']
            add_power_type_parameters(name, description, fields, merged_types)
    return merged_types