github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/upgrades/toolstorage.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package upgrades 5 6 import ( 7 "bytes" 8 "io" 9 10 "github.com/juju/errors" 11 "github.com/juju/utils" 12 13 "github.com/juju/juju/agent" 14 "github.com/juju/juju/environs" 15 "github.com/juju/juju/environs/filestorage" 16 "github.com/juju/juju/environs/simplestreams" 17 "github.com/juju/juju/environs/storage" 18 envtools "github.com/juju/juju/environs/tools" 19 "github.com/juju/juju/provider" 20 "github.com/juju/juju/state" 21 "github.com/juju/juju/state/toolstorage" 22 "github.com/juju/juju/tools" 23 ) 24 25 var stateToolsStorage = (*state.State).ToolsStorage 26 27 // migrateToolsStorage copies tools from provider storage to 28 // environment storage. 29 func migrateToolsStorage(st *state.State, agentConfig agent.Config) error { 30 logger.Debugf("migrating tools to environment storage") 31 32 tstor, err := stateToolsStorage(st) 33 if err != nil { 34 return errors.Annotate(err, "cannot get tools storage") 35 } 36 defer tstor.Close() 37 38 // Local and manual provider host storage on the state server's 39 // filesystem, and serve via HTTP storage. The storage worker 40 // doesn't run yet, so we just open the files directly. 41 var stor storage.StorageReader 42 providerType := agentConfig.Value(agent.ProviderType) 43 if providerType == provider.Local || provider.IsManual(providerType) { 44 storageDir := agentConfig.Value(agent.StorageDir) 45 var err error 46 stor, err = filestorage.NewFileStorageReader(storageDir) 47 if err != nil { 48 return errors.Annotate(err, "cannot get local filesystem storage reader") 49 } 50 } else { 51 var err error 52 stor, err = environs.LegacyStorage(st) 53 if errors.IsNotSupported(err) { 54 return nil 55 } else if err != nil { 56 return errors.Annotate(err, "cannot get provider storage") 57 } 58 } 59 60 // Search provider storage for tools. 61 datasource := storage.NewStorageSimpleStreamsDataSource("provider storage", stor, storage.BaseToolsPath) 62 toolsList, err := envtools.FindToolsForCloud( 63 []simplestreams.DataSource{datasource}, 64 simplestreams.CloudSpec{}, 65 envtools.ReleasedStream, 66 -1, -1, tools.Filter{}) 67 switch err { 68 case nil: 69 break 70 case tools.ErrNoMatches, envtools.ErrNoTools: 71 // No tools in provider storage: nothing to do. 72 return nil 73 default: 74 return errors.Annotate(err, "cannot find tools in provider storage") 75 } 76 77 for _, agentTools := range toolsList { 78 logger.Infof("migrating %v tools to environment storage", agentTools.Version) 79 data, err := fetchToolsArchive(stor, envtools.LegacyReleaseDirectory, agentTools) 80 if err != nil { 81 return errors.Annotatef(err, "failed to fetch %v tools", agentTools.Version) 82 } 83 err = tstor.AddTools(bytes.NewReader(data), toolstorage.Metadata{ 84 Version: agentTools.Version, 85 Size: agentTools.Size, 86 SHA256: agentTools.SHA256, 87 }) 88 if err != nil { 89 return errors.Annotatef(err, "failed to add %v tools to environment storage", agentTools.Version) 90 } 91 } 92 return nil 93 } 94 95 func fetchToolsArchive(stor storage.StorageReader, toolsDir string, agentTools *tools.Tools) ([]byte, error) { 96 r, err := stor.Get(envtools.StorageName(agentTools.Version, toolsDir)) 97 if err != nil { 98 return nil, err 99 } 100 defer r.Close() 101 102 var buf bytes.Buffer 103 hash, size, err := utils.ReadSHA256(io.TeeReader(r, &buf)) 104 if err != nil { 105 return nil, err 106 } 107 if hash != agentTools.SHA256 { 108 return nil, errors.New("hash mismatch") 109 } 110 if size != agentTools.Size { 111 return nil, errors.New("size mismatch") 112 } 113 return buf.Bytes(), nil 114 }