// EnableHASingle applies a single ControllersServersSpec specification to the current environment. // Exported so it can be called by the legacy client API in the client package. func EnableHASingle(st *state.State, spec params.ControllersSpec) (params.ControllersChanges, error) { if !st.IsController() { return params.ControllersChanges{}, errors.New("unsupported with hosted models") } // Check if changes are allowed and the command may proceed. blockChecker := common.NewBlockChecker(st) if err := blockChecker.ChangeAllowed(); err != nil { return params.ControllersChanges{}, errors.Trace(err) } // Validate the environment tag if present. if spec.ModelTag != "" { tag, err := names.ParseModelTag(spec.ModelTag) if err != nil { return params.ControllersChanges{}, errors.Errorf("invalid model tag: %v", err) } if _, err := st.FindEntity(tag); err != nil { return params.ControllersChanges{}, err } } series := spec.Series if series == "" { ssi, err := st.ControllerInfo() if err != nil { return params.ControllersChanges{}, err } // We should always have at least one voting machine // If we *really* wanted we could just pick whatever series is // in the majority, but really, if we always copy the value of // the first one, then they'll stay in sync. if len(ssi.VotingMachineIds) == 0 { // Better than a panic()? return params.ControllersChanges{}, fmt.Errorf("internal error, failed to find any voting machines") } templateMachine, err := st.Machine(ssi.VotingMachineIds[0]) if err != nil { return params.ControllersChanges{}, err } series = templateMachine.Series() } changes, err := st.EnableHA(spec.NumControllers, spec.Constraints, series, spec.Placement) if err != nil { return params.ControllersChanges{}, err } return controllersChanges(changes), nil }
// EnableHASingle applies a single ControllersServersSpec specification to the current environment. // Exported so it can be called by the legacy client API in the client package. func EnableHASingle(st *state.State, spec params.ControllersSpec) (params.ControllersChanges, error) { if !st.IsController() { return params.ControllersChanges{}, errors.New("unsupported with hosted models") } // Check if changes are allowed and the command may proceed. blockChecker := common.NewBlockChecker(st) if err := blockChecker.ChangeAllowed(); err != nil { return params.ControllersChanges{}, errors.Trace(err) } // Validate the environment tag if present. if spec.ModelTag != "" { tag, err := names.ParseModelTag(spec.ModelTag) if err != nil { return params.ControllersChanges{}, errors.Errorf("invalid model tag: %v", err) } if _, err := st.FindEntity(tag); err != nil { return params.ControllersChanges{}, err } } series := spec.Series if series == "" { ssi, err := st.ControllerInfo() if err != nil { return params.ControllersChanges{}, err } // We should always have at least one voting machine // If we *really* wanted we could just pick whatever series is // in the majority, but really, if we always copy the value of // the first one, then they'll stay in sync. if len(ssi.VotingMachineIds) == 0 { // Better than a panic()? return params.ControllersChanges{}, errors.Errorf("internal error, failed to find any voting machines") } templateMachine, err := st.Machine(ssi.VotingMachineIds[0]) if err != nil { return params.ControllersChanges{}, err } series = templateMachine.Series() } if constraints.IsEmpty(&spec.Constraints) { // No constraints specified, so we'll use the constraints off // a running controller. controllerInfo, err := st.ControllerInfo() if err != nil { return params.ControllersChanges{}, err } // We'll sort the controller ids to find the smallest. // This will typically give the initial bootstrap machine. var controllerIds []int for _, id := range controllerInfo.MachineIds { idNum, err := strconv.Atoi(id) if err != nil { logger.Warningf("ignoring non numeric controller id %v", id) continue } controllerIds = append(controllerIds, idNum) } if len(controllerIds) == 0 { errors.Errorf("internal error, failed to find any controllers") } sort.Ints(controllerIds) // Load the controller machine and get its constraints. controllerId := controllerIds[0] controller, err := st.Machine(strconv.Itoa(controllerId)) if err != nil { return params.ControllersChanges{}, errors.Annotatef(err, "reading controller id %v", controllerId) } spec.Constraints, err = controller.Constraints() if err != nil { return params.ControllersChanges{}, errors.Annotatef(err, "reading constraints for controller id %v", controllerId) } } changes, err := st.EnableHA(spec.NumControllers, spec.Constraints, series, spec.Placement) if err != nil { return params.ControllersChanges{}, err } return controllersChanges(changes), nil }