Merge lp:~allenap/gwacl/destroy-deployment into lp:gwacl

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: 172
Merged at revision: 158
Proposed branch: lp:~allenap/gwacl/destroy-deployment
Merge into: lp:gwacl
Diff against target: 400 lines (+304/-15)
3 files modified
management.go (+62/-0)
management_base_test.go (+38/-15)
management_test.go (+204/-0)
To merge this branch: bzr merge lp:~allenap/gwacl/destroy-deployment
Reviewer Review Type Date Requested Status
Julian Edwards (community) Approve
Review via email: mp+172625@code.launchpad.net

Commit message

New utility method, DestroyDeployment, to delete a deployment and all of its assets.

To post a comment you must log in.
Revision history for this message
Julian Edwards (julian-edwards) wrote :
Download full text (14.5 KiB)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

 review: approve

Thanks, nice change. Looks fine to me, just some minor comments you
can ignore:

> === modified file 'management.go' --- management.go 2013-06-28
> 16:41:40 +0000 +++ management.go 2013-07-02 16:49:33 +0000 @@ -3,6
> +3,10 @@
>
> package gwacl
>
> +import ( + "sort" +) + type ListInstancesRequest struct {
> ServiceName string } @@ -66,3 +70,58 @@ } return deployments, nil
> } + +type DestroyDeploymentRequest struct { + ServiceName
> string + DeploymentName string +}

Since this is identical to GetDeploymentRequest I wonder if we can
have a base DeploymentRequest and then embed it in the other structs,
like this:

type DeploymentRequest struct {
    ServiceName string
    DeploymentName string
}

type DestroyDeploymentRequest struct {
     DeploymentRequest
}

type GetDeploymentRequest {
    DeploymentRequest
}

I think the Role stuff could do this as well, e.g.:

type ShutdownRoleRequest {
    DeploymentRequest
    RoleName string
}

Having said that, it might obfuscate the parameters and confuse
callers. Ho hum.

> + +// DestroyDeployment brings down all resources within a
> deployment - running +// instances, disks, etc. - then deletes the
> deployment itself. +func (api *ManagementAPI)
> DestroyDeployment(request *DestroyDeploymentRequest) error { +
> deployment, err := api.GetDeployment(&GetDeploymentRequest{ +
> ServiceName: request.ServiceName, + DeploymentName:
> request.DeploymentName, + }) + if err != nil { +
> return err + } + // 1. Stop VMs. + for _, roleInstance :=
> range deployment.RoleInstanceList { + err =
> api.ShutdownRole(&ShutdownRoleRequest{ + ServiceName:
> request.ServiceName, + DeploymentName:
> request.DeploymentName, + RoleName:
> roleInstance.RoleName, + }) + if err != nil { +
> return err + } + } + // 2. Delete VM disks. +
> diskNameMap := make(map[string]bool) + for _, role := range
> deployment.RoleList { + for _, osVHD := range
> role.OSVirtualHardDisk { + diskNameMap[osVHD.DiskName] =
> true + } + } + // Sort the disk names to aid testing.
> + diskNames := []string{} + for diskName := range diskNameMap
> { + diskNames = append(diskNames, diskName) + } +
> sort.Strings(diskNames) + // Actually delete them. + for _,
> diskName := range diskNames { + err =
> api.DeleteDisk(diskName) + if err != nil { +
> return err + } + } + // 3. Delete deployment. + err
> = api.DeleteDeployment(request.ServiceName,
> request.DeploymentName) + if err != nil { + return err +
> } + // Done. + return nil +}

Given our experience with random failures leaving half of a deployment
behind I wonder if we can't make this better. But I can't really
think of anything to suggest :/

Perhaps at least make it re-entrant such that repeated calls cope with
partial removals from previous calls? In other words, does something
like ShutdownRole return an error if it's already shut down?

>
> === modified file 'management_base_test.go' ---
> management_base_test.go 2013-07-...

review: Approve
Revision history for this message
Julian Edwards (julian-edwards) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Sigh, something has completely mangled the quoted code.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iEYEARECAAYFAlHTfR0ACgkQWhGlTF8G/He1bQCgozT5tVL1sautJKY3c7nvZoee
gGAAnjEnYMyNfX4wavYB6x82bVBzm5cr
=A/Ao
-----END PGP SIGNATURE-----

Revision history for this message
Raphaël Badin (rvb) wrote :

[0]

35 + // 1. Stop VMs.
36 + for _, roleInstance := range deployment.RoleInstanceList {

I was wondering if it's really required to stop the VM…? because we know for a fact that it fails almost all the time and it takes ~15 minutes.

[1]

> Perhaps at least make it re-entrant such that repeated calls cope with
> partial removals from previous calls? In other words, does something
> like ShutdownRole return an error if it's already shut down?

Very good point, I think this means we should ignore 404 errors when trying to delete stuff.

lp:~allenap/gwacl/destroy-deployment updated
169. By Gavin Panella

Switch from 404 to 500 in test.

170. By Gavin Panella

Succeed when deployment is not found.

171. By Gavin Panella

Remove duplication.

172. By Gavin Panella

Succeed when deployment assets are not found.

Revision history for this message
Gavin Panella (allenap) wrote :

> [0]
>
> 35      +    // 1. Stop VMs.
> 36      +    for _, roleInstance := range deployment.RoleInstanceList {
>
> I was wondering if it's really required to stop the VM…? because we know for a
> fact that it fails almost all the time and it takes ~15 minutes.

I'm going to leave this in for now. One of us can remove it later if
it's really not necessary.

>
> [1]
>
> > Perhaps at least make it re-entrant such that repeated calls cope with
> > partial removals from previous calls? In other words, does something
> > like ShutdownRole return an error if it's already shut down?
>
> Very good point, I think this means we should ignore 404 errors when trying to
> delete stuff.

Done.

Revision history for this message
Gavin Panella (allenap) wrote :

> Since this is identical to GetDeploymentRequest I wonder if we can
> have a base DeploymentRequest and then embed it in the other structs,
> like this:
>
> type DeploymentRequest struct {
>     ServiceName    string
>     DeploymentName string
> }
>
> type DestroyDeploymentRequest struct {
>      DeploymentRequest
> }
>
> type GetDeploymentRequest {
>     DeploymentRequest
> }
>
> I think the Role stuff could do this as well, e.g.:
>
> type ShutdownRoleRequest {
>     DeploymentRequest
>     RoleName string
> }
>
> Having said that, it might obfuscate the parameters and confuse
> callers.  Ho hum.

This would be very unweildy because you have to initialise like so:

    request := &ShutdownRoleRequest{
        DeploymentRequest: DeploymentRequest{
            ServiceName: "...",
            DeploymentName: "...",
        },
        RoleName: "...",
    }

From what I've learned so far, struct embedding is just a bit of
misleading sugar, but probably there are some use cases out there
somewhere.

Where they are the same, we can do an alias-like thing:

    type GetDeploymentRequest DeploymentRequest

Let's do a sweep at the end for this stuff, and live with a small
amount of duplication for now.

> I rebelled against you the other day and used backslashes instead of
> the []s - I think they obfuscate the string too much.
>
> c.Check(err, ErrorMatches, `GET request failed \(404: Not Found\)`)
>
> is clearer IMO.

:) We shall have to agree to differ. My in-brain regex parser has
evolved different precedence rules.

Thanks for the review!

Revision history for this message
Julian Edwards (julian-edwards) wrote :

On Wednesday 03 Jul 2013 09:53:28 you wrote:
> This would be very unweildy because you have to initialise like so:
>
> request := &ShutdownRoleRequest{
> DeploymentRequest: DeploymentRequest{
> ServiceName: "...",
> DeploymentName: "...",
> },
> RoleName: "...",
> }
>

Oooo wtf? Really? I thought embedding just saves the typing!

> >From what I've learned so far, struct embedding is just a bit of
>
> misleading sugar, but probably there are some use cases out there
> somewhere.
>
> Where they are the same, we can do an alias-like thing:
>
> type GetDeploymentRequest DeploymentRequest

That works equally well for now, but makes it a little harder to add more
params later.

Having said all that I'm now tending towards just duplicating stuff.

>
> Let's do a sweep at the end for this stuff, and live with a small
> amount of duplication for now.

Yeah, agreed.

>
> > I rebelled against you the other day and used backslashes instead of
> > the []s - I think they obfuscate the string too much.
> >
> > c.Check(err, ErrorMatches, `GET request failed \(404: Not Found\)`)
> >
> > is clearer IMO.
> :
> :) We shall have to agree to differ. My in-brain regex parser has
>
> evolved different precedence rules.

See, there's your problem, your brain can parse regex!

> Thanks for the review!

A pleasure.

Revision history for this message
Raphaël Badin (rvb) wrote :

>> [0]
>>
>> 35 + // 1. Stop VMs.
>> 36 + for _, roleInstance := range deployment.RoleInstanceList {
>>
>> I was wondering if it's really required to stop the VM…? because we know for a
>> fact that it fails almost all the time and it takes ~15 minutes.

> I'm going to leave this in for now. One of us can remove it later if
> it's really not necessary.

I've tested this a bit and stopping the instances always fails with a 500 error for me. I strongly suggest testing if *removing* the VMs instead of stopping them helps.

Revision history for this message
Raphaël Badin (rvb) wrote :

Also, we should update example/management/run.go to use DestroyDeployment().

Revision history for this message
Raphaël Badin (rvb) wrote :

> I've tested this a bit and stopping the instances always fails with a 500 error for me.

What I meant here is that the stopping operation effectively works (i.e. the instance is stopped) but returns an error. Since AFAIK we don't have a method to remove VMs, maybe we could simply ignore the error from the stopping operation. If something really wrong happens and the machine cannot be stopped, we won't be able to remove the disk so the next call to the API from DestroyDeployment() will fail anyway.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'management.go'
2--- management.go 2013-06-28 16:41:40 +0000
3+++ management.go 2013-07-03 09:38:29 +0000
4@@ -3,6 +3,10 @@
5
6 package gwacl
7
8+import (
9+ "sort"
10+)
11+
12 type ListInstancesRequest struct {
13 ServiceName string
14 }
15@@ -66,3 +70,61 @@
16 }
17 return deployments, nil
18 }
19+
20+type DestroyDeploymentRequest struct {
21+ ServiceName string
22+ DeploymentName string
23+}
24+
25+// DestroyDeployment brings down all resources within a deployment - running
26+// instances, disks, etc. - then deletes the deployment itself.
27+func (api *ManagementAPI) DestroyDeployment(request *DestroyDeploymentRequest) error {
28+ deployment, err := api.GetDeployment(&GetDeploymentRequest{
29+ ServiceName: request.ServiceName,
30+ DeploymentName: request.DeploymentName,
31+ })
32+ if err != nil {
33+ if IsNotFoundError(err) {
34+ return nil
35+ }
36+ return err
37+ }
38+ // 1. Stop VMs.
39+ for _, roleInstance := range deployment.RoleInstanceList {
40+ err = api.ShutdownRole(&ShutdownRoleRequest{
41+ ServiceName: request.ServiceName,
42+ DeploymentName: request.DeploymentName,
43+ RoleName: roleInstance.RoleName,
44+ })
45+ if err != nil && !IsNotFoundError(err) {
46+ return err
47+ }
48+ }
49+ // 2. Delete VM disks.
50+ diskNameMap := make(map[string]bool)
51+ for _, role := range deployment.RoleList {
52+ for _, osVHD := range role.OSVirtualHardDisk {
53+ diskNameMap[osVHD.DiskName] = true
54+ }
55+ }
56+ // Sort the disk names to aid testing.
57+ diskNames := []string{}
58+ for diskName := range diskNameMap {
59+ diskNames = append(diskNames, diskName)
60+ }
61+ sort.Strings(diskNames)
62+ // Actually delete them.
63+ for _, diskName := range diskNames {
64+ err = api.DeleteDisk(diskName)
65+ if err != nil && !IsNotFoundError(err) {
66+ return err
67+ }
68+ }
69+ // 3. Delete deployment.
70+ err = api.DeleteDeployment(request.ServiceName, request.DeploymentName)
71+ if err != nil && !IsNotFoundError(err) {
72+ return err
73+ }
74+ // Done.
75+ return nil
76+}
77
78=== modified file 'management_base_test.go'
79--- management_base_test.go 2013-07-03 00:17:53 +0000
80+++ management_base_test.go 2013-07-03 09:38:29 +0000
81@@ -508,16 +508,22 @@
82 checkOneRequest(c, recordedRequests, expectedURL, expectedPayload, "POST")
83 }
84
85+func assertDeleteDeploymentRequest(c *C, api *ManagementAPI, hostedServiceName, deploymentName string, httpRequest *X509Request) {
86+ expectedURL := fmt.Sprintf(
87+ "%s%s/services/hostedservices/%s/deployments/%s", AZURE_URL,
88+ api.session.subscriptionId, hostedServiceName, deploymentName)
89+ checkRequest(c, httpRequest, expectedURL, nil, "DELETE")
90+}
91+
92 func (suite *managementBaseAPISuite) TestDeleteDeployment(c *C) {
93 api := makeAPI(c)
94 recordedRequests := setUpDispatcher("operationID")
95 hostedServiceName := "testHosterServiceName"
96 deploymentName := "testDeploymentName"
97 err := api.DeleteDeployment(hostedServiceName, deploymentName)
98-
99 c.Assert(err, IsNil)
100- expectedURL := AZURE_URL + api.session.subscriptionId + "/services/hostedservices/" + hostedServiceName + "/deployments/" + deploymentName
101- checkOneRequest(c, recordedRequests, expectedURL, []byte{}, "DELETE")
102+ c.Assert(*recordedRequests, HasLen, 1)
103+ assertDeleteDeploymentRequest(c, api, hostedServiceName, deploymentName, (*recordedRequests)[0])
104 }
105
106 var getDeploymentResponse = `
107@@ -595,6 +601,13 @@
108 </Deployment>
109 `
110
111+func assertGetDeploymentRequest(c *C, api *ManagementAPI, request *GetDeploymentRequest, httpRequest *X509Request) {
112+ expectedURL := fmt.Sprintf(
113+ "%s%s/services/hostedservices/%s/deployments/%s", AZURE_URL,
114+ api.session.subscriptionId, request.ServiceName, request.DeploymentName)
115+ checkRequest(c, httpRequest, expectedURL, nil, "GET")
116+}
117+
118 func (suite *managementBaseAPISuite) TestGetDeployment(c *C) {
119 api := makeAPI(c)
120 fixedResponse := x509Response{
121@@ -611,10 +624,8 @@
122 request := &GetDeploymentRequest{ServiceName: serviceName, DeploymentName: deploymentName}
123 deployment, err := api.GetDeployment(request)
124 c.Assert(err, IsNil)
125-
126- expectedURL := AZURE_URL + api.session.subscriptionId + "/services/hostedservices/" + serviceName + "/deployments/" + deploymentName
127- checkOneRequest(c, &recordedRequests, expectedURL, []byte{}, "GET")
128-
129+ c.Assert(recordedRequests, HasLen, 1)
130+ assertGetDeploymentRequest(c, api, request, recordedRequests[0])
131 c.Check(deployment.Name, Equals, deploymentName)
132 }
133
134@@ -682,6 +693,12 @@
135 c.Check(keys.URL, Equals, url)
136 }
137
138+func assertDeleteDiskRequest(c *C, api *ManagementAPI, diskName string, httpRequest *X509Request) {
139+ expectedURL := fmt.Sprintf("%s%s/services/disks/%s", AZURE_URL,
140+ api.session.subscriptionId, diskName)
141+ checkRequest(c, httpRequest, expectedURL, nil, "DELETE")
142+}
143+
144 func (suite *managementBaseAPISuite) TestDeleteDisk(c *C) {
145 // The current implementation of DeleteDisk() works around a bug in
146 // Windows Azure by polling the server. See the documentation in the file
147@@ -694,8 +711,8 @@
148 err := api.DeleteDisk(diskName)
149
150 c.Assert(err, IsNil)
151- expectedURL := api.session.composeURL("services/disks/" + diskName)
152- checkOneRequest(c, recordedRequests, expectedURL, []byte{}, "DELETE")
153+ c.Assert(*recordedRequests, HasLen, 1)
154+ assertDeleteDiskRequest(c, api, diskName, (*recordedRequests)[0])
155 }
156
157 func (suite *managementBaseAPISuite) TestPerformNodeOperation(c *C) {
158@@ -742,18 +759,24 @@
159 checkOneRequest(c, recordedRequests, expectedURL, expectedPayload, "POST")
160 }
161
162+func assertShutdownRoleRequest(c *C, api *ManagementAPI, request *ShutdownRoleRequest, httpRequest *X509Request) {
163+ expectedURL := fmt.Sprintf(
164+ "%s%s/services/hostedservices/%s/deployments/%s/roleinstances/%s/Operations",
165+ AZURE_URL, api.session.subscriptionId, request.ServiceName,
166+ request.DeploymentName, request.RoleName)
167+ expectedPayload, err := marshalXML(shutdownRoleOperation)
168+ c.Assert(err, IsNil)
169+ checkRequest(c, httpRequest, expectedURL, expectedPayload, "POST")
170+}
171+
172 func (suite *managementBaseAPISuite) TestShutdownRole(c *C) {
173 api := makeAPI(c)
174 recordedRequests := setUpDispatcher("operationID")
175 request := &ShutdownRoleRequest{"serviceName", "deploymentName", "roleName"}
176 err := api.ShutdownRole(request)
177 c.Assert(err, IsNil)
178- expectedURL := (AZURE_URL + api.session.subscriptionId + "/services/hostedservices/" +
179- request.ServiceName + "/deployments/" + request.DeploymentName + "/roleinstances/" +
180- request.RoleName + "/Operations")
181- expectedPayload, err := marshalXML(shutdownRoleOperation)
182- c.Assert(err, IsNil)
183- checkOneRequest(c, recordedRequests, expectedURL, expectedPayload, "POST")
184+ c.Assert(*recordedRequests, HasLen, 1)
185+ assertShutdownRoleRequest(c, api, request, (*recordedRequests)[0])
186 }
187
188 func (suite *managementBaseAPISuite) TestGetRole(c *C) {
189
190=== modified file 'management_test.go'
191--- management_test.go 2013-06-28 18:09:28 +0000
192+++ management_test.go 2013-07-03 09:38:29 +0000
193@@ -162,3 +162,207 @@
194 // No deployments are returned.
195 c.Check(len(deployments), Equals, 0)
196 }
197+
198+type suiteDestroyDeployment struct{}
199+
200+var _ = Suite(&suiteDestroyDeployment{})
201+
202+var exampleDeployment = &Deployment{
203+ RoleInstanceList: makeNamedRoleInstances("one", "two"),
204+ RoleList: []Role{
205+ {OSVirtualHardDisk: []OSVirtualHardDisk{
206+ {DiskName: "disk1"}, {DiskName: "disk2"}}},
207+ {OSVirtualHardDisk: []OSVirtualHardDisk{
208+ {DiskName: "disk1"}, {DiskName: "disk3"}}},
209+ },
210+}
211+
212+var exampleOkayResponse = DispatcherResponse{
213+ response: &x509Response{StatusCode: http.StatusOK},
214+}
215+
216+var exampleFailResponse = DispatcherResponse{
217+ response: &x509Response{StatusCode: http.StatusInternalServerError},
218+}
219+
220+var exampleNotFoundResponse = DispatcherResponse{
221+ response: &x509Response{StatusCode: http.StatusNotFound},
222+}
223+
224+func (suite *suiteDestroyDeployment) TestHappyPath(c *C) {
225+ var responses []DispatcherResponse
226+ // Prepare.
227+ responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...)
228+ // For shutting down VMs.
229+ responses = append(responses, exampleOkayResponse, exampleOkayResponse)
230+ // For deleting disks.
231+ responses = append(responses, exampleOkayResponse, exampleOkayResponse, exampleOkayResponse)
232+ // For other requests.
233+ responses = append(responses, exampleOkayResponse)
234+ record := []*X509Request{}
235+ rigRecordingPreparedResponseDispatcher(&record, responses)
236+ // Exercise DestroyDeployment.
237+ api := makeAPI(c)
238+ request := &DestroyDeploymentRequest{
239+ ServiceName: "service-name",
240+ DeploymentName: "deployment-name",
241+ }
242+ err := api.DestroyDeployment(request)
243+ c.Assert(err, IsNil)
244+ c.Check(record, HasLen, 7)
245+ // The first request is for the deployment.
246+ assertGetDeploymentRequest(c, api, &GetDeploymentRequest{
247+ request.ServiceName, request.DeploymentName}, record[0])
248+ // The second is to shutdown RoleInstance "one".
249+ assertShutdownRoleRequest(c, api, &ShutdownRoleRequest{
250+ request.ServiceName, request.DeploymentName, "one"}, record[1])
251+ // The third is to shutdown RoleInstance "two", similar to like the second.
252+ assertShutdownRoleRequest(c, api, &ShutdownRoleRequest{
253+ request.ServiceName, request.DeploymentName, "two"}, record[2])
254+ // The fourth, fifth and sixth requests delete disks.
255+ assertDeleteDiskRequest(c, api, "disk1", record[3])
256+ assertDeleteDiskRequest(c, api, "disk2", record[4])
257+ assertDeleteDiskRequest(c, api, "disk3", record[5])
258+ // The fourth request deletes the deployment.
259+ assertDeleteDeploymentRequest(c, api, request.ServiceName,
260+ request.DeploymentName, record[6])
261+}
262+
263+func (suite *suiteDestroyDeployment) TestOkayWhenDeploymentNotFound(c *C) {
264+ var responses []DispatcherResponse
265+ // Prepare.
266+ responses = []DispatcherResponse{exampleNotFoundResponse}
267+ record := []*X509Request{}
268+ rigRecordingPreparedResponseDispatcher(&record, responses)
269+ // Exercise DestroyDeployment.
270+ api := makeAPI(c)
271+ request := &DestroyDeploymentRequest{
272+ ServiceName: "service-name",
273+ DeploymentName: "deployment-name",
274+ }
275+ err := api.DestroyDeployment(request)
276+ c.Assert(err, IsNil)
277+ c.Check(record, HasLen, 1)
278+}
279+
280+func (suite *suiteDestroyDeployment) TestOkayWhenAssetsNotFound(c *C) {
281+ var responses []DispatcherResponse
282+ // Prepare.
283+ responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...)
284+ // For shutting down VMs.
285+ responses = append(responses, exampleNotFoundResponse, exampleNotFoundResponse)
286+ // For deleting disks.
287+ responses = append(responses, exampleNotFoundResponse, exampleNotFoundResponse, exampleNotFoundResponse)
288+ // For other requests.
289+ responses = append(responses, exampleNotFoundResponse)
290+ record := []*X509Request{}
291+ rigRecordingPreparedResponseDispatcher(&record, responses)
292+ // Exercise DestroyDeployment.
293+ api := makeAPI(c)
294+ request := &DestroyDeploymentRequest{
295+ ServiceName: "service-name",
296+ DeploymentName: "deployment-name",
297+ }
298+ err := api.DestroyDeployment(request)
299+ c.Assert(err, IsNil)
300+ c.Check(record, HasLen, 7)
301+ // The first request is for the deployment.
302+ assertGetDeploymentRequest(c, api, &GetDeploymentRequest{
303+ request.ServiceName, request.DeploymentName}, record[0])
304+ // The second is to shutdown RoleInstance "one".
305+ assertShutdownRoleRequest(c, api, &ShutdownRoleRequest{
306+ request.ServiceName, request.DeploymentName, "one"}, record[1])
307+ // The third is to shutdown RoleInstance "two", similar to like the second.
308+ assertShutdownRoleRequest(c, api, &ShutdownRoleRequest{
309+ request.ServiceName, request.DeploymentName, "two"}, record[2])
310+ // The fourth, fifth and sixth requests delete disks.
311+ assertDeleteDiskRequest(c, api, "disk1", record[3])
312+ assertDeleteDiskRequest(c, api, "disk2", record[4])
313+ assertDeleteDiskRequest(c, api, "disk3", record[5])
314+ // The fourth request deletes the deployment.
315+ assertDeleteDeploymentRequest(c, api, request.ServiceName,
316+ request.DeploymentName, record[6])
317+}
318+
319+func (suite *suiteDestroyDeployment) TestFailsGettingDeployment(c *C) {
320+ var responses []DispatcherResponse
321+ // Prepare.
322+ responses = []DispatcherResponse{exampleFailResponse}
323+ record := []*X509Request{}
324+ rigRecordingPreparedResponseDispatcher(&record, responses)
325+ // Exercise DestroyDeployment.
326+ api := makeAPI(c)
327+ request := &DestroyDeploymentRequest{
328+ ServiceName: "service-name",
329+ DeploymentName: "deployment-name",
330+ }
331+ err := api.DestroyDeployment(request)
332+ c.Assert(err, NotNil)
333+ c.Check(err, ErrorMatches, "GET request failed [(]500: Internal Server Error[)]")
334+ c.Check(record, HasLen, 1)
335+}
336+
337+func (suite *suiteDestroyDeployment) TestFailsShuttingDownRole(c *C) {
338+ var responses []DispatcherResponse
339+ // Prepare.
340+ responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...)
341+ responses = append(responses, exampleFailResponse)
342+ record := []*X509Request{}
343+ rigRecordingPreparedResponseDispatcher(&record, responses)
344+ // Exercise DestroyDeployment.
345+ api := makeAPI(c)
346+ request := &DestroyDeploymentRequest{
347+ ServiceName: "service-name",
348+ DeploymentName: "deployment-name",
349+ }
350+ err := api.DestroyDeployment(request)
351+ c.Assert(err, NotNil)
352+ c.Check(err, ErrorMatches, "POST request failed [(]500: Internal Server Error[)]")
353+ c.Check(record, HasLen, 2)
354+}
355+
356+func (suite *suiteDestroyDeployment) TestFailsDeletingDisk(c *C) {
357+ var responses []DispatcherResponse
358+ // Prepare.
359+ responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...)
360+ // For shutting down VMs.
361+ responses = append(responses, exampleOkayResponse, exampleOkayResponse)
362+ // For deleting disks.
363+ responses = append(responses, exampleFailResponse)
364+ record := []*X509Request{}
365+ rigRecordingPreparedResponseDispatcher(&record, responses)
366+ // Exercise DestroyDeployment.
367+ api := makeAPI(c)
368+ request := &DestroyDeploymentRequest{
369+ ServiceName: "service-name",
370+ DeploymentName: "deployment-name",
371+ }
372+ err := api.DestroyDeployment(request)
373+ c.Assert(err, NotNil)
374+ c.Check(err, ErrorMatches, "DELETE request failed [(]500: Internal Server Error[)]")
375+ c.Check(record, HasLen, 4)
376+}
377+
378+func (suite *suiteDestroyDeployment) TestFailsDeletingDeployment(c *C) {
379+ var responses []DispatcherResponse
380+ // Prepare.
381+ responses = append(responses, makeOKXMLResponse(c, exampleDeployment)...)
382+ // For shutting down VMs.
383+ responses = append(responses, exampleOkayResponse, exampleOkayResponse)
384+ // For deleting disks.
385+ responses = append(responses, exampleOkayResponse, exampleOkayResponse, exampleOkayResponse)
386+ // For other requests.
387+ responses = append(responses, exampleFailResponse)
388+ record := []*X509Request{}
389+ rigRecordingPreparedResponseDispatcher(&record, responses)
390+ // Exercise DestroyDeployment.
391+ api := makeAPI(c)
392+ request := &DestroyDeploymentRequest{
393+ ServiceName: "service-name",
394+ DeploymentName: "deployment-name",
395+ }
396+ err := api.DestroyDeployment(request)
397+ c.Assert(err, NotNil)
398+ c.Check(err, ErrorMatches, "DELETE request failed [(]500: Internal Server Error[)]")
399+ c.Check(record, HasLen, 7)
400+}

Subscribers

People subscribed via source and target branches

to all changes: