github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/controller/killstatus.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controller 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 12 "github.com/juju/juju/apiserver/params" 13 "github.com/juju/utils/clock" 14 "gopkg.in/juju/names.v2" 15 ) 16 17 type ctrData struct { 18 UUID string 19 Life string 20 HostedModelCount int 21 HostedMachineCount int 22 ServiceCount int 23 } 24 25 type modelData struct { 26 UUID string 27 Owner string 28 Name string 29 Life string 30 31 HostedMachineCount int 32 ServiceCount int 33 } 34 35 // newTimedStatusUpdater returns a function which waits a given period of time 36 // before querying the apiserver for updated data. 37 func newTimedStatusUpdater(ctx *cmd.Context, api destroyControllerAPI, controllerModelUUID string, clock clock.Clock) func(time.Duration) (ctrData, []modelData) { 38 return func(wait time.Duration) (ctrData, []modelData) { 39 if wait > 0 { 40 <-clock.After(wait) 41 } 42 43 // If we hit an error, status.HostedModelCount will be 0, the polling 44 // loop will stop and we'll go directly to destroying the model. 45 ctrStatus, modelsStatus, err := newData(api, controllerModelUUID) 46 if err != nil { 47 ctx.Infof("Unable to get the controller summary from the API: %s.", err) 48 } 49 50 return ctrStatus, modelsStatus 51 } 52 } 53 54 func newData(api destroyControllerAPI, controllerModelUUID string) (ctrData, []modelData, error) { 55 models, err := api.AllModels() 56 if err != nil { 57 return ctrData{}, nil, errors.Trace(err) 58 } 59 if len(models) == 0 { 60 return ctrData{}, nil, errors.New("no models found") 61 } 62 63 status, err := api.ModelStatus(names.NewModelTag(controllerModelUUID)) 64 if err != nil { 65 return ctrData{}, nil, errors.Trace(err) 66 } 67 if l := len(status); l != 1 { 68 return ctrData{}, nil, errors.Errorf("error finding controller status: expected one result, got %d", l) 69 } 70 ctrStatus := status[0] 71 72 hostedModelCount := len(models) - 1 73 hostedTags := make([]names.ModelTag, hostedModelCount) 74 modelName := map[string]string{} 75 var i int 76 for _, model := range models { 77 if model.UUID != controllerModelUUID { 78 modelName[model.UUID] = model.Name 79 hostedTags[i] = names.NewModelTag(model.UUID) 80 i++ 81 } 82 } 83 84 hostedStatus, err := api.ModelStatus(hostedTags...) 85 if err != nil { 86 return ctrData{}, nil, errors.Trace(err) 87 } 88 89 hostedMachinesCount := ctrStatus.HostedMachineCount 90 servicesCount := ctrStatus.ServiceCount 91 var modelsData []modelData 92 var aliveModelCount int 93 for _, model := range hostedStatus { 94 if model.Life == string(params.Dead) { 95 continue 96 } 97 modelsData = append(modelsData, modelData{ 98 model.UUID, 99 model.Owner, 100 modelName[model.UUID], 101 model.Life, 102 model.HostedMachineCount, 103 model.ServiceCount, 104 }) 105 106 aliveModelCount++ 107 hostedMachinesCount += model.HostedMachineCount 108 servicesCount += model.ServiceCount 109 } 110 111 ctrFinalStatus := ctrData{ 112 controllerModelUUID, 113 ctrStatus.Life, 114 aliveModelCount, 115 hostedMachinesCount, 116 servicesCount, 117 } 118 119 return ctrFinalStatus, modelsData, nil 120 } 121 122 func hasUnDeadModels(models []modelData) bool { 123 for _, model := range models { 124 if model.Life != string(params.Dead) { 125 return true 126 } 127 } 128 return false 129 } 130 131 func hasAliveModels(models []modelData) bool { 132 for _, model := range models { 133 if model.Life == string(params.Alive) { 134 return true 135 } 136 } 137 return false 138 } 139 140 func s(n int) string { 141 if n > 1 { 142 return "s" 143 } 144 return "" 145 } 146 147 func fmtCtrStatus(data ctrData) string { 148 modelNo := data.HostedModelCount 149 out := fmt.Sprintf("Waiting on %d model%s", modelNo, s(modelNo)) 150 151 if machineNo := data.HostedMachineCount; machineNo > 0 { 152 out += fmt.Sprintf(", %d machine%s", machineNo, s(machineNo)) 153 } 154 155 if serviceNo := data.ServiceCount; serviceNo > 0 { 156 out += fmt.Sprintf(", %d application%s", serviceNo, s(serviceNo)) 157 } 158 159 return out 160 } 161 162 func fmtModelStatus(data modelData) string { 163 out := fmt.Sprintf("\t%s/%s (%s)", data.Owner, data.Name, data.Life) 164 165 if machineNo := data.HostedMachineCount; machineNo > 0 { 166 out += fmt.Sprintf(", %d machine%s", machineNo, s(machineNo)) 167 } 168 169 if serviceNo := data.ServiceCount; serviceNo > 0 { 170 out += fmt.Sprintf(", %d application%s", serviceNo, s(serviceNo)) 171 } 172 173 return out 174 }