github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/state/apiserver/client/destroy.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package client 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/juju/juju/environs" 11 "github.com/juju/juju/instance" 12 "github.com/juju/juju/state" 13 ) 14 15 // DestroyEnvironment destroys all services and non-manager machine 16 // instances in the environment. 17 func (c *Client) DestroyEnvironment() error { 18 // TODO(axw) 2013-08-30 bug 1218688 19 // 20 // There's a race here: a client might add a manual machine 21 // after another client checks. Destroy-environment will 22 // still fail, but the environment will be in a state where 23 // entities can only be destroyed. In the future we should 24 // introduce a method of preventing Environment.Destroy() 25 // from succeeding if machines have been added. 26 27 // First, check for manual machines. We bail out if there are any, 28 // to stop the user from prematurely hobbling the environment. 29 machines, err := c.api.state.AllMachines() 30 if err != nil { 31 return err 32 } 33 if err := checkManualMachines(machines); err != nil { 34 return err 35 } 36 37 // Set the environment to Dying, to lock out new machines and services. 38 // Environment.Destroy() also schedules a cleanup for existing services. 39 // Afterwards, refresh the machines in case any were added between the 40 // first check and the Environment.Destroy(). 41 env, err := c.api.state.Environment() 42 if err != nil { 43 return err 44 } 45 if err = env.Destroy(); err != nil { 46 return err 47 } 48 machines, err = c.api.state.AllMachines() 49 if err != nil { 50 return err 51 } 52 53 // We must destroy instances server-side to support hosted Juju, 54 // as there's no CLI to fall back on. In that case, we only ever 55 // destroy non-state machines; we leave destroying state servers 56 // in non-hosted environments to the CLI, as otherwise the API 57 // server may get cut off. 58 if err := destroyInstances(c.api.state, machines); err != nil { 59 return err 60 } 61 62 // Make sure once again that there are no manually provisioned 63 // non-manager machines. This caters for the race between the 64 // first check and the Environment.Destroy(). 65 if err := checkManualMachines(machines); err != nil { 66 return err 67 } 68 69 // Return to the caller. If it's the CLI, it will finish up 70 // by calling the provider's Destroy method, which will 71 // destroy the state servers, any straggler instances, and 72 // other provider-specific resources. 73 return nil 74 } 75 76 // destroyInstances directly destroys all non-manager, 77 // non-manual machine instances. 78 func destroyInstances(st *state.State, machines []*state.Machine) error { 79 var ids []instance.Id 80 for _, m := range machines { 81 if m.IsManager() { 82 continue 83 } 84 if _, isContainer := m.ParentId(); isContainer { 85 continue 86 } 87 manual, err := m.IsManual() 88 if manual { 89 continue 90 } else if err != nil { 91 return err 92 } 93 id, err := m.InstanceId() 94 if err != nil { 95 continue 96 } 97 ids = append(ids, id) 98 } 99 if len(ids) == 0 { 100 return nil 101 } 102 envcfg, err := st.EnvironConfig() 103 if err != nil { 104 return err 105 } 106 env, err := environs.New(envcfg) 107 if err != nil { 108 return err 109 } 110 return env.StopInstances(ids...) 111 } 112 113 // checkManualMachines checks if any of the machines in the slice were 114 // manually provisioned, and are non-manager machines. These machines 115 // must (currently) be manually destroyed via destroy-machine before 116 // destroy-environment can successfully complete. 117 func checkManualMachines(machines []*state.Machine) error { 118 var ids []string 119 for _, m := range machines { 120 if m.IsManager() { 121 continue 122 } 123 manual, err := m.IsManual() 124 if err != nil { 125 return err 126 } 127 if manual { 128 ids = append(ids, m.Id()) 129 } 130 } 131 if len(ids) > 0 { 132 return fmt.Errorf("manually provisioned machines must first be destroyed with `juju destroy-machine %s`", strings.Join(ids, " ")) 133 } 134 return nil 135 }