github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/commands/synctools.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package commands
     5  
     6  import (
     7  	"bytes"
     8  	"io"
     9  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/loggo"
    12  	"launchpad.net/gnuflag"
    13  
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/cmd/envcmd"
    16  	"github.com/juju/juju/cmd/juju/block"
    17  	"github.com/juju/juju/environs/filestorage"
    18  	"github.com/juju/juju/environs/sync"
    19  	envtools "github.com/juju/juju/environs/tools"
    20  	coretools "github.com/juju/juju/tools"
    21  	"github.com/juju/juju/version"
    22  )
    23  
    24  var syncTools = sync.SyncTools
    25  
    26  // SyncToolsCommand copies all the tools from the us-east-1 bucket to the local
    27  // bucket.
    28  type SyncToolsCommand struct {
    29  	envcmd.EnvCommandBase
    30  	allVersions  bool
    31  	versionStr   string
    32  	majorVersion int
    33  	minorVersion int
    34  	dryRun       bool
    35  	dev          bool
    36  	public       bool
    37  	source       string
    38  	stream       string
    39  	localDir     string
    40  	destination  string
    41  }
    42  
    43  var _ cmd.Command = (*SyncToolsCommand)(nil)
    44  
    45  func (c *SyncToolsCommand) Info() *cmd.Info {
    46  	return &cmd.Info{
    47  		Name:    "sync-tools",
    48  		Purpose: "copy tools from the official tool store into a local environment",
    49  		Doc: `
    50  This copies the Juju tools tarball from the official tools store (located
    51  at https://streams.canonical.com/juju) into your environment.
    52  This is generally done when you want Juju to be able to run without having to
    53  access the Internet. Alternatively you can specify a local directory as source.
    54  
    55  Sometimes this is because the environment does not have public access,
    56  and sometimes you just want to avoid having to access data outside of
    57  the local cloud.
    58  `,
    59  	}
    60  }
    61  
    62  func (c *SyncToolsCommand) SetFlags(f *gnuflag.FlagSet) {
    63  	f.BoolVar(&c.allVersions, "all", false, "copy all versions, not just the latest")
    64  	f.StringVar(&c.versionStr, "version", "", "copy a specific major[.minor] version")
    65  	f.BoolVar(&c.dryRun, "dry-run", false, "don't copy, just print what would be copied")
    66  	f.BoolVar(&c.dev, "dev", false, "consider development versions as well as released ones\n    DEPRECATED: use --stream instead")
    67  	f.BoolVar(&c.public, "public", false, "tools are for a public cloud, so generate mirrors information")
    68  	f.StringVar(&c.source, "source", "", "local source directory")
    69  	f.StringVar(&c.stream, "stream", "", "simplestreams stream for which to sync metadata")
    70  	f.StringVar(&c.localDir, "local-dir", "", "local destination directory")
    71  	f.StringVar(&c.destination, "destination", "", "local destination directory")
    72  }
    73  
    74  func (c *SyncToolsCommand) Init(args []string) error {
    75  	if c.destination != "" {
    76  		// Override localDir with destination as localDir now replaces destination
    77  		c.localDir = c.destination
    78  		logger.Warningf("Use of the --destination flag is deprecated in 1.18. Please use --local-dir instead.")
    79  	}
    80  	if c.versionStr != "" {
    81  		var err error
    82  		if c.majorVersion, c.minorVersion, err = version.ParseMajorMinor(c.versionStr); err != nil {
    83  			return err
    84  		}
    85  	}
    86  	if c.dev {
    87  		c.stream = envtools.TestingStream
    88  	}
    89  	return cmd.CheckEmpty(args)
    90  }
    91  
    92  // syncToolsAPI provides an interface with a subset of the
    93  // api.Client API. This exists to enable mocking.
    94  type syncToolsAPI interface {
    95  	FindTools(majorVersion, minorVersion int, series, arch string) (params.FindToolsResult, error)
    96  	UploadTools(r io.Reader, v version.Binary, series ...string) (*coretools.Tools, error)
    97  	Close() error
    98  }
    99  
   100  var getSyncToolsAPI = func(c *SyncToolsCommand) (syncToolsAPI, error) {
   101  	return c.NewAPIClient()
   102  }
   103  
   104  func (c *SyncToolsCommand) Run(ctx *cmd.Context) (resultErr error) {
   105  	// Register writer for output on screen.
   106  	loggo.RegisterWriter("synctools", cmd.NewCommandLogWriter("juju.environs.sync", ctx.Stdout, ctx.Stderr), loggo.INFO)
   107  	defer loggo.RemoveWriter("synctools")
   108  
   109  	sctx := &sync.SyncContext{
   110  		AllVersions:  c.allVersions,
   111  		MajorVersion: c.majorVersion,
   112  		MinorVersion: c.minorVersion,
   113  		DryRun:       c.dryRun,
   114  		Stream:       c.stream,
   115  		Source:       c.source,
   116  	}
   117  
   118  	if c.localDir != "" {
   119  		stor, err := filestorage.NewFileStorageWriter(c.localDir)
   120  		if err != nil {
   121  			return err
   122  		}
   123  		writeMirrors := envtools.DoNotWriteMirrors
   124  		if c.public {
   125  			writeMirrors = envtools.WriteMirrors
   126  		}
   127  		sctx.TargetToolsFinder = sync.StorageToolsFinder{Storage: stor}
   128  		sctx.TargetToolsUploader = sync.StorageToolsUploader{
   129  			Storage:       stor,
   130  			WriteMetadata: true,
   131  			WriteMirrors:  writeMirrors,
   132  		}
   133  	} else {
   134  		if c.public {
   135  			logger.Warningf("--public is ignored unless --local-dir is specified")
   136  		}
   137  		api, err := getSyncToolsAPI(c)
   138  		if err != nil {
   139  			return err
   140  		}
   141  		defer api.Close()
   142  		adapter := syncToolsAPIAdapter{api}
   143  		sctx.TargetToolsFinder = adapter
   144  		sctx.TargetToolsUploader = adapter
   145  	}
   146  	return block.ProcessBlockedError(syncTools(sctx), block.BlockChange)
   147  }
   148  
   149  // syncToolsAPIAdapter implements sync.ToolsFinder and
   150  // sync.ToolsUploader, adapting a syncToolsAPI. This
   151  // enables the use of sync.SyncTools with the client
   152  // API.
   153  type syncToolsAPIAdapter struct {
   154  	syncToolsAPI
   155  }
   156  
   157  func (s syncToolsAPIAdapter) FindTools(majorVersion int, stream string) (coretools.List, error) {
   158  	result, err := s.syncToolsAPI.FindTools(majorVersion, -1, "", "")
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  	if result.Error != nil {
   163  		if params.IsCodeNotFound(result.Error) {
   164  			return nil, coretools.ErrNoMatches
   165  		}
   166  		return nil, result.Error
   167  	}
   168  	return result.List, nil
   169  }
   170  
   171  func (s syncToolsAPIAdapter) UploadTools(toolsDir, stream string, tools *coretools.Tools, data []byte) error {
   172  	_, err := s.syncToolsAPI.UploadTools(bytes.NewReader(data), tools.Version)
   173  	return err
   174  }