Merge lp:~allenap/gwacl/set-network-configuration into lp:gwacl

Proposed by Gavin Panella on 2013-07-10
Status: Merged
Approved by: Julian Edwards on 2013-07-11
Approved revision: 186
Merged at revision: 176
Proposed branch: lp:~allenap/gwacl/set-network-configuration
Merge into: lp:gwacl
Diff against target: 539 lines (+166/-50)
11 files modified
example/management/run.go (+44/-13)
management_base.go (+3/-3)
management_base_test.go (+1/-2)
names.go (+20/-0)
names_test.go (+16/-3)
x509dispatcher.go (+8/-7)
x509dispatcher_test.go (+27/-11)
x509session.go (+3/-3)
x509session_test.go (+1/-1)
xmlobjects.go (+1/-2)
xmlobjects_test.go (+42/-5)
To merge this branch: bzr merge lp:~allenap/gwacl/set-network-configuration
Reviewer Review Type Date Requested Status
Julian Edwards (community) 2013-07-10 Approve on 2013-07-11
Review via email: mp+174001@code.launchpad.net

Commit message

Get SetNetworkConfiguration working in practice.

Description of the change

This is mostly yak hair.

- Azure doesn't actually like the Label tag in VirtualNetworkSite
  elements, even though the example operation docs show it.

- Other sub-elements are optional in the VirtualNetworkSite.

- PUT with the x509 dispatcher didn't work. I added a Request struct
  in the tests so that we can capture the request body content, and
  this showed up the problem. I fixed that by using the OPT_UPLOAD
  flag and requesting chunked transfers.

- PUT requests should also have a content-type, so I added this.

- I added a function for creating a random virtual network name. I
  also ensured that all random identifiers have at least 5 random
  characters, which gives about a 1 in 60 million chance of a
  collision.

- Built on the work Julian did on the example to create an affinity
  group and virtual network, then tear it down again. This is a work
  in progress; the deployed VMs are not using the virtual network or
  affinity group, and the network config gets clobbered. However,
  these are tasks for a subsequent branch.

To post a comment you must log in.
Julian Edwards (julian-edwards) wrote :
Download full text (4.6 KiB)

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

 review: approve
 merge: approve

Nice change, thank you. I'll land it right away, if there's anything
coming out of my questions below it can get fixed later.

On 11/07/13 03:11, Gavin Panella wrote:
> - Azure doesn't actually like the Label tag in VirtualNetworkSite
> elements, even though the example operation docs show it.

Can you file a bug on ***sing please, they asked if we could do this
for any doc problems.

> - Built on the work Julian did on the example to create an
> affinity group and virtual network, then tear it down again. This
> is a work in progress; the deployed VMs are not using the virtual
> network or affinity group, and the network config gets clobbered.
> However, these are tasks for a subsequent branch.

That's cool, at least it shows the actual API calls work.

> === modified file 'example/management/run.go'

Gosh those changes looked familiar :)

> === modified file 'management_base_test.go' ---
> management_base_test.go 2013-07-10 10:08:25 +0000 +++
> management_base_test.go 2013-07-10 17:10:42 +0000 @@ -929,7 +929,6
> @@ { Name: "virtual-network-name", AffinityGroup:
> "affinity-group-name", - Label:
> "label-for-the-site", AddressSpacePrefixes: []string{
> "CIDR-identifier", }, @@ -944,7 +943,7 @@ Name:
> "primary-DNS-name", }, }, - Gateway: Gateway{ +
> Gateway: &Gateway{

Urgh, the fact that we have to work around the Go omitempty bug with
pointers like is particularly f'in annoying as it leaves our
structures inconsistently presented.

> === modified file 'x509dispatcher.go' --- x509dispatcher.go
> 2013-07-01 13:04:17 +0000 +++ x509dispatcher.go 2013-07-10 17:10:42
> +0000 @@ -61,12 +61,13 @@
>
> // newX509RequestPUT initializes an X509Request for a PUT. You may
> still // need to set further values. -func newX509RequestPUT(url
> string, payload []byte) *X509Request { +func newX509RequestPUT(url
> string, payload []byte, contentType string) *X509Request { return
> &X509Request{ - Method: "PUT", - URL:
> url, - APIVersion: baseAPIVersion, - Payload:
> payload, + Method: "PUT", + URL: url, +
> APIVersion: baseAPIVersion, + Payload: payload, +
> ContentType: contentType,

Sigh, gofmt, SIGH.

> } }
>
> @@ -201,7 +202,7 @@ if len(request.Payload) != 0 { headers =
> append(headers, "Content-Type: "+request.ContentType) // Arrange
> for the request body to be written. -
> ch.Setopt(curl.OPT_POSTFIELDSIZE, len(request.Payload)) +
> headers = append(headers, "Transfer-Encoding: chunked")
> ch.Setopt(curl.OPT_READFUNCTION, func(buf []byte, _ interface{})
> int { // Buffered request write. Copy as much of the payload as
> will // fit into the buffer curl gave us for it, and return the
> number @@ -242,7 +243,7 @@ case "POST": ch.Setopt(curl.OPT_POST,
> true) case "PUT": - ch.Setopt(curl.OPT_CUSTOMREQUEST,
> "PUT") + ch.Setopt(curl.OPT_UPLOAD, true)

Out of interest, where is PUT set now? Does OPT_UPLOAD imply PUT?
(Sorry, I know bugger all about curl)

> case "DELETE": ch.Setopt(curl.OPT_CUSTOMREQUEST, "DELETE")
> default:
>
> === modified f...

Read more...

review: Approve
Gavin Panella (allenap) wrote :

Thanks for the review :)

> > - Azure doesn't actually like the Label tag in VirtualNetworkSite
> > elements, even though the example operation docs show it.
>
> Can you file a bug on ***sing please, they asked if we could do this
> for any doc problems.

Filed as bug 1200120.

...
> > === modified file 'management_base_test.go' ---
> > management_base_test.go     2013-07-10 10:08:25 +0000 +++
> > management_base_test.go     2013-07-10 17:10:42 +0000 @@ -929,7 +929,6
> > @@ { Name:          "virtual-network-name", AffinityGroup:
> > "affinity-group-name", -                Label:
> > "label-for-the-site", AddressSpacePrefixes: []string{
> > "CIDR-identifier", }, @@ -944,7 +943,7 @@ Name:
> > "primary-DNS-name", }, }, -                Gateway: Gateway{ +
> > Gateway: &Gateway{
>
> Urgh, the fact that we have to work around the Go omitempty bug with
> pointers like is particularly f'in annoying as it leaves our
> structures inconsistently presented.

Indeed :-/

...
> > @@ -201,7 +202,7 @@ if len(request.Payload) != 0 { headers =
> > append(headers, "Content-Type: "+request.ContentType) // Arrange
> > for the request body to be written. -
> > ch.Setopt(curl.OPT_POSTFIELDSIZE, len(request.Payload)) +
> > headers = append(headers, "Transfer-Encoding: chunked")
> > ch.Setopt(curl.OPT_READFUNCTION, func(buf []byte, _ interface{})
> > int { // Buffered request write.  Copy as much of the payload as
> > will // fit into the buffer curl gave us for it, and return the
> > number @@ -242,7 +243,7 @@ case "POST": ch.Setopt(curl.OPT_POST,
> > true) case "PUT": -        ch.Setopt(curl.OPT_CUSTOMREQUEST,
> > "PUT") +        ch.Setopt(curl.OPT_UPLOAD, true)
>
> Out of interest, where is PUT set now?  Does OPT_UPLOAD imply PUT?
> (Sorry, I know bugger all about curl)

Yeah, I just bumbled my way to
http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTUPLOAD

...
> > === modified file 'x509dispatcher_test.go' ---
...
> > inspection. +        requestBody, err := ioutil.ReadAll(r.Body)
>
> Doesn't this need the NopCloser trick?  Or is r.Body still readable later?

r.Body isn't readable in the test; it seems that it gets sucked dry
well before; I suspect that it's something that the ServeMux sorts
out.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'example/management/run.go'
2--- example/management/run.go 2013-07-10 12:49:25 +0000
3+++ example/management/run.go 2013-07-10 17:10:42 +0000
4@@ -88,16 +88,6 @@
5
6 func ExerciseHostedServicesAPI(api *gwacl.ManagementAPI) {
7 var err error
8- networkConfig, err := api.GetNetworkConfiguration()
9- checkError(err)
10- if networkConfig == nil {
11- fmt.Println("No network configuration is set.")
12- } else {
13- xml, err := networkConfig.Serialize()
14- checkError(err)
15- fmt.Println(xml)
16- }
17-
18 location := "West US"
19 release := "13.04"
20
21@@ -110,11 +100,52 @@
22 fmt.Printf("Created affinity group %s\n", affinityGroupName)
23
24 defer func() {
25- fmt.Println("Deleting affinity group %s", affinityGroupName)
26+ fmt.Printf("Deleting affinity group %s\n", affinityGroupName)
27 api.DeleteAffinityGroup(&gwacl.DeleteAffinityGroupRequest{
28 Name: affinityGroupName})
29- fmt.Println("Done deleting affinity group %s", affinityGroupName)
30- }()
31+ fmt.Printf("Done deleting affinity group %s\n", affinityGroupName)
32+ }()
33+
34+ virtualNetworkName := gwacl.MakeRandomVirtualNetworkName("virtual-net-")
35+ fmt.Printf("Creating virtual network %s...\n", virtualNetworkName)
36+ // FIXME: This clobbers *all* networking configuration instead of just
37+ // adding the specific virtual network.
38+ vnetRequest := &gwacl.NetworkConfiguration{
39+ XMLNS: gwacl.XMLNS_NC,
40+ VirtualNetworkSites: &[]gwacl.VirtualNetworkSite{
41+ {
42+ Name: virtualNetworkName,
43+ AffinityGroup: affinityGroupName,
44+ AddressSpacePrefixes: []string{
45+ "10.0.0.0/8",
46+ },
47+ },
48+ },
49+ }
50+ err = api.SetNetworkConfiguration(vnetRequest)
51+ checkError(err)
52+ fmt.Println("Done creating virtual network")
53+
54+ defer func() {
55+ fmt.Println("Deleting virtual network...")
56+ // FIXME: This destroys *all* networking configuration instead of just
57+ // removing the specific network we created.
58+ api.SetNetworkConfiguration(&gwacl.NetworkConfiguration{
59+ XMLNS: gwacl.XMLNS_NC,
60+ VirtualNetworkSites: &[]gwacl.VirtualNetworkSite{},
61+ })
62+ fmt.Println("Done deleting virtual network")
63+ }()
64+
65+ networkConfig, err := api.GetNetworkConfiguration()
66+ checkError(err)
67+ if networkConfig == nil {
68+ fmt.Println("No network configuration is set")
69+ } else {
70+ xml, err := networkConfig.Serialize()
71+ checkError(err)
72+ fmt.Println(xml)
73+ }
74
75 fmt.Printf("Getting OS Image for release '%s' and location '%s'...\n", release, location)
76 images, err := api.ListOSImages()
77
78=== modified file 'management_base.go'
79--- management_base.go 2013-07-10 09:12:01 +0000
80+++ management_base.go 2013-07-10 17:10:42 +0000
81@@ -131,7 +131,7 @@
82 if err != nil {
83 return err
84 }
85- response, err := api.session.put(URI, []byte(body))
86+ response, err := api.session.put(URI, []byte(body), "application/xml")
87 if err != nil {
88 return err
89 }
90@@ -388,7 +388,7 @@
91 if err != nil {
92 return err
93 }
94- response, err := api.session.put(url, []byte(body))
95+ response, err := api.session.put(url, []byte(body), "application/xml")
96 if err != nil {
97 return err
98 }
99@@ -442,7 +442,7 @@
100 if err != nil {
101 return err
102 }
103- response, err := api.session.put("services/networking/media", []byte(body))
104+ response, err := api.session.put("services/networking/media", []byte(body), "application/octet-stream")
105 if err != nil {
106 return err
107 }
108
109=== modified file 'management_base_test.go'
110--- management_base_test.go 2013-07-10 10:08:25 +0000
111+++ management_base_test.go 2013-07-10 17:10:42 +0000
112@@ -929,7 +929,6 @@
113 {
114 Name: "virtual-network-name",
115 AffinityGroup: "affinity-group-name",
116- Label: "label-for-the-site",
117 AddressSpacePrefixes: []string{
118 "CIDR-identifier",
119 },
120@@ -944,7 +943,7 @@
121 Name: "primary-DNS-name",
122 },
123 },
124- Gateway: Gateway{
125+ Gateway: &Gateway{
126 Profile: "Small",
127 VPNClientAddressPoolPrefixes: []string{
128 "CIDR-identifier",
129
130=== modified file 'names.go'
131--- names.go 2013-07-10 12:49:25 +0000
132+++ names.go 2013-07-10 17:10:42 +0000
133@@ -18,6 +18,7 @@
134 // consisting of only ASCII digits and lower-case ASCII letters.
135 // The identifier will start with the given prefix. The prefix must be no
136 // longer than the specified length, or there'll be trouble.
137+
138 func makeRandomIdentifier(prefix string, length int) string {
139 // Only digits and lower-case ASCII letters are accepted.
140 const (
141@@ -30,6 +31,12 @@
142 panic(fmt.Errorf("prefix '%s' is more than the requested %d characters long", prefix, length))
143 }
144
145+ if len(prefix)+5 > length {
146+ panic(fmt.Errorf(
147+ "prefix '%s' is too long; space is needed for at least 5 random characters, only %d given",
148+ prefix, length-len(prefix)))
149+ }
150+
151 if len(prefix) == 0 {
152 // No prefix. Still have to start with a letter, so pick one.
153 prefix = pickOne(letters)
154@@ -102,3 +109,16 @@
155 // is. Testing indicate that 50 works.
156 return makeRandomIdentifier(prefix, 50)
157 }
158+
159+// MakeRandomVirtualNetworkName generates a pseudo-random name for a virtual
160+// network with the given prefix.
161+//
162+// The prefix must be as short as possible, be entirely in ASCII, start with
163+// a lower-case letter, and contain only lower-case letters and digits after
164+// that.
165+//
166+// Be sure your random generator is initialized, or this will always produce
167+// the same sequence!
168+func MakeRandomVirtualNetworkName(prefix string) string {
169+ return makeRandomIdentifier(prefix, 20)
170+}
171
172=== modified file 'names_test.go'
173--- names_test.go 2013-07-10 12:58:52 +0000
174+++ names_test.go 2013-07-10 17:10:42 +0000
175@@ -17,10 +17,19 @@
176 }
177
178 func (*namesSuite) TestMakeRandomIdentifierObeysLength(c *C) {
179- length := 1 + rand.Intn(50)
180+ length := 6 + rand.Intn(50)
181 c.Check(len(makeRandomIdentifier("x", length)), Equals, length)
182 }
183
184+// makeRandomIdentifier ensures that there are at least 5 random characters in
185+// an identifier.
186+func (*namesSuite) TestMakeRandomIdentifierEnsuresSomeRandomness(c *C) {
187+ c.Check(makeRandomIdentifier("1234-", 10), Matches, "1234-[a-z0-9]{5}")
188+ c.Check(
189+ func() { makeRandomIdentifier("12345-", 10) }, PanicMatches,
190+ "prefix '12345-' is too long; space is needed for at least 5 random characters, only 4 given")
191+}
192+
193 func (*namesSuite) TestMakeRandomIdentifierRandomizes(c *C) {
194 // There is a minute chance that this will start failing just because
195 // the randomizer repeats a pattern of results. If so, seed it.
196@@ -41,7 +50,7 @@
197 }
198
199 func (*namesSuite) TestMakeRandomIdentifierUsesPrefix(c *C) {
200- c.Check(makeRandomIdentifier("prefix", 10), Matches, "prefix.*")
201+ c.Check(makeRandomIdentifier("prefix", 11), Matches, "prefix.*")
202 }
203
204 func (*namesSuite) TestMakeRandomIdentifierUsesOnlyAcceptedCharacters(c *C) {
205@@ -50,7 +59,7 @@
206
207 func (*namesSuite) TestMakeRandomIdentifierAcceptsEmptyPrefix(c *C) {
208 // In particular, the first character must still be a letter.
209- c.Check(makeRandomIdentifier("", 1), Matches, "[a-z]")
210+ c.Check(makeRandomIdentifier("", 5), Matches, "[a-z].*")
211 }
212
213 func (*namesSuite) TestMakeRandomDiskName(c *C) {
214@@ -60,3 +69,7 @@
215 func (*namesSuite) TestMakeRandomRoleName(c *C) {
216 c.Check(MakeRandomRoleName(""), Not(HasLen), 0)
217 }
218+
219+func (*namesSuite) TestMakeRandomVirtualNetworkName(c *C) {
220+ c.Check(MakeRandomVirtualNetworkName(""), Not(HasLen), 0)
221+}
222
223=== modified file 'x509dispatcher.go'
224--- x509dispatcher.go 2013-07-01 13:04:17 +0000
225+++ x509dispatcher.go 2013-07-10 17:10:42 +0000
226@@ -61,12 +61,13 @@
227
228 // newX509RequestPUT initializes an X509Request for a PUT. You may still
229 // need to set further values.
230-func newX509RequestPUT(url string, payload []byte) *X509Request {
231+func newX509RequestPUT(url string, payload []byte, contentType string) *X509Request {
232 return &X509Request{
233- Method: "PUT",
234- URL: url,
235- APIVersion: baseAPIVersion,
236- Payload: payload,
237+ Method: "PUT",
238+ URL: url,
239+ APIVersion: baseAPIVersion,
240+ Payload: payload,
241+ ContentType: contentType,
242 }
243 }
244
245@@ -201,7 +202,7 @@
246 if len(request.Payload) != 0 {
247 headers = append(headers, "Content-Type: "+request.ContentType)
248 // Arrange for the request body to be written.
249- ch.Setopt(curl.OPT_POSTFIELDSIZE, len(request.Payload))
250+ headers = append(headers, "Transfer-Encoding: chunked")
251 ch.Setopt(curl.OPT_READFUNCTION, func(buf []byte, _ interface{}) int {
252 // Buffered request write. Copy as much of the payload as will
253 // fit into the buffer curl gave us for it, and return the number
254@@ -242,7 +243,7 @@
255 case "POST":
256 ch.Setopt(curl.OPT_POST, true)
257 case "PUT":
258- ch.Setopt(curl.OPT_CUSTOMREQUEST, "PUT")
259+ ch.Setopt(curl.OPT_UPLOAD, true)
260 case "DELETE":
261 ch.Setopt(curl.OPT_CUSTOMREQUEST, "DELETE")
262 default:
263
264=== modified file 'x509dispatcher_test.go'
265--- x509dispatcher_test.go 2013-07-02 07:15:53 +0000
266+++ x509dispatcher_test.go 2013-07-10 17:10:42 +0000
267@@ -1,6 +1,7 @@
268 package gwacl
269
270 import (
271+ "io/ioutil"
272 . "launchpad.net/gocheck"
273 "net/http"
274 "net/http/httptest"
275@@ -10,13 +11,24 @@
276
277 var _ = Suite(&x509DispatcherSuite{})
278
279+type Request struct {
280+ *http.Request
281+ BodyContent []byte
282+}
283+
284 // makeRecordingHTTPServer creates an http server (don't forget to Close() it when done)
285 // that serves at the given base URL, copies incoming requests into the given
286 // channel, and finally returns the given status code. If body is not nil, it
287 // will be returned as the request body.
288-func makeRecordingHTTPServer(requests chan *http.Request, status int, body []byte, headers http.Header) *httptest.Server {
289+func makeRecordingHTTPServer(requests chan *Request, status int, body []byte, headers http.Header) *httptest.Server {
290 returnRequest := func(w http.ResponseWriter, r *http.Request) {
291- requests <- r
292+ // Capture all the request body content for later inspection.
293+ requestBody, err := ioutil.ReadAll(r.Body)
294+ if err != nil {
295+ panic(err)
296+ }
297+ requests <- &Request{r, requestBody}
298+
299 for header, values := range headers {
300 for _, value := range values {
301 w.Header().Set(header, value)
302@@ -59,7 +71,7 @@
303 }
304
305 func (*x509DispatcherSuite) TestGetRequestDoesHTTPGET(c *C) {
306- httpRequests := make(chan *http.Request, 1)
307+ httpRequests := make(chan *Request, 1)
308 server := makeRecordingHTTPServer(httpRequests, http.StatusOK, nil, nil)
309 defer server.Close()
310 // No real certificate needed since we're testing on http, not https.
311@@ -75,11 +87,12 @@
312 httpRequest := <-httpRequests
313 c.Check(httpRequest.Method, Equals, "GET")
314 c.Check(httpRequest.URL.String(), Equals, path)
315+ c.Check(httpRequest.BodyContent, HasLen, 0)
316 }
317
318 func (*x509DispatcherSuite) TestGetFollowsRedirects(c *C) {
319 redirectPath := "/redirect/path"
320- httpRequests := make(chan *http.Request, _CURL_MAX_REDIRECTS+1)
321+ httpRequests := make(chan *Request, _CURL_MAX_REDIRECTS+1)
322 locationHeaders := http.Header{}
323 locationHeaders.Add("Location", redirectPath)
324 server := makeRecordingHTTPServer(httpRequests, http.StatusTemporaryRedirect, nil, locationHeaders)
325@@ -93,7 +106,7 @@
326 _, err = performX509CurlRequest(session, request)
327 c.Check(err, ErrorMatches, ".*Number of redirects hit maximum amount.*")
328
329- var httpRequest *http.Request
330+ var httpRequest *Request
331 // The original GET request has been performed.
332 select {
333 case httpRequest = <-httpRequests:
334@@ -116,7 +129,7 @@
335 }
336
337 func (*x509DispatcherSuite) TestPostRequestDoesHTTPPOST(c *C) {
338- httpRequests := make(chan *http.Request, 1)
339+ httpRequests := make(chan *Request, 1)
340 requestBody := []byte{1, 2, 3}
341 responseBody := []byte{4, 5, 6}
342 requestContentType := "bogusContentType"
343@@ -131,17 +144,18 @@
344 response, err := performX509CurlRequest(session, request)
345 c.Assert(err, IsNil)
346 c.Assert(response.StatusCode, Equals, http.StatusOK)
347+ c.Check(response.Body, DeepEquals, responseBody)
348
349 httpRequest := <-httpRequests
350 c.Check(httpRequest.Header[http.CanonicalHeaderKey("Content-Type")], DeepEquals, []string{requestContentType})
351 c.Check(httpRequest.Header[http.CanonicalHeaderKey("X-Ms-Version")], DeepEquals, []string{request.APIVersion})
352 c.Check(httpRequest.Method, Equals, "POST")
353 c.Check(httpRequest.URL.String(), Equals, path)
354- c.Check(response.Body, DeepEquals, responseBody)
355+ c.Check(httpRequest.BodyContent, DeepEquals, requestBody)
356 }
357
358 func (*x509DispatcherSuite) TestDeleteRequestDoesHTTPDELETE(c *C) {
359- httpRequests := make(chan *http.Request, 1)
360+ httpRequests := make(chan *Request, 1)
361 server := makeRecordingHTTPServer(httpRequests, http.StatusOK, nil, nil)
362 defer server.Close()
363 // No real certificate needed since we're testing on http, not https.
364@@ -157,10 +171,11 @@
365 httpRequest := <-httpRequests
366 c.Check(httpRequest.Method, Equals, "DELETE")
367 c.Check(httpRequest.URL.String(), Equals, path)
368+ c.Check(httpRequest.BodyContent, HasLen, 0)
369 }
370
371 func (*x509DispatcherSuite) TestPutRequestDoesHTTPPUT(c *C) {
372- httpRequests := make(chan *http.Request, 1)
373+ httpRequests := make(chan *Request, 1)
374 requestBody := []byte{1, 2, 3}
375 responseBody := []byte{4, 5, 6}
376 server := makeRecordingHTTPServer(httpRequests, http.StatusOK, responseBody, nil)
377@@ -169,16 +184,17 @@
378 session, err := newX509Session("subscriptionid", "cert.pem")
379 c.Assert(err, IsNil)
380 path := "/foo/bar"
381- request := newX509RequestPUT(server.URL+path, requestBody)
382+ request := newX509RequestPUT(server.URL+path, requestBody, "application/octet-stream")
383
384 response, err := performX509CurlRequest(session, request)
385 c.Assert(err, IsNil)
386 c.Assert(response.StatusCode, Equals, http.StatusOK)
387+ c.Check(response.Body, DeepEquals, responseBody)
388
389 httpRequest := <-httpRequests
390 c.Check(httpRequest.Method, Equals, "PUT")
391 c.Check(httpRequest.URL.String(), Equals, path)
392- c.Check(response.Body, DeepEquals, responseBody)
393+ c.Check(httpRequest.BodyContent, DeepEquals, requestBody)
394 }
395
396 func (*x509DispatcherSuite) TestRequestRegistersHeader(c *C) {
397
398=== modified file 'x509session.go'
399--- x509session.go 2013-06-27 11:53:50 +0000
400+++ x509session.go 2013-07-10 17:10:42 +0000
401@@ -102,12 +102,12 @@
402 // put performs a PUT request to the Azure management API.
403 // Be aware that Azure may perform PUT operations asynchronously. If you are
404 // not sure, call blockUntilCompleted() on the response.
405-func (session *x509Session) put(path string, body []byte) (*x509Response, error) {
406- request := newX509RequestPUT(session.composeURL(path), body)
407+func (session *x509Session) put(path string, body []byte, contentType string) (*x509Response, error) {
408+ request := newX509RequestPUT(session.composeURL(path), body, contentType)
409 response, err := _X509Dispatcher(session, request)
410 if err != nil {
411 return nil, err
412 }
413- err = session.getServerError(response.StatusCode, response.Body, "POST request failed")
414+ err = session.getServerError(response.StatusCode, response.Body, "PUT request failed")
415 return response, err
416 }
417
418=== modified file 'x509session_test.go'
419--- x509session_test.go 2013-06-27 10:55:35 +0000
420+++ x509session_test.go 2013-07-10 17:10:42 +0000
421@@ -321,7 +321,7 @@
422 recordedRequests := make([]*X509Request, 0)
423 rigRecordingDispatcher(&recordedRequests)
424
425- _, err = session.put(uri, requestBody)
426+ _, err = session.put(uri, requestBody, "text/plain")
427 c.Assert(err, IsNil)
428
429 c.Assert(len(recordedRequests), Equals, 1)
430
431=== modified file 'xmlobjects.go'
432--- xmlobjects.go 2013-07-10 15:37:52 +0000
433+++ xmlobjects.go 2013-07-10 17:10:42 +0000
434@@ -629,11 +629,10 @@
435 XMLName string `xml:"VirtualNetworkSite"`
436 Name string `xml:"name,attr"`
437 AffinityGroup string `xml:"AffinityGroup,attr"`
438- Label string `xml:"Label"`
439 AddressSpacePrefixes []string `xml:"AddressSpace>AddressPrefix"`
440 Subnets *[]Subnet `xml:"Subnets>Subnet",omitempty`
441 DnsServersRef *[]DnsServerRef `xml:"DnsServersRef>DnsServerRef",omitempty`
442- Gateway Gateway `xml:"Gateway"`
443+ Gateway *Gateway `xml:"Gateway",omitempty`
444 }
445
446 type NetworkConfiguration struct {
447
448=== modified file 'xmlobjects_test.go'
449--- xmlobjects_test.go 2013-07-10 15:44:14 +0000
450+++ xmlobjects_test.go 2013-07-10 17:10:42 +0000
451@@ -279,7 +279,6 @@
452 </LocalNetworkSites>
453 <VirtualNetworkSites>
454 <VirtualNetworkSite name="virtual-network-name" AffinityGroup="affinity-group-name">
455- <Label>label-for-the-site</Label>
456 <AddressSpace>
457 <AddressPrefix>CIDR-identifier</AddressPrefix>
458 </AddressSpace>
459@@ -327,7 +326,6 @@
460 {
461 Name: "virtual-network-name",
462 AffinityGroup: "affinity-group-name",
463- Label: "label-for-the-site",
464 AddressSpacePrefixes: []string{
465 "CIDR-identifier",
466 },
467@@ -342,7 +340,7 @@
468 Name: "primary-DNS-name",
469 },
470 },
471- Gateway: Gateway{
472+ Gateway: &Gateway{
473 Profile: "Small",
474 VPNClientAddressPoolPrefixes: []string{
475 "CIDR-identifier",
476@@ -363,6 +361,46 @@
477 c.Assert(observed, Equals, expected)
478 }
479
480+func (suite *xmlSuite) TestNetworkConfigurationSerializeMinimal(c *C) {
481+ expected := fmt.Sprintf(
482+ "\n<NetworkConfiguration xmlns=\"%s\"></NetworkConfiguration>",
483+ XMLNS_NC)
484+ input := NetworkConfiguration{XMLNS: XMLNS_NC}
485+ observed, err := input.Serialize()
486+ c.Assert(err, IsNil)
487+ c.Assert(observed, Equals, expected)
488+}
489+
490+func (suite *xmlSuite) TestNetworkConfigurationSerializeSimpleVirtualNetworkSite(c *C) {
491+ expected := dedent.Dedent(`
492+ <NetworkConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration">
493+ <VirtualNetworkConfiguration>
494+ <VirtualNetworkSites>
495+ <VirtualNetworkSite name="virtual-network-name" AffinityGroup="affinity-group-name">
496+ <AddressSpace>
497+ <AddressPrefix>CIDR-identifier</AddressPrefix>
498+ </AddressSpace>
499+ </VirtualNetworkSite>
500+ </VirtualNetworkSites>
501+ </VirtualNetworkConfiguration>
502+ </NetworkConfiguration>`)
503+ input := NetworkConfiguration{
504+ XMLNS: XMLNS_NC,
505+ VirtualNetworkSites: &[]VirtualNetworkSite{
506+ {
507+ Name: "virtual-network-name",
508+ AffinityGroup: "affinity-group-name",
509+ AddressSpacePrefixes: []string{
510+ "CIDR-identifier",
511+ },
512+ },
513+ },
514+ }
515+ observed, err := input.Serialize()
516+ c.Assert(err, IsNil)
517+ c.Assert(observed, Equals, expected)
518+}
519+
520 func (suite *xmlSuite) TestCreateAffinityGroup(c *C) {
521 expected := dedent.Dedent(`
522 <CreateAffinityGroup xmlns="http://schemas.microsoft.com/windowsazure">
523@@ -492,7 +530,6 @@
524 {
525 Name: "virtual-network-name",
526 AffinityGroup: "affinity-group-name",
527- Label: "label-for-the-site",
528 AddressSpacePrefixes: []string{
529 "CIDR-identifier",
530 },
531@@ -507,7 +544,7 @@
532 Name: "primary-DNS-name",
533 },
534 },
535- Gateway: Gateway{
536+ Gateway: &Gateway{
537 Profile: "Small",
538 VPNClientAddressPoolPrefixes: []string{
539 "CIDR-identifier",

Subscribers

People subscribed via source and target branches

to all changes: