/usr/lib/python3/dist-packages/provisioningserver/rpc/pods.py is in python3-maas-provisioningserver 2.4.0~beta2-6865-gec43e47e6-0ubuntu1.
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 | # Copyright 2016-2017 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Pod RPC functions."""
__all__ = [
"discover_pod",
]
from provisioningserver.drivers.pod import (
DiscoveredMachine,
DiscoveredPod,
DiscoveredPodHints,
get_error_message,
)
from provisioningserver.drivers.pod.registry import PodDriverRegistry
from provisioningserver.logger import (
get_maas_logger,
LegacyLogger,
)
from provisioningserver.rpc.exceptions import (
PodActionFail,
PodInvalidResources,
UnknownPodType,
)
from provisioningserver.utils.twisted import asynchronous
from twisted.internet.defer import Deferred
maaslog = get_maas_logger("pod")
log = LegacyLogger()
@asynchronous
def discover_pod(pod_type, context, pod_id=None, name=None):
"""Discover all the pod information and return the result to the
region controller.
The region controller handles parsing the output and updating the database
as required.
"""
pod_driver = PodDriverRegistry.get_item(pod_type)
if pod_driver is None:
raise UnknownPodType(pod_type)
d = pod_driver.discover(pod_id, context)
if not isinstance(d, Deferred):
raise PodActionFail(
"bad pod driver '%s'; 'discover' did not return Deferred." % (
pod_type))
def convert(result):
"""Convert the result to send over RPC."""
if result is None:
raise PodActionFail("unable to discover pod information.")
elif not isinstance(result, DiscoveredPod):
raise PodActionFail(
"bad pod driver '%s'; 'discover' returned invalid result." % (
pod_type))
else:
return {
"pod": result
}
def catch_all(failure):
"""Convert all failures into `PodActionFail` unless already a
`PodActionFail` or `NotImplementedError`."""
# Log locally to help debugging.
log.err(failure, "Failed to discover pod.")
if failure.check(NotImplementedError, PodActionFail):
return failure
else:
raise PodActionFail(get_error_message(failure.value))
d.addCallback(convert)
d.addErrback(catch_all)
return d
@asynchronous
def compose_machine(pod_type, context, request, pod_id, name):
"""Compose a machine that at least matches equal to or greater than
`request`.
The region controller handles parsing the outputed `DiscoveredMachine` and
updating the database as required.
"""
pod_driver = PodDriverRegistry.get_item(pod_type)
if pod_driver is None:
raise UnknownPodType(pod_type)
d = pod_driver.compose(pod_id, context, request)
if not isinstance(d, Deferred):
raise PodActionFail(
"bad pod driver '%s'; 'compose' did not return Deferred." % (
pod_type))
def convert(result):
"""Convert the result to send over RPC."""
if result is None:
# None is allowed when a machine could not be composed with the
# driver. This means it could not match the request. Returning None
# allows the region to try another pod if available to compose
# that machine.
raise PodInvalidResources()
else:
if (isinstance(result, tuple) and
len(result) == 2 and
isinstance(result[0], DiscoveredMachine) and
isinstance(result[1], DiscoveredPodHints)):
return {
"machine": result[0],
"hints": result[1],
}
else:
raise PodActionFail(
"bad pod driver '%s'; 'compose' returned "
"invalid result." % pod_type)
def catch_all(failure):
"""Convert all failures into `PodActionFail` unless already a
`PodActionFail`, `PodInvalidResources` or `NotImplementedError`."""
if failure.check(PodInvalidResources):
# Driver returned its own invalid resource exception instead of
# None. Just pass this onto the region.
return failure
# Log locally to help debugging.
log.err(failure, "%s: Failed to compose machine: %s" % (name, request))
if failure.check(NotImplementedError, PodActionFail):
return failure
else:
raise PodActionFail(get_error_message(failure.value))
d.addCallback(convert)
d.addErrback(catch_all)
return d
@asynchronous
def decompose_machine(pod_type, context, pod_id, name):
"""Decompose a machine. The machine to delete is contained in the `context`
just like power actions."""
pod_driver = PodDriverRegistry.get_item(pod_type)
if pod_driver is None:
raise UnknownPodType(pod_type)
d = pod_driver.decompose(pod_id, context)
if not isinstance(d, Deferred):
raise PodActionFail(
"bad pod driver '%s'; 'decompose' did not return Deferred." % (
pod_type))
def convert(result):
"""Convert the result to send over RPC."""
if result is None or not isinstance(result, DiscoveredPodHints):
raise PodActionFail(
"bad pod driver '%s'; 'decompose' returned invalid result." % (
pod_type))
else:
return {
"hints": result
}
def catch_all(failure):
"""Convert all failures into `PodActionFail` unless already a
`PodActionFail` or `NotImplementedError`."""
# Log locally to help debugging.
log.err(failure, "Failed to decompose machine.")
if failure.check(NotImplementedError, PodActionFail):
return failure
else:
raise PodActionFail(get_error_message(failure.value))
d.addCallback(convert)
d.addErrback(catch_all)
return d
|