github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/storageprovisioner/common.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storageprovisioner
     5  
     6  import (
     7  	"path/filepath"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/names"
    11  
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/environs/config"
    14  	"github.com/juju/juju/storage"
    15  	"github.com/juju/juju/storage/provider/registry"
    16  	"github.com/juju/juju/watcher"
    17  )
    18  
    19  // storageEntityLife queries the lifecycle state of each specified
    20  // storage entity (volume or filesystem), and then partitions the
    21  // tags by them.
    22  func storageEntityLife(ctx *context, tags []names.Tag) (alive, dying, dead []names.Tag, _ error) {
    23  	lifeResults, err := ctx.config.Life.Life(tags)
    24  	if err != nil {
    25  		return nil, nil, nil, errors.Annotate(err, "getting storage entity life")
    26  	}
    27  	for i, result := range lifeResults {
    28  		if result.Error != nil {
    29  			return nil, nil, nil, errors.Annotatef(
    30  				result.Error, "getting life of %s",
    31  				names.ReadableString(tags[i]),
    32  			)
    33  		}
    34  		switch result.Life {
    35  		case params.Alive:
    36  			alive = append(alive, tags[i])
    37  		case params.Dying:
    38  			dying = append(dying, tags[i])
    39  		case params.Dead:
    40  			dead = append(dead, tags[i])
    41  		}
    42  	}
    43  	return alive, dying, dead, nil
    44  }
    45  
    46  // attachmentLife queries the lifecycle state of each specified
    47  // attachment, and then partitions the IDs by them.
    48  func attachmentLife(ctx *context, ids []params.MachineStorageId) (
    49  	alive, dying, dead []params.MachineStorageId, _ error,
    50  ) {
    51  	lifeResults, err := ctx.config.Life.AttachmentLife(ids)
    52  	if err != nil {
    53  		return nil, nil, nil, errors.Annotate(err, "getting machine attachment life")
    54  	}
    55  	for i, result := range lifeResults {
    56  		if result.Error != nil {
    57  			return nil, nil, nil, errors.Annotatef(
    58  				result.Error, "getting life of %s attached to %s",
    59  				ids[i].AttachmentTag, ids[i].MachineTag,
    60  			)
    61  		}
    62  		switch result.Life {
    63  		case params.Alive:
    64  			alive = append(alive, ids[i])
    65  		case params.Dying:
    66  			dying = append(dying, ids[i])
    67  		case params.Dead:
    68  			dead = append(dead, ids[i])
    69  		}
    70  	}
    71  	return alive, dying, dead, nil
    72  }
    73  
    74  // removeEntities removes each specified Dead entity from state.
    75  func removeEntities(ctx *context, tags []names.Tag) error {
    76  	if len(tags) == 0 {
    77  		return nil
    78  	}
    79  	logger.Debugf("removing entities: %v", tags)
    80  	errorResults, err := ctx.config.Life.Remove(tags)
    81  	if err != nil {
    82  		return errors.Annotate(err, "removing storage entities")
    83  	}
    84  	for i, result := range errorResults {
    85  		if result.Error != nil {
    86  			return errors.Annotatef(result.Error, "removing %s from state", names.ReadableString(tags[i]))
    87  		}
    88  	}
    89  	return nil
    90  }
    91  
    92  // removeAttachments removes each specified attachment from state.
    93  func removeAttachments(ctx *context, ids []params.MachineStorageId) error {
    94  	if len(ids) == 0 {
    95  		return nil
    96  	}
    97  	errorResults, err := ctx.config.Life.RemoveAttachments(ids)
    98  	if err != nil {
    99  		return errors.Annotate(err, "removing attachments")
   100  	}
   101  	for i, result := range errorResults {
   102  		if result.Error != nil {
   103  			return errors.Annotatef(
   104  				result.Error, "removing attachment of %s to %s from state",
   105  				ids[i].AttachmentTag, ids[i].MachineTag,
   106  			)
   107  		}
   108  	}
   109  	return nil
   110  }
   111  
   112  // setStatus sets the given entity statuses, if any. If setting
   113  // the status fails the error is logged but otherwise ignored.
   114  func setStatus(ctx *context, statuses []params.EntityStatusArgs) {
   115  	if len(statuses) > 0 {
   116  		if err := ctx.config.Status.SetStatus(statuses); err != nil {
   117  			logger.Errorf("failed to set status: %v", err)
   118  		}
   119  	}
   120  }
   121  
   122  var errNonDynamic = errors.New("non-dynamic storage provider")
   123  
   124  // volumeSource returns a volume source given a name, provider type,
   125  // environment config and storage directory.
   126  //
   127  // TODO(axw) move this to the main storageprovisioner, and have
   128  // it watch for changes to storage source configurations, updating
   129  // a map in-between calls to the volume/filesystem/attachment
   130  // event handlers.
   131  func volumeSource(
   132  	environConfig *config.Config,
   133  	baseStorageDir string,
   134  	sourceName string,
   135  	providerType storage.ProviderType,
   136  ) (storage.VolumeSource, error) {
   137  	provider, sourceConfig, err := sourceParams(providerType, sourceName, baseStorageDir)
   138  	if err != nil {
   139  		return nil, errors.Annotatef(err, "getting storage source %q params", sourceName)
   140  	}
   141  	if !provider.Dynamic() {
   142  		return nil, errNonDynamic
   143  	}
   144  	source, err := provider.VolumeSource(environConfig, sourceConfig)
   145  	if err != nil {
   146  		return nil, errors.Annotatef(err, "getting storage source %q", sourceName)
   147  	}
   148  	return source, nil
   149  }
   150  
   151  // filesystemSource returns a filesystem source given a name, provider type,
   152  // environment config and storage directory.
   153  //
   154  // TODO(axw) move this to the main storageprovisioner, and have
   155  // it watch for changes to storage source configurations, updating
   156  // a map in-between calls to the volume/filesystem/attachment
   157  // event handlers.
   158  func filesystemSource(
   159  	environConfig *config.Config,
   160  	baseStorageDir string,
   161  	sourceName string,
   162  	providerType storage.ProviderType,
   163  ) (storage.FilesystemSource, error) {
   164  	provider, sourceConfig, err := sourceParams(providerType, sourceName, baseStorageDir)
   165  	if err != nil {
   166  		return nil, errors.Annotatef(err, "getting storage source %q params", sourceName)
   167  	}
   168  	source, err := provider.FilesystemSource(environConfig, sourceConfig)
   169  	if err != nil {
   170  		return nil, errors.Annotatef(err, "getting storage source %q", sourceName)
   171  	}
   172  	return source, nil
   173  }
   174  
   175  func sourceParams(providerType storage.ProviderType, sourceName, baseStorageDir string) (storage.Provider, *storage.Config, error) {
   176  	provider, err := registry.StorageProvider(providerType)
   177  	if err != nil {
   178  		return nil, nil, errors.Annotate(err, "getting provider")
   179  	}
   180  	attrs := make(map[string]interface{})
   181  	if baseStorageDir != "" {
   182  		storageDir := filepath.Join(baseStorageDir, sourceName)
   183  		attrs[storage.ConfigStorageDir] = storageDir
   184  	}
   185  	sourceConfig, err := storage.NewConfig(sourceName, providerType, attrs)
   186  	if err != nil {
   187  		return nil, nil, errors.Annotate(err, "getting config")
   188  	}
   189  	return provider, sourceConfig, nil
   190  }
   191  
   192  func copyMachineStorageIds(src []watcher.MachineStorageId) []params.MachineStorageId {
   193  	dst := make([]params.MachineStorageId, len(src))
   194  	for i, msid := range src {
   195  		dst[i] = params.MachineStorageId{
   196  			MachineTag:    msid.MachineTag,
   197  			AttachmentTag: msid.AttachmentTag,
   198  		}
   199  	}
   200  	return dst
   201  }