github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/common/environdestroy.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names" 9 10 "github.com/juju/juju/apiserver/metricsender" 11 "github.com/juju/juju/environs" 12 "github.com/juju/juju/instance" 13 "github.com/juju/juju/state" 14 ) 15 16 var sendMetrics = func(st *state.State) error { 17 err := metricsender.SendMetrics(st, metricsender.DefaultMetricSender(), metricsender.DefaultMaxBatchesPerSend()) 18 return errors.Trace(err) 19 } 20 21 // DestroyEnvironment destroys all services and non-manager machine 22 // instances in the specified environment. This function assumes that all 23 // necessary authentication checks have been done. 24 func DestroyEnvironment(st *state.State, environTag names.EnvironTag) error { 25 var err error 26 if environTag != st.EnvironTag() { 27 if st, err = st.ForEnviron(environTag); err != nil { 28 return errors.Trace(err) 29 } 30 defer st.Close() 31 } 32 33 check := NewBlockChecker(st) 34 if err = check.DestroyAllowed(); err != nil { 35 return errors.Trace(err) 36 } 37 38 env, err := st.Environment() 39 if err != nil { 40 return errors.Trace(err) 41 } 42 43 if err = env.Destroy(); err != nil { 44 return errors.Trace(err) 45 } 46 47 machines, err := st.AllMachines() 48 if err != nil { 49 return errors.Trace(err) 50 } 51 52 err = sendMetrics(st) 53 if err != nil { 54 logger.Warningf("failed to send leftover metrics: %v", err) 55 } 56 57 // We must destroy instances server-side to support JES (Juju Environment 58 // Server), as there's no CLI to fall back on. In that case, we only ever 59 // destroy non-state machines; we leave destroying state servers in non- 60 // hosted environments to the CLI, as otherwise the API server may get cut 61 // off. 62 if err := destroyNonManagerMachines(st, machines); err != nil { 63 return errors.Trace(err) 64 } 65 66 // If this is not the state server environment, remove all documents from 67 // state associated with the environment. 68 if env.EnvironTag() != env.ServerTag() { 69 return errors.Trace(st.RemoveAllEnvironDocs()) 70 } 71 72 // Return to the caller. If it's the CLI, it will finish up 73 // by calling the provider's Destroy method, which will 74 // destroy the state servers, any straggler instances, and 75 // other provider-specific resources. 76 return nil 77 } 78 79 // destroyNonManagerMachines directly destroys all non-manager, non-manual 80 // machine instances. 81 func destroyNonManagerMachines(st *state.State, machines []*state.Machine) error { 82 var ids []instance.Id 83 for _, m := range machines { 84 if m.IsManager() { 85 continue 86 } 87 if _, isContainer := m.ParentId(); isContainer { 88 continue 89 } 90 manual, err := m.IsManual() 91 if err != nil { 92 return err 93 } else if manual { 94 continue 95 } 96 // There is a possible race here if a machine is being 97 // provisioned, but hasn't yet come up. 98 id, err := m.InstanceId() 99 if err != nil { 100 continue 101 } 102 ids = append(ids, id) 103 } 104 if len(ids) == 0 { 105 return nil 106 } 107 envcfg, err := st.EnvironConfig() 108 if err != nil { 109 return err 110 } 111 env, err := environs.New(envcfg) 112 if err != nil { 113 return err 114 } 115 return env.StopInstances(ids...) 116 }