github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/environs"
    12  	"github.com/juju/juju/instance"
    13  	"github.com/juju/juju/storage"
    14  )
    15  
    16  // Destroy is a common implementation of the Destroy method defined on
    17  // environs.Environ; we strongly recommend that this implementation be
    18  // used when writing a new provider.
    19  func Destroy(env environs.Environ) error {
    20  	logger.Infof("destroying model %q", env.Config().Name())
    21  	if err := destroyInstances(env); err != nil {
    22  		return errors.Annotate(err, "destroying instances")
    23  	}
    24  	if err := destroyStorage(env); err != nil {
    25  		return errors.Annotate(err, "destroying storage")
    26  	}
    27  	return nil
    28  }
    29  
    30  func destroyInstances(env environs.Environ) error {
    31  	logger.Infof("destroying instances")
    32  	instances, err := env.AllInstances()
    33  	switch err {
    34  	case nil:
    35  		ids := make([]instance.Id, len(instances))
    36  		for i, inst := range instances {
    37  			ids[i] = inst.Id()
    38  		}
    39  		if err := env.StopInstances(ids...); err != nil {
    40  			return err
    41  		}
    42  		fallthrough
    43  	case environs.ErrNoInstances:
    44  		return nil
    45  	default:
    46  		return err
    47  	}
    48  }
    49  
    50  func destroyStorage(env environs.Environ) error {
    51  	logger.Infof("destroying storage")
    52  	storageProviderTypes, err := env.StorageProviderTypes()
    53  	if err != nil {
    54  		return errors.Trace(err)
    55  	}
    56  	for _, storageProviderType := range storageProviderTypes {
    57  		storageProvider, err := env.StorageProvider(storageProviderType)
    58  		if err != nil {
    59  			return errors.Trace(err)
    60  		}
    61  		if !storageProvider.Dynamic() {
    62  			continue
    63  		}
    64  		if storageProvider.Scope() != storage.ScopeEnviron {
    65  			continue
    66  		}
    67  		if err := destroyVolumes(storageProviderType, storageProvider); err != nil {
    68  			return errors.Trace(err)
    69  		}
    70  		// TODO(axw) destroy env-level filesystems when we have them.
    71  	}
    72  	return nil
    73  }
    74  
    75  func destroyVolumes(
    76  	storageProviderType storage.ProviderType,
    77  	storageProvider storage.Provider,
    78  ) error {
    79  	if !storageProvider.Supports(storage.StorageKindBlock) {
    80  		return nil
    81  	}
    82  
    83  	storageConfig, err := storage.NewConfig(
    84  		string(storageProviderType),
    85  		storageProviderType,
    86  		map[string]interface{}{},
    87  	)
    88  	if err != nil {
    89  		return errors.Trace(err)
    90  	}
    91  
    92  	volumeSource, err := storageProvider.VolumeSource(storageConfig)
    93  	if err != nil {
    94  		return errors.Annotate(err, "getting volume source")
    95  	}
    96  
    97  	volumeIds, err := volumeSource.ListVolumes()
    98  	if err != nil {
    99  		return errors.Annotate(err, "listing volumes")
   100  	}
   101  
   102  	var errStrings []string
   103  	errs, err := volumeSource.DestroyVolumes(volumeIds)
   104  	if err != nil {
   105  		return errors.Annotate(err, "destroying volumes")
   106  	}
   107  	for _, err := range errs {
   108  		if err != nil {
   109  			errStrings = append(errStrings, err.Error())
   110  		}
   111  	}
   112  	if len(errStrings) > 0 {
   113  		return errors.Errorf("destroying volumes: %s", strings.Join(errStrings, ", "))
   114  	}
   115  	return nil
   116  }