Merge lp:~natefinch/juju-core/005-azure-address into lp:~go-bot/juju-core/trunk
- 005-azure-address
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | John A Meinel |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1767 |
Proposed branch: | lp:~natefinch/juju-core/005-azure-address |
Merge into: | lp:~go-bot/juju-core/trunk |
Diff against target: |
222 lines (+120/-34) 2 files modified
provider/azure/instance.go (+73/-32) provider/azure/instance_test.go (+47/-2) |
To merge this branch: | bzr merge lp:~natefinch/juju-core/005-azure-address |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+181117@code.launchpad.net |
Commit message
Description of the change
Nate Finch (natefinch) wrote : | # |
John A Meinel (jameinel) wrote : | # |
the code and tests for Addresses looks sane to me, though it might be
good to have someone on Red squad confirm the actual APIs you are
calling.
I have some questions about the Checker you implemented. The only bit
I'm genuinely worried about is mutating slices passed in by the caller.
If you add a test to reassure me we aren't changing them, the rest is
all just suggestions.
https:/
File testing/
https:/
testing/
Is it hard to create a smart implementation that notices if the types
are hashable and can then just insert them into a map with counts and
then compare it?
counts := make(map[TYPE]int)
for i, v := range expected:
counts[v] += 1
countsObtained := make(map[TYPE]int)
for i, v := range obtained:
countsObtain
Obviously you need a bit more reflect magic than I've typed here, but
you also end up with nice summaries of the contents and what is
different. (You could even do it as a delta map and count up with
expected, and down with obtained.)
If it is "cheap" to determine if something is hashable, I think the
algorithm to count them is nice and short and reasonably obvious. And
probably most things we're doing are strings, structs, and ints anyway.
https:/
testing/
duplicate items is the same
I'm a little concerned if removing them would mutate the caller's
slices. (You might compare to make sure they match, and then do other
things with the slice.)
Can you confirm that it doesn't?
Even better, add it as a test case so we ensure that we don't grow that
behavior accidentally in the future.
Another option that avoids rewriting the array N times would be to just
allocate a 'bool' array of the same length, and flag each entry with
True once you've seen it. When you iterate later, you can just check and
'continue' if that entry has already been seen.
You still end up with N^2 comparisons, but you have a lot fewer
reallocations.
My theoretical mind wonders if optimizing for the case of "lists are
identical" is worthwhile and starting the nested search at the offset of
the outer search. Or just doing one pass against all items until we have
something that doesn't match, and only then switch to the N^2 form.
Certainly not terribly important here.
https:/
File testing/
https:/
testing/
TestSameContents(c *gc.C) {
I personally would rather see these split out as separate "Test*" cases,
rather than just commented sections. So a new suite for SameContents and
then test cases in that.
func (s *SameContentsSuite) TestSame(c *gc.C) {
c.Check([]int(1, 2, 3), jc.SameContents, []int(1,2,3))
}
func (s *SameContentsSuite) TestE...
Nate Finch (natefinch) wrote : | # |
Please take a look.
Nate Finch (natefinch) wrote : | # |
Nate Finch (natefinch) wrote : | # |
Somehow my last message contents got dropped on the floor... not sure
how that happened.
The checker stuff was moved into a different branch, and the diffs now
reflect that (and I had implemented the changes john mentioned there).
This code was looked at by allenap, since I was having difficulty
figuring out how to mock out the server responses for the tests, so I'm
pretty sure they're good to go.
John A Meinel (jameinel) wrote : | # |
LGTM as long as it has been tested live.
John A Meinel (jameinel) wrote : | # |
On 2013/08/23 13:33:18, jameinel wrote:
> LGTM as long as it has been tested live.
You commented that this has been reviewed by others, but then didn't
land this. Is it blocked on something else?
Nate Finch (natefinch) wrote : | # |
Please take a look.
Martin Packman (gz) wrote : | # |
LGTM.
https:/
File provider/
https:/
provider/
*azureManagemen
I find this closure pretty hard to read, what with it being most of the
outer function and has differing return spelling.
https:/
File provider/
https:/
provider/
You don't actually need to repeat the type here.
Go Bot (go-bot) wrote : | # |
The attempt to merge lp:~natefinch/juju-core/005-azure-address into lp:juju-core failed. Below is the output from the failed tests.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
-------
FAIL: relationunit_
[LOG] 93.14353 INFO juju.state opening state; mongo addresses: ["localhost:
[LOG] 93.14798 INFO juju.state connection established
[LOG] 93.16266 INFO juju.state initializing environme...
Preview Diff
1 | === modified file 'provider/azure/instance.go' | |||
2 | --- provider/azure/instance.go 2013-08-27 18:33:36 +0000 | |||
3 | +++ provider/azure/instance.go 2013-09-04 15:14:28 +0000 | |||
4 | @@ -38,8 +38,54 @@ | |||
5 | 38 | 38 | ||
6 | 39 | // Addresses is specified in the Instance interface. | 39 | // Addresses is specified in the Instance interface. |
7 | 40 | func (azInstance *azureInstance) Addresses() ([]instance.Address, error) { | 40 | func (azInstance *azureInstance) Addresses() ([]instance.Address, error) { |
10 | 41 | logger.Errorf("azureInstance.Addresses not implemented") | 41 | addrs := []instance.Address{} |
11 | 42 | return nil, nil | 42 | ip, netname, err := azInstance.netInfo() |
12 | 43 | if err != nil { | ||
13 | 44 | return nil, err | ||
14 | 45 | } | ||
15 | 46 | if ip != "" { | ||
16 | 47 | addrs = append(addrs, instance.Address{ | ||
17 | 48 | ip, | ||
18 | 49 | instance.Ipv4Address, | ||
19 | 50 | netname, | ||
20 | 51 | instance.NetworkCloudLocal}) | ||
21 | 52 | } | ||
22 | 53 | |||
23 | 54 | name, err := azInstance.DNSName() | ||
24 | 55 | if err != nil { | ||
25 | 56 | return nil, err | ||
26 | 57 | } | ||
27 | 58 | host := instance.Address{name, instance.HostName, "", instance.NetworkPublic} | ||
28 | 59 | addrs = append(addrs, host) | ||
29 | 60 | return addrs, nil | ||
30 | 61 | } | ||
31 | 62 | |||
32 | 63 | func (azInstance *azureInstance) netInfo() (ip, netname string, err error) { | ||
33 | 64 | err = azInstance.apiCall(false, func(c *azureManagementContext) error { | ||
34 | 65 | d, err := c.GetDeployment(&gwacl.GetDeploymentRequest{ | ||
35 | 66 | ServiceName: azInstance.ServiceName, | ||
36 | 67 | DeploymentName: azInstance.ServiceName, | ||
37 | 68 | }) | ||
38 | 69 | if err != nil { | ||
39 | 70 | return err | ||
40 | 71 | } | ||
41 | 72 | switch len(d.RoleInstanceList) { | ||
42 | 73 | case 0: | ||
43 | 74 | // nothing to do, this can happen if the instances aren't finished deploying | ||
44 | 75 | return nil | ||
45 | 76 | case 1: | ||
46 | 77 | // success | ||
47 | 78 | ip = d.RoleInstanceList[0].IPAddress | ||
48 | 79 | netname = d.VirtualNetworkName | ||
49 | 80 | return nil | ||
50 | 81 | default: | ||
51 | 82 | return fmt.Errorf("Too many instances, expected one, got %d", len(d.RoleInstanceList)) | ||
52 | 83 | } | ||
53 | 84 | }) | ||
54 | 85 | if err != nil { | ||
55 | 86 | return "", "", err | ||
56 | 87 | } | ||
57 | 88 | return ip, netname, nil | ||
58 | 43 | } | 89 | } |
59 | 44 | 90 | ||
60 | 45 | // DNSName is specified in the Instance interface. | 91 | // DNSName is specified in the Instance interface. |
61 | @@ -60,6 +106,14 @@ | |||
62 | 60 | 106 | ||
63 | 61 | // OpenPorts is specified in the Instance interface. | 107 | // OpenPorts is specified in the Instance interface. |
64 | 62 | func (azInstance *azureInstance) OpenPorts(machineId string, ports []instance.Port) error { | 108 | func (azInstance *azureInstance) OpenPorts(machineId string, ports []instance.Port) error { |
65 | 109 | return azInstance.apiCall(true, func(context *azureManagementContext) error { | ||
66 | 110 | return azInstance.openEndpoints(context, ports) | ||
67 | 111 | }) | ||
68 | 112 | } | ||
69 | 113 | |||
70 | 114 | // apiCall wraps a call to the azure API to ensure it is properly disposed, optionally locking | ||
71 | 115 | // the environment | ||
72 | 116 | func (azInstance *azureInstance) apiCall(lock bool, f func(*azureManagementContext) error) error { | ||
73 | 63 | env := azInstance.environ | 117 | env := azInstance.environ |
74 | 64 | 118 | ||
75 | 65 | context, err := env.getManagementAPI() | 119 | context, err := env.getManagementAPI() |
76 | @@ -68,10 +122,11 @@ | |||
77 | 68 | } | 122 | } |
78 | 69 | defer env.releaseManagementAPI(context) | 123 | defer env.releaseManagementAPI(context) |
79 | 70 | 124 | ||
84 | 71 | env.Lock() | 125 | if lock { |
85 | 72 | defer env.Unlock() | 126 | env.Lock() |
86 | 73 | 127 | defer env.Unlock() | |
87 | 74 | return azInstance.openEndpoints(context, ports) | 128 | } |
88 | 129 | return f(context) | ||
89 | 75 | } | 130 | } |
90 | 76 | 131 | ||
91 | 77 | // openEndpoints opens the endpoints in the Azure deployment. The caller is | 132 | // openEndpoints opens the endpoints in the Azure deployment. The caller is |
92 | @@ -113,18 +168,9 @@ | |||
93 | 113 | 168 | ||
94 | 114 | // ClosePorts is specified in the Instance interface. | 169 | // ClosePorts is specified in the Instance interface. |
95 | 115 | func (azInstance *azureInstance) ClosePorts(machineId string, ports []instance.Port) error { | 170 | func (azInstance *azureInstance) ClosePorts(machineId string, ports []instance.Port) error { |
108 | 116 | env := azInstance.environ | 171 | return azInstance.apiCall(true, func(context *azureManagementContext) error { |
109 | 117 | 172 | return azInstance.closeEndpoints(context, ports) | |
110 | 118 | context, err := env.getManagementAPI() | 173 | }) |
99 | 119 | if err != nil { | ||
100 | 120 | return err | ||
101 | 121 | } | ||
102 | 122 | defer env.releaseManagementAPI(context) | ||
103 | 123 | |||
104 | 124 | env.Lock() | ||
105 | 125 | defer env.Unlock() | ||
106 | 126 | |||
107 | 127 | return azInstance.closeEndpoints(context, ports) | ||
111 | 128 | } | 174 | } |
112 | 129 | 175 | ||
113 | 130 | // closeEndpoints closes the endpoints in the Azure deployment. The caller is | 176 | // closeEndpoints closes the endpoints in the Azure deployment. The caller is |
114 | @@ -185,20 +231,15 @@ | |||
115 | 185 | } | 231 | } |
116 | 186 | 232 | ||
117 | 187 | // Ports is specified in the Instance interface. | 233 | // Ports is specified in the Instance interface. |
132 | 188 | func (azInstance *azureInstance) Ports(machineId string) ([]instance.Port, error) { | 234 | func (azInstance *azureInstance) Ports(machineId string) (ports []instance.Port, err error) { |
133 | 189 | env := azInstance.environ | 235 | err = azInstance.apiCall(false, func(context *azureManagementContext) error { |
134 | 190 | context, err := env.getManagementAPI() | 236 | ports, err = azInstance.listPorts(context) |
135 | 191 | if err != nil { | 237 | return err |
136 | 192 | return nil, err | 238 | }) |
137 | 193 | } | 239 | if ports != nil { |
138 | 194 | defer env.releaseManagementAPI(context) | 240 | state.SortPorts(ports) |
139 | 195 | 241 | } | |
140 | 196 | ports, err := azInstance.listPorts(context) | 242 | return ports, err |
127 | 197 | if err != nil { | ||
128 | 198 | return nil, err | ||
129 | 199 | } | ||
130 | 200 | state.SortPorts(ports) | ||
131 | 201 | return ports, nil | ||
141 | 202 | } | 243 | } |
142 | 203 | 244 | ||
143 | 204 | // listPorts returns the slice of ports (instance.Port) that this machine | 245 | // listPorts returns the slice of ports (instance.Port) that this machine |
144 | 205 | 246 | ||
145 | === modified file 'provider/azure/instance_test.go' | |||
146 | --- provider/azure/instance_test.go 2013-08-09 15:13:09 +0000 | |||
147 | +++ provider/azure/instance_test.go 2013-09-04 15:14:28 +0000 | |||
148 | @@ -5,13 +5,14 @@ | |||
149 | 5 | 5 | ||
150 | 6 | import ( | 6 | import ( |
151 | 7 | "encoding/base64" | 7 | "encoding/base64" |
152 | 8 | "fmt" | ||
153 | 9 | "net/http" | ||
154 | 8 | 10 | ||
155 | 9 | gc "launchpad.net/gocheck" | 11 | gc "launchpad.net/gocheck" |
156 | 10 | "launchpad.net/gwacl" | 12 | "launchpad.net/gwacl" |
157 | 11 | 13 | ||
158 | 12 | "fmt" | ||
159 | 13 | "launchpad.net/juju-core/instance" | 14 | "launchpad.net/juju-core/instance" |
161 | 14 | "net/http" | 15 | jc "launchpad.net/juju-core/testing/checkers" |
162 | 15 | ) | 16 | ) |
163 | 16 | 17 | ||
164 | 17 | type instanceSuite struct{} | 18 | type instanceSuite struct{} |
165 | @@ -95,6 +96,14 @@ | |||
166 | 95 | return []byte(xml) | 96 | return []byte(xml) |
167 | 96 | } | 97 | } |
168 | 97 | 98 | ||
169 | 99 | func prepareDeploymentInfoResponse( | ||
170 | 100 | c *gc.C, dep gwacl.Deployment) []gwacl.DispatcherResponse { | ||
171 | 101 | return []gwacl.DispatcherResponse{ | ||
172 | 102 | gwacl.NewDispatcherResponse( | ||
173 | 103 | serialize(c, &dep), http.StatusOK, nil), | ||
174 | 104 | } | ||
175 | 105 | } | ||
176 | 106 | |||
177 | 98 | func preparePortChangeConversation( | 107 | func preparePortChangeConversation( |
178 | 99 | c *gc.C, service *gwacl.HostedServiceDescriptor, | 108 | c *gc.C, service *gwacl.HostedServiceDescriptor, |
179 | 100 | deployments ...gwacl.Deployment) []gwacl.DispatcherResponse { | 109 | deployments ...gwacl.Deployment) []gwacl.DispatcherResponse { |
180 | @@ -146,6 +155,42 @@ | |||
181 | 146 | } | 155 | } |
182 | 147 | } | 156 | } |
183 | 148 | 157 | ||
184 | 158 | func (*instanceSuite) TestAddresses(c *gc.C) { | ||
185 | 159 | name := "service-name" | ||
186 | 160 | vnn := "Virt Net Name" | ||
187 | 161 | service := makeHostedServiceDescriptor(name) | ||
188 | 162 | responses := prepareDeploymentInfoResponse(c, | ||
189 | 163 | gwacl.Deployment{ | ||
190 | 164 | RoleInstanceList: []gwacl.RoleInstance{ | ||
191 | 165 | gwacl.RoleInstance{IPAddress: "1.2.3.4"}, | ||
192 | 166 | }, | ||
193 | 167 | VirtualNetworkName: vnn, | ||
194 | 168 | }) | ||
195 | 169 | |||
196 | 170 | gwacl.PatchManagementAPIResponses(responses) | ||
197 | 171 | inst := azureInstance{*service, makeEnviron(c)} | ||
198 | 172 | |||
199 | 173 | expected := []instance.Address{ | ||
200 | 174 | instance.Address{ | ||
201 | 175 | "1.2.3.4", | ||
202 | 176 | instance.Ipv4Address, | ||
203 | 177 | vnn, | ||
204 | 178 | instance.NetworkCloudLocal, | ||
205 | 179 | }, | ||
206 | 180 | instance.Address{ | ||
207 | 181 | name + "." + AZURE_DOMAIN_NAME, | ||
208 | 182 | instance.HostName, | ||
209 | 183 | "", | ||
210 | 184 | instance.NetworkPublic, | ||
211 | 185 | }, | ||
212 | 186 | } | ||
213 | 187 | |||
214 | 188 | addrs, err := inst.Addresses() | ||
215 | 189 | c.Check(err, gc.IsNil) | ||
216 | 190 | |||
217 | 191 | c.Check(addrs, jc.SameContents, expected) | ||
218 | 192 | } | ||
219 | 193 | |||
220 | 149 | func (*instanceSuite) TestOpenPorts(c *gc.C) { | 194 | func (*instanceSuite) TestOpenPorts(c *gc.C) { |
221 | 150 | service := makeHostedServiceDescriptor("service-name") | 195 | service := makeHostedServiceDescriptor("service-name") |
222 | 151 | responses := preparePortChangeConversation(c, service, | 196 | responses := preparePortChangeConversation(c, service, |
Reviewers: mp+181117_ code.launchpad. net,
Message:
Please take a look.
Description:
azure addressability changes
Implement Addresses()
https:/ /code.launchpad .net/~natefinch /juju-core/ 005-azure- address/ +merge/ 181117
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/13082044/
Affected files: azure/instance. go azure/instance_ test.go checkers/ checker. go checkers/ checker_ test.go
A [revision details]
M environs/
M environs/
M testing/
M testing/