193
193
var Upload UploadFunc = upload
195
195
func upload(stor storage.Storage, forceVersion *version.Number, fakeSeries ...string) (*coretools.Tools, error) {
196
// TODO(rog) find binaries from $PATH when not using a development
197
// version of juju within a $GOPATH.
196
builtTools, err := BuildToolsTarball(forceVersion)
200
defer os.RemoveAll(builtTools.Dir)
199
201
logger.Debugf("Uploading tools for %v", fakeSeries)
200
// We create the entire archive before asking the environment to
201
// start uploading so that we can be sure we have archived
203
f, err := ioutil.TempFile("", "juju-tgz")
208
defer os.Remove(f.Name())
209
toolsVersion, sha256Hash, err := envtools.BundleTools(f, forceVersion)
213
fileInfo, err := f.Stat()
215
return nil, fmt.Errorf("cannot stat newly made tools archive: %v", err)
217
size := fileInfo.Size()
218
logger.Infof("built tools %v (%dkB)", toolsVersion, (size+512)/1024)
219
baseToolsDir, err := ioutil.TempDir("", "")
223
defer os.RemoveAll(baseToolsDir)
202
return SyncBuiltTools(stor, builtTools, fakeSeries...)
205
// cloneToolsForSeries copies the built tools tarball into a tarball for the specified
206
// series and generates corresponding metadata.
207
func cloneToolsForSeries(toolsInfo *BuiltTools, series ...string) error {
225
208
// Copy the tools to the target storage, recording a Tools struct for each one.
226
209
var targetTools coretools.List
210
targetTools = append(targetTools, &coretools.Tools{
211
Version: toolsInfo.Version,
212
Size: toolsInfo.Size,
213
SHA256: toolsInfo.Sha256Hash,
227
215
putTools := func(vers version.Binary) (string, error) {
228
216
name := envtools.StorageName(vers)
229
err = utils.CopyFile(filepath.Join(baseToolsDir, name), f.Name())
217
src := filepath.Join(toolsInfo.Dir, toolsInfo.StorageName)
218
dest := filepath.Join(toolsInfo.Dir, name)
219
err := utils.CopyFile(dest, src)
233
223
// Append to targetTools the attributes required to write out tools metadata.
234
224
targetTools = append(targetTools, &coretools.Tools{
226
Size: toolsInfo.Size,
227
SHA256: toolsInfo.Sha256Hash,
241
err = os.MkdirAll(filepath.Join(baseToolsDir, storage.BaseToolsPath, "releases"), 0755)
245
logger.Debugf("generating tarballs for %v", fakeSeries)
246
for _, series := range fakeSeries {
231
logger.Debugf("generating tarballs for %v", series)
232
for _, series := range series {
247
233
_, err := simplestreams.SeriesVersion(series)
251
if series != toolsVersion.Series {
252
fakeVersion := toolsVersion
237
if series != toolsInfo.Version.Series {
238
fakeVersion := toolsInfo.Version
253
239
fakeVersion.Series = series
254
240
if _, err := putTools(fakeVersion); err != nil {
259
name, err := putTools(toolsVersion)
263
245
// The tools have been copied to a temp location from which they will be uploaded,
264
246
// now write out the matching simplestreams metadata so that SyncTools can find them.
265
metadataStore, err := filestorage.NewFileStorageWriter(baseToolsDir, filestorage.UseDefaultTmpDir)
247
metadataStore, err := filestorage.NewFileStorageWriter(toolsInfo.Dir)
269
251
logger.Debugf("generating tools metadata")
270
err = envtools.MergeAndWriteMetadata(metadataStore, targetTools, false)
252
return envtools.MergeAndWriteMetadata(metadataStore, targetTools, false)
255
// BuiltTools contains metadata for a tools tarball resulting from
256
// a call to BundleTools.
257
type BuiltTools struct {
258
Version version.Binary
265
// BuildToolsTarballFunc is a function which can build a tools tarball.
266
type BuildToolsTarballFunc func(forceVersion *version.Number) (*BuiltTools, error)
268
// Override for testing.
269
var BuildToolsTarball BuildToolsTarballFunc = buildToolsTarball
271
// buildToolsTarball bundles a tools tarball and places it in a temp directory in
272
// the expected tools path.
273
func buildToolsTarball(forceVersion *version.Number) (builtTools *BuiltTools, err error) {
274
// TODO(rog) find binaries from $PATH when not using a development
275
// version of juju within a $GOPATH.
277
logger.Debugf("Building tools")
278
// We create the entire archive before asking the environment to
279
// start uploading so that we can be sure we have archived
281
f, err := ioutil.TempFile("", "juju-tgz")
286
defer os.Remove(f.Name())
287
toolsVersion, sha256Hash, err := envtools.BundleTools(f, forceVersion)
291
fileInfo, err := f.Stat()
293
return nil, fmt.Errorf("cannot stat newly made tools archive: %v", err)
295
size := fileInfo.Size()
296
logger.Infof("built tools %v (%dkB)", toolsVersion, (size+512)/1024)
297
baseToolsDir, err := ioutil.TempDir("", "")
302
// If we exit with an error, clean up the built tools directory.
305
os.RemoveAll(baseToolsDir)
309
err = os.MkdirAll(filepath.Join(baseToolsDir, storage.BaseToolsPath, "releases"), 0755)
313
storageName := envtools.StorageName(toolsVersion)
314
err = utils.CopyFile(filepath.Join(baseToolsDir, storageName), f.Name())
319
Version: toolsVersion,
321
StorageName: storageName,
323
Sha256Hash: sha256Hash,
327
// SyncBuiltTools copies to storage a tools tarball and cloned copies for each series.
328
func SyncBuiltTools(stor storage.Storage, builtTools *BuiltTools, fakeSeries ...string) (*coretools.Tools, error) {
329
if err := cloneToolsForSeries(builtTools, fakeSeries...); err != nil {
275
332
syncContext := &SyncContext{
276
Source: baseToolsDir,
333
Source: builtTools.Dir,
278
335
AllVersions: true,
279
Dev: toolsVersion.IsDev(),
280
MajorVersion: toolsVersion.Major,
336
Dev: builtTools.Version.IsDev(),
337
MajorVersion: builtTools.Version.Major,
281
338
MinorVersion: -1,
283
340
logger.Debugf("uploading tools to cloud storage")
284
err = SyncTools(syncContext)
341
err := SyncTools(syncContext)
288
url, err := stor.URL(name)
345
url, err := stor.URL(builtTools.StorageName)
292
349
return &coretools.Tools{
293
Version: toolsVersion,
350
Version: builtTools.Version,
352
Size: builtTools.Size,
353
SHA256: builtTools.Sha256Hash,