1
1
# Copyright 2014-2016 Canonical Ltd. This software is licensed under the
2
2
# GNU Affero General Public License version 3 (see the file LICENSE).
4
"""Hardware Drivers."""
8
8
"ArchitectureRegistry",
17
11
from jsonschema import validate
18
from provisioningserver.power.schema import JSON_POWER_TYPE_PARAMETERS
19
12
from provisioningserver.utils import typed
20
13
from provisioningserver.utils.registry import Registry
16
class IP_EXTRACTOR_PATTERNS:
17
"""Commonly used patterns IP extractor patterns."""
19
# Use the entire string as the value.
20
IDENTITY = '^(?P<address>.+?)$'
22
# The typical URL pattern. Extracts address field as the value.
23
# The given URL has an address component that is one of:
24
# (1) an IPv6 IP address surrounded by []
25
# (2) an IPv4 IP address (no [])
27
# (4) the empty string.
28
# Cases 2 and 3 are processed in the regex by excluding all []/: from the
29
# allowed values. The need to verify the [] around the IPv6 IP address
30
# introduces a goodly amount of complexity due to looking forward/backward
31
# to determine if [] is ok/expected.
32
# The resulting address is simply the IP address (v6 or v4), or a hostname.
34
r'((?P<schema>.+?)://)?'
35
r'((?P<user>.+?)(:(?P<password>.*?))?@)?'
37
r'(?:\[(?=[0-9a-fA-F]*:[0-9a-fA-F.:]+\]))?'
38
r'(?P<address>(?:(?:[^\[\]/:]*(?!\]))|'
39
r'(?:(?<=\[)[0-9a-fA-F:.]+(?=\]))))\]?'
48
# Python REGEX pattern for extracting IP address from parameter field.
49
# The field_name tells the extractor which power_parameter field to use.
50
# Name the address field 'address' in your Python regex pattern.
51
# The pattern will be used as in 're.match(pattern, field_value)'.
52
IP_EXTRACTOR_SCHEMA = {
53
'title': "IP Extractor Configuration",
64
"field_name": ["pattern"],
65
"pattern": ["field_name"]
22
69
# JSON schema representing the Django choices format as JSON; an array of
24
71
CHOICE_FIELD_SCHEMA = {
77
128
'items': SETTING_PARAMETER_FIELD_SCHEMA,
130
'ip_extractor': IP_EXTRACTOR_SCHEMA,
134
'missing_packages': {
80
141
'required': ['name', 'description', 'fields'],
145
def make_ip_extractor(field_name, pattern=IP_EXTRACTOR_PATTERNS.IDENTITY):
147
'field_name': field_name,
84
157
def make_setting_field(
85
158
name, label, field_type=None, choices=None, default=None,
159
required=False, scope=SETTING_SCOPE.BMC):
87
160
"""Helper function for building a JSON setting parameters field.
89
162
:param name: The name of the field.
101
174
:type default: string
102
175
:param required: Whether or not a value for the field is required.
103
176
:type required: boolean
177
:param scope: 'bmc' or 'node' - Whether value is bmc or node specific.
105
if field_type not in ('string', 'mac_address', 'choice'):
181
if field_type not in ('string', 'mac_address', 'choice', 'password'):
106
182
field_type = 'string'
107
183
if choices is None:
109
185
validate(choices, CHOICE_FIELD_SCHEMA)
110
186
if default is None:
188
if scope not in (SETTING_SCOPE.BMC, SETTING_SCOPE.NODE):
189
scope = SETTING_SCOPE.BMC
115
193
'required': required,
116
194
'field_type': field_type,
117
195
'choices': choices,
118
196
'default': default,
123
def validate_settings(setting_fields):
124
"""Helper that validates that the fields adhere to the JSON schema."""
125
validate(setting_fields, JSON_SETTING_SCHEMA)
128
def gen_power_types():
129
from provisioningserver.drivers.power import power_drivers_by_name
130
for power_type in JSON_POWER_TYPE_PARAMETERS:
131
driver = power_drivers_by_name.get(power_type['name'])
132
if driver is not None:
133
power_type['missing_packages'] = driver.detect_missing_packages()
137
201
class Architecture:
158
222
self.kernel_options = kernel_options
161
class BootResource(metaclass=ABCMeta):
162
"""Abstraction of ephemerals and pxe resources required for a hardware
165
This resource is responsible for importing and reporting on
166
what is potentially available in relation to a cluster controller.
169
def __init__(self, name):
173
def import_resources(self, at_location, filter=None):
174
"""Import the specified resources.
176
:param at_location: URL to a Simplestreams index or a local path
177
to a directory containing boot resources.
178
:param filter: A simplestreams filter.
179
e.g. "release=trusty label=beta-2 arch=amd64"
180
This is ignored if the location is a local path, all resources
181
at the location will be imported.
182
TBD: How to provide progress information.
186
def describe_resources(self, at_location):
187
"""Enumerate all the boot resources.
189
:param at_location: URL to a Simplestreams index or a local path
190
to a directory containing boot resources.
192
:return: a list of dictionaries describing the available resources,
193
which will need to be imported so the driver can use them.
206
class HardwareDiscoverContext(metaclass=ABCMeta):
209
def startDiscovery(self):
213
def stopDiscovery(self):
217
225
class ArchitectureRegistry(Registry):
218
226
"""Registry for architecture classes."""
229
class BootResourceRegistry(Registry):
230
"""Registry for boot resource classes."""
233
237
builtin_architectures = [
234
238
Architecture(name="i386/generic", description="i386"),
235
239
Architecture(name="amd64/generic", description="amd64"),