Merge lp:~axwalk/juju-core/lp1300264-manual-unresolvable-address into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Merged
Approved by: Andrew Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 2535
Proposed branch: lp:~axwalk/juju-core/lp1300264-manual-unresolvable-address
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 229 lines (+95/-60)
5 files modified
environs/manual/addresses.go (+25/-12)
environs/manual/addresses_test.go (+57/-17)
environs/manual/export_test.go (+1/-1)
environs/manual/provisioner.go (+7/-29)
provider/manual/instance.go (+5/-1)
To merge this branch: bzr merge lp:~axwalk/juju-core/lp1300264-manual-unresolvable-address
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+213581@code.launchpad.net

Commit message

environs/manual: don't require resolvable hostname

This change makes it so that the hostname provided
during manual provisioning is not necessarily
resolvable from the machine provisioning. If this
is the case, the machine will not be given a public
address.

There's another change here, which is that we no
longer perform a reverse lookup or record the
resolved addresses in state; we only store the
input address if it's an IP or if it's a resolvable
hostname. All other addresses will come from the
machine agent itself.

Fixes lp:1300264

https://codereview.appspot.com/82930044/

Description of the change

environs/manual: don't require resolvable hostname

This change makes it so that the hostname provided
during manual provisioning is not necessarily
resolvable from the machine provisioning. If this
is the case, the machine will not be given a public
address.

There's another change here, which is that we no
longer perform a reverse lookup or record the
resolved addresses in state; we only store the
input address if it's an IP or if it's a resolvable
hostname. All other addresses will come from the
machine agent itself.

Fixes lp:1300264

https://codereview.appspot.com/82930044/

To post a comment you must log in.
Revision history for this message
Andrew Wilkins (axwalk) wrote :

Reviewers: mp+213581_code.launchpad.net,

Message:
Please take a look.

Description:
environs/manual: don't require resolvable hostname

This change makes it so that the hostname provided
during manual provisioning is not necessarily
resolvable from the machine provisioning. If this
is the case, the machine will not be given a public
address.

There's another change here, which is that we no
longer perform a reverse lookup or record the
resolved addresses in state; we only store the
input address if it's an IP or if it's a resolvable
hostname. All other addresses will come from the
machine agent itself.

Fixes lp:1300264

https://code.launchpad.net/~axwalk/juju-core/lp1300264-manual-unresolvable-address/+merge/213581

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/82930044/

Affected files (+86, -60 lines):
   A [revision details]
   M environs/manual/addresses.go
   M environs/manual/addresses_test.go
   M environs/manual/export_test.go
   M environs/manual/provisioner.go
   M provider/manual/instance.go

Revision history for this message
Ian Booth (wallyworld) wrote :

LGTM but please consider the suggestion to improve the test

https://codereview.appspot.com/82930044/diff/1/environs/manual/addresses_test.go
File environs/manual/addresses_test.go (right):

https://codereview.appspot.com/82930044/diff/1/environs/manual/addresses_test.go#newcode22
environs/manual/addresses_test.go:22: func (s *addressesSuite)
TestHostAddress(c *gc.C) {
I'd prefer this test split up into different tests for IP address vs
hostname etc. Also, it would be good if the mocked NetLookupHost
function would error based on the input arg eg if host were "valid.host"
it would resolve, if it were "invalid.host", it would raise an error. I
think that's cleaner than the approach taken and removes the extra
variables.

https://codereview.appspot.com/82930044/diff/1/environs/manual/provisioner.go
File environs/manual/provisioner.go (right):

https://codereview.appspot.com/82930044/diff/1/environs/manual/provisioner.go#newcode236
environs/manual/provisioner.go:236: addrs = append(addrs, addr)
Did we want any logging here?

https://codereview.appspot.com/82930044/

Revision history for this message
Andrew Wilkins (axwalk) wrote :

Please take a look.

https://codereview.appspot.com/82930044/diff/1/environs/manual/addresses_test.go
File environs/manual/addresses_test.go (right):

https://codereview.appspot.com/82930044/diff/1/environs/manual/addresses_test.go#newcode22
environs/manual/addresses_test.go:22: func (s *addressesSuite)
TestHostAddress(c *gc.C) {
On 2014/04/01 04:46:17, wallyworld wrote:
> I'd prefer this test split up into different tests for IP address vs
hostname
> etc. Also, it would be good if the mocked NetLookupHost function would
error
> based on the input arg eg if host were "valid.host" it would resolve,
if it were
> "invalid.host", it would raise an error. I think that's cleaner than
the
> approach taken and removes the extra variables.

Done.

https://codereview.appspot.com/82930044/diff/1/environs/manual/provisioner.go
File environs/manual/provisioner.go (right):

https://codereview.appspot.com/82930044/diff/1/environs/manual/provisioner.go#newcode236
environs/manual/provisioner.go:236: addrs = append(addrs, addr)
On 2014/04/01 04:46:17, wallyworld wrote:
> Did we want any logging here?

There's nothing really to log. We no longer use the result of resolving,
other than success/failure. No log message == success.

https://codereview.appspot.com/82930044/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'environs/manual/addresses.go'
2--- environs/manual/addresses.go 2014-01-30 03:18:20 +0000
3+++ environs/manual/addresses.go 2014-04-02 02:23:48 +0000
4@@ -4,20 +4,33 @@
5 package manual
6
7 import (
8+ "net"
9+
10 "launchpad.net/juju-core/instance"
11 )
12
13-var instanceHostAddresses = instance.HostAddresses
14+var netLookupHost = net.LookupHost
15
16-// HostAddresses returns the addresses for the specified
17-// hostname, and marks the input address as being public;
18-// all other addresses have "unknown" scope.
19-func HostAddresses(hostname string) ([]instance.Address, error) {
20- addrs, err := instanceHostAddresses(hostname)
21- if err != nil {
22- return nil, err
23- }
24- // The final address is the one we fed in: mark it as public.
25- addrs[len(addrs)-1].NetworkScope = instance.NetworkPublic
26- return addrs, nil
27+// HostAddress returns an instance.Address for the specified
28+// hostname, depending on whether it is an IP or a resolvable
29+// hostname. The address is given public scope.
30+func HostAddress(hostname string) (instance.Address, error) {
31+ if ip := net.ParseIP(hostname); ip != nil {
32+ addr := instance.Address{
33+ Value: ip.String(),
34+ Type: instance.DeriveAddressType(ip.String()),
35+ NetworkScope: instance.NetworkPublic,
36+ }
37+ return addr, nil
38+ }
39+ // Only a resolvable hostname may be used as a public address.
40+ if _, err := netLookupHost(hostname); err != nil {
41+ return instance.Address{}, err
42+ }
43+ addr := instance.Address{
44+ Value: hostname,
45+ Type: instance.HostName,
46+ NetworkScope: instance.NetworkPublic,
47+ }
48+ return addr, nil
49 }
50
51=== modified file 'environs/manual/addresses_test.go'
52--- environs/manual/addresses_test.go 2014-03-28 06:56:55 +0000
53+++ environs/manual/addresses_test.go 2014-04-02 02:23:48 +0000
54@@ -4,6 +4,8 @@
55 package manual_test
56
57 import (
58+ "errors"
59+
60 gc "launchpad.net/gocheck"
61
62 "launchpad.net/juju-core/environs/manual"
63@@ -11,27 +13,65 @@
64 "launchpad.net/juju-core/testing/testbase"
65 )
66
67+const (
68+ invalidHost = "testing.invalid"
69+ validHost = "testing.valid"
70+)
71+
72 type addressesSuite struct {
73 testbase.LoggingSuite
74+ netLookupHostCalled int
75 }
76
77 var _ = gc.Suite(&addressesSuite{})
78
79-func (s *addressesSuite) TestHostAddresses(c *gc.C) {
80- const hostname = "boxen0"
81- s.PatchValue(manual.InstanceHostAddresses, func(host string) ([]instance.Address, error) {
82- c.Check(host, gc.Equals, hostname)
83- return []instance.Address{
84- instance.NewAddress("192.168.0.1", instance.NetworkUnknown),
85- instance.NewAddress("nickname", instance.NetworkUnknown),
86- instance.NewAddress(hostname, instance.NetworkUnknown),
87- }, nil
88- })
89- addrs, err := manual.HostAddresses(hostname)
90- c.Assert(err, gc.IsNil)
91- c.Assert(addrs, gc.HasLen, 3)
92- // The last address is marked public, all others are unknown.
93- c.Assert(addrs[0].NetworkScope, gc.Equals, instance.NetworkUnknown)
94- c.Assert(addrs[1].NetworkScope, gc.Equals, instance.NetworkUnknown)
95- c.Assert(addrs[2].NetworkScope, gc.Equals, instance.NetworkPublic)
96+func (s *addressesSuite) SetUpTest(c *gc.C) {
97+ s.netLookupHostCalled = 0
98+ s.PatchValue(manual.NetLookupHost, func(host string) ([]string, error) {
99+ s.netLookupHostCalled++
100+ if host == invalidHost {
101+ return nil, errors.New("invalid host: " + invalidHost)
102+ }
103+ return []string{"127.0.0.1"}, nil
104+ })
105+}
106+
107+func (s *addressesSuite) TestHostAddress(c *gc.C) {
108+ addr, err := manual.HostAddress(validHost)
109+ c.Assert(s.netLookupHostCalled, gc.Equals, 1)
110+ c.Assert(err, gc.IsNil)
111+ c.Assert(addr, gc.Equals, instance.Address{
112+ Value: validHost,
113+ Type: instance.HostName,
114+ NetworkScope: instance.NetworkPublic,
115+ })
116+}
117+
118+func (s *addressesSuite) TestHostAddressError(c *gc.C) {
119+ addr, err := manual.HostAddress(invalidHost)
120+ c.Assert(s.netLookupHostCalled, gc.Equals, 1)
121+ c.Assert(err, gc.ErrorMatches, "invalid host: "+invalidHost)
122+ c.Assert(addr, gc.Equals, instance.Address{})
123+}
124+
125+func (s *addressesSuite) TestHostAddressIPv4(c *gc.C) {
126+ addr, err := manual.HostAddress("127.0.0.1")
127+ c.Assert(s.netLookupHostCalled, gc.Equals, 0)
128+ c.Assert(err, gc.IsNil)
129+ c.Assert(addr, gc.Equals, instance.Address{
130+ Value: "127.0.0.1",
131+ Type: instance.Ipv4Address,
132+ NetworkScope: instance.NetworkPublic,
133+ })
134+}
135+
136+func (s *addressesSuite) TestHostAddressIPv6(c *gc.C) {
137+ addr, err := manual.HostAddress("::1")
138+ c.Assert(s.netLookupHostCalled, gc.Equals, 0)
139+ c.Assert(err, gc.IsNil)
140+ c.Assert(addr, gc.Equals, instance.Address{
141+ Value: "::1",
142+ Type: instance.Ipv6Address,
143+ NetworkScope: instance.NetworkPublic,
144+ })
145 }
146
147=== modified file 'environs/manual/export_test.go'
148--- environs/manual/export_test.go 2014-03-12 12:21:40 +0000
149+++ environs/manual/export_test.go 2014-04-02 02:23:48 +0000
150@@ -4,7 +4,7 @@
151 package manual
152
153 var (
154- InstanceHostAddresses = &instanceHostAddresses
155+ NetLookupHost = &netLookupHost
156 ProvisionMachineAgent = &provisionMachineAgent
157 CheckProvisioned = checkProvisioned
158 )
159
160=== modified file 'environs/manual/provisioner.go'
161--- environs/manual/provisioner.go 2014-03-17 03:17:04 +0000
162+++ environs/manual/provisioner.go 2014-04-02 02:23:48 +0000
163@@ -8,7 +8,6 @@
164 "errors"
165 "fmt"
166 "io"
167- "net"
168 "strings"
169
170 "github.com/juju/loggo"
171@@ -229,34 +228,13 @@
172 if err != nil {
173 return nil, err
174 }
175- // First, gather the parameters needed to inject the existing host into state.
176- if ip := net.ParseIP(hostname); ip != nil {
177- // Do a reverse-lookup on the IP. The IP may not have
178- // a DNS entry, so just log a warning if this fails.
179- names, err := net.LookupAddr(ip.String())
180- if err != nil {
181- logger.Infof("failed to resolve %v: %v", ip, err)
182- } else {
183- logger.Infof("resolved %v to %v", ip, names)
184- hostname = names[0]
185- // TODO: jam 2014-01-09 https://bugs.launchpad.net/bugs/1267387
186- // We change what 'hostname' we are using here (rather
187- // than an IP address we use the DNS name). I'm not
188- // sure why that is better, but if we are changing the
189- // host, we should probably be returning the hostname
190- // to the parent function.
191- // Also, we don't seem to try and compare if 'ip' is in
192- // the list of addrs returned from
193- // instance.HostAddresses in case you might get
194- // multiple and one of them is what you are supposed to
195- // be using.
196- }
197- }
198- addrs, err := HostAddresses(hostname)
199- if err != nil {
200- return nil, err
201- }
202- logger.Infof("addresses for %v: %v", hostname, addrs)
203+
204+ var addrs []instance.Address
205+ if addr, err := HostAddress(hostname); err != nil {
206+ logger.Warningf("failed to compute public address for %q: %v", hostname, err)
207+ } else {
208+ addrs = append(addrs, addr)
209+ }
210
211 provisioned, err := checkProvisioned(hostname)
212 if err != nil {
213
214=== modified file 'provider/manual/instance.go'
215--- provider/manual/instance.go 2014-01-31 05:38:42 +0000
216+++ provider/manual/instance.go 2014-04-02 02:23:48 +0000
217@@ -26,7 +26,11 @@
218 }
219
220 func (inst manualBootstrapInstance) Addresses() (addresses []instance.Address, err error) {
221- return manual.HostAddresses(inst.host)
222+ addr, err := manual.HostAddress(inst.host)
223+ if err != nil {
224+ return nil, err
225+ }
226+ return []instance.Address{addr}, nil
227 }
228
229 func (inst manualBootstrapInstance) DNSName() (string, error) {

Subscribers

People subscribed via source and target branches

to status/vote changes: