github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/common/destroy.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/juju/errors"
    10  
    11  	"github.com/juju/juju/core/instance"
    12  	"github.com/juju/juju/environs"
    13  	"github.com/juju/juju/environs/context"
    14  	"github.com/juju/juju/storage"
    15  )
    16  
    17  // Destroy is a common implementation of the Destroy method defined on
    18  // environs.Environ; we strongly recommend that this implementation be
    19  // used when writing a new provider.
    20  func Destroy(env environs.Environ, ctx context.ProviderCallContext) error {
    21  	logger.Infof("destroying model %q", env.Config().Name())
    22  	if err := destroyInstances(env, ctx); err != nil {
    23  		return errors.Annotate(err, "destroying instances")
    24  	}
    25  	if err := destroyStorage(env, ctx); err != nil {
    26  		return errors.Annotate(err, "destroying storage")
    27  	}
    28  	return nil
    29  }
    30  
    31  func destroyInstances(env environs.Environ, ctx context.ProviderCallContext) error {
    32  	logger.Infof("destroying instances")
    33  	instances, err := env.AllInstances(ctx)
    34  	switch err {
    35  	case nil:
    36  		ids := make([]instance.Id, len(instances))
    37  		for i, inst := range instances {
    38  			ids[i] = inst.Id()
    39  		}
    40  		if err := env.StopInstances(ctx, ids...); err != nil {
    41  			return err
    42  		}
    43  		fallthrough
    44  	case environs.ErrNoInstances:
    45  		return nil
    46  	default:
    47  		return err
    48  	}
    49  }
    50  
    51  // TODO(axw) we should just make it Environ.Destroy's responsibility
    52  // to destroy persistent storage. Trying to include it in the storage
    53  // source abstraction doesn't work well with dynamic, non-persistent
    54  // storage like tmpfs, rootfs, etc.
    55  func destroyStorage(env environs.Environ, ctx context.ProviderCallContext) error {
    56  	logger.Infof("destroying storage")
    57  	storageProviderTypes, err := env.StorageProviderTypes()
    58  	if err != nil {
    59  		return errors.Trace(err)
    60  	}
    61  	for _, storageProviderType := range storageProviderTypes {
    62  		storageProvider, err := env.StorageProvider(storageProviderType)
    63  		if err != nil {
    64  			return errors.Trace(err)
    65  		}
    66  		if !storageProvider.Dynamic() {
    67  			continue
    68  		}
    69  		if storageProvider.Scope() != storage.ScopeEnviron {
    70  			continue
    71  		}
    72  		storageConfig, err := storage.NewConfig(
    73  			string(storageProviderType),
    74  			storageProviderType,
    75  			map[string]interface{}{},
    76  		)
    77  		if err != nil {
    78  			return errors.Trace(err)
    79  		}
    80  		if storageProvider.Supports(storage.StorageKindBlock) {
    81  			volumeSource, err := storageProvider.VolumeSource(storageConfig)
    82  			if err != nil {
    83  				return errors.Annotate(err, "getting volume source")
    84  			}
    85  			if err := destroyVolumes(volumeSource, ctx); err != nil {
    86  				return errors.Trace(err)
    87  			}
    88  		}
    89  	}
    90  	return nil
    91  }
    92  
    93  func destroyVolumes(volumeSource storage.VolumeSource, ctx context.ProviderCallContext) error {
    94  	volumeIds, err := volumeSource.ListVolumes(ctx)
    95  	if err != nil {
    96  		return errors.Annotate(err, "listing volumes")
    97  	}
    98  
    99  	var errStrings []string
   100  	errs, err := volumeSource.DestroyVolumes(ctx, volumeIds)
   101  	if err != nil {
   102  		return errors.Annotate(err, "destroying volumes")
   103  	}
   104  	for _, err := range errs {
   105  		if err != nil {
   106  			errStrings = append(errStrings, err.Error())
   107  		}
   108  	}
   109  	if len(errStrings) > 0 {
   110  		return errors.Errorf("destroying volumes: %s", strings.Join(errStrings, ", "))
   111  	}
   112  	return nil
   113  }