github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/storage/import.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storage
     5  
     6  import (
     7  	"regexp"
     8  
     9  	"gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  
    14  	apistorage "github.com/juju/juju/api/storage"
    15  	jujucmd "github.com/juju/juju/cmd"
    16  	"github.com/juju/juju/cmd/modelcmd"
    17  	"github.com/juju/juju/jujuclient"
    18  	"github.com/juju/juju/storage"
    19  )
    20  
    21  // NewImportFilesystemCommand returns a command used to import a filesystem.
    22  //
    23  // newStorageImporter is the function to use to acquire a StorageImporter.
    24  // A non-nil function must be provided.
    25  //
    26  // store is an optional ClientStore to use for interacting with the client
    27  // model/controller storage. If nil, the default file-based store will be
    28  // used.
    29  func NewImportFilesystemCommand(
    30  	newStorageImporter NewStorageImporterFunc,
    31  	store jujuclient.ClientStore,
    32  ) cmd.Command {
    33  	cmd := &importFilesystemCommand{}
    34  	cmd.newAPIFunc = newStorageImporter
    35  	if store != nil {
    36  		cmd.SetClientStore(store)
    37  	}
    38  	return modelcmd.Wrap(cmd)
    39  }
    40  
    41  // NewStorageImporterFunc is the type of a function passed to
    42  // NewImportFilesystemCommand, in order to acquire a StorageImporter.
    43  type NewStorageImporterFunc func(*StorageCommandBase) (StorageImporter, error)
    44  
    45  // NewStorageImporter returns a new StorageImporter,
    46  // given a StorageCommandBase.
    47  func NewStorageImporter(cmd *StorageCommandBase) (StorageImporter, error) {
    48  	api, err := cmd.NewStorageAPI()
    49  	return apiStorageImporter{api}, err
    50  }
    51  
    52  const (
    53  	importFilesystemCommandDoc = `
    54  Import an existing filesystem into the model. This will lead to the model
    55  taking ownership of the storage, so you must take care not to import storage
    56  that is in use by another Juju model.
    57  
    58  To import a filesystem, you must specify three things:
    59  
    60   - the storage provider which manages the storage, and with
    61     which the storage will be associated
    62   - the storage provider ID for the filesystem, or
    63     volume that backs the filesystem
    64   - the storage name to assign to the filesystem,
    65     corresponding to the storage name used by a charm
    66  
    67  Once a filesystem is imported, Juju will create an associated storage
    68  instance using the given storage name.
    69  
    70  Examples:
    71      # Import an existing filesystem backed by an EBS volume,
    72      # and assign it the "pgdata" storage name. Juju will
    73      # associate a storage instance ID like "pgdata/0" with
    74      # the volume and filesystem contained within.
    75      juju import-filesystem ebs vol-123456 pgdata
    76  `
    77  	importFilesystemCommandAgs = `
    78  <storage-provider> <provider-id> <storage-name>
    79  `
    80  )
    81  
    82  // importFilesystemCommand imports filesystems into the model.
    83  type importFilesystemCommand struct {
    84  	StorageCommandBase
    85  	modelcmd.IAASOnlyCommand
    86  	newAPIFunc NewStorageImporterFunc
    87  
    88  	storagePool       string
    89  	storageProviderId string
    90  	storageName       string
    91  }
    92  
    93  // Init implements Command.Init.
    94  func (c *importFilesystemCommand) Init(args []string) error {
    95  	if len(args) < 3 {
    96  		return errors.New("import-filesystem requires a storage provider, provider ID, and storage name")
    97  	}
    98  	c.storagePool = args[0]
    99  	c.storageProviderId = args[1]
   100  	c.storageName = args[2]
   101  
   102  	if !storage.IsValidPoolName(c.storagePool) {
   103  		return errors.NotValidf("pool name %q", c.storagePool)
   104  	}
   105  
   106  	validStorageName, err := regexp.MatchString(names.StorageNameSnippet, c.storageName)
   107  	if err != nil {
   108  		return errors.Trace(err)
   109  	}
   110  	if !validStorageName {
   111  		return errors.Errorf("%q is not a valid storage name", c.storageName)
   112  	}
   113  	return nil
   114  }
   115  
   116  // Info implements Command.Info.
   117  func (c *importFilesystemCommand) Info() *cmd.Info {
   118  	return jujucmd.Info(&cmd.Info{
   119  		Name:    "import-filesystem",
   120  		Purpose: "Imports a filesystem into the model.",
   121  		Doc:     importFilesystemCommandDoc,
   122  		Args:    importFilesystemCommandAgs,
   123  	})
   124  }
   125  
   126  // Run implements Command.Run.
   127  func (c *importFilesystemCommand) Run(ctx *cmd.Context) (err error) {
   128  	api, err := c.newAPIFunc(&c.StorageCommandBase)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	defer api.Close()
   133  
   134  	ctx.Infof(
   135  		"importing %q from storage pool %q as storage %q",
   136  		c.storageProviderId, c.storagePool, c.storageName,
   137  	)
   138  	storageTag, err := api.ImportStorage(
   139  		storage.StorageKindFilesystem,
   140  		c.storagePool, c.storageProviderId, c.storageName,
   141  	)
   142  	if err != nil {
   143  		return err
   144  	}
   145  	ctx.Infof("imported storage %s", storageTag.Id())
   146  	return nil
   147  }
   148  
   149  // StorageImporter provides a method for importing storage into the model.
   150  type StorageImporter interface {
   151  	Close() error
   152  
   153  	ImportStorage(
   154  		kind storage.StorageKind,
   155  		storagePool, storageProviderId, storageName string,
   156  	) (names.StorageTag, error)
   157  }
   158  
   159  type apiStorageImporter struct {
   160  	*apistorage.Client
   161  }
   162  
   163  func (a apiStorageImporter) ImportStorage(
   164  	kind storage.StorageKind, storagePool, storageProviderId, storageName string,
   165  ) (names.StorageTag, error) {
   166  	return a.Import(kind, storagePool, storageProviderId, storageName)
   167  }