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