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 }