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