Merge ~d0ugal/maas:bug/1876855 into maas:master

Proposed by Dougal Matthews
Status: Merged
Approved by: Dougal Matthews
Approved revision: e1568b038dba1e83178514ca58fd13b2ce3fca68
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~d0ugal/maas:bug/1876855
Merge into: maas:master
Diff against target: 675 lines (+122/-42)
30 files modified
src/maasserver/api/machines.py (+33/-17)
src/maasserver/api/tests/test_machines.py (+19/-4)
src/maasserver/clusterrpc/driver_parameters.py (+6/-0)
src/maasserver/clusterrpc/tests/test_driver_parameters.py (+5/-0)
src/provisioningserver/drivers/pod/lxd.py (+1/-0)
src/provisioningserver/drivers/pod/rsd.py (+1/-0)
src/provisioningserver/drivers/pod/tests/test_base.py (+2/-0)
src/provisioningserver/drivers/pod/tests/test_registry.py (+2/-0)
src/provisioningserver/drivers/pod/virsh.py (+1/-0)
src/provisioningserver/drivers/power/__init__.py (+6/-0)
src/provisioningserver/drivers/power/amt.py (+1/-0)
src/provisioningserver/drivers/power/apc.py (+1/-0)
src/provisioningserver/drivers/power/dli.py (+1/-0)
src/provisioningserver/drivers/power/hmc.py (+1/-0)
src/provisioningserver/drivers/power/ipmi.py (+1/-0)
src/provisioningserver/drivers/power/manual.py (+1/-0)
src/provisioningserver/drivers/power/moonshot.py (+1/-0)
src/provisioningserver/drivers/power/mscm.py (+1/-0)
src/provisioningserver/drivers/power/msftocs.py (+1/-0)
src/provisioningserver/drivers/power/nova.py (+1/-0)
src/provisioningserver/drivers/power/openbmc.py (+1/-0)
src/provisioningserver/drivers/power/recs.py (+1/-0)
src/provisioningserver/drivers/power/redfish.py (+1/-0)
src/provisioningserver/drivers/power/seamicro.py (+1/-0)
src/provisioningserver/drivers/power/tests/test_base.py (+4/-1)
src/provisioningserver/drivers/power/tests/test_registry.py (+4/-1)
src/provisioningserver/drivers/power/ucsm.py (+1/-0)
src/provisioningserver/drivers/power/vmware.py (+1/-0)
src/provisioningserver/drivers/power/wedge.py (+1/-0)
src/provisioningserver/tests/test_power_driver_command.py (+21/-19)
Reviewer Review Type Date Requested Status
MAAS Lander Approve
Lee Trager (community) Approve
Review via email: mp+384349@code.launchpad.net

Commit message

LP: #1876855 Add can_probe to the driver power classes

This boolean flag determines if the power driver is suitable for use with
add_chassis.

The http API has been updated to use this flag when validating the allowed
list of driver names and the websocket API now includes this flag when
returning the list of power drivers from the general.power_drivers call.

To support backwards compatibility a new alias field was added to the driver classes. This allows them to be referred to by other names. For example "powerkvm" for virsh and "seamicro15k" for "sm15k"

To post a comment you must log in.
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b bug/1876855 lp:~d0ugal/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/7587/console
COMMIT: 6d422ef802f869a9bb8b22c1fcace07a50a991c4

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b bug/1876855 lp:~d0ugal/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/7588/console
COMMIT: 56a25e7063c3f2ab44a65510f282553baa08dbed

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b bug/1876855 lp:~d0ugal/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 7d9c44fea608a1fa06cf0945682253a61d9552e1

review: Approve
Revision history for this message
Dougal Matthews (d0ugal) wrote :

I think this change is mostly ready for feedback. Sure there are some improvements that can be made

Revision history for this message
Lee Trager (ltrager) wrote :

Power drivers and Pod drivers use a different base class. get_all_power_types() should only be returning power drivers so you should be able to skip modifying the Pod drivers.

Revision history for this message
Dougal Matthews (d0ugal) wrote :

> Power drivers and Pod drivers use a different base class.
> get_all_power_types() should only be returning power drivers so you should be
> able to skip modifying the Pod drivers.

I made that change because I was seeing some unexpected behaviour. The PowerDriverRegistry also contains the pod drivers (as per the end of provisioningserver.drivers.power.registry).

However, because some of the names are duplicated (there is a virsh power driver and pod driver) I think the power driver is replaced by the pod driver in the registry. I thought this was a bug and got stuck trying to figure it out. I wonder if we still need the power drivers that also have pod drivers?

Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b bug/1876855 lp:~d0ugal/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: FAILED
LOG: http://maas-ci.internal:8080/job/maas/job/branch-tester/7700/console
COMMIT: 31c2f3091ff479c097d6ec8f379d94cb42dfd637

review: Needs Fixing
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b bug/1876855 lp:~d0ugal/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 035697a137f9fa67d7e1edcfa70add790f980e9a

review: Approve
Revision history for this message
Dougal Matthews (d0ugal) wrote :

> Power drivers and Pod drivers use a different base class.
> get_all_power_types() should only be returning power drivers so you should be
> able to skip modifying the Pod drivers.

I attempted to do this. However, I think this is the class heirachy;

provisioningserver.drivers.pod.PodDriver -> provisioningserver.drivers.pod.PodDriverBase -> provisioningserver.drivers.power.PowerDriverBase

So it seems that I can't skip pod drivers when adding a new abstract property to the power drivers. Maybe this wasn't intentional?

The method get_all_power_types currently returns all of the power drivers and pod drivers. I added a quick test to verify that which currently fails; https://pastebin.ubuntu.com/p/hm5qx9kdZn/

Revision history for this message
Dougal Matthews (d0ugal) wrote :

I also noticed that in provisioningserver.drivers.power.registry the PodDriverRegistry entries are added to the PowerDriverRegistry. However, since they are registered by name this means the virsh power driver is replaced by the virsh pod driver.

Revision history for this message
Lee Trager (ltrager) wrote :

LGTM!

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b bug/1876855 lp:~d0ugal/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: c4bc28e1217465a86e1a26eefd02c20461b087db

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b bug/1876855 lp:~d0ugal/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: 0bbca16f198642ab6e971245800d0808e5224695

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

UNIT TESTS
-b bug/1876855 lp:~d0ugal/maas/+git/maas into -b master lp:~maas-committers/maas

STATUS: SUCCESS
COMMIT: b586e6323baa1b28a66fae55e1dba8ede9de04a4

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Revision history for this message
MAAS Lander (maas-lander) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/api/machines.py b/src/maasserver/api/machines.py
index 72281b4..0ecf00a 100644
--- a/src/maasserver/api/machines.py
+++ b/src/maasserver/api/machines.py
@@ -43,6 +43,7 @@ from maasserver.api.utils import (
43 get_optional_list,43 get_optional_list,
44 get_optional_param,44 get_optional_param,
45)45)
46from maasserver.clusterrpc.driver_parameters import get_all_power_types
46from maasserver.enum import (47from maasserver.enum import (
47 BMC_TYPE,48 BMC_TYPE,
48 BRIDGE_TYPE,49 BRIDGE_TYPE,
@@ -2508,6 +2509,34 @@ class MachinesHandler(NodesHandler, PowersMixin):
2508 machine.constraints_by_type["verbose_interfaces"] = interfaces2509 machine.constraints_by_type["verbose_interfaces"] = interfaces
2509 return machine2510 return machine
25102511
2512 def _get_chassis_param(self, request):
2513 power_type_names = [
2514 pt["name"] for pt in get_all_power_types() if pt["can_probe"]
2515 ]
2516
2517 # NOTE: The http API accepts two additional names for backwards
2518 # compatability. Previously the hardcoded list of chassis_type's was
2519 # stored here and included powerkvm and seamicro15k. Neither of these
2520 # are valid power driver names but they can be treated as virsh and
2521 # sm15k.
2522 power_type_names.extend(["powerkvm", "seamicro15k"])
2523
2524 chassis_type = get_mandatory_param(
2525 request.POST,
2526 "chassis_type",
2527 validator=validators.OneOf(power_type_names),
2528 )
2529
2530 # Convert sm15k to seamicro15k. This code was written to work with
2531 # 'seamicro15k' but the power driver name in the provisioningserver is
2532 # 'sm15k'. The following code expects the longer name. See the NOTE
2533 # above for more context. Both powerkvm and virsh were previously
2534 # supported so they don't need to be converted.
2535 if chassis_type == "sm15k":
2536 chassis_type = "seamicro15k"
2537
2538 return chassis_type
2539
2511 @admin_method2540 @admin_method
2512 @operation(idempotent=False)2541 @operation(idempotent=False)
2513 def add_chassis(self, request):2542 def add_chassis(self, request):
@@ -2521,7 +2550,7 @@ class MachinesHandler(NodesHandler, PowersMixin):
2521 - ``msftocs``: Microsoft OCS Chassis Manager.2550 - ``msftocs``: Microsoft OCS Chassis Manager.
2522 - ``powerkvm``: Virtual Machines on Power KVM, managed by Virsh.2551 - ``powerkvm``: Virtual Machines on Power KVM, managed by Virsh.
2523 - ``recs_box``: Christmann RECS|Box servers.2552 - ``recs_box``: Christmann RECS|Box servers.
2524 - ``seamicro15k``: Seamicro 1500 Chassis.2553 - ``sm15k``: Seamicro 1500 Chassis.
2525 - ``ucsm``: Cisco UCS Manager.2554 - ``ucsm``: Cisco UCS Manager.
2526 - ``virsh``: virtual machines managed by Virsh.2555 - ``virsh``: virtual machines managed by Virsh.
2527 - ``vmware`` is the type for virtual machines managed by VMware.2556 - ``vmware`` is the type for virtual machines managed by VMware.
@@ -2585,22 +2614,9 @@ class MachinesHandler(NodesHandler, PowersMixin):
2585 @error (http-status-code) "400" 4002614 @error (http-status-code) "400" 400
2586 @error (content) "bad-params" Required parameters are missing.2615 @error (content) "bad-params" Required parameters are missing.
2587 """2616 """
2588 chassis_type = get_mandatory_param(2617
2589 request.POST,2618 chassis_type = self._get_chassis_param(request)
2590 "chassis_type",2619
2591 validator=validators.OneOf(
2592 [
2593 "mscm",
2594 "msftocs",
2595 "powerkvm",
2596 "recs_box",
2597 "seamicro15k",
2598 "ucsm",
2599 "virsh",
2600 "vmware",
2601 ]
2602 ),
2603 )
2604 hostname = get_mandatory_param(request.POST, "hostname")2620 hostname = get_mandatory_param(request.POST, "hostname")
26052621
2606 if chassis_type in (2622 if chassis_type in (
diff --git a/src/maasserver/api/tests/test_machines.py b/src/maasserver/api/tests/test_machines.py
index 98c4485..3adf781 100644
--- a/src/maasserver/api/tests/test_machines.py
+++ b/src/maasserver/api/tests/test_machines.py
@@ -2665,6 +2665,21 @@ class TestMachinesAPI(APITestCase.ForUser):
2665 )2665 )
2666 self.assertEqual(b"No provided chassis_type!", response.content)2666 self.assertEqual(b"No provided chassis_type!", response.content)
26672667
2668 def test_POST_add_chassis_invalid_chasis_type(self):
2669 self.become_admin()
2670 response = self.client.post(
2671 reverse("machines_handler"),
2672 {"op": "add_chassis", "chassis_type": "invalid"},
2673 )
2674 self.assertEqual(
2675 http.client.BAD_REQUEST, response.status_code, response.content
2676 )
2677 self.assertTrue(
2678 response.content.startswith(
2679 b"Invalid chassis_type: Value must be one of: "
2680 )
2681 )
2682
2668 def test_POST_add_chassis_requires_hostname(self):2683 def test_POST_add_chassis_requires_hostname(self):
2669 self.become_admin()2684 self.become_admin()
2670 response = self.client.post(2685 response = self.client.post(
@@ -3058,7 +3073,7 @@ class TestMachinesAPI(APITestCase.ForUser):
3058 ),3073 ),
3059 )3074 )
30603075
3061 def test_POST_add_chasis_only_allows_port_with_vmware_and_msftocs(self):3076 def test_POST_add_chassis_only_allows_port_with_vmware_and_msftocs(self):
3062 self.become_admin()3077 self.become_admin()
3063 for chassis_type in (3078 for chassis_type in (
3064 "mscm",3079 "mscm",
@@ -3088,7 +3103,7 @@ class TestMachinesAPI(APITestCase.ForUser):
3088 response.content,3103 response.content,
3089 )3104 )
30903105
3091 def test_POST_add_chasis_checks_port_too_high(self):3106 def test_POST_add_chassis_checks_port_too_high(self):
3092 self.become_admin()3107 self.become_admin()
3093 for chassis_type in ("msftocs", "recs_box", "vmware"):3108 for chassis_type in ("msftocs", "recs_box", "vmware"):
3094 params = {3109 params = {
@@ -3110,7 +3125,7 @@ class TestMachinesAPI(APITestCase.ForUser):
3110 response.content,3125 response.content,
3111 )3126 )
31123127
3113 def test_POST_add_chasis_checks_port_too_low(self):3128 def test_POST_add_chassis_checks_port_too_low(self):
3114 self.become_admin()3129 self.become_admin()
3115 for chassis_type in ("msftocs", "recs_box", "vmware"):3130 for chassis_type in ("msftocs", "recs_box", "vmware"):
3116 params = {3131 params = {
@@ -3175,7 +3190,7 @@ class TestMachinesAPI(APITestCase.ForUser):
3175 ),3190 ),
3176 )3191 )
31773192
3178 def test_POST_add_chasis_only_allows_protocol_with_vmware(self):3193 def test_POST_add_chassis_only_allows_protocol_with_vmware(self):
3179 self.become_admin()3194 self.become_admin()
3180 for chassis_type in (3195 for chassis_type in (
3181 "mscm",3196 "mscm",
diff --git a/src/maasserver/clusterrpc/driver_parameters.py b/src/maasserver/clusterrpc/driver_parameters.py
index 3c2175e..c29bba0 100644
--- a/src/maasserver/clusterrpc/driver_parameters.py
+++ b/src/maasserver/clusterrpc/driver_parameters.py
@@ -94,6 +94,7 @@ def add_power_driver_parameters(
94 name,94 name,
95 description,95 description,
96 chassis,96 chassis,
97 can_probe,
97 fields,98 fields,
98 missing_packages,99 missing_packages,
99 parameters_set,100 parameters_set,
@@ -111,6 +112,8 @@ def add_power_driver_parameters(
111 :type description: string112 :type description: string
112 :param chassis: Whether the power driver is for a chassis113 :param chassis: Whether the power driver is for a chassis
113 :type chassis: bool114 :type chassis: bool
115 :param can_probe: Whether the power driver supports add_chassis
116 :type can_probe: bool
114 :param fields: The fields that make up the parameters for the power117 :param fields: The fields that make up the parameters for the power
115 type. Will be validated against118 type. Will be validated against
116 SETTING_PARAMETER_FIELD_SCHEMA.119 SETTING_PARAMETER_FIELD_SCHEMA.
@@ -137,6 +140,7 @@ def add_power_driver_parameters(
137 "fields": fields,140 "fields": fields,
138 "missing_packages": missing_packages,141 "missing_packages": missing_packages,
139 "chassis": chassis,142 "chassis": chassis,
143 "can_probe": can_probe,
140 }144 }
141 if queryable is not None:145 if queryable is not None:
142 params["queryable"] = queryable146 params["queryable"] = queryable
@@ -262,6 +266,7 @@ def get_all_power_types(controllers=None, ignore_errors=True):
262 fields = power_type.get("fields", [])266 fields = power_type.get("fields", [])
263 description = power_type["description"]267 description = power_type["description"]
264 chassis = power_type["chassis"]268 chassis = power_type["chassis"]
269 can_probe = power_type["can_probe"]
265 missing_packages = power_type["missing_packages"]270 missing_packages = power_type["missing_packages"]
266 queryable = power_type.get("queryable")271 queryable = power_type.get("queryable")
267 add_power_driver_parameters(272 add_power_driver_parameters(
@@ -269,6 +274,7 @@ def get_all_power_types(controllers=None, ignore_errors=True):
269 name,274 name,
270 description,275 description,
271 chassis,276 chassis,
277 can_probe,
272 fields,278 fields,
273 missing_packages,279 missing_packages,
274 merged_types,280 merged_types,
diff --git a/src/maasserver/clusterrpc/tests/test_driver_parameters.py b/src/maasserver/clusterrpc/tests/test_driver_parameters.py
index 6e31cad..9334fa3 100644
--- a/src/maasserver/clusterrpc/tests/test_driver_parameters.py
+++ b/src/maasserver/clusterrpc/tests/test_driver_parameters.py
@@ -297,6 +297,7 @@ class TestAddPowerTypeParameters(MAASServerTestCase):
297 name="blah",297 name="blah",
298 description="baz",298 description="baz",
299 chassis=True,299 chassis=True,
300 can_probe=False,
300 fields=[self.make_field()],301 fields=[self.make_field()],
301 missing_packages=[],302 missing_packages=[],
302 parameters_set=existing_parameters,303 parameters_set=existing_parameters,
@@ -323,6 +324,7 @@ class TestAddPowerTypeParameters(MAASServerTestCase):
323 name="blah",324 name="blah",
324 description="baz",325 description="baz",
325 chassis=False,326 chassis=False,
327 can_probe=False,
326 fields=fields,328 fields=fields,
327 missing_packages=missing_packages,329 missing_packages=missing_packages,
328 parameters_set=existing_parameters,330 parameters_set=existing_parameters,
@@ -334,6 +336,7 @@ class TestAddPowerTypeParameters(MAASServerTestCase):
334 "name": "blah",336 "name": "blah",
335 "description": "baz",337 "description": "baz",
336 "chassis": False,338 "chassis": False,
339 "can_probe": False,
337 "fields": fields,340 "fields": fields,
338 "missing_packages": missing_packages,341 "missing_packages": missing_packages,
339 }342 }
@@ -349,6 +352,7 @@ class TestAddPowerTypeParameters(MAASServerTestCase):
349 name="blah",352 name="blah",
350 description="baz",353 description="baz",
351 chassis=False,354 chassis=False,
355 can_probe=False,
352 fields=[{}],356 fields=[{}],
353 missing_packages=[],357 missing_packages=[],
354 parameters_set=[],358 parameters_set=[],
@@ -362,6 +366,7 @@ class TestAddPowerTypeParameters(MAASServerTestCase):
362 name="blah",366 name="blah",
363 description="baz",367 description="baz",
364 chassis=False,368 chassis=False,
369 can_probe=False,
365 fields=fields,370 fields=fields,
366 missing_packages=[],371 missing_packages=[],
367 parameters_set=parameters_set,372 parameters_set=parameters_set,
diff --git a/src/provisioningserver/drivers/pod/lxd.py b/src/provisioningserver/drivers/pod/lxd.py
index 5e06104..bd47a07 100644
--- a/src/provisioningserver/drivers/pod/lxd.py
+++ b/src/provisioningserver/drivers/pod/lxd.py
@@ -93,6 +93,7 @@ class LXDPodDriver(PodDriver):
9393
94 name = "lxd"94 name = "lxd"
95 chassis = True95 chassis = True
96 can_probe = False
96 description = "LXD (virtual systems)"97 description = "LXD (virtual systems)"
97 settings = [98 settings = [
98 make_setting_field("power_address", "LXD address", required=True),99 make_setting_field("power_address", "LXD address", required=True),
diff --git a/src/provisioningserver/drivers/pod/rsd.py b/src/provisioningserver/drivers/pod/rsd.py
index 91aceef..25401b3 100644
--- a/src/provisioningserver/drivers/pod/rsd.py
+++ b/src/provisioningserver/drivers/pod/rsd.py
@@ -68,6 +68,7 @@ RSD_NODE_POWER_STATE = {"PoweredOn": "on", "PoweredOff": "off"}
68class RSDPodDriver(RedfishPowerDriverBase, PodDriverBase):68class RSDPodDriver(RedfishPowerDriverBase, PodDriverBase):
6969
70 chassis = True # Pods are always a chassis70 chassis = True # Pods are always a chassis
71 can_probe = False
7172
72 # RSDPodDriver inherits from RedfishPowerDriver.73 # RSDPodDriver inherits from RedfishPowerDriver.
73 # Power parameters will need to be changed to reflect this.74 # Power parameters will need to be changed to reflect this.
diff --git a/src/provisioningserver/drivers/pod/tests/test_base.py b/src/provisioningserver/drivers/pod/tests/test_base.py
index 829761a..df60ddc 100644
--- a/src/provisioningserver/drivers/pod/tests/test_base.py
+++ b/src/provisioningserver/drivers/pod/tests/test_base.py
@@ -874,6 +874,7 @@ class FakePodDriverBase(PodDriverBase):
874874
875 name = ""875 name = ""
876 chassis = True876 chassis = True
877 can_probe = True
877 description = ""878 description = ""
878 settings = []879 settings = []
879 ip_extractor = None880 ip_extractor = None
@@ -1020,6 +1021,7 @@ class TestPodDriverBase(MAASTestCase):
1020 "queryable": fake_driver.queryable,1021 "queryable": fake_driver.queryable,
1021 "missing_packages": [],1022 "missing_packages": [],
1022 "chassis": True,1023 "chassis": True,
1024 "can_probe": True,
1023 },1025 },
1024 fake_driver.get_schema(),1026 fake_driver.get_schema(),
1025 )1027 )
diff --git a/src/provisioningserver/drivers/pod/tests/test_registry.py b/src/provisioningserver/drivers/pod/tests/test_registry.py
index 1e1c2e5..34e790b 100644
--- a/src/provisioningserver/drivers/pod/tests/test_registry.py
+++ b/src/provisioningserver/drivers/pod/tests/test_registry.py
@@ -41,6 +41,7 @@ class TestPodDriverRegistry(MAASTestCase):
41 "queryable": fake_driver_one.queryable,41 "queryable": fake_driver_one.queryable,
42 "missing_packages": fake_driver_one.detect_missing_packages(),42 "missing_packages": fake_driver_one.detect_missing_packages(),
43 "chassis": True,43 "chassis": True,
44 "can_probe": True,
44 },45 },
45 {46 {
46 "driver_type": "pod",47 "driver_type": "pod",
@@ -50,6 +51,7 @@ class TestPodDriverRegistry(MAASTestCase):
50 "queryable": fake_driver_two.queryable,51 "queryable": fake_driver_two.queryable,
51 "missing_packages": fake_driver_two.detect_missing_packages(),52 "missing_packages": fake_driver_two.detect_missing_packages(),
52 "chassis": True,53 "chassis": True,
54 "can_probe": True,
53 },55 },
54 ],56 ],
55 PodDriverRegistry.get_schema(),57 PodDriverRegistry.get_schema(),
diff --git a/src/provisioningserver/drivers/pod/virsh.py b/src/provisioningserver/drivers/pod/virsh.py
index 50a8b97..690e015 100644
--- a/src/provisioningserver/drivers/pod/virsh.py
+++ b/src/provisioningserver/drivers/pod/virsh.py
@@ -1292,6 +1292,7 @@ class VirshPodDriver(PodDriver):
12921292
1293 name = "virsh"1293 name = "virsh"
1294 description = "Virsh (virtual systems)"1294 description = "Virsh (virtual systems)"
1295 can_probe = True
1295 settings = [1296 settings = [
1296 make_setting_field("power_address", "Address", required=True),1297 make_setting_field("power_address", "Address", required=True),
1297 make_setting_field(1298 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/__init__.py b/src/provisioningserver/drivers/power/__init__.py
index c9534f1..b6e68af 100644
--- a/src/provisioningserver/drivers/power/__init__.py
+++ b/src/provisioningserver/drivers/power/__init__.py
@@ -49,6 +49,7 @@ JSON_POWER_DRIVER_SCHEMA = {
49 "driver_type": {"type": "string"},49 "driver_type": {"type": "string"},
50 "name": {"type": "string"},50 "name": {"type": "string"},
51 "chassis": {"type": "boolean"},51 "chassis": {"type": "boolean"},
52 "can_probe": {"type": "boolean"},
52 "description": {"type": "string"},53 "description": {"type": "string"},
53 "fields": {"type": "array", "items": SETTING_PARAMETER_FIELD_SCHEMA},54 "fields": {"type": "array", "items": SETTING_PARAMETER_FIELD_SCHEMA},
54 "ip_extractor": IP_EXTRACTOR_SCHEMA,55 "ip_extractor": IP_EXTRACTOR_SCHEMA,
@@ -168,6 +169,10 @@ class PowerDriverBase(metaclass=ABCMeta):
168 def chassis(self):169 def chassis(self):
169 """Return True if the power driver is for a chassis."""170 """Return True if the power driver is for a chassis."""
170171
172 @abstractproperty
173 def can_probe(self):
174 """Return True if the power driver can be used with add_chassis."""
175
171 @abstractmethod176 @abstractmethod
172 def detect_missing_packages(self):177 def detect_missing_packages(self):
173 """Implement this method for the actual implementation178 """Implement this method for the actual implementation
@@ -220,6 +225,7 @@ class PowerDriverBase(metaclass=ABCMeta):
220 name=self.name,225 name=self.name,
221 description=self.description,226 description=self.description,
222 chassis=self.chassis,227 chassis=self.chassis,
228 can_probe=self.can_probe,
223 fields=self.settings,229 fields=self.settings,
224 queryable=self.queryable,230 queryable=self.queryable,
225 missing_packages=(231 missing_packages=(
diff --git a/src/provisioningserver/drivers/power/amt.py b/src/provisioningserver/drivers/power/amt.py
index 7410383..14288a0 100644
--- a/src/provisioningserver/drivers/power/amt.py
+++ b/src/provisioningserver/drivers/power/amt.py
@@ -47,6 +47,7 @@ class AMTPowerDriver(PowerDriver):
4747
48 name = "amt"48 name = "amt"
49 chassis = False49 chassis = False
50 can_probe = False
50 description = "Intel AMT"51 description = "Intel AMT"
51 settings = [52 settings = [
52 make_setting_field(53 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/apc.py b/src/provisioningserver/drivers/power/apc.py
index 680175c..1fe8505 100644
--- a/src/provisioningserver/drivers/power/apc.py
+++ b/src/provisioningserver/drivers/power/apc.py
@@ -29,6 +29,7 @@ class APCPowerDriver(PowerDriver):
2929
30 name = "apc"30 name = "apc"
31 chassis = True31 chassis = True
32 can_probe = False
32 description = "American Power Conversion (APC) PDU"33 description = "American Power Conversion (APC) PDU"
33 settings = [34 settings = [
34 make_setting_field("power_address", "IP for APC PDU", required=True),35 make_setting_field("power_address", "IP for APC PDU", required=True),
diff --git a/src/provisioningserver/drivers/power/dli.py b/src/provisioningserver/drivers/power/dli.py
index d389d20..f27bdf3 100644
--- a/src/provisioningserver/drivers/power/dli.py
+++ b/src/provisioningserver/drivers/power/dli.py
@@ -29,6 +29,7 @@ from provisioningserver.utils.shell import (
29class DLIPowerDriver(PowerDriver):29class DLIPowerDriver(PowerDriver):
30 name = "dli"30 name = "dli"
31 chassis = True31 chassis = True
32 can_probe = False
32 description = "Digital Loggers, Inc. PDU"33 description = "Digital Loggers, Inc. PDU"
33 settings = [34 settings = [
34 make_setting_field(35 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/hmc.py b/src/provisioningserver/drivers/power/hmc.py
index b12ea76..1679d7e 100644
--- a/src/provisioningserver/drivers/power/hmc.py
+++ b/src/provisioningserver/drivers/power/hmc.py
@@ -35,6 +35,7 @@ class HMCPowerDriver(PowerDriver):
3535
36 name = "hmc"36 name = "hmc"
37 chassis = True37 chassis = True
38 can_probe = False
38 description = "IBM Hardware Management Console (HMC)"39 description = "IBM Hardware Management Console (HMC)"
39 settings = [40 settings = [
40 make_setting_field("power_address", "IP for HMC", required=True),41 make_setting_field("power_address", "IP for HMC", required=True),
diff --git a/src/provisioningserver/drivers/power/ipmi.py b/src/provisioningserver/drivers/power/ipmi.py
index 02d49a0..877fff9 100644
--- a/src/provisioningserver/drivers/power/ipmi.py
+++ b/src/provisioningserver/drivers/power/ipmi.py
@@ -203,6 +203,7 @@ class IPMIPowerDriver(PowerDriver):
203203
204 name = "ipmi"204 name = "ipmi"
205 chassis = False205 chassis = False
206 can_probe = False
206 description = "IPMI"207 description = "IPMI"
207 settings = [208 settings = [
208 make_setting_field(209 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/manual.py b/src/provisioningserver/drivers/power/manual.py
index daaf5ed..44edd69 100644
--- a/src/provisioningserver/drivers/power/manual.py
+++ b/src/provisioningserver/drivers/power/manual.py
@@ -17,6 +17,7 @@ class ManualPowerDriver(PowerDriver):
1717
18 name = "manual"18 name = "manual"
19 chassis = False19 chassis = False
20 can_probe = False
20 description = "Manual"21 description = "Manual"
21 settings = []22 settings = []
22 ip_extractor = None23 ip_extractor = None
diff --git a/src/provisioningserver/drivers/power/moonshot.py b/src/provisioningserver/drivers/power/moonshot.py
index c8f2bf5..9608528 100644
--- a/src/provisioningserver/drivers/power/moonshot.py
+++ b/src/provisioningserver/drivers/power/moonshot.py
@@ -26,6 +26,7 @@ class MoonshotIPMIPowerDriver(PowerDriver):
2626
27 name = "moonshot"27 name = "moonshot"
28 chassis = True28 chassis = True
29 can_probe = False
29 description = "HP Moonshot - iLO4 (IPMI)"30 description = "HP Moonshot - iLO4 (IPMI)"
30 settings = [31 settings = [
31 make_setting_field("power_address", "Power address", required=True),32 make_setting_field("power_address", "Power address", required=True),
diff --git a/src/provisioningserver/drivers/power/mscm.py b/src/provisioningserver/drivers/power/mscm.py
index 02f21a6..3db65f8 100644
--- a/src/provisioningserver/drivers/power/mscm.py
+++ b/src/provisioningserver/drivers/power/mscm.py
@@ -56,6 +56,7 @@ class MSCMPowerDriver(PowerDriver):
5656
57 name = "mscm"57 name = "mscm"
58 chassis = True58 chassis = True
59 can_probe = True
59 description = "HP Moonshot - iLO Chassis Manager"60 description = "HP Moonshot - iLO Chassis Manager"
60 settings = [61 settings = [
61 make_setting_field(62 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/msftocs.py b/src/provisioningserver/drivers/power/msftocs.py
index 5b09f96..a549a76 100644
--- a/src/provisioningserver/drivers/power/msftocs.py
+++ b/src/provisioningserver/drivers/power/msftocs.py
@@ -37,6 +37,7 @@ class MicrosoftOCSPowerDriver(PowerDriver):
3737
38 name = "msftocs"38 name = "msftocs"
39 chassis = True39 chassis = True
40 can_probe = True
40 description = "Microsoft OCS - Chassis Manager"41 description = "Microsoft OCS - Chassis Manager"
41 settings = [42 settings = [
42 make_setting_field("power_address", "Power address", required=True),43 make_setting_field("power_address", "Power address", required=True),
diff --git a/src/provisioningserver/drivers/power/nova.py b/src/provisioningserver/drivers/power/nova.py
index 392ae4b..607515c 100644
--- a/src/provisioningserver/drivers/power/nova.py
+++ b/src/provisioningserver/drivers/power/nova.py
@@ -39,6 +39,7 @@ class NovaPowerDriver(PowerDriver):
3939
40 name = "nova"40 name = "nova"
41 chassis = True41 chassis = True
42 can_probe = False
42 description = "OpenStack Nova"43 description = "OpenStack Nova"
43 settings = [44 settings = [
44 make_setting_field(45 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/openbmc.py b/src/provisioningserver/drivers/power/openbmc.py
index 24c7c21..3c0a461 100644
--- a/src/provisioningserver/drivers/power/openbmc.py
+++ b/src/provisioningserver/drivers/power/openbmc.py
@@ -39,6 +39,7 @@ REG_MODE = {"data": "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"}
39class OpenBMCPowerDriver(PowerDriver):39class OpenBMCPowerDriver(PowerDriver):
4040
41 chassis = False41 chassis = False
42 can_probe = False
4243
43 name = "openbmc"44 name = "openbmc"
44 description = "OpenBMC Power Driver"45 description = "OpenBMC Power Driver"
diff --git a/src/provisioningserver/drivers/power/recs.py b/src/provisioningserver/drivers/power/recs.py
index 4f45beb..3d1b948 100644
--- a/src/provisioningserver/drivers/power/recs.py
+++ b/src/provisioningserver/drivers/power/recs.py
@@ -206,6 +206,7 @@ class RECSPowerDriver(PowerDriver):
206206
207 name = "recs_box"207 name = "recs_box"
208 chassis = True208 chassis = True
209 can_probe = True
209 description = "Christmann RECS|Box Power Driver"210 description = "Christmann RECS|Box Power Driver"
210 settings = [211 settings = [
211 make_setting_field(212 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/redfish.py b/src/provisioningserver/drivers/power/redfish.py
index 27f6354..bd388a6 100644
--- a/src/provisioningserver/drivers/power/redfish.py
+++ b/src/provisioningserver/drivers/power/redfish.py
@@ -134,6 +134,7 @@ class RedfishPowerDriverBase(PowerDriver):
134class RedfishPowerDriver(RedfishPowerDriverBase):134class RedfishPowerDriver(RedfishPowerDriverBase):
135135
136 chassis = True # Redfish API endpoints can be probed and enlisted.136 chassis = True # Redfish API endpoints can be probed and enlisted.
137 can_probe = False
137138
138 name = "redfish"139 name = "redfish"
139 description = "Redfish"140 description = "Redfish"
diff --git a/src/provisioningserver/drivers/power/seamicro.py b/src/provisioningserver/drivers/power/seamicro.py
index 7b5134d..aee9b4c 100644
--- a/src/provisioningserver/drivers/power/seamicro.py
+++ b/src/provisioningserver/drivers/power/seamicro.py
@@ -40,6 +40,7 @@ class SeaMicroPowerDriver(PowerDriver):
4040
41 name = "sm15k"41 name = "sm15k"
42 chassis = True42 chassis = True
43 can_probe = True
43 description = "SeaMicro 15000"44 description = "SeaMicro 15000"
44 settings = [45 settings = [
45 make_setting_field(46 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/tests/test_base.py b/src/provisioningserver/drivers/power/tests/test_base.py
index 0e6039e..8c56180 100644
--- a/src/provisioningserver/drivers/power/tests/test_base.py
+++ b/src/provisioningserver/drivers/power/tests/test_base.py
@@ -43,6 +43,7 @@ class FakePowerDriverBase(PowerDriverBase):
4343
44 name = ""44 name = ""
45 chassis = False45 chassis = False
46 can_probe = False
46 description = ""47 description = ""
47 settings = []48 settings = []
48 ip_extractor = None49 ip_extractor = None
@@ -183,6 +184,7 @@ class TestPowerDriverBase(MAASTestCase):
183 "name": fake_name,184 "name": fake_name,
184 "description": fake_description,185 "description": fake_description,
185 "chassis": fake_chassis,186 "chassis": fake_chassis,
187 "can_probe": False,
186 "fields": fake_settings,188 "fields": fake_settings,
187 "queryable": fake_driver.queryable,189 "queryable": fake_driver.queryable,
188 "missing_packages": fake_driver.detect_missing_packages(),190 "missing_packages": fake_driver.detect_missing_packages(),
@@ -251,6 +253,7 @@ class FakePowerDriver(PowerDriver):
251253
252 name = ""254 name = ""
253 chassis = False255 chassis = False
256 can_probe = False
254 description = ""257 description = ""
255 settings = []258 settings = []
256 ip_extractor = None259 ip_extractor = None
@@ -264,7 +267,7 @@ class FakePowerDriver(PowerDriver):
264 self.settings = settings267 self.settings = settings
265 if wait_time is not None:268 if wait_time is not None:
266 self.wait_time = wait_time269 self.wait_time = wait_time
267 super(FakePowerDriver, self).__init__(clock)270 super().__init__(clock)
268271
269 def detect_missing_packages(self):272 def detect_missing_packages(self):
270 return []273 return []
diff --git a/src/provisioningserver/drivers/power/tests/test_registry.py b/src/provisioningserver/drivers/power/tests/test_registry.py
index 9ee55eb..0e9c392 100644
--- a/src/provisioningserver/drivers/power/tests/test_registry.py
+++ b/src/provisioningserver/drivers/power/tests/test_registry.py
@@ -18,7 +18,7 @@ from provisioningserver.utils.testing import RegistryFixture
1818
19class TestPowerDriverRegistry(MAASTestCase):19class TestPowerDriverRegistry(MAASTestCase):
20 def setUp(self):20 def setUp(self):
21 super(TestPowerDriverRegistry, self).setUp()21 super().setUp()
22 # Ensure the global registry is empty for each test run.22 # Ensure the global registry is empty for each test run.
23 self.useFixture(RegistryFixture())23 self.useFixture(RegistryFixture())
2424
@@ -49,6 +49,7 @@ class TestPowerDriverRegistry(MAASTestCase):
49 "name": fake_driver_one.name,49 "name": fake_driver_one.name,
50 "description": fake_driver_one.description,50 "description": fake_driver_one.description,
51 "chassis": fake_driver_one.chassis,51 "chassis": fake_driver_one.chassis,
52 "can_probe": fake_driver_one.can_probe,
52 "fields": [],53 "fields": [],
53 "queryable": fake_driver_one.queryable,54 "queryable": fake_driver_one.queryable,
54 "missing_packages": fake_driver_one.detect_missing_packages(),55 "missing_packages": fake_driver_one.detect_missing_packages(),
@@ -58,6 +59,7 @@ class TestPowerDriverRegistry(MAASTestCase):
58 "name": fake_driver_two.name,59 "name": fake_driver_two.name,
59 "description": fake_driver_two.description,60 "description": fake_driver_two.description,
60 "chassis": fake_driver_two.chassis,61 "chassis": fake_driver_two.chassis,
62 "can_probe": fake_driver_two.can_probe,
61 "fields": [],63 "fields": [],
62 "queryable": fake_driver_two.queryable,64 "queryable": fake_driver_two.queryable,
63 "missing_packages": fake_driver_two.detect_missing_packages(),65 "missing_packages": fake_driver_two.detect_missing_packages(),
@@ -67,6 +69,7 @@ class TestPowerDriverRegistry(MAASTestCase):
67 "name": fake_pod_driver.name,69 "name": fake_pod_driver.name,
68 "description": fake_pod_driver.description,70 "description": fake_pod_driver.description,
69 "chassis": fake_pod_driver.chassis,71 "chassis": fake_pod_driver.chassis,
72 "can_probe": fake_pod_driver.can_probe,
70 "fields": [],73 "fields": [],
71 "queryable": fake_pod_driver.queryable,74 "queryable": fake_pod_driver.queryable,
72 "missing_packages": fake_pod_driver.detect_missing_packages(),75 "missing_packages": fake_pod_driver.detect_missing_packages(),
diff --git a/src/provisioningserver/drivers/power/ucsm.py b/src/provisioningserver/drivers/power/ucsm.py
index bc9accb..6fdd9b1 100644
--- a/src/provisioningserver/drivers/power/ucsm.py
+++ b/src/provisioningserver/drivers/power/ucsm.py
@@ -30,6 +30,7 @@ class UCSMPowerDriver(PowerDriver):
3030
31 name = "ucsm"31 name = "ucsm"
32 chassis = True32 chassis = True
33 can_probe = True
33 description = "Cisco UCS Manager"34 description = "Cisco UCS Manager"
34 settings = [35 settings = [
35 make_setting_field(36 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/vmware.py b/src/provisioningserver/drivers/power/vmware.py
index 86b7e2c..b222a24 100644
--- a/src/provisioningserver/drivers/power/vmware.py
+++ b/src/provisioningserver/drivers/power/vmware.py
@@ -38,6 +38,7 @@ class VMwarePowerDriver(PowerDriver):
3838
39 name = "vmware"39 name = "vmware"
40 chassis = True40 chassis = True
41 can_probe = True
41 description = "VMware"42 description = "VMware"
42 settings = [43 settings = [
43 make_setting_field(44 make_setting_field(
diff --git a/src/provisioningserver/drivers/power/wedge.py b/src/provisioningserver/drivers/power/wedge.py
index aee85df..6470b5d 100644
--- a/src/provisioningserver/drivers/power/wedge.py
+++ b/src/provisioningserver/drivers/power/wedge.py
@@ -27,6 +27,7 @@ class WedgePowerDriver(PowerDriver):
2727
28 name = "wedge"28 name = "wedge"
29 chassis = False29 chassis = False
30 can_probe = False
30 description = "Facebook's Wedge"31 description = "Facebook's Wedge"
31 settings = [32 settings = [
32 make_setting_field("power_address", "IP address", required=True),33 make_setting_field("power_address", "IP address", required=True),
diff --git a/src/provisioningserver/tests/test_power_driver_command.py b/src/provisioningserver/tests/test_power_driver_command.py
index 2884951..12f505a 100644
--- a/src/provisioningserver/tests/test_power_driver_command.py
+++ b/src/provisioningserver/tests/test_power_driver_command.py
@@ -15,6 +15,27 @@ from provisioningserver import power_driver_command
15from provisioningserver.drivers.power import PowerDriver15from provisioningserver.drivers.power import PowerDriver
1616
1717
18class FakeDriver(PowerDriver):
19 # These are required by the base class, but unused in this test.
20 chassis = False
21 can_probe = False
22 description = None
23 detect_missing_packages = None
24 ip_extractor = None
25 name = None
26 settings = []
27 _state = "off"
28
29 def power_on(self, *args, **kwargs):
30 self._state = "on"
31
32 def power_off(self, *args, **kwargs):
33 self._state = "off"
34
35 def power_query(self, *args, **kwargs):
36 return self._state
37
38
18class TestPowerDriverCommand(MAASTestCase):39class TestPowerDriverCommand(MAASTestCase):
1940
20 run_tests_with = MAASTwistedRunTest.make_factory(timeout=5000)41 run_tests_with = MAASTwistedRunTest.make_factory(timeout=5000)
@@ -90,25 +111,6 @@ class TestPowerDriverCommand(MAASTestCase):
90 args.command = "on"111 args.command = "on"
91 args.driver = "fake"112 args.driver = "fake"
92113
93 class FakeDriver(PowerDriver):
94 # These are required by the base class, but unused in this test.
95 chassis = None
96 description = None
97 detect_missing_packages = None
98 ip_extractor = None
99 name = None
100 settings = []
101 _state = "off"
102
103 def power_on(self, *args, **kwargs):
104 self._state = "on"
105
106 def power_off(self, *args, **kwargs):
107 self._state = "off"
108
109 def power_query(self, *args, **kwargs):
110 return self._state
111
112 driver = FakeDriver()114 driver = FakeDriver()
113 registry = {"fake": driver}115 registry = {"fake": driver}
114116

Subscribers

People subscribed via source and target branches