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