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