|
1 This upstream patch addresses CVE-2014-3608 and is tracked under Launchpad |
|
2 bug 1319182. It is addressed in Juno 2014.2 and Icehouse 2014.1.3. It has |
|
3 been modified to apply cleanly into our current Havana implementation. |
|
4 |
|
5 From 8ff170dc95bf3101fe38a2624e941bfa3b7c1138 Mon Sep 17 00:00:00 2001 |
|
6 From: "Leandro I. Costantino" <[email protected]> |
|
7 Date: Mon, 19 May 2014 19:58:47 -0300 |
|
8 Subject: [PATCH] VM in rescue state must have a restricted set of actions |
|
9 |
|
10 Right now it is possible to pause, suspend and stop a VM in state RESCUED, |
|
11 so after the state is changed, it's not possible to trigger unrescue anymore |
|
12 since the original state is lost. |
|
13 |
|
14 This patch remove vm_states.RESCUED as valid state from stop, |
|
15 pause and suspend actions. |
|
16 |
|
17 The vm_states devref is also updated to reflect this change including the |
|
18 current reboot flow.( vm_states.RESCUED cannot be rebooted as per |
|
19 today code) |
|
20 |
|
21 DocImpact |
|
22 Closes-Bug: #1319182 |
|
23 Co-Authored-By: Cyril Roelandt <[email protected]> |
|
24 Change-Id: I531dea5a5499bf93c24bea37850d562134dee281 |
|
25 --- |
|
26 doc/source/devref/vmstates.rst | 7 ++++-- |
|
27 nova/compute/api.py | 7 +++--- |
|
28 nova/tests/compute/test_compute_api.py | 46 ++++++++++++++++++++++++++++++++-- |
|
29 3 files changed, 52 insertions(+), 8 deletions(-) |
|
30 |
|
31 --- nova-2013.2.3/doc/source/devref/vmstates.rst 2014-04-03 11:49:38.000000000 -0700 |
|
32 +++ nova-2013.2.3/doc/source/devref/vmstates.rst 2014-09-29 10:32:35.921504377 -0700 |
|
33 @@ -88,6 +88,7 @@ |
|
34 rescue -> error |
|
35 active -> rescue |
|
36 stopped -> rescue |
|
37 + error -> rescue |
|
38 |
|
39 unrescue [shape="rectangle"] |
|
40 unrescue -> active |
|
41 @@ -139,7 +140,9 @@ |
|
42 reboot -> error |
|
43 active -> reboot |
|
44 stopped -> reboot |
|
45 - rescued -> reboot |
|
46 + paused -> reboot |
|
47 + suspended -> reboot |
|
48 + error -> reboot |
|
49 |
|
50 live_migrate [shape="rectangle"] |
|
51 live_migrate -> active |
|
52 @@ -159,4 +162,4 @@ |
|
53 power states when a new VM instance is created. |
|
54 |
|
55 |
|
56 -.. image:: /images/run_instance_walkthrough.png |
|
57 \ No newline at end of file |
|
58 +.. image:: /images/run_instance_walkthrough.png |
|
59 --- nova-2013.2.3/nova/compute/api.py 2014-04-03 11:49:46.000000000 -0700 |
|
60 +++ nova-2013.2.3/nova/compute/api.py 2014-09-29 10:32:50.868945930 -0700 |
|
61 @@ -1619,8 +1619,7 @@ |
|
62 @check_instance_lock |
|
63 @check_instance_host |
|
64 @check_instance_cell |
|
65 - @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED, |
|
66 - vm_states.ERROR], |
|
67 + @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED], |
|
68 task_state=[None]) |
|
69 def stop(self, context, instance, do_cast=True): |
|
70 """Stop an instance.""" |
|
71 @@ -2429,7 +2428,7 @@ |
|
72 @wrap_check_policy |
|
73 @check_instance_lock |
|
74 @check_instance_cell |
|
75 - @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED]) |
|
76 + @check_instance_state(vm_state=[vm_states.ACTIVE]) |
|
77 def pause(self, context, instance): |
|
78 """Pause the given instance.""" |
|
79 instance.task_state = task_states.PAUSING |
|
80 @@ -2456,7 +2455,7 @@ |
|
81 @wrap_check_policy |
|
82 @check_instance_lock |
|
83 @check_instance_cell |
|
84 - @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.RESCUED]) |
|
85 + @check_instance_state(vm_state=[vm_states.ACTIVE]) |
|
86 def suspend(self, context, instance): |
|
87 """Suspend the given instance.""" |
|
88 instance.task_state = task_states.SUSPENDING |
|
89 --- nova-2013.2.3/nova/tests/compute/test_compute_api.py 2014-04-03 11:49:46.000000000 -0700 |
|
90 +++ nova-2013.2.3/nova/tests/compute/test_compute_api.py 2014-09-29 10:32:35.926521781 -0700 |
|
91 @@ -56,6 +56,16 @@ |
|
92 self.context = context.RequestContext(self.user_id, |
|
93 self.project_id) |
|
94 |
|
95 + def _get_vm_states(self, exclude_states=None): |
|
96 + vm_state = set([vm_states.ACTIVE, vm_states.BUILDING, vm_states.PAUSED, |
|
97 + vm_states.SUSPENDED, vm_states.RESCUED, vm_states.STOPPED, |
|
98 + vm_states.RESIZED, vm_states.SOFT_DELETED, |
|
99 + vm_states.DELETED, vm_states.ERROR, vm_states.SHELVED, |
|
100 + vm_states.SHELVED_OFFLOADED]) |
|
101 + if not exclude_states: |
|
102 + exclude_states = set() |
|
103 + return vm_state - exclude_states |
|
104 + |
|
105 def _create_flavor(self, params=None): |
|
106 flavor = {'id': 1, |
|
107 'flavorid': 1, |
|
108 @@ -193,6 +203,19 @@ |
|
109 self.assertEqual(task_states.SUSPENDING, |
|
110 instance.task_state) |
|
111 |
|
112 + def _test_suspend_fails(self, vm_state): |
|
113 + params = dict(vm_state=vm_state) |
|
114 + instance = self._create_instance_obj(params=params) |
|
115 + self.assertIsNone(instance.task_state) |
|
116 + self.assertRaises(exception.InstanceInvalidState, |
|
117 + self.compute_api.suspend, |
|
118 + self.context, instance) |
|
119 + |
|
120 + def test_suspend_fails_invalid_states(self): |
|
121 + invalid_vm_states = self._get_vm_states(set([vm_states.ACTIVE])) |
|
122 + for state in invalid_vm_states: |
|
123 + self._test_suspend_fails(state) |
|
124 + |
|
125 def test_resume(self): |
|
126 # Ensure instance can be resumed (if suspended). |
|
127 instance = self._create_instance_obj( |
|
128 @@ -298,13 +321,19 @@ |
|
129 def test_stop_stopped_instance_with_bypass(self): |
|
130 self._test_stop(vm_states.STOPPED, force=True) |
|
131 |
|
132 - def test_stop_invalid_state(self): |
|
133 - params = dict(vm_state=vm_states.PAUSED) |
|
134 + def _test_stop_invalid_state(self, vm_state): |
|
135 + params = dict(vm_state=vm_state) |
|
136 instance = self._create_instance_obj(params=params) |
|
137 self.assertRaises(exception.InstanceInvalidState, |
|
138 self.compute_api.stop, |
|
139 self.context, instance) |
|
140 |
|
141 + def test_stop_fails_invalid_states(self): |
|
142 + invalid_vm_states = self._get_vm_states(set([vm_states.ACTIVE, |
|
143 + vm_states.ERROR])) |
|
144 + for state in invalid_vm_states: |
|
145 + self._test_stop_invalid_state(state) |
|
146 + |
|
147 def test_stop_a_stopped_inst(self): |
|
148 params = {'vm_state': vm_states.STOPPED} |
|
149 instance = self._create_instance_obj(params=params) |
|
150 @@ -1075,6 +1104,19 @@ |
|
151 self.assertEqual(task_states.PAUSING, |
|
152 instance.task_state) |
|
153 |
|
154 + def _test_pause_fails(self, vm_state): |
|
155 + params = dict(vm_state=vm_state) |
|
156 + instance = self._create_instance_obj(params=params) |
|
157 + self.assertIsNone(instance.task_state) |
|
158 + self.assertRaises(exception.InstanceInvalidState, |
|
159 + self.compute_api.pause, |
|
160 + self.context, instance) |
|
161 + |
|
162 + def test_pause_fails_invalid_states(self): |
|
163 + invalid_vm_states = self._get_vm_states(set([vm_states.ACTIVE])) |
|
164 + for state in invalid_vm_states: |
|
165 + self._test_pause_fails(state) |
|
166 + |
|
167 def test_unpause(self): |
|
168 # Ensure instance can be unpaused. |
|
169 params = dict(vm_state=vm_states.PAUSED) |