Merge lp:~thumper/juju-core/local-provider-machine-0 into lp:~go-bot/juju-core/trunk

Proposed by Tim Penhey
Status: Merged
Approved by: Tim Penhey
Approved revision: no longer in the source branch.
Merged at revision: 1472
Proposed branch: lp:~thumper/juju-core/local-provider-machine-0
Merge into: lp:~go-bot/juju-core/trunk
Prerequisite: lp:~thumper/juju-core/find-jujud
Diff against target: 213 lines (+72/-15)
5 files modified
cmd/juju/bootstrap.go (+4/-1)
environs/local/config.go (+5/-0)
environs/local/environ.go (+60/-11)
environs/local/environprovider.go (+2/-2)
environs/local/instance.go (+1/-1)
To merge this branch: bzr merge lp:~thumper/juju-core/local-provider-machine-0
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+174921@code.launchpad.net

Commit message

Machine agent for local provider bootstrap

If you are using a local provider, always upload tools.
This uses the standard mechanism for getting tools into
the local provider storage.

From there the tools are unpacked the same way as an
agent would normally do it, although we do cheat and go
directly to the file on disk so we don't have to pretend
to download it somewhere else.

https://codereview.appspot.com/11327043/

Description of the change

Machine agent for local provider bootstrap

If you are using a local provider, alway upload tools.
This uses the standard mechanism for getting tools into
the local provider storage.

From there the tools are unpacked the same way as an
agent would normally do it, although we do cheat and go
directly to the file on disk so we don't have to pretend
to download it somewhere else.

I changed the error message for the not implemented errors
so I could see which thing was failing and needed to be
implemented to get the next step working.

https://codereview.appspot.com/11327043/

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :
Download full text (8.9 KiB)

Reviewers: mp+174921_code.launchpad.net,

Message:
Please take a look.

Description:
Machine agent for local provider bootstrap

If you are using a local provider, alway upload tools.
This uses the standard mechanism for getting tools into
the local provider storage.

 From there the tools are unpacked the same way as an
agent would normally do it, although we do cheat and go
directly to the file on disk so we don't have to pretend
to download it somewhere else.

I changed the error message for the not implemented errors
so I could see which thing was failing and needed to be
implemented to get the next step working.

https://code.launchpad.net/~thumper/juju-core/local-provider-machine-0/+merge/174921

Requires:
https://code.launchpad.net/~thumper/juju-core/find-jujud/+merge/174918

(do not edit description out of merge proposal)

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

Affected files:
   A [revision details]
   M cmd/juju/bootstrap.go
   M environs/local/config.go
   M environs/local/environ.go
   M environs/local/environprovider.go
   M environs/local/instance.go

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>

Index: cmd/juju/bootstrap.go
=== modified file 'cmd/juju/bootstrap.go'
--- cmd/juju/bootstrap.go 2013-05-02 15:55:42 +0000
+++ cmd/juju/bootstrap.go 2013-07-14 21:51:24 +0000
@@ -68,7 +68,10 @@
   if err != nil {
    return err
   }
-
+ // If we are using a local provider, always upload tools.
+ if environ.Config().Type() == "local" {
+ c.UploadTools = true
+ }
   if c.UploadTools {
    // Force version.Current, for consistency with subsequent upgrade-juju
    // (see UpgradeJujuCommand).

Index: environs/local/config.go
=== modified file 'environs/local/config.go'
--- environs/local/config.go 2013-07-09 02:28:22 +0000
+++ environs/local/config.go 2013-07-14 23:07:24 +0000
@@ -73,6 +73,10 @@
   return filepath.Join(c.rootDir(), "db")
  }

+func (c *environConfig) logDir() string {
+ return filepath.Join(c.rootDir(), "log")
+}
+
  func (c *environConfig) configFile(filename string) string {
   return filepath.Join(c.rootDir(), filename)
  }
@@ -107,6 +111,7 @@
    c.sharedStorageDir(),
    c.storageDir(),
    c.mongoDir(),
+ c.logDir(),
   } {
    logger.Tracef("creating directory %s", dirname)
    if err := os.MkdirAll(dirname, 0755); err != nil {

Index: environs/local/environ.go
=== modified file 'environs/local/environ.go'
--- environs/local/environ.go 2013-07-12 02:08:36 +0000
+++ environs/local/environ.go 2013-07-14 23:07:24 +0000
@@ -7,6 +7,7 @@
   "fmt"
   "io/ioutil"
   "net"
+ "net/url"
   "os"
   "path/filepath"
   "sync"
@@ -22,6 +23,7 @@
   "launchpad.net/juju-core/state/api"
   "launchpad.net/juju-core/upstart"
   "launchpad.net/juju-core/utils"
+ "launchpad.net/juju-core/version"
  )

  // lxcBridgeName is the name of the network interface that the local
provider
@@ -64,6 +66,10 @@
   return "juju-db-" + env.config.names...

Read more...

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

LGTM. I wonder if uploading tools really is required for the local
provider, seems synctools in some form should be extendable to work with
the local provider as well (download to well-known location or similar).

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go
File environs/local/environ.go (right):

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go#newcode370
environs/local/environ.go:370: tools.Binary.Series =
version.CurrentSeries()
Rather than doing this, can't we take the user's machine series when
finding tools, and retry if that finds nothing, using the configured
series?

https://codereview.appspot.com/11327043/

Revision history for this message
Tim Penhey (thumper) wrote :

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go
File environs/local/environ.go (right):

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go#newcode370
environs/local/environ.go:370: tools.Binary.Series =
version.CurrentSeries()
On 2013/07/16 10:06:57, gz wrote:
> Rather than doing this, can't we take the user's machine series when
finding
> tools, and retry if that finds nothing, using the configured series?

Unfortunately that is kinda hard-coded further down the path in
FindBootstrapTools, and somewhat out of the scope of this change.

https://codereview.appspot.com/11327043/

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

The encapsulation breaks and tools version issues make me sad but I
appreciate the need to get this landed. So long as bugs and TODOs are
raised to ensure stuff gets fixed.

LGTM

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go
File environs/local/environ.go (right):

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go#newcode363
environs/local/environ.go:363: // Again, brutally abuse our knowledge
here.
These breaks in encapsulation - can we raise a bug and add a TODO to fix
them. Or is it expected that the sync-tools work can be used. Either
way, a TODO is warranted as we don't want to leave this as is long term.

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go#newcode370
environs/local/environ.go:370: tools.Binary.Series =
version.CurrentSeries()
On 2013/07/17 01:45:47, thumper wrote:
> On 2013/07/16 10:06:57, gz wrote:
> > Rather than doing this, can't we take the user's machine series when
finding
> > tools, and retry if that finds nothing, using the configured series?

> Unfortunately that is kinda hard-coded further down the path in
> FindBootstrapTools, and somewhat out of the scope of this change.

So if I am on Saucy, precise tools might still be used locally. Can we
please raise a bug and add a TODO to ensure this gets fixed.

https://codereview.appspot.com/11327043/

Revision history for this message
Tim Penhey (thumper) wrote :

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go
File environs/local/environ.go (right):

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go#newcode363
environs/local/environ.go:363: // Again, brutally abuse our knowledge
here.
On 2013/07/17 02:33:41, wallyworld wrote:
> These breaks in encapsulation - can we raise a bug and add a TODO to
fix them.
> Or is it expected that the sync-tools work can be used. Either way, a
TODO is
> warranted as we don't want to leave this as is long term.

Actually I'm not entirely convinced that we have to. We are in the
special case of bringing up a machine agent. It is ok to use knowledge
here.

https://codereview.appspot.com/11327043/diff/1/environs/local/environ.go#newcode370
environs/local/environ.go:370: tools.Binary.Series =
version.CurrentSeries()
On 2013/07/17 02:33:41, wallyworld wrote:
> On 2013/07/17 01:45:47, thumper wrote:
> > On 2013/07/16 10:06:57, gz wrote:
> > > Rather than doing this, can't we take the user's machine series
when finding
> > > tools, and retry if that finds nothing, using the configured
series?
> >
> > Unfortunately that is kinda hard-coded further down the path in
> > FindBootstrapTools, and somewhat out of the scope of this change.

> So if I am on Saucy, precise tools might still be used locally. Can we
please
> raise a bug and add a TODO to ensure this gets fixed.

No. What is used is the jujud on your machine, which is either built
for you locally, or part of the package. Either way, they are fine.
Also, these same tools are uploaded for the machines. Since Go makes
stand alone executables, this too works.

https://codereview.appspot.com/11327043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmd/juju/bootstrap.go'
2--- cmd/juju/bootstrap.go 2013-05-02 15:55:42 +0000
3+++ cmd/juju/bootstrap.go 2013-07-17 03:17:27 +0000
4@@ -68,7 +68,10 @@
5 if err != nil {
6 return err
7 }
8-
9+ // If we are using a local provider, always upload tools.
10+ if environ.Config().Type() == "local" {
11+ c.UploadTools = true
12+ }
13 if c.UploadTools {
14 // Force version.Current, for consistency with subsequent upgrade-juju
15 // (see UpgradeJujuCommand).
16
17=== modified file 'environs/local/config.go'
18--- environs/local/config.go 2013-07-16 21:56:22 +0000
19+++ environs/local/config.go 2013-07-17 03:17:27 +0000
20@@ -73,6 +73,10 @@
21 return filepath.Join(c.rootDir(), "db")
22 }
23
24+func (c *environConfig) logDir() string {
25+ return filepath.Join(c.rootDir(), "log")
26+}
27+
28 func (c *environConfig) configFile(filename string) string {
29 return filepath.Join(c.rootDir(), filename)
30 }
31@@ -104,6 +108,7 @@
32 c.sharedStorageDir(),
33 c.storageDir(),
34 c.mongoDir(),
35+ c.logDir(),
36 } {
37 logger.Tracef("creating directory %s", dirname)
38 if err := os.MkdirAll(dirname, 0755); err != nil {
39
40=== modified file 'environs/local/environ.go'
41--- environs/local/environ.go 2013-07-17 00:26:31 +0000
42+++ environs/local/environ.go 2013-07-17 03:17:27 +0000
43@@ -7,6 +7,7 @@
44 "fmt"
45 "io/ioutil"
46 "net"
47+ "net/url"
48 "os"
49 "path/filepath"
50 "sync"
51@@ -22,6 +23,7 @@
52 "launchpad.net/juju-core/state/api"
53 "launchpad.net/juju-core/upstart"
54 "launchpad.net/juju-core/utils"
55+ "launchpad.net/juju-core/version"
56 )
57
58 // lxcBridgeName is the name of the network interface that the local provider
59@@ -64,6 +66,10 @@
60 return "juju-db-" + env.config.namespace()
61 }
62
63+func (env *localEnviron) machineAgentServiceName() string {
64+ return "juju-agent-" + env.config.namespace()
65+}
66+
67 // ensureCertOwner checks to make sure that the cert files created
68 // by the bootstrap command are owned by the user and not root.
69 func (env *localEnviron) ensureCertOwner() error {
70@@ -143,11 +149,7 @@
71 }
72 defer stateConnection.Close()
73
74- // TODO(thumper): upload tools into the storage
75-
76- // TODO(thumper): start the machine agent for machine-0
77-
78- return nil
79+ return env.setupLocalMachineAgent(cons)
80 }
81
82 // StateInfo is specified in the Environ interface.
83@@ -219,12 +221,12 @@
84 info *state.Info,
85 apiInfo *api.Info,
86 ) (instance.Instance, *instance.HardwareCharacteristics, error) {
87- return nil, nil, fmt.Errorf("not implemented")
88+ return nil, nil, fmt.Errorf("start instance not implemented")
89 }
90
91 // StopInstances is specified in the Environ interface.
92 func (env *localEnviron) StopInstances([]instance.Instance) error {
93- return fmt.Errorf("not implemented")
94+ return fmt.Errorf("stop instance not implemented")
95 }
96
97 // Instances is specified in the Environ interface.
98@@ -285,17 +287,17 @@
99
100 // OpenPorts is specified in the Environ interface.
101 func (env *localEnviron) OpenPorts(ports []instance.Port) error {
102- return fmt.Errorf("not implemented")
103+ return fmt.Errorf("open ports not implemented")
104 }
105
106 // ClosePorts is specified in the Environ interface.
107 func (env *localEnviron) ClosePorts(ports []instance.Port) error {
108- return fmt.Errorf("not implemented")
109+ return fmt.Errorf("close ports not implemented")
110 }
111
112 // Ports is specified in the Environ interface.
113 func (env *localEnviron) Ports() ([]instance.Port, error) {
114- return nil, fmt.Errorf("not implemented")
115+ return nil, nil
116 }
117
118 // Provider is specified in the Environ interface.
119@@ -340,6 +342,53 @@
120 return cert, key, nil
121 }
122
123+func (env *localEnviron) setupLocalMachineAgent(cons constraints.Value) error {
124+ dataDir := env.config.rootDir()
125+ toolList, err := environs.FindBootstrapTools(env, cons)
126+ if err != nil {
127+ return err
128+ }
129+ // ensure we have at least one valid tools
130+ if len(toolList) == 0 {
131+ return fmt.Errorf("No bootstrap tools found")
132+ }
133+ // unpack the first tools into the agent dir.
134+ tools := toolList[0]
135+ logger.Infof("tools: %#v", tools)
136+ // brutally abuse our knowledge of storage to directly open the file
137+ toolsUrl, err := url.Parse(tools.URL)
138+ toolsLocation := filepath.Join(env.config.storageDir(), toolsUrl.Path)
139+ logger.Infof("tools location: %v", toolsLocation)
140+ toolsFile, err := os.Open(toolsLocation)
141+ defer toolsFile.Close()
142+ // Again, brutally abuse our knowledge here.
143+
144+ // The tools that FindBootstrapTools has returned us are based on the
145+ // default series in the config. However we are running potentially on a
146+ // different series. When the machine agent is started, it will be
147+ // looking based on the current series, so we need to override the series
148+ // returned in the tools to be the current series.
149+ tools.Binary.Series = version.CurrentSeries()
150+ err = agent.UnpackTools(dataDir, tools, toolsFile)
151+
152+ machineId := "0" // Always machine 0
153+ tag := state.MachineTag(machineId)
154+ toolsDir := agent.SharedToolsDir(dataDir, tools.Binary)
155+ logDir := env.config.logDir()
156+ logConfig := "--debug" // TODO(thumper): specify loggo config
157+ agent := upstart.MachineAgentUpstartService(
158+ env.machineAgentServiceName(),
159+ toolsDir, dataDir, logDir, tag, machineId, logConfig)
160+
161+ agent.InitDir = upstartScriptLocation
162+ logger.Infof("installing service %s to %s", env.machineAgentServiceName(), agent.InitDir)
163+ if err := agent.Install(); err != nil {
164+ logger.Errorf("could not install machine agent service: %v", err)
165+ return err
166+ }
167+ return nil
168+}
169+
170 func (env *localEnviron) findBridgeAddress() (string, error) {
171 bridge, err := net.InterfaceByName(lxcBridgeName)
172 if err != nil {
173@@ -370,7 +419,7 @@
174 StateServerCert: cert,
175 StateServerKey: key,
176 StatePort: env.config.StatePort(),
177- APIPort: env.config.StatePort(),
178+ APIPort: env.config.APIPort(),
179 MachineNonce: state.BootstrapNonce,
180 }
181 if err := conf.Write(); err != nil {
182
183=== modified file 'environs/local/environprovider.go'
184--- environs/local/environprovider.go 2013-07-16 22:32:42 +0000
185+++ environs/local/environprovider.go 2013-07-17 03:17:27 +0000
186@@ -107,12 +107,12 @@
187
188 // PublicAddress implements environs.EnvironProvider.PublicAddress.
189 func (environProvider) PublicAddress() (string, error) {
190- return "", fmt.Errorf("not implemented")
191+ return "", fmt.Errorf("public address not implemented")
192 }
193
194 // PrivateAddress implements environs.EnvironProvider.PrivateAddress.
195 func (environProvider) PrivateAddress() (string, error) {
196- return "", fmt.Errorf("not implemented")
197+ return "", fmt.Errorf("private address not implemented")
198 }
199
200 // InstanceId implements environs.EnvironProvider.InstanceId.
201
202=== modified file 'environs/local/instance.go'
203--- environs/local/instance.go 2013-07-17 00:26:31 +0000
204+++ environs/local/instance.go 2013-07-17 03:17:27 +0000
205@@ -55,7 +55,7 @@
206
207 // Ports implements instance.Instance.Ports.
208 func (inst *localInstance) Ports(machineId string) ([]instance.Port, error) {
209- return nil, fmt.Errorf("not implemented")
210+ return nil, nil
211 }
212
213 // Add a string representation of the id.

Subscribers

People subscribed via source and target branches

to status/vote changes: