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  }