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