Merge lp:~thumper/juju-core/local-config into lp:~go-bot/juju-core/trunk
- local-config
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Tim Penhey |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1374 |
Proposed branch: | lp:~thumper/juju-core/local-config |
Merge into: | lp:~go-bot/juju-core/trunk |
Prerequisite: | lp:~thumper/juju-core/local-provider-skeleton |
Diff against target: |
502 lines (+382/-8) 10 files modified
environs/local/config.go (+53/-0) environs/local/config_test.go (+89/-0) environs/local/environ.go (+16/-3) environs/local/environ_test.go (+25/-0) environs/local/environprovider.go (+89/-5) environs/local/environprovider_test.go (+35/-0) environs/local/export_test.go (+6/-0) environs/local/local_test.go (+1/-0) utils/file.go (+19/-0) utils/file_test.go (+49/-0) |
To merge this branch: | bzr merge lp:~thumper/juju-core/local-config |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+171956@code.launchpad.net |
Commit message
Add initial local provider config.
Right now, just looking at the directories for storing
the files used by public and private storage. The branch
also adds in the Validation and setting/getting methods
for the config.
Description of the change
Add initial local provider config.
Right now, just looking at the directories for storing
the files used by public and private storage. The branch
also adds in the Validation and setting/getting methods
for the config.
Tim Penhey (thumper) wrote : | # |
Ian Booth (wallyworld) wrote : | # |
A few comments inline.
It would be great also if the config tests could be structured a little
like the ones used for the other providers, where and array of test
scenarios for things like default value handling etc is tested.
https:/
File environs/
https:/
environs/
"/var/lib/
Perhaps a stupid question - do we really want to make these in a
location where the user needs privileges or access granted? Why not
somewhere in their home dir? That would also allow many users on the one
machine to run juju with a local provider without interfering with each
other/
https:/
environs/
error {
Just curious - do we already have this function somewhere? If not, could
we consider putting it in a utils package or something. I'm a bit
perplexed the std libs don't have this built in.
https:/
File environs/
https:/
environs/
TestValidateCon
Could we follow the other providers and put config tests in a
config_test.go file?
https:/
File environs/
https:/
environs/
Other providers need more than one mutex. The one protecting config is
called cfgMutex. Perhaps we can follow that convention? Or do we think
there will only be the one mutex required?
https:/
environs/
*config.Config {
Other providers use an intermediate ecfg() method. I'm not sure why.
Perhaps we could find out if that approach is for a good reason and
adopt it if required here too?
William Reade (fwereade) wrote : | # |
LGTM, I think, modulo quibbles below:
https:/
File environs/
https:/
environs/
"/var/lib/
On 2013/06/28 06:22:57, wallyworld wrote:
> Perhaps a stupid question - do we really want to make these in a
location where
> the user needs privileges or access granted? Why not somewhere in
their home
> dir? That would also allow many users on the one machine to run juju
with a
> local provider without interfering with each other/
This is a good point and a noble goal. Somewhat implies badging things
like containers with username as well as environment name; probably a
good thing.
https:/
environs/
error {
On 2013/06/28 06:22:57, wallyworld wrote:
> Just curious - do we already have this function somewhere? If not,
could we
> consider putting it in a utils package or something. I'm a bit
perplexed the std
> libs don't have this built in.
os.MkdirAll
https:/
environs/
We need to check the storage dirs don't change, I think.
https:/
File environs/
https:/
environs/
On 2013/06/28 06:22:57, wallyworld wrote:
> Other providers need more than one mutex. The one protecting config is
called
> cfgMutex. Perhaps we can follow that convention? Or do we think there
will only
> be the one mutex required?
I'm ok with this as it is... I don't think this is going to be an
overwhelmingly complex provider. I hope.
https:/
environs/
These are immutable, right?
https:/
File environs/
https:/
environs/
This'll run all the tests in providerSuite a second time, won't it?
Tim Penhey (thumper) wrote : | # |
Please take a look.
https:/
File environs/
https:/
environs/
"/var/lib/
On 2013/06/28 06:22:57, wallyworld wrote:
> Perhaps a stupid question - do we really want to make these in a
location where
> the user needs privileges or access granted? Why not somewhere in
their home
> dir? That would also allow many users on the one machine to run juju
with a
> local provider without interfering with each other/
Interesting point. But there is a bigger problem here. lxc containers
(at least in precise now) require the containers to be in /var/lib/lxc.
This means that while also namespacing the storage area, we should also
make sure that we namespace the containers with the user id.
I really didn't consider multiple users using a local provider on one
machine as this was a little outside the scope of the local provider.
However we should probably support it.
With respect to the privileged location, this isn't an issue as the user
will need to 'sudo juju bootstrap' the local provider as we need to do
stuff with lxc containers, which requires root.
https:/
environs/
error {
On 2013/06/28 14:43:50, fwereade wrote:
> On 2013/06/28 06:22:57, wallyworld wrote:
> > Just curious - do we already have this function somewhere? If not,
could we
> > consider putting it in a utils package or something. I'm a bit
perplexed the
> std
> > libs don't have this built in.
> os.MkdirAll
Hmm... will just simplify to use os.MkdirAll.
https:/
environs/
On 2013/06/28 14:43:50, fwereade wrote:
> We need to check the storage dirs don't change, I think.
OK
https:/
File environs/
https:/
environs/
TestValidateCon
On 2013/06/28 06:22:57, wallyworld wrote:
> Could we follow the other providers and put config tests in a
config_test.go
> file?
OK.
https:/
File environs/
https:/
environs/
*config.Config {
On 2013/06/28 06:22:57, wallyworld wrote:
> Other providers use an intermediate ecfg() method. I'm not sure why.
Perhaps we
> could find out if that approach is for a good reason and adopt it if
required
> here too?
I may do this if we decide that it is necessary. I'm not convinced that
it is necessary yet though.
Ian Booth (wallyworld) wrote : | # |
LGTM. I think I'd prefer the config tests to use a similar structure as
those for other providers wrt testing default value handling etc but
won't block on that.
John A Meinel (jameinel) wrote : | # |
LGTM
https:/
File environs/
https:/
environs/
"/var/lib/
> With respect to the privileged location, this isn't an issue as the
user will
> need to 'sudo juju bootstrap' the local provider as we need to do
stuff with lxc
> containers, which requires root.
Since you need sudo access, I think just badging the instances with the
environment gets you enough. You don't really need to also add the
username.
https:/
environs/
You don't have to add them here, but wouldn't you want to document the 2
fields that you just added (private-storage and public-storage).
Also, I think you don't support 'default-series' yet, so it doesn't make
sense to have it commented out, since people would think they could just
uncomment it and change it. (Though that is probably where you are
heading.)
https:/
File environs/
https:/
environs/
see LICENCE file for details.
I'm a bit surprised the file is named 'environ-
isn't valid as a go identifier, I believe, though only the package name
must match)
I don't think we have any other filenames with '-' in them, though.
https:/
environs/
I've been following more of a:
stdlib
3rd-party-libs
juju-core libs
For imports. Does that make sense, or is it splitting them up too much?
It would look like:
import (
"fmt"
"path/filepath"
. "launchpad.
"launchpad.
"launchpad.
"launchpad.
"launchpad.
. "launchpad.
)
Tim Penhey (thumper) wrote : | # |
On 2013/07/01 02:45:43, wallyworld wrote:
> LGTM. I think I'd prefer the config tests to use a similar structure
as those
> for other providers wrt testing default value handling etc but won't
block on
> that.
Actually I did try that, but there is too much state to deal with in the
tests
for this to be useful.
Tim Penhey (thumper) wrote : | # |
On 2013/07/01 10:34:04, jameinel wrote:
> LGTM
https:/
> File environs/
https:/
> environs/
> "/var/lib/
> >
> > With respect to the privileged location, this isn't an issue as the
user will
> > need to 'sudo juju bootstrap' the local provider as we need to do
stuff with
> lxc
> > containers, which requires root.
> Since you need sudo access, I think just badging the instances with
the
> environment gets you enough. You don't really need to also add the
username.
Not if multiple people use the default environment name called "local".
https:/
> environs/
> You don't have to add them here, but wouldn't you want to document the
2 fields
> that you just added (private-storage and public-storage).
I did in patch 2.
> Also, I think you don't support 'default-series' yet, so it doesn't
make sense
> to have it commented out, since people would think they could just
uncomment it
> and change it. (Though that is probably where you are heading.)
Removed it.
https:/
> File environs/
https:/
> environs/
AGPLv3, see
> LICENCE file for details.
> I'm a bit surprised the file is named 'environ-
isn't
> valid as a go identifier, I believe, though only the package name must
match)
> I don't think we have any other filenames with '-' in them, though.
We do, but I may have added them too. I've renamed it
environprovider.go and environprovider
https:/
> environs/
> I've been following more of a:
> stdlib
> 3rd-party-libs
> juju-core libs
> For imports. Does that make sense, or is it splitting them up too
much?
> It would look like:
> import (
> "fmt"
> "path/filepath"
> . "launchpad.
> "launchpad.
> "launchpad.
> "launchpad.
> "launchpad.
> . "launchpad.
> )
Actually I like that even more, and fixed the code to follow this.
John A Meinel (jameinel) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
...
>
>> Since you need sudo access, I think just badging the instances
>> with
> the
>> environment gets you enough. You don't really need to also add
>> the
> username.
>
> Not if multiple people use the default environment name called
> "local".
>
That is true, but it is also true if you use shared credentials on
Openstack or EC2 or anywhere else.
I think if people want to share a local system they can use different
names for their environments. (A lot of people run the user 'ubuntu'
anyway, right?)
We *can* add user, I just don't think it actually adds much, and it
isn't something we do anywhere else.
John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.13 (Cygwin)
Comment: Using GnuPG with Thunderbird - http://
iEYEARECAAYFAlH
UBIAoIebSwSIn7V
=NnXm
-----END PGP SIGNATURE-----
Preview Diff
1 | === added file 'environs/local/config.go' |
2 | --- environs/local/config.go 1970-01-01 00:00:00 +0000 |
3 | +++ environs/local/config.go 2013-07-02 04:37:23 +0000 |
4 | @@ -0,0 +1,53 @@ |
5 | +// Copyright 2013 Canonical Ltd. |
6 | +// Licensed under the AGPLv3, see LICENCE file for details. |
7 | + |
8 | +package local |
9 | + |
10 | +import ( |
11 | + "fmt" |
12 | + "os" |
13 | + |
14 | + "launchpad.net/juju-core/environs/config" |
15 | + "launchpad.net/juju-core/schema" |
16 | +) |
17 | + |
18 | +var configChecker = schema.StrictFieldMap( |
19 | + schema.Fields{ |
20 | + "shared-storage": schema.String(), |
21 | + "storage": schema.String(), |
22 | + }, |
23 | + schema.Defaults{ |
24 | + "shared-storage": "", |
25 | + "storage": "", |
26 | + }, |
27 | +) |
28 | + |
29 | +type environConfig struct { |
30 | + *config.Config |
31 | + user string |
32 | + attrs map[string]interface{} |
33 | +} |
34 | + |
35 | +func newEnvironConfig(config *config.Config, attrs map[string]interface{}) *environConfig { |
36 | + user := os.Getenv("USER") |
37 | + return &environConfig{ |
38 | + Config: config, |
39 | + user: user, |
40 | + attrs: attrs, |
41 | + } |
42 | +} |
43 | + |
44 | +// Since it is technically possible for two different users on one machine to |
45 | +// have the same local provider name, we need to have a simple way to |
46 | +// namespace the file locations, but more importantly the lxc containers. |
47 | +func (c *environConfig) namespace() string { |
48 | + return fmt.Sprintf("%s-%s", c.user, c.Name()) |
49 | +} |
50 | + |
51 | +func (c *environConfig) publicStorageDir() string { |
52 | + return c.attrs["shared-storage"].(string) |
53 | +} |
54 | + |
55 | +func (c *environConfig) privateStorageDir() string { |
56 | + return c.attrs["storage"].(string) |
57 | +} |
58 | |
59 | === added file 'environs/local/config_test.go' |
60 | --- environs/local/config_test.go 1970-01-01 00:00:00 +0000 |
61 | +++ environs/local/config_test.go 2013-07-02 04:37:23 +0000 |
62 | @@ -0,0 +1,89 @@ |
63 | +// Copyright 2013 Canonical Ltd. |
64 | +// Licensed under the AGPLv3, see LICENCE file for details. |
65 | + |
66 | +package local_test |
67 | + |
68 | +import ( |
69 | + "fmt" |
70 | + "os" |
71 | + "path/filepath" |
72 | + |
73 | + gc "launchpad.net/gocheck" |
74 | + "launchpad.net/juju-core/environs/config" |
75 | + "launchpad.net/juju-core/environs/local" |
76 | + "launchpad.net/juju-core/testing" |
77 | + jc "launchpad.net/juju-core/testing/checkers" |
78 | +) |
79 | + |
80 | +type configSuite struct { |
81 | + baseProviderSuite |
82 | + oldUser string |
83 | +} |
84 | + |
85 | +var _ = gc.Suite(&configSuite{}) |
86 | + |
87 | +func (s *configSuite) SetUpTest(c *gc.C) { |
88 | + s.baseProviderSuite.SetUpTest(c) |
89 | + s.oldUser = os.Getenv("USER") |
90 | + err := os.Setenv("USER", "tester") |
91 | + c.Assert(err, gc.IsNil) |
92 | + c.Assert(err, gc.IsNil) |
93 | +} |
94 | + |
95 | +func (s *configSuite) TearDownTest(c *gc.C) { |
96 | + os.Setenv("USER", s.oldUser) |
97 | + s.baseProviderSuite.TearDownTest(c) |
98 | +} |
99 | + |
100 | +func minimalConfigValues() map[string]interface{} { |
101 | + return map[string]interface{}{ |
102 | + "name": "test", |
103 | + "type": "local", |
104 | + // While the ca-cert bits aren't entirely minimal, they avoid the need |
105 | + // to set up a fake home. |
106 | + "ca-cert": testing.CACert, |
107 | + "ca-private-key": testing.CAKey, |
108 | + } |
109 | +} |
110 | + |
111 | +func minimalConfig(c *gc.C) *config.Config { |
112 | + minimal := minimalConfigValues() |
113 | + testConfig, err := config.New(minimal) |
114 | + c.Assert(err, gc.IsNil) |
115 | + return testConfig |
116 | +} |
117 | + |
118 | +func (s *configSuite) TestValidateConfig(c *gc.C) { |
119 | + testConfig := minimalConfig(c) |
120 | + |
121 | + valid, err := local.Provider.Validate(testConfig, nil) |
122 | + c.Assert(err, gc.IsNil) |
123 | + unknownAttrs := valid.UnknownAttrs() |
124 | + |
125 | + publicDir := fmt.Sprintf(s.public, "tester-test") |
126 | + c.Assert(publicDir, jc.IsDirectory) |
127 | + c.Assert(unknownAttrs["shared-storage"], gc.Equals, publicDir) |
128 | + |
129 | + privateDir := fmt.Sprintf(s.private, "tester-test") |
130 | + c.Assert(privateDir, jc.IsDirectory) |
131 | + c.Assert(unknownAttrs["storage"], gc.Equals, privateDir) |
132 | +} |
133 | + |
134 | +func (s *configSuite) TestValidateConfigWithStorage(c *gc.C) { |
135 | + values := minimalConfigValues() |
136 | + public := filepath.Join(c.MkDir(), "public", "storage") |
137 | + private := filepath.Join(c.MkDir(), "private", "storage") |
138 | + values["shared-storage"] = public |
139 | + values["storage"] = private |
140 | + testConfig, err := config.New(values) |
141 | + c.Assert(err, gc.IsNil) |
142 | + |
143 | + valid, err := local.Provider.Validate(testConfig, nil) |
144 | + c.Assert(err, gc.IsNil) |
145 | + unknownAttrs := valid.UnknownAttrs() |
146 | + |
147 | + c.Assert(public, jc.IsDirectory) |
148 | + c.Assert(unknownAttrs["shared-storage"], gc.Equals, public) |
149 | + c.Assert(private, jc.IsDirectory) |
150 | + c.Assert(unknownAttrs["storage"], gc.Equals, private) |
151 | +} |
152 | |
153 | === modified file 'environs/local/environ.go' |
154 | --- environs/local/environ.go 2013-06-28 02:35:59 +0000 |
155 | +++ environs/local/environ.go 2013-07-02 04:37:23 +0000 |
156 | @@ -5,6 +5,7 @@ |
157 | |
158 | import ( |
159 | "fmt" |
160 | + "sync" |
161 | |
162 | "launchpad.net/juju-core/constraints" |
163 | "launchpad.net/juju-core/environs" |
164 | @@ -18,7 +19,9 @@ |
165 | var _ environs.Environ = (*localEnviron)(nil) |
166 | |
167 | type localEnviron struct { |
168 | - name string |
169 | + localMutex sync.Mutex |
170 | + config *environConfig |
171 | + name string |
172 | } |
173 | |
174 | // Name is specified in the Environ interface. |
175 | @@ -38,12 +41,22 @@ |
176 | |
177 | // Config is specified in the Environ interface. |
178 | func (env *localEnviron) Config() *config.Config { |
179 | - panic("unimplemented") |
180 | + env.localMutex.Lock() |
181 | + defer env.localMutex.Unlock() |
182 | + return env.config.Config |
183 | } |
184 | |
185 | // SetConfig is specified in the Environ interface. |
186 | func (env *localEnviron) SetConfig(cfg *config.Config) error { |
187 | - return fmt.Errorf("not implemented") |
188 | + config, err := provider.newConfig(cfg) |
189 | + if err != nil { |
190 | + logger.Errorf("failed to create new environ config: %v", err) |
191 | + return err |
192 | + } |
193 | + env.localMutex.Lock() |
194 | + defer env.localMutex.Unlock() |
195 | + env.config = config |
196 | + return nil |
197 | } |
198 | |
199 | // StartInstance is specified in the Environ interface. |
200 | |
201 | === added file 'environs/local/environ_test.go' |
202 | --- environs/local/environ_test.go 1970-01-01 00:00:00 +0000 |
203 | +++ environs/local/environ_test.go 2013-07-02 04:37:23 +0000 |
204 | @@ -0,0 +1,25 @@ |
205 | +// Copyright 2013 Canonical Ltd. |
206 | +// Licensed under the AGPLv3, see LICENCE file for details. |
207 | + |
208 | +package local_test |
209 | + |
210 | +import ( |
211 | + gc "launchpad.net/gocheck" |
212 | + |
213 | + "launchpad.net/juju-core/environs/local" |
214 | +) |
215 | + |
216 | +type environSuite struct { |
217 | + baseProviderSuite |
218 | +} |
219 | + |
220 | +var _ = gc.Suite(&environSuite{}) |
221 | + |
222 | +func (*environSuite) TestName(c *gc.C) { |
223 | + testConfig := minimalConfig(c) |
224 | + |
225 | + environ, err := local.Provider.Open(testConfig) |
226 | + c.Assert(err, gc.IsNil) |
227 | + |
228 | + c.Assert(environ.Name(), gc.Equals, "test") |
229 | +} |
230 | |
231 | === renamed file 'environs/local/environ-provider.go' => 'environs/local/environprovider.go' |
232 | --- environs/local/environ-provider.go 2013-06-28 01:58:45 +0000 |
233 | +++ environs/local/environprovider.go 2013-07-02 04:37:23 +0000 |
234 | @@ -5,11 +5,14 @@ |
235 | |
236 | import ( |
237 | "fmt" |
238 | + "os" |
239 | + |
240 | + "launchpad.net/loggo" |
241 | |
242 | "launchpad.net/juju-core/environs" |
243 | "launchpad.net/juju-core/environs/config" |
244 | "launchpad.net/juju-core/instance" |
245 | - "launchpad.net/loggo" |
246 | + "launchpad.net/juju-core/utils" |
247 | ) |
248 | |
249 | var logger = loggo.GetLogger("juju.environs.local") |
250 | @@ -24,19 +27,92 @@ |
251 | environs.RegisterProvider("local", &environProvider{}) |
252 | } |
253 | |
254 | +var ( |
255 | + defaultPublicStorageDir = "/var/lib/juju/local/%s/public" |
256 | + defaultPrivateStorageDir = "/var/lib/juju/local/%s/private" |
257 | +) |
258 | + |
259 | // Open implements environs.EnvironProvider.Open. |
260 | func (environProvider) Open(cfg *config.Config) (environs.Environ, error) { |
261 | - return nil, fmt.Errorf("not implemented") |
262 | + logger.Infof("opening environment %q", cfg.Name()) |
263 | + environ := &localEnviron{name: cfg.Name()} |
264 | + err := environ.SetConfig(cfg) |
265 | + if err != nil { |
266 | + logger.Errorf("failure setting config: %v", err) |
267 | + return nil, err |
268 | + } |
269 | + return environ, nil |
270 | } |
271 | |
272 | // Validate implements environs.EnvironProvider.Validate. |
273 | -func (environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { |
274 | - return nil, fmt.Errorf("not implemented") |
275 | +func (provider environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { |
276 | + // Check for valid changes for the base config values. |
277 | + if err := config.Validate(cfg, old); err != nil { |
278 | + return nil, err |
279 | + } |
280 | + v, err := configChecker.Coerce(cfg.UnknownAttrs(), nil) |
281 | + if err != nil { |
282 | + return nil, err |
283 | + } |
284 | + localConfig := newEnvironConfig(cfg, v.(map[string]interface{})) |
285 | + // Before potentially creating directories, make sure that the |
286 | + // public storage and private storage values have not changed. |
287 | + if old != nil { |
288 | + oldLocalConfig, err := provider.newConfig(old) |
289 | + if err != nil { |
290 | + return nil, fmt.Errorf("old config is not a valid local config: %v", old) |
291 | + } |
292 | + if localConfig.publicStorageDir() != oldLocalConfig.publicStorageDir() { |
293 | + return nil, fmt.Errorf("cannot change shared-storage from %q to %q", |
294 | + oldLocalConfig.publicStorageDir(), |
295 | + localConfig.publicStorageDir()) |
296 | + } |
297 | + if localConfig.privateStorageDir() != oldLocalConfig.privateStorageDir() { |
298 | + return nil, fmt.Errorf("cannot change storage from %q to %q", |
299 | + oldLocalConfig.privateStorageDir(), |
300 | + localConfig.privateStorageDir()) |
301 | + } |
302 | + } |
303 | + dir := utils.NormalizePath(localConfig.publicStorageDir()) |
304 | + if dir == "." { |
305 | + dir = fmt.Sprintf(defaultPublicStorageDir, localConfig.namespace()) |
306 | + localConfig.attrs["shared-storage"] = dir |
307 | + } |
308 | + logger.Tracef("ensure shared-storage dir %s exists", dir) |
309 | + if err := os.MkdirAll(dir, 0755); err != nil { |
310 | + logger.Errorf("failed to make directory for shared storage at %s: %v", dir, err) |
311 | + return nil, err |
312 | + } |
313 | + |
314 | + dir = utils.NormalizePath(localConfig.privateStorageDir()) |
315 | + if dir == "." { |
316 | + dir = fmt.Sprintf(defaultPrivateStorageDir, localConfig.namespace()) |
317 | + localConfig.attrs["storage"] = dir |
318 | + } |
319 | + logger.Tracef("ensure storage dir %s exists", dir) |
320 | + if err := os.MkdirAll(dir, 0755); err != nil { |
321 | + logger.Errorf("failed to make directory for storage at %s: %v", dir, err) |
322 | + return nil, err |
323 | + } |
324 | + |
325 | + // Apply the coerced unknown values back into the config. |
326 | + return cfg.Apply(localConfig.attrs) |
327 | } |
328 | |
329 | // BoilerplateConfig implements environs.EnvironProvider.BoilerplateConfig. |
330 | func (environProvider) BoilerplateConfig() string { |
331 | - return "not implemented" |
332 | + return ` |
333 | +## https://juju.ubuntu.com/get-started/local/ |
334 | +local: |
335 | + type: local |
336 | + # Override the storage location to store the private files for this environment in the |
337 | + # specified location. The default location is /var/lib/juju/local/<USER>-<ENV>/private |
338 | + # storage: ~/.juju/local/private |
339 | + # Override the shared-storage location to store the public files for this environment in the |
340 | + # specified location. The default location is /var/lib/juju/local/<USER>-<ENV>/public |
341 | + # shared-storage: ~/.juju/local/public |
342 | + |
343 | +`[1:] |
344 | } |
345 | |
346 | // SecretAttrs implements environs.EnvironProvider.SecretAttrs. |
347 | @@ -63,3 +139,11 @@ |
348 | func (environProvider) InstanceId() (instance.Id, error) { |
349 | return "", fmt.Errorf("not implemented") |
350 | } |
351 | + |
352 | +func (environProvider) newConfig(cfg *config.Config) (*environConfig, error) { |
353 | + valid, err := provider.Validate(cfg, nil) |
354 | + if err != nil { |
355 | + return nil, err |
356 | + } |
357 | + return newEnvironConfig(valid, valid.UnknownAttrs()), nil |
358 | +} |
359 | |
360 | === added file 'environs/local/environprovider_test.go' |
361 | --- environs/local/environprovider_test.go 1970-01-01 00:00:00 +0000 |
362 | +++ environs/local/environprovider_test.go 2013-07-02 04:37:23 +0000 |
363 | @@ -0,0 +1,35 @@ |
364 | +// Copyright 2013 Canonical Ltd. |
365 | +// Licensed under the AGPLv3, see LICENCE file for details. |
366 | + |
367 | +package local_test |
368 | + |
369 | +import ( |
370 | + "path/filepath" |
371 | + |
372 | + gc "launchpad.net/gocheck" |
373 | + "launchpad.net/loggo" |
374 | + |
375 | + "launchpad.net/juju-core/environs/local" |
376 | + "launchpad.net/juju-core/testing" |
377 | +) |
378 | + |
379 | +type baseProviderSuite struct { |
380 | + testing.LoggingSuite |
381 | + public string |
382 | + private string |
383 | + oldPublic string |
384 | + oldPrivate string |
385 | +} |
386 | + |
387 | +func (s *baseProviderSuite) SetUpTest(c *gc.C) { |
388 | + s.LoggingSuite.SetUpTest(c) |
389 | + loggo.GetLogger("juju.environs.local").SetLogLevel(loggo.TRACE) |
390 | + s.public = filepath.Join(c.MkDir(), "%s", "public") |
391 | + s.private = filepath.Join(c.MkDir(), "%s", "private") |
392 | + s.oldPublic, s.oldPrivate = local.SetDefaultStorageDirs(s.public, s.private) |
393 | +} |
394 | + |
395 | +func (s *baseProviderSuite) TearDownTest(c *gc.C) { |
396 | + local.SetDefaultStorageDirs(s.oldPublic, s.oldPrivate) |
397 | + s.LoggingSuite.TearDownTest(c) |
398 | +} |
399 | |
400 | === modified file 'environs/local/export_test.go' |
401 | --- environs/local/export_test.go 2013-06-30 22:58:37 +0000 |
402 | +++ environs/local/export_test.go 2013-07-02 04:37:23 +0000 |
403 | @@ -4,3 +4,9 @@ |
404 | package local |
405 | |
406 | var Provider = provider |
407 | + |
408 | +func SetDefaultStorageDirs(public, private string) (oldPublic, oldPrivate string) { |
409 | + oldPublic, defaultPublicStorageDir = defaultPublicStorageDir, public |
410 | + oldPrivate, defaultPrivateStorageDir = defaultPrivateStorageDir, private |
411 | + return |
412 | +} |
413 | |
414 | === modified file 'environs/local/local_test.go' |
415 | --- environs/local/local_test.go 2013-06-30 22:58:37 +0000 |
416 | +++ environs/local/local_test.go 2013-07-02 04:37:23 +0000 |
417 | @@ -7,6 +7,7 @@ |
418 | stdtesting "testing" |
419 | |
420 | . "launchpad.net/gocheck" |
421 | + |
422 | "launchpad.net/juju-core/environs" |
423 | "launchpad.net/juju-core/environs/local" |
424 | "launchpad.net/juju-core/testing" |
425 | |
426 | === added file 'utils/file.go' |
427 | --- utils/file.go 1970-01-01 00:00:00 +0000 |
428 | +++ utils/file.go 2013-07-02 04:37:23 +0000 |
429 | @@ -0,0 +1,19 @@ |
430 | +// Copyright 2013 Canonical Ltd. |
431 | +// Licensed under the AGPLv3, see LICENCE file for details. |
432 | + |
433 | +package utils |
434 | + |
435 | +import ( |
436 | + "os" |
437 | + "path/filepath" |
438 | + "strings" |
439 | +) |
440 | + |
441 | +// NormalizePath replaces a leading ~ with $HOME, and removes any .. or . path |
442 | +// elements. |
443 | +func NormalizePath(dir string) string { |
444 | + if strings.HasPrefix(dir, "~/") { |
445 | + dir = filepath.Join(os.Getenv("HOME"), dir[2:]) |
446 | + } |
447 | + return filepath.Clean(dir) |
448 | +} |
449 | |
450 | === added file 'utils/file_test.go' |
451 | --- utils/file_test.go 1970-01-01 00:00:00 +0000 |
452 | +++ utils/file_test.go 2013-07-02 04:37:23 +0000 |
453 | @@ -0,0 +1,49 @@ |
454 | +// Copyright 2013 Canonical Ltd. |
455 | +// Licensed under the AGPLv3, see LICENCE file for details. |
456 | + |
457 | +package utils_test |
458 | + |
459 | +import ( |
460 | + "os" |
461 | + |
462 | + gc "launchpad.net/gocheck" |
463 | + "launchpad.net/juju-core/utils" |
464 | +) |
465 | + |
466 | +type fileSuite struct { |
467 | + oldHome string |
468 | +} |
469 | + |
470 | +var _ = gc.Suite(&fileSuite{}) |
471 | + |
472 | +func (s *fileSuite) SetUpTest(c *gc.C) { |
473 | + s.oldHome = os.Getenv("HOME") |
474 | + err := os.Setenv("HOME", "/home/test-user") |
475 | + c.Assert(err, gc.IsNil) |
476 | +} |
477 | + |
478 | +func (s *fileSuite) TearDownTest(c *gc.C) { |
479 | + err := os.Setenv("HOME", s.oldHome) |
480 | + c.Assert(err, gc.IsNil) |
481 | +} |
482 | + |
483 | +func (*fileSuite) TestNormalizePath(c *gc.C) { |
484 | + for _, test := range []struct { |
485 | + path string |
486 | + expected string |
487 | + }{{ |
488 | + path: "/var/lib/juju", |
489 | + expected: "/var/lib/juju", |
490 | + }, { |
491 | + path: "~/foo", |
492 | + expected: "/home/test-user/foo", |
493 | + }, { |
494 | + path: "~/foo//../bar", |
495 | + expected: "/home/test-user/bar", |
496 | + }, { |
497 | + path: "~bob/foo", |
498 | + expected: "~bob/foo", |
499 | + }} { |
500 | + c.Assert(utils.NormalizePath(test.path), gc.Equals, test.expected) |
501 | + } |
502 | +} |
Reviewers: mp+171956_ code.launchpad. net,
Message:
Please take a look.
Description:
Add initial local provider config.
Right now, just looking at the directories for storing
the files used by public and private storage. The branch
also adds in the Validation and setting/getting methods
for the config.
https:/ /code.launchpad .net/~thumper/ juju-core/ local-config/ +merge/ 171956
Requires: /code.launchpad .net/~thumper/ juju-core/ local-provider- skeleton/ +merge/ 171951
https:/
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/10734043/
Affected files: local/config. go local/environ- provider. go local/environ- provider_ test.go local/environ. go local/environ_ test.go local/export_ test.go
A [revision details]
A environs/
M environs/
A environs/
M environs/
A environs/
A environs/