Merge lp:~rvb/gwacl/fix-destroydeploy2 into lp:gwacl
- fix-destroydeploy2
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Raphaël Badin |
Approved revision: | 166 |
Merged at revision: | 163 |
Proposed branch: | lp:~rvb/gwacl/fix-destroydeploy2 |
Merge into: | lp:gwacl |
Diff against target: |
257 lines (+33/-102) 3 files modified
example/management/run.go (+4/-18) management.go (+9/-19) management_test.go (+20/-65) |
To merge this branch: | bzr merge lp:~rvb/gwacl/fix-destroydeploy2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella | Approve | ||
Review via email: mp+173095@code.launchpad.net |
Commit message
Do not attempt to stop the VMs inside DestroyDeployment.
Description of the change
I found that it's quicker a more reliable to just delete the deployment instead of trying to shutdown the VMs when destroying a deployment. When we delete the deployment object, the VMs are shut down are removed. The only thing left are the disks.
Added bonus: the testing becomes simpler as we issue less API requests.
Julian Edwards (julian-edwards) wrote : | # |
On Thursday 04 Jul 2013 22:17:24 you wrote:
> Review: Approve
>
> I surprised this works, but looks good.
Me too, it doesn't work in the UI!
Raphaël Badin (rvb) wrote : | # |
> On Thursday 04 Jul 2013 22:17:24 you wrote:
> > Review: Approve
> >
> > I surprised this works, but looks good.
Surprisingly, it seems to be very reliable and the only long operation is removing the disk(s) (takes ~10 minutes for one disk). Can you confirm that it works fine for you too?
> Me too, it doesn't work in the UI!
Hum, AFAIK deployments are not exposed as first-class objects in the UI so how can you say that it does not work in the UI?
In the UI, when you delete a cloud service with a deployment in it, you get a popup to ask you if you want to delete the deployment as well. That's how I got the idea for this branch (this uses the API to mimic this behavior — plus the removal of the disks).
Also, the doc page for "delete hosted service" mentions that you have to delete the deployments inside the service before you can get rid of the service (http://
Julian Edwards (julian-edwards) wrote : | # |
On Friday 05 Jul 2013 05:57:25 you wrote:
> > On Thursday 04 Jul 2013 22:17:24 you wrote:
> > > Review: Approve
> > >
> > > I surprised this works, but looks good.
>
> Surprisingly, it seems to be very reliable and the only long operation is
> removing the disk(s) (takes ~10 minutes for one disk). Can you confirm
> that it works fine for you too?
> > Me too, it doesn't work in the UI!
>
> Hum, AFAIK deployments are not exposed as first-class objects in the UI so
> how can you say that it does not work in the UI?
I'm talking about deleting the service.
Preview Diff
1 | === modified file 'example/management/run.go' | |||
2 | --- example/management/run.go 2013-07-02 13:53:21 +0000 | |||
3 | +++ example/management/run.go 2013-07-04 20:25:31 +0000 | |||
4 | @@ -172,17 +172,10 @@ | |||
5 | 172 | fmt.Println("Done adding VM deployment\n") | 172 | fmt.Println("Done adding VM deployment\n") |
6 | 173 | 173 | ||
7 | 174 | defer func() { | 174 | defer func() { |
19 | 175 | fmt.Println("Deleting VM disk...") | 175 | fmt.Printf("Destroying deployment %s...\n", machineName) |
20 | 176 | err = api.DeleteDisk(diskName) | 176 | requestDestroyDeployment := &gwacl.DestroyDeploymentRequest{ServiceName: hostServiceName, DeploymentName: machineName} |
21 | 177 | checkError(err) | 177 | api.DestroyDeployment(requestDestroyDeployment) |
22 | 178 | fmt.Println("Done deleting VM disk\n") | 178 | fmt.Println("Done destroying deployment\n") |
12 | 179 | }() | ||
13 | 180 | |||
14 | 181 | defer func() { | ||
15 | 182 | fmt.Println("Deleting deployment...") | ||
16 | 183 | err = api.DeleteDeployment(hostServiceName, deployment.Name) | ||
17 | 184 | checkError(err) | ||
18 | 185 | fmt.Println("Done deleting deployment\n") | ||
23 | 186 | }() | 179 | }() |
24 | 187 | 180 | ||
25 | 188 | fmt.Println("Starting VM...") | 181 | fmt.Println("Starting VM...") |
26 | @@ -190,13 +183,6 @@ | |||
27 | 190 | checkError(err) | 183 | checkError(err) |
28 | 191 | fmt.Println("Done starting VM\n") | 184 | fmt.Println("Done starting VM\n") |
29 | 192 | 185 | ||
30 | 193 | defer func() { | ||
31 | 194 | fmt.Println("Stopping VM...") | ||
32 | 195 | err = api.ShutdownRole(&gwacl.ShutdownRoleRequest{hostServiceName, deployment.Name, role.RoleName}) | ||
33 | 196 | checkError(err) | ||
34 | 197 | fmt.Println("Done stopping VM\n") | ||
35 | 198 | }() | ||
36 | 199 | |||
37 | 200 | fmt.Println("Listing VM...") | 186 | fmt.Println("Listing VM...") |
38 | 201 | instances, err := api.ListInstances(&gwacl.ListInstancesRequest{hostServiceName}) | 187 | instances, err := api.ListInstances(&gwacl.ListInstancesRequest{hostServiceName}) |
39 | 202 | checkError(err) | 188 | checkError(err) |
40 | 203 | 189 | ||
41 | === modified file 'management.go' | |||
42 | --- management.go 2013-07-04 09:53:30 +0000 | |||
43 | +++ management.go 2013-07-04 20:25:31 +0000 | |||
44 | @@ -102,7 +102,7 @@ | |||
45 | 102 | } | 102 | } |
46 | 103 | 103 | ||
47 | 104 | // DestroyDeployment brings down all resources within a deployment - running | 104 | // DestroyDeployment brings down all resources within a deployment - running |
49 | 105 | // instances, disks, etc. - then deletes the deployment itself. | 105 | // instances, disks, etc. - and deletes the deployment itself. |
50 | 106 | func (api *ManagementAPI) DestroyDeployment(request *DestroyDeploymentRequest) error { | 106 | func (api *ManagementAPI) DestroyDeployment(request *DestroyDeploymentRequest) error { |
51 | 107 | deployment, err := api.GetDeployment(&GetDeploymentRequest{ | 107 | deployment, err := api.GetDeployment(&GetDeploymentRequest{ |
52 | 108 | ServiceName: request.ServiceName, | 108 | ServiceName: request.ServiceName, |
53 | @@ -114,42 +114,32 @@ | |||
54 | 114 | } | 114 | } |
55 | 115 | return err | 115 | return err |
56 | 116 | } | 116 | } |
69 | 117 | // 1. Stop VMs. | 117 | // 1. Get the list of the VM disks. |
58 | 118 | for _, roleInstance := range deployment.RoleInstanceList { | ||
59 | 119 | err = api.ShutdownRole(&ShutdownRoleRequest{ | ||
60 | 120 | ServiceName: request.ServiceName, | ||
61 | 121 | DeploymentName: request.DeploymentName, | ||
62 | 122 | RoleName: roleInstance.RoleName, | ||
63 | 123 | }) | ||
64 | 124 | if err != nil && !IsNotFoundError(err) { | ||
65 | 125 | return err | ||
66 | 126 | } | ||
67 | 127 | } | ||
68 | 128 | // 2. Delete VM disks. | ||
70 | 129 | diskNameMap := make(map[string]bool) | 118 | diskNameMap := make(map[string]bool) |
71 | 130 | for _, role := range deployment.RoleList { | 119 | for _, role := range deployment.RoleList { |
72 | 131 | for _, osVHD := range role.OSVirtualHardDisk { | 120 | for _, osVHD := range role.OSVirtualHardDisk { |
73 | 132 | diskNameMap[osVHD.DiskName] = true | 121 | diskNameMap[osVHD.DiskName] = true |
74 | 133 | } | 122 | } |
75 | 134 | } | 123 | } |
76 | 124 | // 2. Delete deployment. This will delete all the role instances inside | ||
77 | 125 | // this deployment as a side effect. | ||
78 | 126 | err = api.DeleteDeployment(request.ServiceName, request.DeploymentName) | ||
79 | 127 | if err != nil && !IsNotFoundError(err) { | ||
80 | 128 | return err | ||
81 | 129 | } | ||
82 | 135 | // Sort the disk names to aid testing. | 130 | // Sort the disk names to aid testing. |
83 | 136 | diskNames := []string{} | 131 | diskNames := []string{} |
84 | 137 | for diskName := range diskNameMap { | 132 | for diskName := range diskNameMap { |
85 | 138 | diskNames = append(diskNames, diskName) | 133 | diskNames = append(diskNames, diskName) |
86 | 139 | } | 134 | } |
87 | 140 | sort.Strings(diskNames) | 135 | sort.Strings(diskNames) |
89 | 141 | // Actually delete them. | 136 | // 3. Delete the disks. |
90 | 142 | for _, diskName := range diskNames { | 137 | for _, diskName := range diskNames { |
91 | 143 | err = api.DeleteDisk(diskName) | 138 | err = api.DeleteDisk(diskName) |
92 | 144 | if err != nil && !IsNotFoundError(err) { | 139 | if err != nil && !IsNotFoundError(err) { |
93 | 145 | return err | 140 | return err |
94 | 146 | } | 141 | } |
95 | 147 | } | 142 | } |
96 | 148 | // 3. Delete deployment. | ||
97 | 149 | err = api.DeleteDeployment(request.ServiceName, request.DeploymentName) | ||
98 | 150 | if err != nil && !IsNotFoundError(err) { | ||
99 | 151 | return err | ||
100 | 152 | } | ||
101 | 153 | // Done. | 143 | // Done. |
102 | 154 | return nil | 144 | return nil |
103 | 155 | } | 145 | } |
104 | 156 | 146 | ||
105 | === modified file 'management_test.go' | |||
106 | --- management_test.go 2013-07-04 10:53:40 +0000 | |||
107 | +++ management_test.go 2013-07-04 20:25:31 +0000 | |||
108 | @@ -250,12 +250,10 @@ | |||
109 | 250 | var responses []DispatcherResponse | 250 | var responses []DispatcherResponse |
110 | 251 | // Prepare. | 251 | // Prepare. |
111 | 252 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) | 252 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) |
117 | 253 | // For shutting down VMs. | 253 | // For deleting the deployment. |
113 | 254 | responses = append(responses, exampleOkayResponse, exampleOkayResponse) | ||
114 | 255 | // For deleting disks. | ||
115 | 256 | responses = append(responses, exampleOkayResponse, exampleOkayResponse, exampleOkayResponse) | ||
116 | 257 | // For other requests. | ||
118 | 258 | responses = append(responses, exampleOkayResponse) | 254 | responses = append(responses, exampleOkayResponse) |
119 | 255 | // For deleting disks. | ||
120 | 256 | responses = append(responses, exampleOkayResponse, exampleOkayResponse, exampleOkayResponse) | ||
121 | 259 | record := []*X509Request{} | 257 | record := []*X509Request{} |
122 | 260 | rigRecordingPreparedResponseDispatcher(&record, responses) | 258 | rigRecordingPreparedResponseDispatcher(&record, responses) |
123 | 261 | // Exercise DestroyDeployment. | 259 | // Exercise DestroyDeployment. |
124 | @@ -266,23 +264,14 @@ | |||
125 | 266 | } | 264 | } |
126 | 267 | err := api.DestroyDeployment(request) | 265 | err := api.DestroyDeployment(request) |
127 | 268 | c.Assert(err, IsNil) | 266 | c.Assert(err, IsNil) |
130 | 269 | c.Check(record, HasLen, 7) | 267 | c.Check(record, HasLen, 5) |
129 | 270 | // The first request is for the deployment. | ||
131 | 271 | assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ | 268 | assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ |
132 | 272 | request.ServiceName, request.DeploymentName}, record[0]) | 269 | request.ServiceName, request.DeploymentName}, record[0]) |
133 | 273 | // The second is to shutdown RoleInstance "one". | ||
134 | 274 | assertShutdownRoleRequest(c, api, &ShutdownRoleRequest{ | ||
135 | 275 | request.ServiceName, request.DeploymentName, "one"}, record[1]) | ||
136 | 276 | // The third is to shutdown RoleInstance "two", similar to like the second. | ||
137 | 277 | assertShutdownRoleRequest(c, api, &ShutdownRoleRequest{ | ||
138 | 278 | request.ServiceName, request.DeploymentName, "two"}, record[2]) | ||
139 | 279 | // The fourth, fifth and sixth requests delete disks. | ||
140 | 280 | assertDeleteDiskRequest(c, api, "disk1", record[3]) | ||
141 | 281 | assertDeleteDiskRequest(c, api, "disk2", record[4]) | ||
142 | 282 | assertDeleteDiskRequest(c, api, "disk3", record[5]) | ||
143 | 283 | // The fourth request deletes the deployment. | ||
144 | 284 | assertDeleteDeploymentRequest(c, api, request.ServiceName, | 270 | assertDeleteDeploymentRequest(c, api, request.ServiceName, |
146 | 285 | request.DeploymentName, record[6]) | 271 | request.DeploymentName, record[1]) |
147 | 272 | assertDeleteDiskRequest(c, api, "disk1", record[2]) | ||
148 | 273 | assertDeleteDiskRequest(c, api, "disk2", record[3]) | ||
149 | 274 | assertDeleteDiskRequest(c, api, "disk3", record[4]) | ||
150 | 286 | } | 275 | } |
151 | 287 | 276 | ||
152 | 288 | func (suite *suiteDestroyDeployment) TestOkayWhenDeploymentNotFound(c *C) { | 277 | func (suite *suiteDestroyDeployment) TestOkayWhenDeploymentNotFound(c *C) { |
153 | @@ -306,12 +295,10 @@ | |||
154 | 306 | var responses []DispatcherResponse | 295 | var responses []DispatcherResponse |
155 | 307 | // Prepare. | 296 | // Prepare. |
156 | 308 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) | 297 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) |
160 | 309 | // For shutting down VMs. | 298 | // For deleting the deployment. |
161 | 310 | responses = append(responses, exampleNotFoundResponse, exampleNotFoundResponse) | 299 | responses = append(responses, exampleNotFoundResponse) |
162 | 311 | // For deleting disks. | 300 | // For deleting the disks. |
163 | 312 | responses = append(responses, exampleNotFoundResponse, exampleNotFoundResponse, exampleNotFoundResponse) | 301 | responses = append(responses, exampleNotFoundResponse, exampleNotFoundResponse, exampleNotFoundResponse) |
164 | 313 | // For other requests. | ||
165 | 314 | responses = append(responses, exampleNotFoundResponse) | ||
166 | 315 | record := []*X509Request{} | 302 | record := []*X509Request{} |
167 | 316 | rigRecordingPreparedResponseDispatcher(&record, responses) | 303 | rigRecordingPreparedResponseDispatcher(&record, responses) |
168 | 317 | // Exercise DestroyDeployment. | 304 | // Exercise DestroyDeployment. |
169 | @@ -322,23 +309,14 @@ | |||
170 | 322 | } | 309 | } |
171 | 323 | err := api.DestroyDeployment(request) | 310 | err := api.DestroyDeployment(request) |
172 | 324 | c.Assert(err, IsNil) | 311 | c.Assert(err, IsNil) |
175 | 325 | c.Check(record, HasLen, 7) | 312 | c.Check(record, HasLen, 5) |
174 | 326 | // The first request is for the deployment. | ||
176 | 327 | assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ | 313 | assertGetDeploymentRequest(c, api, &GetDeploymentRequest{ |
177 | 328 | request.ServiceName, request.DeploymentName}, record[0]) | 314 | request.ServiceName, request.DeploymentName}, record[0]) |
178 | 329 | // The second is to shutdown RoleInstance "one". | ||
179 | 330 | assertShutdownRoleRequest(c, api, &ShutdownRoleRequest{ | ||
180 | 331 | request.ServiceName, request.DeploymentName, "one"}, record[1]) | ||
181 | 332 | // The third is to shutdown RoleInstance "two", similar to like the second. | ||
182 | 333 | assertShutdownRoleRequest(c, api, &ShutdownRoleRequest{ | ||
183 | 334 | request.ServiceName, request.DeploymentName, "two"}, record[2]) | ||
184 | 335 | // The fourth, fifth and sixth requests delete disks. | ||
185 | 336 | assertDeleteDiskRequest(c, api, "disk1", record[3]) | ||
186 | 337 | assertDeleteDiskRequest(c, api, "disk2", record[4]) | ||
187 | 338 | assertDeleteDiskRequest(c, api, "disk3", record[5]) | ||
188 | 339 | // The fourth request deletes the deployment. | ||
189 | 340 | assertDeleteDeploymentRequest(c, api, request.ServiceName, | 315 | assertDeleteDeploymentRequest(c, api, request.ServiceName, |
191 | 341 | request.DeploymentName, record[6]) | 316 | request.DeploymentName, record[1]) |
192 | 317 | assertDeleteDiskRequest(c, api, "disk1", record[2]) | ||
193 | 318 | assertDeleteDiskRequest(c, api, "disk2", record[3]) | ||
194 | 319 | assertDeleteDiskRequest(c, api, "disk3", record[4]) | ||
195 | 342 | } | 320 | } |
196 | 343 | 321 | ||
197 | 344 | func (suite *suiteDestroyDeployment) TestFailsGettingDeployment(c *C) { | 322 | func (suite *suiteDestroyDeployment) TestFailsGettingDeployment(c *C) { |
198 | @@ -359,10 +337,11 @@ | |||
199 | 359 | c.Check(record, HasLen, 1) | 337 | c.Check(record, HasLen, 1) |
200 | 360 | } | 338 | } |
201 | 361 | 339 | ||
203 | 362 | func (suite *suiteDestroyDeployment) TestFailsShuttingDownRole(c *C) { | 340 | func (suite *suiteDestroyDeployment) TestFailsDeletingDisk(c *C) { |
204 | 363 | var responses []DispatcherResponse | 341 | var responses []DispatcherResponse |
205 | 364 | // Prepare. | 342 | // Prepare. |
206 | 365 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) | 343 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) |
207 | 344 | // For deleting disks. | ||
208 | 366 | responses = append(responses, exampleFailResponse) | 345 | responses = append(responses, exampleFailResponse) |
209 | 367 | record := []*X509Request{} | 346 | record := []*X509Request{} |
210 | 368 | rigRecordingPreparedResponseDispatcher(&record, responses) | 347 | rigRecordingPreparedResponseDispatcher(&record, responses) |
211 | @@ -374,38 +353,14 @@ | |||
212 | 374 | } | 353 | } |
213 | 375 | err := api.DestroyDeployment(request) | 354 | err := api.DestroyDeployment(request) |
214 | 376 | c.Assert(err, NotNil) | 355 | c.Assert(err, NotNil) |
216 | 377 | c.Check(err, ErrorMatches, "POST request failed [(]500: Internal Server Error[)]") | 356 | c.Check(err, ErrorMatches, "DELETE request failed [(]500: Internal Server Error[)]") |
217 | 378 | c.Check(record, HasLen, 2) | 357 | c.Check(record, HasLen, 2) |
218 | 379 | } | 358 | } |
219 | 380 | 359 | ||
220 | 381 | func (suite *suiteDestroyDeployment) TestFailsDeletingDisk(c *C) { | ||
221 | 382 | var responses []DispatcherResponse | ||
222 | 383 | // Prepare. | ||
223 | 384 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) | ||
224 | 385 | // For shutting down VMs. | ||
225 | 386 | responses = append(responses, exampleOkayResponse, exampleOkayResponse) | ||
226 | 387 | // For deleting disks. | ||
227 | 388 | responses = append(responses, exampleFailResponse) | ||
228 | 389 | record := []*X509Request{} | ||
229 | 390 | rigRecordingPreparedResponseDispatcher(&record, responses) | ||
230 | 391 | // Exercise DestroyDeployment. | ||
231 | 392 | api := makeAPI(c) | ||
232 | 393 | request := &DestroyDeploymentRequest{ | ||
233 | 394 | ServiceName: "service-name", | ||
234 | 395 | DeploymentName: "deployment-name", | ||
235 | 396 | } | ||
236 | 397 | err := api.DestroyDeployment(request) | ||
237 | 398 | c.Assert(err, NotNil) | ||
238 | 399 | c.Check(err, ErrorMatches, "DELETE request failed [(]500: Internal Server Error[)]") | ||
239 | 400 | c.Check(record, HasLen, 4) | ||
240 | 401 | } | ||
241 | 402 | |||
242 | 403 | func (suite *suiteDestroyDeployment) TestFailsDeletingDeployment(c *C) { | 360 | func (suite *suiteDestroyDeployment) TestFailsDeletingDeployment(c *C) { |
243 | 404 | var responses []DispatcherResponse | 361 | var responses []DispatcherResponse |
244 | 405 | // Prepare. | 362 | // Prepare. |
245 | 406 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) | 363 | responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...) |
246 | 407 | // For shutting down VMs. | ||
247 | 408 | responses = append(responses, exampleOkayResponse, exampleOkayResponse) | ||
248 | 409 | // For deleting disks. | 364 | // For deleting disks. |
249 | 410 | responses = append(responses, exampleOkayResponse, exampleOkayResponse, exampleOkayResponse) | 365 | responses = append(responses, exampleOkayResponse, exampleOkayResponse, exampleOkayResponse) |
250 | 411 | // For other requests. | 366 | // For other requests. |
251 | @@ -421,5 +376,5 @@ | |||
252 | 421 | err := api.DestroyDeployment(request) | 376 | err := api.DestroyDeployment(request) |
253 | 422 | c.Assert(err, NotNil) | 377 | c.Assert(err, NotNil) |
254 | 423 | c.Check(err, ErrorMatches, "DELETE request failed [(]500: Internal Server Error[)]") | 378 | c.Check(err, ErrorMatches, "DELETE request failed [(]500: Internal Server Error[)]") |
256 | 424 | c.Check(record, HasLen, 7) | 379 | c.Check(record, HasLen, 5) |
257 | 425 | } | 380 | } |
I surprised this works, but looks good.