OLD | NEW |
1 // Copyright 2013 Canonical Ltd. | 1 // Copyright 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package tools | 4 package tools |
5 | 5 |
6 import ( | 6 import ( |
7 "archive/tar" | 7 "archive/tar" |
8 "compress/gzip" | 8 "compress/gzip" |
9 "crypto/sha256" | 9 "crypto/sha256" |
10 "encoding/json" | 10 "encoding/json" |
11 "fmt" | 11 "fmt" |
12 "io" | 12 "io" |
13 "io/ioutil" | 13 "io/ioutil" |
14 "os" | 14 "os" |
15 "path" | 15 "path" |
16 "strings" | 16 "strings" |
17 | 17 |
18 » "github.com/errgo/errgo" | 18 » "github.com/juju/errgo/errors" |
19 | 19 |
20 coretools "launchpad.net/juju-core/tools" | 20 coretools "launchpad.net/juju-core/tools" |
21 "launchpad.net/juju-core/version" | 21 "launchpad.net/juju-core/version" |
22 ) | 22 ) |
23 | 23 |
24 const toolsFile = "downloaded-tools.txt" | 24 const toolsFile = "downloaded-tools.txt" |
25 | 25 |
26 // SharedToolsDir returns the directory that is used to | 26 // SharedToolsDir returns the directory that is used to |
27 // store binaries for the given version of the juju tools | 27 // store binaries for the given version of the juju tools |
28 // within the dataDir directory. | 28 // within the dataDir directory. |
(...skipping 27 matching lines...) Expand all Loading... |
56 _, err = io.Copy(f, zr) | 56 _, err = io.Copy(f, zr) |
57 if err != nil { | 57 if err != nil { |
58 return err | 58 return err |
59 } | 59 } |
60 defer os.Remove(f.Name()) | 60 defer os.Remove(f.Name()) |
61 // TODO(wallyworld) - 2013-09-24 bug=1229512 | 61 // TODO(wallyworld) - 2013-09-24 bug=1229512 |
62 // When we can ensure all tools records have valid checksums recorded, | 62 // When we can ensure all tools records have valid checksums recorded, |
63 // we can remove this test short circuit. | 63 // we can remove this test short circuit. |
64 gzipSHA256 := fmt.Sprintf("%x", sha256hash.Sum(nil)) | 64 gzipSHA256 := fmt.Sprintf("%x", sha256hash.Sum(nil)) |
65 if tools.SHA256 != "" && tools.SHA256 != gzipSHA256 { | 65 if tools.SHA256 != "" && tools.SHA256 != gzipSHA256 { |
66 » » return fmt.Errorf("tarball sha256 mismatch, expected %s, got %s"
, tools.SHA256, gzipSHA256) | 66 » » return errors.Newf("tarball sha256 mismatch, expected %s, got %s
", tools.SHA256, gzipSHA256) |
67 } | 67 } |
68 | 68 |
69 // Make a temporary directory in the tools directory, | 69 // Make a temporary directory in the tools directory, |
70 // first ensuring that the tools directory exists. | 70 // first ensuring that the tools directory exists. |
71 toolsDir := path.Join(dataDir, "tools") | 71 toolsDir := path.Join(dataDir, "tools") |
72 err = os.MkdirAll(toolsDir, 0755) | 72 err = os.MkdirAll(toolsDir, 0755) |
73 if err != nil { | 73 if err != nil { |
74 return err | 74 return err |
75 } | 75 } |
76 dir, err := ioutil.TempDir(toolsDir, "unpacking-") | 76 dir, err := ioutil.TempDir(toolsDir, "unpacking-") |
(...skipping 10 matching lines...) Expand all Loading... |
87 tr := tar.NewReader(f) | 87 tr := tar.NewReader(f) |
88 for { | 88 for { |
89 hdr, err := tr.Next() | 89 hdr, err := tr.Next() |
90 if err == io.EOF { | 90 if err == io.EOF { |
91 break | 91 break |
92 } | 92 } |
93 if err != nil { | 93 if err != nil { |
94 return err | 94 return err |
95 } | 95 } |
96 if strings.ContainsAny(hdr.Name, "/\\") { | 96 if strings.ContainsAny(hdr.Name, "/\\") { |
97 » » » return fmt.Errorf("bad name %q in tools archive", hdr.Na
me) | 97 » » » return errors.Newf("bad name %q in tools archive", hdr.N
ame) |
98 } | 98 } |
99 if hdr.Typeflag != tar.TypeReg { | 99 if hdr.Typeflag != tar.TypeReg { |
100 » » » return fmt.Errorf("bad file type %c in file %q in tools
archive", hdr.Typeflag, hdr.Name) | 100 » » » return errors.Newf("bad file type %c in file %q in tools
archive", hdr.Typeflag, hdr.Name) |
101 } | 101 } |
102 name := path.Join(dir, hdr.Name) | 102 name := path.Join(dir, hdr.Name) |
103 if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err !
= nil { | 103 if err := writeFile(name, os.FileMode(hdr.Mode&0777), tr); err !
= nil { |
104 » » » return errgo.Annotatef(err, "tar extract %q failed", nam
e) | 104 » » » return errors.Notef(err, "tar extract %q failed", name) |
105 } | 105 } |
106 } | 106 } |
107 toolsMetadataData, err := json.Marshal(tools) | 107 toolsMetadataData, err := json.Marshal(tools) |
108 if err != nil { | 108 if err != nil { |
109 return err | 109 return err |
110 } | 110 } |
111 err = ioutil.WriteFile(path.Join(dir, toolsFile), []byte(toolsMetadataDa
ta), 0644) | 111 err = ioutil.WriteFile(path.Join(dir, toolsFile), []byte(toolsMetadataDa
ta), 0644) |
112 if err != nil { | 112 if err != nil { |
113 return err | 113 return err |
114 } | 114 } |
(...skipping 28 matching lines...) Expand all Loading... |
143 return err | 143 return err |
144 } | 144 } |
145 | 145 |
146 // ReadTools checks that the tools information for the given version exists | 146 // ReadTools checks that the tools information for the given version exists |
147 // in the dataDir directory, and returns a Tools instance. | 147 // in the dataDir directory, and returns a Tools instance. |
148 // The tools information is json encoded in a text file, "downloaded-tools.txt". | 148 // The tools information is json encoded in a text file, "downloaded-tools.txt". |
149 func ReadTools(dataDir string, vers version.Binary) (*coretools.Tools, error) { | 149 func ReadTools(dataDir string, vers version.Binary) (*coretools.Tools, error) { |
150 dir := SharedToolsDir(dataDir, vers) | 150 dir := SharedToolsDir(dataDir, vers) |
151 toolsData, err := ioutil.ReadFile(path.Join(dir, toolsFile)) | 151 toolsData, err := ioutil.ReadFile(path.Join(dir, toolsFile)) |
152 if err != nil { | 152 if err != nil { |
153 » » return nil, fmt.Errorf("cannot read tools metadata in tools dire
ctory: %v", err) | 153 » » return nil, errors.Notef(err, "cannot read tools metadata in too
ls directory") |
154 } | 154 } |
155 var tools coretools.Tools | 155 var tools coretools.Tools |
156 if err := json.Unmarshal(toolsData, &tools); err != nil { | 156 if err := json.Unmarshal(toolsData, &tools); err != nil { |
157 » » return nil, fmt.Errorf("invalid tools metadata in tools director
y %q: %v", dir, err) | 157 » » return nil, errors.Notef(err, "invalid tools metadata in tools d
irectory %q", dir) |
158 } | 158 } |
159 return &tools, nil | 159 return &tools, nil |
160 } | 160 } |
161 | 161 |
162 // ChangeAgentTools atomically replaces the agent-specific symlink | 162 // ChangeAgentTools atomically replaces the agent-specific symlink |
163 // under dataDir so it points to the previously unpacked | 163 // under dataDir so it points to the previously unpacked |
164 // version vers. It returns the new tools read. | 164 // version vers. It returns the new tools read. |
165 func ChangeAgentTools(dataDir string, agentName string, vers version.Binary) (*c
oretools.Tools, error) { | 165 func ChangeAgentTools(dataDir string, agentName string, vers version.Binary) (*c
oretools.Tools, error) { |
166 tools, err := ReadTools(dataDir, vers) | 166 tools, err := ReadTools(dataDir, vers) |
167 if err != nil { | 167 if err != nil { |
168 return nil, err | 168 return nil, err |
169 } | 169 } |
170 tmpName := ToolsDir(dataDir, "tmplink-"+agentName) | 170 tmpName := ToolsDir(dataDir, "tmplink-"+agentName) |
171 err = os.Symlink(tools.Version.String(), tmpName) | 171 err = os.Symlink(tools.Version.String(), tmpName) |
172 if err != nil { | 172 if err != nil { |
173 » » return nil, fmt.Errorf("cannot create tools symlink: %v", err) | 173 » » return nil, errors.Notef(err, "cannot create tools symlink") |
174 } | 174 } |
175 err = os.Rename(tmpName, ToolsDir(dataDir, agentName)) | 175 err = os.Rename(tmpName, ToolsDir(dataDir, agentName)) |
176 if err != nil { | 176 if err != nil { |
177 » » return nil, fmt.Errorf("cannot update tools symlink: %v", err) | 177 » » return nil, errors.Notef(err, "cannot update tools symlink") |
178 } | 178 } |
179 return tools, nil | 179 return tools, nil |
180 } | 180 } |
OLD | NEW |