Merge lp:~natefinch/juju-core/005-azure-address into lp:~go-bot/juju-core/trunk

Proposed by Nate Finch
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
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+181117@code.launchpad.net

Commit message

azure addressability changes

Implement Addresses()

https://codereview.appspot.com/13082044/

Description of the change

azure addressability changes

Implement Addresses()

https://codereview.appspot.com/13082044/

To post a comment you must log in.
Revision history for this message
Nate Finch (natefinch) wrote :

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:
   A [revision details]
   M environs/azure/instance.go
   M environs/azure/instance_test.go
   M testing/checkers/checker.go
   M testing/checkers/checker_test.go

Revision history for this message
John A Meinel (jameinel) wrote :
Download full text (3.5 KiB)

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://codereview.appspot.com/13082044/diff/1/testing/checkers/checker.go
File testing/checkers/checker.go (right):

https://codereview.appspot.com/13082044/diff/1/testing/checkers/checker.go#newcode157
testing/checkers/checker.go:157: // use it on very large slices
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:
   countsObtained[v] += 1

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://codereview.appspot.com/13082044/diff/1/testing/checkers/checker.go#newcode198
testing/checkers/checker.go:198: // that way we make sure the count of
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://codereview.appspot.com/13082044/diff/1/testing/checkers/checker_test.go
File testing/checkers/checker_test.go (right):

https://codereview.appspot.com/13082044/diff/1/testing/checkers/checker_test.go#newcode37
testing/checkers/checker_test.go:37: func (s *CheckerSuite)
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...

Read more...

Revision history for this message
Nate Finch (natefinch) wrote :
Revision history for this message
Nate Finch (natefinch) wrote :
Revision history for this message
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.

https://codereview.appspot.com/13082044/

Revision history for this message
John A Meinel (jameinel) wrote :

LGTM as long as it has been tested live.

https://codereview.appspot.com/13082044/

Revision history for this message
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?

https://codereview.appspot.com/13082044/

Revision history for this message
Nate Finch (natefinch) wrote :
Revision history for this message
Martin Packman (gz) wrote :

LGTM.

https://codereview.appspot.com/13082044/diff/18001/provider/azure/instance.go
File provider/azure/instance.go (right):

https://codereview.appspot.com/13082044/diff/18001/provider/azure/instance.go#newcode64
provider/azure/instance.go:64: err = azInstance.apiCall(false, func(c
*azureManagementContext) error {
I find this closure pretty hard to read, what with it being most of the
outer function and has differing return spelling.

https://codereview.appspot.com/13082044/diff/18001/provider/azure/instance_test.go
File provider/azure/instance_test.go (right):

https://codereview.appspot.com/13082044/diff/18001/provider/azure/instance_test.go#newcode174
provider/azure/instance_test.go:174: instance.Address{
You don't actually need to repeat the type here.

https://codereview.appspot.com/13082044/

Revision history for this message
Go Bot (go-bot) wrote :
Download full text (7.2 KiB)

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.net/juju-core/agent 0.764s
ok launchpad.net/juju-core/agent/tools 0.240s
ok launchpad.net/juju-core/bzr 7.547s
ok launchpad.net/juju-core/cert 2.411s
ok launchpad.net/juju-core/charm 0.551s
? launchpad.net/juju-core/charm/hooks [no test files]
ok launchpad.net/juju-core/cloudinit 0.021s
ok launchpad.net/juju-core/cmd 0.201s
? launchpad.net/juju-core/cmd/builddb [no test files]
? launchpad.net/juju-core/cmd/charmd [no test files]
? launchpad.net/juju-core/cmd/charmload [no test files]
ok launchpad.net/juju-core/cmd/juju 120.106s
ok launchpad.net/juju-core/cmd/jujud 37.565s
ok launchpad.net/juju-core/cmd/plugins/juju-metadata 1.570s
ok launchpad.net/juju-core/constraints 0.029s
ok launchpad.net/juju-core/container/lxc 0.365s
? launchpad.net/juju-core/container/lxc/mock [no test files]
ok launchpad.net/juju-core/downloader 5.298s
ok launchpad.net/juju-core/environs 1.228s
ok launchpad.net/juju-core/environs/bootstrap 6.613s
ok launchpad.net/juju-core/environs/cloudinit 0.438s
ok launchpad.net/juju-core/environs/config 0.708s
? launchpad.net/juju-core/environs/filestorage [no test files]
ok launchpad.net/juju-core/environs/imagemetadata 0.377s
ok launchpad.net/juju-core/environs/instances 0.221s
ok launchpad.net/juju-core/environs/jujutest 0.254s
ok launchpad.net/juju-core/environs/localstorage 0.246s
ok launchpad.net/juju-core/environs/manual 1.039s
ok launchpad.net/juju-core/environs/simplestreams 0.255s
? launchpad.net/juju-core/environs/simplestreams/testing [no test files]
ok launchpad.net/juju-core/environs/sync 0.247s
ok launchpad.net/juju-core/environs/testing 0.010s
ok launchpad.net/juju-core/environs/tools 27.439s
? launchpad.net/juju-core/errors [no test files]
ok launchpad.net/juju-core/instance 0.019s
ok launchpad.net/juju-core/juju 14.954s
ok launchpad.net/juju-core/juju/osenv 0.247s
? launchpad.net/juju-core/juju/testing [no test files]
ok launchpad.net/juju-core/log 0.016s
ok launchpad.net/juju-core/log/syslog 0.017s
ok launchpad.net/juju-core/names 0.031s
ok launchpad.net/juju-core/provider 0.250s
? launchpad.net/juju-core/provider/all [no test files]
ok launchpad.net/juju-core/provider/azure 4.455s
ok launchpad.net/juju-core/provider/dummy 17.648s
ok launchpad.net/juju-core/provider/ec2 4.427s
ok launchpad.net/juju-core/provider/local 1.301s
? launchpad.net/juju-core/provider/local/storage [no test files]
ok launchpad.net/juju-core/provider/maas 2.115s
ok launchpad.net/juju-core/provider/openstack 3.982s
ok launchpad.net/juju-core/rpc 0.258s
ok launchpad.net/juju-core/rpc/jsoncodec 0.259s
ok launchpad.net/juju-core/schema 0.018s

----------------------------------------------------------------------
FAIL: relationunit_test.go:555: RelationUnitSuite.TestContainerWatchScope

[LOG] 93.14353 INFO juju.state opening state; mongo addresses: ["localhost:51340"]; entity ""
[LOG] 93.14798 INFO juju.state connection established
[LOG] 93.16266 INFO juju.state initializing environme...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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
6 // Addresses is specified in the Instance interface.
7 func (azInstance *azureInstance) Addresses() ([]instance.Address, error) {
8- logger.Errorf("azureInstance.Addresses not implemented")
9- return nil, nil
10+ addrs := []instance.Address{}
11+ ip, netname, err := azInstance.netInfo()
12+ if err != nil {
13+ return nil, err
14+ }
15+ if ip != "" {
16+ addrs = append(addrs, instance.Address{
17+ ip,
18+ instance.Ipv4Address,
19+ netname,
20+ instance.NetworkCloudLocal})
21+ }
22+
23+ name, err := azInstance.DNSName()
24+ if err != nil {
25+ return nil, err
26+ }
27+ host := instance.Address{name, instance.HostName, "", instance.NetworkPublic}
28+ addrs = append(addrs, host)
29+ return addrs, nil
30+}
31+
32+func (azInstance *azureInstance) netInfo() (ip, netname string, err error) {
33+ err = azInstance.apiCall(false, func(c *azureManagementContext) error {
34+ d, err := c.GetDeployment(&gwacl.GetDeploymentRequest{
35+ ServiceName: azInstance.ServiceName,
36+ DeploymentName: azInstance.ServiceName,
37+ })
38+ if err != nil {
39+ return err
40+ }
41+ switch len(d.RoleInstanceList) {
42+ case 0:
43+ // nothing to do, this can happen if the instances aren't finished deploying
44+ return nil
45+ case 1:
46+ // success
47+ ip = d.RoleInstanceList[0].IPAddress
48+ netname = d.VirtualNetworkName
49+ return nil
50+ default:
51+ return fmt.Errorf("Too many instances, expected one, got %d", len(d.RoleInstanceList))
52+ }
53+ })
54+ if err != nil {
55+ return "", "", err
56+ }
57+ return ip, netname, nil
58 }
59
60 // DNSName is specified in the Instance interface.
61@@ -60,6 +106,14 @@
62
63 // OpenPorts is specified in the Instance interface.
64 func (azInstance *azureInstance) OpenPorts(machineId string, ports []instance.Port) error {
65+ return azInstance.apiCall(true, func(context *azureManagementContext) error {
66+ return azInstance.openEndpoints(context, ports)
67+ })
68+}
69+
70+// apiCall wraps a call to the azure API to ensure it is properly disposed, optionally locking
71+// the environment
72+func (azInstance *azureInstance) apiCall(lock bool, f func(*azureManagementContext) error) error {
73 env := azInstance.environ
74
75 context, err := env.getManagementAPI()
76@@ -68,10 +122,11 @@
77 }
78 defer env.releaseManagementAPI(context)
79
80- env.Lock()
81- defer env.Unlock()
82-
83- return azInstance.openEndpoints(context, ports)
84+ if lock {
85+ env.Lock()
86+ defer env.Unlock()
87+ }
88+ return f(context)
89 }
90
91 // openEndpoints opens the endpoints in the Azure deployment. The caller is
92@@ -113,18 +168,9 @@
93
94 // ClosePorts is specified in the Instance interface.
95 func (azInstance *azureInstance) ClosePorts(machineId string, ports []instance.Port) error {
96- env := azInstance.environ
97-
98- context, err := env.getManagementAPI()
99- if err != nil {
100- return err
101- }
102- defer env.releaseManagementAPI(context)
103-
104- env.Lock()
105- defer env.Unlock()
106-
107- return azInstance.closeEndpoints(context, ports)
108+ return azInstance.apiCall(true, func(context *azureManagementContext) error {
109+ return azInstance.closeEndpoints(context, ports)
110+ })
111 }
112
113 // closeEndpoints closes the endpoints in the Azure deployment. The caller is
114@@ -185,20 +231,15 @@
115 }
116
117 // Ports is specified in the Instance interface.
118-func (azInstance *azureInstance) Ports(machineId string) ([]instance.Port, error) {
119- env := azInstance.environ
120- context, err := env.getManagementAPI()
121- if err != nil {
122- return nil, err
123- }
124- defer env.releaseManagementAPI(context)
125-
126- ports, err := azInstance.listPorts(context)
127- if err != nil {
128- return nil, err
129- }
130- state.SortPorts(ports)
131- return ports, nil
132+func (azInstance *azureInstance) Ports(machineId string) (ports []instance.Port, err error) {
133+ err = azInstance.apiCall(false, func(context *azureManagementContext) error {
134+ ports, err = azInstance.listPorts(context)
135+ return err
136+ })
137+ if ports != nil {
138+ state.SortPorts(ports)
139+ }
140+ return ports, err
141 }
142
143 // listPorts returns the slice of ports (instance.Port) that this machine
144
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
150 import (
151 "encoding/base64"
152+ "fmt"
153+ "net/http"
154
155 gc "launchpad.net/gocheck"
156 "launchpad.net/gwacl"
157
158- "fmt"
159 "launchpad.net/juju-core/instance"
160- "net/http"
161+ jc "launchpad.net/juju-core/testing/checkers"
162 )
163
164 type instanceSuite struct{}
165@@ -95,6 +96,14 @@
166 return []byte(xml)
167 }
168
169+func prepareDeploymentInfoResponse(
170+ c *gc.C, dep gwacl.Deployment) []gwacl.DispatcherResponse {
171+ return []gwacl.DispatcherResponse{
172+ gwacl.NewDispatcherResponse(
173+ serialize(c, &dep), http.StatusOK, nil),
174+ }
175+}
176+
177 func preparePortChangeConversation(
178 c *gc.C, service *gwacl.HostedServiceDescriptor,
179 deployments ...gwacl.Deployment) []gwacl.DispatcherResponse {
180@@ -146,6 +155,42 @@
181 }
182 }
183
184+func (*instanceSuite) TestAddresses(c *gc.C) {
185+ name := "service-name"
186+ vnn := "Virt Net Name"
187+ service := makeHostedServiceDescriptor(name)
188+ responses := prepareDeploymentInfoResponse(c,
189+ gwacl.Deployment{
190+ RoleInstanceList: []gwacl.RoleInstance{
191+ gwacl.RoleInstance{IPAddress: "1.2.3.4"},
192+ },
193+ VirtualNetworkName: vnn,
194+ })
195+
196+ gwacl.PatchManagementAPIResponses(responses)
197+ inst := azureInstance{*service, makeEnviron(c)}
198+
199+ expected := []instance.Address{
200+ instance.Address{
201+ "1.2.3.4",
202+ instance.Ipv4Address,
203+ vnn,
204+ instance.NetworkCloudLocal,
205+ },
206+ instance.Address{
207+ name + "." + AZURE_DOMAIN_NAME,
208+ instance.HostName,
209+ "",
210+ instance.NetworkPublic,
211+ },
212+ }
213+
214+ addrs, err := inst.Addresses()
215+ c.Check(err, gc.IsNil)
216+
217+ c.Check(addrs, jc.SameContents, expected)
218+}
219+
220 func (*instanceSuite) TestOpenPorts(c *gc.C) {
221 service := makeHostedServiceDescriptor("service-name")
222 responses := preparePortChangeConversation(c, service,

Subscribers

People subscribed via source and target branches

to status/vote changes: