Merge ~exsdev/juju-verify:lp1916231-neutron-gateway-juju-verifier-plugin into ~canonical-solutions-engineering/juju-verify:master

Proposed by Edin S
Status: Rejected
Rejected by: Martin Kalcok
Proposed branch: ~exsdev/juju-verify:lp1916231-neutron-gateway-juju-verifier-plugin
Merge into: ~canonical-solutions-engineering/juju-verify:master
Diff against target: 518 lines (+477/-0)
4 files modified
juju_verify/utils/unit.py (+6/-0)
juju_verify/verifiers/__init__.py (+2/-0)
juju_verify/verifiers/neutron_gateway.py (+159/-0)
tests/unit/verifiers/test_neutron_gateway.py (+310/-0)
Reviewer Review Type Date Requested Status
Martin Kalcok (community) Needs Fixing
Robert Gildein Needs Fixing
🤖 prod-jenkaas-bootstack (community) continuous-integration Needs Fixing
Review via email: mp+399961@code.launchpad.net

Commit message

Add Juju verify plugin for Neutron Gateway

Description of the change

Fixes LP#1916231

The other half of the required code (the required Charm actions) can be found here: https://review.opendev.org/c/openstack/charm-neutron-gateway/+/782896

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Unable to determine commit message from repository - please click "Set commit message" and enter the commit message manually.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :

A CI job is currently in progress. A follow up comment will be added when it completes.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :

FAILED: Continuous integration, rev:ddf29dc6f8628857a266a8223d32915d657e12b8

No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want jenkins to rebuild you need to trigger it yourself):
https://code.launchpad.net/~exsdev/juju-verify/+git/juju-verify/+merge/399961/+edit-commit-message

https://jenkins.canonical.com/bootstack/job/juju-verify-test/50/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/bootstack/job/generic-make-test/71/
    None: https://jenkins.canonical.com/bootstack/job/lp-update-mp/50/

Click here to trigger a rebuild:
https://jenkins.canonical.com/bootstack/job/juju-verify-test/50//rebuild

review: Needs Fixing (continuous-integration)
f244ee1... by Edin S

NGW: fix lint issues including typing information

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :

A CI job is currently in progress. A follow up comment will be added when it completes.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
8c7ff94... by Edin S

NGW: fix issues raised by pylint

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :

A CI job is currently in progress. A follow up comment will be added when it completes.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
b3f7b69... by Edin S

NGW: Add test for verifying reboot/shutdown

bc56476... by Edin S

NGW: Add test for getting unit's hostname

83d72cb... by Edin S

NGW: Add test for getting a unit's agent resource list

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :

A CI job is currently in progress. A follow up comment will be added when it completes.

Revision history for this message
🤖 prod-jenkaas-bootstack (prod-jenkaas-bootstack) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Edin S (exsdev) wrote :

NeutronGateway.get_all_ngw_units() currently doesn't have a unit test for it, but is well-suited for functional tests.

Revision history for this message
Robert Gildein (rgildein) :
review: Needs Fixing
Revision history for this message
Martin Kalcok (martin-kalcok) wrote :

I have few inline suggestions here, otherwise it looks good, thanks.

Regarding the code coverage, I think it's important that we keep 100% coverage in unit tests unless there's a really good reason why something is not unit-testable. Anyway, that's not high priority and can be done by someone else if you won't manage to finish it by the end of your rotation.

review: Needs Fixing
Revision history for this message
Martin Kalcok (martin-kalcok) wrote :

juju-verify development was moved to https://github.com/canonical/juju-verify

Unmerged commits

83d72cb... by Edin S

NGW: Add test for getting a unit's agent resource list

bc56476... by Edin S

NGW: Add test for getting unit's hostname

b3f7b69... by Edin S

NGW: Add test for verifying reboot/shutdown

8c7ff94... by Edin S

NGW: fix issues raised by pylint

f244ee1... by Edin S

NGW: fix lint issues including typing information

ddf29dc... by Edin S

Add NGW tests for warning about manual failover of HA routers

ff315e1... by Edin S

Add NGW tests for determining redundancy of resources

20f6288... by Edin S

Add NGW tests for generating list of resources that will remain online

ebd233b... by Edin S

Add NGW tests for generating list of resources to be shutdown

e1e6433... by Edin S

Add NGW tests for getting resource list

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/juju_verify/utils/unit.py b/juju_verify/utils/unit.py
index 05a9785..f672b20 100644
--- a/juju_verify/utils/unit.py
+++ b/juju_verify/utils/unit.py
@@ -64,6 +64,12 @@ def run_action_on_units(
64 return result_map64 return result_map
6565
6666
67def run_action_on_unit(unit: Unit, action: str, **params: str) -> Any:
68 """Run Juju action on single unit, returning the result."""
69 results = run_action_on_units([unit], action=action, **params)
70 return results[unit.entity_id]
71
72
67def parse_charm_name(charm_url: str) -> str:73def parse_charm_name(charm_url: str) -> str:
68 """Parse charm name from full charm url.74 """Parse charm name from full charm url.
6975
diff --git a/juju_verify/verifiers/__init__.py b/juju_verify/verifiers/__init__.py
index 4400e0f..3908db2 100644
--- a/juju_verify/verifiers/__init__.py
+++ b/juju_verify/verifiers/__init__.py
@@ -28,6 +28,7 @@ from juju_verify.verifiers.base import BaseVerifier
28from juju_verify.verifiers.ceph import CephOsd28from juju_verify.verifiers.ceph import CephOsd
29from juju_verify.verifiers.nova_compute import NovaCompute29from juju_verify.verifiers.nova_compute import NovaCompute
30from juju_verify.verifiers.result import Result30from juju_verify.verifiers.result import Result
31from juju_verify.verifiers.neutron_gateway import NeutronGateway
3132
32logger = logging.getLogger(__name__)33logger = logging.getLogger(__name__)
3334
@@ -35,6 +36,7 @@ logger = logging.getLogger(__name__)
35SUPPORTED_CHARMS = {36SUPPORTED_CHARMS = {
36 'nova-compute': NovaCompute,37 'nova-compute': NovaCompute,
37 'ceph-osd': CephOsd,38 'ceph-osd': CephOsd,
39 'neutron-gateway': NeutronGateway,
38}40}
3941
4042
diff --git a/juju_verify/verifiers/neutron_gateway.py b/juju_verify/verifiers/neutron_gateway.py
41new file mode 10064443new file mode 100644
index 0000000..d818ef0
--- /dev/null
+++ b/juju_verify/verifiers/neutron_gateway.py
@@ -0,0 +1,159 @@
1# Copyright 2021 Canonical Limited.
2#
3# This file is part of juju-verify.
4#
5# juju-verify is free software: you can redistribute it and/or modify it under
6# the terms of the GNU General Public License as published by the Free Software
7# Foundation, either version 3 of the License, or (at your option) any later
8# version.
9#
10# juju-verify is distributed in the hope that it will be useful, but WITHOUT
11# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13# details.
14#
15# You should have received a copy of the GNU General Public License along with
16# this program. If not, see https://www.gnu.org/licenses/.
17"""neutron-gateway verification."""
18import json
19from typing import Dict, List
20
21from juju.unit import Unit
22
23from juju_verify.verifiers.base import BaseVerifier, Result
24from juju_verify.verifiers.result import aggregate_results
25from juju_verify.utils.action import data_from_action
26from juju_verify.utils.unit import run_action_on_unit
27
28
29def get_unit_hostname(unit: Unit) -> str:
30 """Return name of the host on which the unit is running."""
31 get_hostname_action = run_action_on_unit(unit, "node-name")
32 hostname = data_from_action(get_hostname_action, "node-name")
33 return hostname
34
35
36def get_unit_resource_list(unit: Unit, get_resource_action_name: str) -> List[dict]:
37 """Given a get resource action, return the relevant resources on the unit."""
38 get_resource_action = run_action_on_unit(unit, get_resource_action_name)
39 action_name_res = NeutronGateway.action_name_result_map[get_resource_action_name]
40 resource_list_json = data_from_action(get_resource_action, action_name_res)
41 resource_list = json.loads(resource_list_json)
42 return resource_list
43
44
45class NeutronGateway(BaseVerifier):
46 """Implementation of verification checks for the neutron-gateway charm."""
47
48 NAME = 'neutron-gateway'
49 action_name_result_map = {"get-status-routers": "router-list",
50 "get-status-dhcp": "dhcp-networks",
51 "get-status-lb": "load-balancers"}
52 action_name_failure_string_map = {"get-status-routers": ("The following routers are "
53 "non-redundant: {}."),
54 "get-status-dhcp": ("The following DHCP networks "
55 "are non-redundant: {}"),
56 "get-status-lb": ("The following LBaasV2 LBs were "
57 "found: {}. LBaasV2 does not "
58 "offer HA.")}
59
60 def __init__(self, units: List[Unit]) -> None:
61 """Neutron Gateway verifier constructor."""
62 super().__init__(units)
63 self.cache_action_resource_list_map: Dict[str, List] = {}
64
65 def get_all_ngw_units(self) -> List[Unit]:
66 """Get all neutron-gateway units, including those not being shutdown."""
67 application_name = NeutronGateway.NAME
68 for rel in self.model.relations:
69 if rel.matches("{}:cluster".format(application_name)):
70 application = rel.applications.pop()
71 all_ngw_units = application.units
72 return all_ngw_units
73
74 def get_resource_list(self, get_resource_action_name: str) -> List[dict]:
75 """Given a get resource action, return matching resources from all units."""
76 try:
77 return self.cache_action_resource_list_map[get_resource_action_name]
78 except KeyError:
79 pass
80
81 resource_list = []
82 shutdown_hostname_list = [get_unit_hostname(unit) for unit in self.units]
83
84 for unit in self.get_all_ngw_units():
85 hostname = get_unit_hostname(unit)
86 host_resource_list = get_unit_resource_list(unit,
87 get_resource_action_name)
88
89 # add host metadata to resource
90 for resource in host_resource_list:
91 resource["host"] = hostname
92 resource["juju-entity-id"] = unit.entity_id
93 resource["shutdown"] = False
94
95 if hostname in shutdown_hostname_list:
96 resource["shutdown"] = True
97
98 resource_list.append(resource)
99
100 self.cache_action_resource_list_map[get_resource_action_name] = resource_list
101 return resource_list
102
103 def get_shutdown_resource_list(self, get_resource_action_name: str) -> List[dict]:
104 """Return a list of resources matching action that are going to be shutdown."""
105 res_list = self.get_resource_list(get_resource_action_name)
106 return [r for r in res_list if r["shutdown"] and r["status"] == "ACTIVE"]
107
108 def get_online_resource_list(self, get_resource_action_name: str) -> List[dict]:
109 """Return a list of resources matching action, that will remain online."""
110 res_list = self.get_resource_list(get_resource_action_name)
111 return [r for r in res_list if not r["shutdown"] and r["status"] == "ACTIVE"]
112
113 def check_non_redundant_resource(self, action_name: str) -> Result:
114 """Check that there are no non-redundant resources matching the resource type."""
115 result = Result(True)
116 shutdown_resource_list = self.get_shutdown_resource_list(action_name)
117 redundant_resource_list = self.get_online_resource_list(action_name)
118
119 shutdown_resource_set = set(r["id"] for r in shutdown_resource_list)
120 redundant_resource_set = set(r["id"] for r in redundant_resource_list)
121 non_redundant_list = shutdown_resource_set - redundant_resource_set
122 if non_redundant_list:
123 result.success = False
124 failure_string = NeutronGateway.action_name_failure_string_map[action_name]
125 result.reason = failure_string.format(", ".join(non_redundant_list))
126 return result
127
128 def warn_router_ha(self) -> Result:
129 """Warn that HA routers should be manually failed over."""
130 action_name = "get-status-routers"
131 result = Result(True)
132 shutdown_resource_list = self.get_shutdown_resource_list(action_name)
133
134 router_failover_err_list = []
135 for router in shutdown_resource_list:
136 if router["ha"]:
137 _id = router["id"]
138 entity_id = router["juju-entity-id"]
139 host = router["host"]
140 error_string = "{} (on {}, hostname: {})".format(_id, entity_id, host)
141 router_failover_err_list.append(error_string)
142
143 if router_failover_err_list:
144 error_string = ("It's recommended that you manually failover the following "
145 "routers: {}")
146 result.reason = error_string.format(", ".join(router_failover_err_list))
147
148 return result
149
150 def verify_reboot(self) -> Result:
151 """Verify that it's safe to reboot selected neutron-gateway units."""
152 return self.verify_shutdown()
153
154 def verify_shutdown(self) -> Result:
155 """Verify that it's safe to shutdown selected neutron-gateway units."""
156 return aggregate_results(self.warn_router_ha(),
157 self.check_non_redundant_resource("get-status-routers"),
158 self.check_non_redundant_resource("get-status-dhcp"),
159 self.check_non_redundant_resource("get-status-lb"))
diff --git a/tests/unit/verifiers/test_neutron_gateway.py b/tests/unit/verifiers/test_neutron_gateway.py
0new file mode 100644160new file mode 100644
index 0000000..4aeb48d
--- /dev/null
+++ b/tests/unit/verifiers/test_neutron_gateway.py
@@ -0,0 +1,310 @@
1# Copyright 2021 Canonical Limited.
2#
3# This file is part of juju-verify.
4#
5# juju-verify is free software: you can redistribute it and/or modify it under
6# the terms of the GNU General Public License as published by the Free Software
7# Foundation, either version 3 of the License, or (at your option) any later
8# version.
9#
10# juju-verify is distributed in the hope that it will be useful, but WITHOUT
11# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13# details.
14#
15# You should have received a copy of the GNU General Public License along with
16# this program. If not, see https://www.gnu.org/licenses/.
17"""NeutronGateway verifier class test suite."""
18import json
19from unittest import mock
20from unittest.mock import MagicMock
21
22from juju.unit import Unit
23
24from juju_verify.verifiers import NeutronGateway
25from juju_verify.verifiers.neutron_gateway import get_unit_hostname
26from juju_verify.verifiers.neutron_gateway import get_unit_resource_list
27
28all_ngw_units = []
29for i in range(3):
30 ngw = MagicMock()
31 ngw.entity_id = "neutron-gateway/{}".format(i)
32 all_ngw_units.append(ngw)
33
34mock_data = [
35 {
36 "host": "host0",
37 "shutdown": True,
38 "unit": all_ngw_units[0],
39 "routers": [{"id": "router0", "ha": False, "status": "ACTIVE"},
40 {"id": "router1", "ha": False, "status": "ACTIVE"}]
41 },
42 {
43 "host": "host1",
44 "shutdown": False,
45 "unit": all_ngw_units[1],
46 "routers": [{"id": "router2", "ha": False, "status": "ACTIVE"}],
47 },
48 {
49 "host": "host2",
50 "shutdown": False,
51 "unit": all_ngw_units[2],
52 "routers": [{"id": "router3", "ha": False, "status": "ACTIVE"},
53 {"id": "router4", "ha": False, "status": "ACTIVE"}],
54 },
55]
56
57all_ngw_host_names = [h["host"] for h in mock_data]
58
59model = MagicMock()
60
61
62def get_ngw_verifier():
63 """Get new NeutronGateway verifier (used for applying changes in shutdown list)."""
64 return NeutronGateway([Unit(h["unit"].entity_id, model)
65 for h in mock_data if h["shutdown"]])
66
67
68def get_resource_lists():
69 """Get all routers in mock data."""
70 return [h["routers"] for h in mock_data]
71
72
73def get_shutdown_host_name_list():
74 """Get all hostnames of all hosts being shutdown."""
75 return [h["host"] for h in mock_data if h["shutdown"]]
76
77
78def set_router_status(routerid, status):
79 """Set status of given router id in mock data."""
80 for host in mock_data:
81 for router in host["routers"]:
82 if router["id"] == routerid:
83 router["status"] = status
84
85
86@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_resource_list")
87@mock.patch("juju_verify.verifiers.neutron_gateway.NeutronGateway.get_all_ngw_units")
88@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_hostname")
89def test_get_resource_list(mock_get_unit_hostname,
90 mock_get_all_ngw_units,
91 mock_get_unit_resource_list):
92 """Test list of resources returned by get_resource_list."""
93 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
94 all_ngw_host_names)
95 mock_get_all_ngw_units.return_value = all_ngw_units
96 mock_get_unit_resource_list.side_effect = get_resource_lists()
97
98 ngw_verifier = get_ngw_verifier()
99 router_list = ngw_verifier.get_resource_list("get-status-routers")
100
101 router_count = 0
102 for host in mock_data:
103 router_count += len(host["routers"])
104 assert len(router_list) == router_count
105
106
107@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_resource_list")
108@mock.patch("juju_verify.verifiers.neutron_gateway.NeutronGateway.get_all_ngw_units")
109@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_hostname")
110def test_get_shutdown_resource_list(mock_get_unit_hostname,
111 mock_get_all_ngw_units,
112 mock_get_unit_resource_list):
113 """Test validity of list of resources to be shutdown."""
114 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
115 all_ngw_host_names)
116 mock_get_all_ngw_units.return_value = all_ngw_units
117 mock_get_unit_resource_list.side_effect = get_resource_lists()
118
119 ngw_verifier = get_ngw_verifier()
120
121 router_shutdown_count = 0
122 for host in mock_data:
123 if host["shutdown"]:
124 router_shutdown_count += len(host["routers"])
125
126 shutdown_routers = ngw_verifier.get_shutdown_resource_list("get-status-routers")
127 assert len(shutdown_routers) == router_shutdown_count
128
129 # test that inactive resources are not being listed as being shutdown
130 set_router_status("router0", "NOTACTIVE")
131
132 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
133 all_ngw_host_names)
134 mock_get_all_ngw_units.return_value = all_ngw_units
135 mock_get_unit_resource_list.side_effect = get_resource_lists()
136
137 shutdown_routers = ngw_verifier.get_shutdown_resource_list("get-status-routers")
138 assert len(shutdown_routers) == router_shutdown_count - 1
139
140 # set router0 back to active
141 set_router_status("router0", "ACTIVE")
142
143
144@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_resource_list")
145@mock.patch("juju_verify.verifiers.neutron_gateway.NeutronGateway.get_all_ngw_units")
146@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_hostname")
147def test_get_online_resource_list(mock_get_unit_hostname,
148 mock_get_all_ngw_units,
149 mock_get_unit_resource_list):
150 """Test validity of resources that will remain online."""
151 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
152 all_ngw_host_names)
153 mock_get_all_ngw_units.return_value = all_ngw_units
154 mock_get_unit_resource_list.side_effect = get_resource_lists()
155
156 ngw_verifier = get_ngw_verifier()
157
158 router_online_count = 0
159 for host in mock_data:
160 if not host["shutdown"]:
161 router_online_count += len(host["routers"])
162
163 online_routers = ngw_verifier.get_online_resource_list("get-status-routers")
164 assert len(online_routers) == router_online_count
165
166 # test that NOT ACTIVE resources are not being listed as online/available
167 set_router_status("router2", "NOTACTIVE")
168
169 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
170 all_ngw_host_names)
171 mock_get_all_ngw_units.return_value = all_ngw_units
172 mock_get_unit_resource_list.side_effect = get_resource_lists()
173
174 online_routers = ngw_verifier.get_online_resource_list("get-status-routers")
175 assert len(online_routers) == router_online_count - 1
176
177 # set router2 back to active
178 set_router_status("router2", "ACTIVE")
179
180
181@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_resource_list")
182@mock.patch("juju_verify.verifiers.neutron_gateway.NeutronGateway.get_all_ngw_units")
183@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_hostname")
184def test_check_non_redundant_resource(mock_get_unit_hostname,
185 mock_get_all_ngw_units,
186 mock_get_unit_resource_list):
187 """Test validity of list of resources determined to not be redundant."""
188 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
189 all_ngw_host_names)
190 mock_get_all_ngw_units.return_value = all_ngw_units
191 mock_get_unit_resource_list.side_effect = get_resource_lists()
192
193 ngw_verifier = get_ngw_verifier()
194
195 # host0 being shutdown, with no redundancy for its routers (router0, router1)
196 result = ngw_verifier.check_non_redundant_resource("get-status-routers")
197 assert result.success is False
198
199 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
200 all_ngw_host_names)
201 mock_get_all_ngw_units.return_value = all_ngw_units
202 mock_get_unit_resource_list.side_effect = get_resource_lists()
203
204 ngw_verifier = get_ngw_verifier()
205
206 # add redundancy (but not HA) for router0, router1 onto non-shutdown hosts
207 mock_data[1]["routers"].append({"id": "router0", "ha": False, "status": "ACTIVE"})
208 mock_data[2]["routers"].append({"id": "router1", "ha": False, "status": "ACTIVE"})
209 mock_get_unit_resource_list.side_effect = get_resource_lists()
210 result = ngw_verifier.check_non_redundant_resource("get-status-routers")
211 assert result.success
212
213 # test setting redundant redundant router0 to NOTACTIVE will result in failure
214 mock_data[1]["routers"][-1]["status"] = "NOTACTIVE"
215 mock_get_unit_resource_list.side_effect = get_resource_lists()
216 result = ngw_verifier.check_non_redundant_resource("get-status-routers")
217 assert result.success is False
218
219 # test shutdown host1, which will take down the redundant router0
220 mock_data[1]["shutdown"] = True
221 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
222 all_ngw_host_names)
223 mock_get_all_ngw_units.return_value = all_ngw_units
224 mock_get_unit_resource_list.side_effect = get_resource_lists()
225
226 ngw_verifier = get_ngw_verifier()
227 result = ngw_verifier.check_non_redundant_resource("get-status-routers")
228 assert result.success is False
229
230 # reset shutdown for next tests
231 mock_data[1]["shutdown"] = False
232
233
234@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_resource_list")
235@mock.patch("juju_verify.verifiers.neutron_gateway.NeutronGateway.get_all_ngw_units")
236@mock.patch("juju_verify.verifiers.neutron_gateway.get_unit_hostname")
237def test_warn_router_ha(mock_get_unit_hostname,
238 mock_get_all_ngw_units,
239 mock_get_unit_resource_list):
240 """Test existence of warning messages to manually failover HA routers when found."""
241 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
242 all_ngw_host_names)
243 mock_get_all_ngw_units.return_value = all_ngw_units
244 mock_get_unit_resource_list.side_effect = get_resource_lists()
245
246 ngw_verifier = get_ngw_verifier()
247
248 result = ngw_verifier.warn_router_ha()
249 # no HA to failover, lack of redundancy is detected by check_non_redundant_resource
250 assert result.reason == ""
251
252 # Find router0 set it to HA
253 for host in mock_data:
254 for router in host["routers"]:
255 if router["id"] == "router0":
256 router["ha"] = True
257
258 mock_get_unit_hostname.side_effect = (get_shutdown_host_name_list() +
259 all_ngw_host_names)
260 mock_get_all_ngw_units.return_value = all_ngw_units
261 mock_get_unit_resource_list.side_effect = get_resource_lists()
262
263 ngw_verifier = get_ngw_verifier()
264
265 result = ngw_verifier.warn_router_ha()
266 # router is in HA, given instructions to failover
267 assert result.reason
268
269
270@mock.patch("juju_verify.verifiers.neutron_gateway.NeutronGateway.check_non_redundant_resource") # noqa: E501 pylint: disable=C0301
271@mock.patch("juju_verify.verifiers.neutron_gateway.NeutronGateway.warn_router_ha")
272@mock.patch("juju_verify.verifiers.neutron_gateway.aggregate_results")
273def test_verify_reboot_shutdown(mock_aggregate_results,
274 mock_warn_router_ha,
275 mock_check_non_redundant_resource):
276 """Test that reboot/shutdown call appropriate checks."""
277 ngw_verifier = get_ngw_verifier()
278 ngw_verifier.verify_reboot()
279 assert mock_check_non_redundant_resource.call_count == 3
280 mock_warn_router_ha.assert_called_once()
281 mock_aggregate_results.assert_called_once()
282
283 mock_check_non_redundant_resource.reset_mock()
284 mock_warn_router_ha.reset_mock()
285 mock_aggregate_results.reset_mock()
286
287 ngw_verifier.verify_shutdown()
288 mock_warn_router_ha.assert_called_once()
289 assert mock_check_non_redundant_resource.call_count == 3
290 mock_aggregate_results.assert_called_once()
291
292
293@mock.patch("juju_verify.verifiers.neutron_gateway.run_action_on_unit")
294@mock.patch("juju_verify.verifiers.neutron_gateway.data_from_action")
295def test_get_unit_hostname(mock_data_from_action, mock_run_action_on_unit):
296 """Test getting remote Unit's hostname."""
297 get_unit_hostname(all_ngw_units[0])
298 mock_run_action_on_unit.assert_called_once()
299 mock_data_from_action.assert_called_once()
300
301
302@mock.patch("juju_verify.verifiers.neutron_gateway.run_action_on_unit")
303@mock.patch("juju_verify.verifiers.neutron_gateway.data_from_action")
304def test_get_unit_resource_list(mock_data_from_action, mock_run_action_on_unit):
305 """Test Neutron agent resources are retrieved via Juju actions."""
306 resource = {"routers": [{"id": "r1"}]}
307 mock_data_from_action.return_value = json.dumps(resource)
308 resource_list = get_unit_resource_list(all_ngw_units[0], "get-status-routers")
309 mock_run_action_on_unit.assert_called_once()
310 assert resource == resource_list

Subscribers

People subscribed via source and target branches