Skip to content

Commit 7538791

Browse files
authored
Merge pull request openstack-charmers#145 from gnuoy/add-openstack-upgrade-lib
Add functions for performing OpenStack upgrades
2 parents 6f446a2 + 4af37d9 commit 7538791

File tree

2 files changed

+644
-0
lines changed

2 files changed

+644
-0
lines changed
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
# Copyright 2019 Canonical Ltd.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import copy
16+
import mock
17+
18+
import unit_tests.utils as ut_utils
19+
import zaza.openstack.utilities.openstack_upgrade as openstack_upgrade
20+
21+
22+
class TestOpenStackUpgradeUtils(ut_utils.BaseTestCase):
23+
24+
async def _arun_action_on_units(self, units, cmd, model_name=None,
25+
raise_on_failure=True):
26+
pass
27+
28+
def setUp(self):
29+
super(TestOpenStackUpgradeUtils, self).setUp()
30+
self.patch_object(
31+
openstack_upgrade.zaza.model,
32+
"async_run_action_on_units")
33+
self.async_run_action_on_units.side_effect = self._arun_action_on_units
34+
self.patch_object(
35+
openstack_upgrade.zaza.model,
36+
"get_units")
37+
self.juju_status = mock.MagicMock()
38+
self.patch_object(
39+
openstack_upgrade.zaza.model,
40+
"get_status",
41+
return_value=self.juju_status)
42+
self.patch_object(
43+
openstack_upgrade.zaza.model,
44+
"set_application_config")
45+
self.patch_object(
46+
openstack_upgrade.zaza.model,
47+
"get_application_config")
48+
49+
def _get_application_config(app, model_name=None):
50+
app_config = {
51+
'ceph-mon': {'verbose': True, 'source': 'old-src'},
52+
'neutron-openvswitch': {'verbose': True},
53+
'ntp': {'verbose': True},
54+
'percona-cluster': {'verbose': True, 'source': 'old-src'},
55+
'cinder': {
56+
'verbose': True,
57+
'openstack-origin': 'old-src',
58+
'action-managed-upgrade': False},
59+
'neutron-api': {
60+
'verbose': True,
61+
'openstack-origin': 'old-src',
62+
'action-managed-upgrade': False},
63+
'nova-compute': {
64+
'verbose': True,
65+
'openstack-origin': 'old-src',
66+
'action-managed-upgrade': False},
67+
}
68+
return app_config[app]
69+
self.get_application_config.side_effect = _get_application_config
70+
self.juju_status.applications = {
71+
'mydb': { # Filter as it is on UPGRADE_EXCLUDE_LIST
72+
'charm': 'cs:percona-cluster'},
73+
'neutron-openvswitch': { # Filter as it is a subordinates
74+
'charm': 'cs:neutron-openvswitch',
75+
'subordinate-to': 'nova-compute'},
76+
'ntp': { # Filter as it has no source option
77+
'charm': 'cs:ntp'},
78+
'nova-compute': {
79+
'charm': 'cs:nova-compute',
80+
'units': {
81+
'nova-compute/0': {
82+
'subordinates': {
83+
'neutron-openvswitch/2': {
84+
'charm': 'cs:neutron-openvswitch-22'}}}}},
85+
'cinder': {
86+
'charm': 'cs:cinder-23',
87+
'units': {
88+
'cinder/1': {
89+
'subordinates': {
90+
'cinder-hacluster/0': {
91+
'charm': 'cs:hacluster-42'},
92+
'cinder-ceph/3': {
93+
'charm': 'cs:cinder-ceph-2'}}}}}}
94+
95+
def test_pause_units(self):
96+
openstack_upgrade.pause_units(['cinder/1', 'glance/2'])
97+
self.async_run_action_on_units.assert_called_once_with(
98+
['cinder/1', 'glance/2'],
99+
'pause',
100+
model_name=None,
101+
raise_on_failure=True)
102+
103+
def test_resume_units(self):
104+
openstack_upgrade.resume_units(['cinder/1', 'glance/2'])
105+
self.async_run_action_on_units.assert_called_once_with(
106+
['cinder/1', 'glance/2'],
107+
'resume',
108+
model_name=None,
109+
raise_on_failure=True)
110+
111+
def test_action_unit_upgrade(self):
112+
openstack_upgrade.action_unit_upgrade(['cinder/1', 'glance/2'])
113+
self.async_run_action_on_units.assert_called_once_with(
114+
['cinder/1', 'glance/2'],
115+
'openstack-upgrade',
116+
model_name=None,
117+
raise_on_failure=True)
118+
119+
def test_action_upgrade_group(self):
120+
self.patch_object(openstack_upgrade, "pause_units")
121+
self.patch_object(openstack_upgrade, "action_unit_upgrade")
122+
self.patch_object(openstack_upgrade, "resume_units")
123+
mock_nova_compute_0 = mock.MagicMock()
124+
mock_nova_compute_0.entity_id = 'nova-compute/0'
125+
mock_cinder_1 = mock.MagicMock()
126+
mock_cinder_1.entity_id = 'cinder/1'
127+
units = {
128+
'nova-compute': [mock_nova_compute_0],
129+
'cinder': [mock_cinder_1]}
130+
self.get_units.side_effect = lambda app, model_name: units[app]
131+
openstack_upgrade.action_upgrade_group(['nova-compute', 'cinder'])
132+
pause_calls = [
133+
mock.call(['cinder-hacluster/0'], model_name=None),
134+
mock.call(['nova-compute/0', 'cinder/1'], model_name=None)]
135+
self.pause_units.assert_has_calls(pause_calls, any_order=False)
136+
action_unit_upgrade_calls = [
137+
mock.call(['nova-compute/0', 'cinder/1'], model_name=None)]
138+
self.action_unit_upgrade.assert_has_calls(
139+
action_unit_upgrade_calls,
140+
any_order=False)
141+
resume_calls = [
142+
mock.call(['nova-compute/0', 'cinder/1'], model_name=None),
143+
mock.call(['cinder-hacluster/0'], model_name=None)]
144+
self.resume_units.assert_has_calls(resume_calls, any_order=False)
145+
146+
def test_set_upgrade_application_config(self):
147+
openstack_upgrade.set_upgrade_application_config(
148+
['neutron-api', 'cinder'],
149+
'new-src')
150+
set_app_calls = [
151+
mock.call(
152+
'neutron-api',
153+
{
154+
'openstack-origin': 'new-src',
155+
'action-managed-upgrade': 'True'},
156+
model_name=None),
157+
mock.call(
158+
'cinder',
159+
{
160+
'openstack-origin': 'new-src',
161+
'action-managed-upgrade': 'True'},
162+
model_name=None)]
163+
self.set_application_config.assert_has_calls(set_app_calls)
164+
165+
self.set_application_config.reset_mock()
166+
openstack_upgrade.set_upgrade_application_config(
167+
['percona-cluster'],
168+
'new-src',
169+
action_managed=False)
170+
self.set_application_config.assert_called_once_with(
171+
'percona-cluster',
172+
{'source': 'new-src'},
173+
model_name=None)
174+
175+
def test__extract_charm_name_from_url(self):
176+
self.assertEqual(
177+
openstack_upgrade._extract_charm_name_from_url(
178+
'local:bionic/heat-12'),
179+
'heat')
180+
self.assertEqual(
181+
openstack_upgrade._extract_charm_name_from_url(
182+
'cs:bionic/heat-12'),
183+
'heat')
184+
self.assertEqual(
185+
openstack_upgrade._extract_charm_name_from_url('cs:heat'),
186+
'heat')
187+
188+
def test_get_upgrade_candidates(self):
189+
expect = copy.deepcopy(self.juju_status.applications)
190+
del expect['mydb'] # Filter as it is on UPGRADE_EXCLUDE_LIST
191+
del expect['ntp'] # Filter as it has no source option
192+
del expect['neutron-openvswitch'] # Filter as it is a subordinates
193+
self.assertEqual(
194+
openstack_upgrade.get_upgrade_candidates(),
195+
expect)
196+
197+
def test_get_upgrade_groups(self):
198+
self.assertEqual(
199+
openstack_upgrade.get_upgrade_groups(),
200+
{
201+
'Compute': ['nova-compute'],
202+
'Control Plane': ['cinder'],
203+
'Core Identity': [],
204+
'Storage': [],
205+
'sweep_up': []})
206+
207+
def test_is_action_upgradable(self):
208+
self.assertTrue(
209+
openstack_upgrade.is_action_upgradable('cinder'))
210+
self.assertFalse(
211+
openstack_upgrade.is_action_upgradable('percona-cluster'))
212+
213+
def test_run_action_upgrade(self):
214+
self.patch_object(openstack_upgrade, "set_upgrade_application_config")
215+
self.patch_object(openstack_upgrade, "action_upgrade_group")
216+
openstack_upgrade.run_action_upgrade(
217+
['cinder', 'neutron-api'],
218+
'new-src')
219+
self.set_upgrade_application_config.assert_called_once_with(
220+
['cinder', 'neutron-api'],
221+
'new-src',
222+
model_name=None)
223+
self.action_upgrade_group.assert_called_once_with(
224+
['cinder', 'neutron-api'],
225+
model_name=None)
226+
227+
def test_run_all_in_one_upgrade(self):
228+
self.patch_object(openstack_upgrade, "set_upgrade_application_config")
229+
self.patch_object(
230+
openstack_upgrade.zaza.model,
231+
'block_until_all_units_idle')
232+
openstack_upgrade.run_all_in_one_upgrade(
233+
['percona-cluster'],
234+
'new-src')
235+
self.set_upgrade_application_config.assert_called_once_with(
236+
['percona-cluster'],
237+
'new-src',
238+
action_managed=False,
239+
model_name=None)
240+
self.block_until_all_units_idle.assert_called_once_with()
241+
242+
def test_run_upgrade(self):
243+
self.patch_object(openstack_upgrade, "run_all_in_one_upgrade")
244+
self.patch_object(openstack_upgrade, "run_action_upgrade")
245+
openstack_upgrade.run_upgrade(
246+
['cinder', 'neutron-api', 'ceph-mon'],
247+
'new-src')
248+
self.run_all_in_one_upgrade.assert_called_once_with(
249+
['ceph-mon'],
250+
'new-src',
251+
model_name=None)
252+
self.run_action_upgrade.assert_called_once_with(
253+
['cinder', 'neutron-api'],
254+
'new-src',
255+
model_name=None)
256+
257+
def test_run_upgrade_tests(self):
258+
self.patch_object(openstack_upgrade, "run_upgrade")
259+
self.patch_object(openstack_upgrade, "get_upgrade_groups")
260+
self.get_upgrade_groups.return_value = {
261+
'Compute': ['nova-compute'],
262+
'Control Plane': ['cinder', 'neutron-api'],
263+
'Core Identity': ['keystone'],
264+
'Storage': ['ceph-mon'],
265+
'sweep_up': ['designate']}
266+
openstack_upgrade.run_upgrade_tests('new-src', model_name=None)
267+
run_upgrade_calls = [
268+
mock.call(['keystone'], 'new-src', model_name=None),
269+
mock.call(['ceph-mon'], 'new-src', model_name=None),
270+
mock.call(['cinder', 'neutron-api'], 'new-src', model_name=None),
271+
mock.call(['nova-compute'], 'new-src', model_name=None),
272+
mock.call(['designate'], 'new-src', model_name=None)]
273+
self.run_upgrade.assert_has_calls(run_upgrade_calls, any_order=False)

0 commit comments

Comments
 (0)