Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(416)

Side by Side Diff: environs/tools.go

Issue 6501106: environs: remove VarDir global
Patch Set: environs: remove VarDir global Created 11 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « environs/ec2/ec2.go ('k') | environs/tools_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 package environs 1 package environs
2 2
3 import ( 3 import (
4 "archive/tar" 4 "archive/tar"
5 "compress/gzip" 5 "compress/gzip"
6 "fmt" 6 "fmt"
7 "io" 7 "io"
8 "io/ioutil" 8 "io/ioutil"
9 "launchpad.net/juju-core/log" 9 "launchpad.net/juju-core/log"
10 "launchpad.net/juju-core/state" 10 "launchpad.net/juju-core/state"
11 "launchpad.net/juju-core/version" 11 "launchpad.net/juju-core/version"
12 "os" 12 "os"
13 "os/exec" 13 "os/exec"
14 "path" 14 "path"
15 "path/filepath" 15 "path/filepath"
16 "strings" 16 "strings"
17 ) 17 )
18 18
19 // VarDir is the directory where juju data is stored.
20 // The tools directories are stored inside the "tools" subdirectory
21 // inside VarDir.
22 var VarDir = "/var/lib/juju"
23
24 var toolPrefix = "tools/juju-" 19 var toolPrefix = "tools/juju-"
25 20
26 // ToolsList holds a list of available tools. Private tools take 21 // ToolsList holds a list of available tools. Private tools take
27 // precedence over public tools, even if they have a lower 22 // precedence over public tools, even if they have a lower
28 // version number. 23 // version number.
29 type ToolsList struct { 24 type ToolsList struct {
30 Private []*state.Tools 25 Private []*state.Tools
31 Public []*state.Tools 26 Public []*state.Tools
32 } 27 }
33 28
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
233 if bestTools == nil || bestTools.Number.Less(t.Number) { 228 if bestTools == nil || bestTools.Number.Less(t.Number) {
234 bestTools = t 229 bestTools = t
235 } 230 }
236 } 231 }
237 return bestTools 232 return bestTools
238 } 233 }
239 234
240 const urlFile = "downloaded-url.txt" 235 const urlFile = "downloaded-url.txt"
241 236
242 // toolsParentDir returns the tools parent directory. 237 // toolsParentDir returns the tools parent directory.
243 func toolsParentDir() string { 238 func toolsParentDir(dataDir string) string {
244 » return path.Join(VarDir, "tools") 239 » return path.Join(dataDir, "tools")
245 } 240 }
246 241
247 // UnpackTools reads a set of juju tools in gzipped tar-archive 242 // UnpackTools reads a set of juju tools in gzipped tar-archive
248 // format and unpacks them into the appropriate tools directory. 243 // format and unpacks them into the appropriate tools directory
249 // If a valid tools directory already exists, UnpackTools returns 244 // within dataDir. If a valid tools directory already exists,
250 // without error. 245 // UnpackTools returns without error.
251 func UnpackTools(tools *state.Tools, r io.Reader) (err error) { 246 func UnpackTools(dataDir string, tools *state.Tools, r io.Reader) (err error) {
252 zr, err := gzip.NewReader(r) 247 zr, err := gzip.NewReader(r)
253 if err != nil { 248 if err != nil {
254 return err 249 return err
255 } 250 }
256 defer zr.Close() 251 defer zr.Close()
257 252
258 // Make a temporary directory in the tools directory, 253 // Make a temporary directory in the tools directory,
259 // first ensuring that the tools directory exists. 254 // first ensuring that the tools directory exists.
260 » err = os.MkdirAll(toolsParentDir(), 0755) 255 » err = os.MkdirAll(toolsParentDir(dataDir), 0755)
261 if err != nil { 256 if err != nil {
262 return err 257 return err
263 } 258 }
264 » dir, err := ioutil.TempDir(toolsParentDir(), "unpacking-") 259 » dir, err := ioutil.TempDir(toolsParentDir(dataDir), "unpacking-")
265 if err != nil { 260 if err != nil {
266 return err 261 return err
267 } 262 }
268 defer removeAll(dir) 263 defer removeAll(dir)
269 264
270 tr := tar.NewReader(zr) 265 tr := tar.NewReader(zr)
271 for { 266 for {
272 hdr, err := tr.Next() 267 hdr, err := tr.Next()
273 if err == io.EOF { 268 if err == io.EOF {
274 break 269 break
(...skipping 10 matching lines...) Expand all
285 name := filepath.Join(dir, hdr.Name) 280 name := filepath.Join(dir, hdr.Name)
286 if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err ! = nil { 281 if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err ! = nil {
287 return fmt.Errorf("tar extract %q failed: %v", name, err ) 282 return fmt.Errorf("tar extract %q failed: %v", name, err )
288 } 283 }
289 } 284 }
290 err = ioutil.WriteFile(filepath.Join(dir, urlFile), []byte(tools.URL), 0 644) 285 err = ioutil.WriteFile(filepath.Join(dir, urlFile), []byte(tools.URL), 0 644)
291 if err != nil { 286 if err != nil {
292 return err 287 return err
293 } 288 }
294 289
295 » err = os.Rename(dir, ToolsDir(tools.Binary)) 290 » err = os.Rename(dir, ToolsDir(dataDir, tools.Binary))
296 // If we've failed to rename the directory, it may be because 291 // If we've failed to rename the directory, it may be because
297 // the directory already exists - if ReadTools succeeds, we 292 // the directory already exists - if ReadTools succeeds, we
298 // assume all's ok. 293 // assume all's ok.
299 if err != nil { 294 if err != nil {
300 » » _, err := ReadTools(tools.Binary) 295 » » _, err := ReadTools(dataDir, tools.Binary)
301 if err == nil { 296 if err == nil {
302 return nil 297 return nil
303 } 298 }
304 } 299 }
305 return nil 300 return nil
306 } 301 }
307 302
308 func removeAll(dir string) { 303 func removeAll(dir string) {
309 err := os.RemoveAll(dir) 304 err := os.RemoveAll(dir)
310 if err == nil || os.IsNotExist(err) { 305 if err == nil || os.IsNotExist(err) {
311 return 306 return
312 } 307 }
313 log.Printf("environs: cannot remove %q: %v", dir, err) 308 log.Printf("environs: cannot remove %q: %v", dir, err)
314 } 309 }
315 310
316 func writeFile(name string, mode os.FileMode, r io.Reader) error { 311 func writeFile(name string, mode os.FileMode, r io.Reader) error {
317 f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) 312 f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
318 if err != nil { 313 if err != nil {
319 return err 314 return err
320 } 315 }
321 defer f.Close() 316 defer f.Close()
322 _, err = io.Copy(f, r) 317 _, err = io.Copy(f, r)
323 return err 318 return err
324 } 319 }
325 320
326 // ReadTools checks that the tools for the given version exist 321 // ReadTools checks that the tools for the given version exist
327 // and returns a Tools instance describing them. 322 // in the dataDir directory, and returns a Tools instance describing them.
328 func ReadTools(vers version.Binary) (*state.Tools, error) { 323 func ReadTools(dataDir string, vers version.Binary) (*state.Tools, error) {
329 » dir := ToolsDir(vers) 324 » dir := ToolsDir(dataDir, vers)
330 urlData, err := ioutil.ReadFile(filepath.Join(dir, urlFile)) 325 urlData, err := ioutil.ReadFile(filepath.Join(dir, urlFile))
331 if err != nil { 326 if err != nil {
332 return nil, fmt.Errorf("cannot read URL in tools directory: %v", err) 327 return nil, fmt.Errorf("cannot read URL in tools directory: %v", err)
333 } 328 }
334 url := strings.TrimSpace(string(urlData)) 329 url := strings.TrimSpace(string(urlData))
335 if len(url) == 0 { 330 if len(url) == 0 {
336 return nil, fmt.Errorf("empty URL in tools directory %q", dir) 331 return nil, fmt.Errorf("empty URL in tools directory %q", dir)
337 } 332 }
338 // TODO(rog): do more verification here too, such as checking 333 // TODO(rog): do more verification here too, such as checking
339 // for the existence of certain files. 334 // for the existence of certain files.
340 return &state.Tools{ 335 return &state.Tools{
341 URL: url, 336 URL: url,
342 Binary: vers, 337 Binary: vers,
343 }, nil 338 }, nil
344 } 339 }
345 340
346 // ChangeAgentTools atomically replaces the agent-specific symlink 341 // ChangeAgentTools atomically replaces the agent-specific symlink
347 // under the tools directory so it points to the previously unpacked 342 // under dataDir so it points to the previously unpacked
348 // version vers. It returns the new tools read. 343 // version vers. It returns the new tools read.
349 func ChangeAgentTools(agentName string, vers version.Binary) (*state.Tools, erro r) { 344 func ChangeAgentTools(dataDir string, agentName string, vers version.Binary) (*s tate.Tools, error) {
350 » tools, err := ReadTools(vers) 345 » tools, err := ReadTools(dataDir, vers)
351 if err != nil { 346 if err != nil {
352 return nil, err 347 return nil, err
353 } 348 }
354 » tmpName := AgentToolsDir("tmplink-" + agentName) 349 » tmpName := AgentToolsDir(dataDir, "tmplink-"+agentName)
355 err = os.Symlink(tools.Binary.String(), tmpName) 350 err = os.Symlink(tools.Binary.String(), tmpName)
356 if err != nil { 351 if err != nil {
357 return nil, fmt.Errorf("cannot create tools symlink: %v", err) 352 return nil, fmt.Errorf("cannot create tools symlink: %v", err)
358 } 353 }
359 » err = os.Rename(tmpName, AgentToolsDir(agentName)) 354 » err = os.Rename(tmpName, AgentToolsDir(dataDir, agentName))
360 if err != nil { 355 if err != nil {
361 return nil, fmt.Errorf("cannot update tools symlink: %v", err) 356 return nil, fmt.Errorf("cannot update tools symlink: %v", err)
362 } 357 }
363 return tools, nil 358 return tools, nil
364 } 359 }
365 360
366 // ToolsStoragePath returns the slash-separated path that is used to store and 361 // ToolsStoragePath returns the slash-separated path that is used to store and
367 // retrieve the given version of the juju tools in a Storage. 362 // retrieve the given version of the juju tools in a Storage.
368 func ToolsStoragePath(vers version.Binary) string { 363 func ToolsStoragePath(vers version.Binary) string {
369 return toolPrefix + vers.String() + ".tgz" 364 return toolPrefix + vers.String() + ".tgz"
370 } 365 }
371 366
372 // ToolsDir returns the slash-separated directory name that is used to 367 // ToolsDir returns the slash-separated directory name that is used to
373 // store binaries for the given version of the juju tools. 368 // store binaries for the given version of the juju tools
374 func ToolsDir(vers version.Binary) string { 369 // within the dataDir directory.
375 » return path.Join(VarDir, "tools", vers.String()) 370 func ToolsDir(dataDir string, vers version.Binary) string {
371 » return path.Join(dataDir, "tools", vers.String())
376 } 372 }
377 373
378 // AgentToolsDir returns the slash-separated directory name that is used 374 // AgentToolsDir returns the slash-separated directory name that is used
379 // to store binaries for the tools used by the given agent. 375 // to store binaries for the tools used by the given agent
376 // within the given dataDir directory.
380 // Conventionally it is a symbolic link to the actual tools directory. 377 // Conventionally it is a symbolic link to the actual tools directory.
381 func AgentToolsDir(agentName string) string { 378 func AgentToolsDir(dataDir, agentName string) string {
382 » return path.Join(VarDir, "tools", agentName) 379 » return path.Join(dataDir, "tools", agentName)
383 } 380 }
384 381
385 // ToolsSearchFlags gives options when searching 382 // ToolsSearchFlags gives options when searching
386 // for tools. 383 // for tools.
387 type ToolsSearchFlags int 384 type ToolsSearchFlags int
388 385
389 const ( 386 const (
390 // HighestVersion indicates that versions above the version being 387 // HighestVersion indicates that versions above the version being
391 // searched for may be included in the search. The default behavior 388 // searched for may be included in the search. The default behavior
392 // is to search for versions <= the one provided. 389 // is to search for versions <= the one provided.
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 return nil, &NotFoundError{fmt.Errorf("file %q not found in empty storag e", name)} 474 return nil, &NotFoundError{fmt.Errorf("file %q not found in empty storag e", name)}
478 } 475 }
479 476
480 func (s emptyStorage) URL(string) (string, error) { 477 func (s emptyStorage) URL(string) (string, error) {
481 return "", fmt.Errorf("empty storage has no URLs") 478 return "", fmt.Errorf("empty storage has no URLs")
482 } 479 }
483 480
484 func (s emptyStorage) List(prefix string) ([]string, error) { 481 func (s emptyStorage) List(prefix string) ([]string, error) {
485 return nil, nil 482 return nil, nil
486 } 483 }
OLDNEW
« no previous file with comments | « environs/ec2/ec2.go ('k') | environs/tools_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b