// CanDeploy returns if the currently authenticated entity (a machine // agent) can deploy each passed unit entity. func (d *DeployerAPI) CanDeploy(args params.Entities) (params.BoolResults, error) { result := params.BoolResults{ Results: make([]params.BoolResult, len(args.Entities)), } for i, entity := range args.Entities { unitName := state.UnitNameFromTag(entity.Tag) unit, err := d.st.Unit(unitName) if errors.IsNotFoundError(err) { // Unit not found, so no need to continue. continue } else if err != nil { // Any other error get reported back. result.Results[i].Error = common.ServerError(err) continue } machineId, err := unit.AssignedMachineId() if err != nil && !state.IsNotAssigned(err) && !errors.IsNotFoundError(err) { // Any other errors get reported back. result.Results[i].Error = common.ServerError(err) continue } else if err != nil { // This means the unit wasn't assigned to the machine // agent or it wasn't found. In both cases we just return // false so as not to leak information about the existence // of a unit to a potentially rogue machine agent. continue } // Finally, check if we're allowed to access this unit. // When assigned machineId == "" it will fail. result.Results[i].Result = d.authorizer.AuthOwner(state.MachineTag(machineId)) } return result, nil }
// changed ensures that the named unit is deployed, recalled, or removed, as // indicated by its state. func (d *Deployer) changed(unitName string) error { // Determine unit life state, and whether we're responsible for it. logger.Infof("checking unit %q", unitName) var life state.Life responsible := false unit, err := d.st.Unit(unitName) if errors.IsNotFoundError(err) { life = state.Dead } else if err != nil { return err } else { life = unit.Life() if machineId, err := unit.AssignedMachineId(); state.IsNotAssigned(err) { logger.Warningf("ignoring unit %q (not assigned)", unitName) // Unit is not assigned, so we're not responsible for its deployment. responsible = false } else if err != nil { return err } else { // We're only responsible for this unit's deployment when we're // running inside the machine agent of the machine this unit // is assigned to. responsible = (machineId == d.machineId) } } // Deployed units must be removed if they're Dead, or if the deployer // is no longer responsible for them. if d.deployed.Contains(unitName) { if life == state.Dead || !responsible { if err := d.recall(unitName); err != nil { return err } } } // The only units that should be deployed are those that (1) we are responsible // for and (2) are Alive -- if we're responsible for a Dying unit that is not // yet deployed, we should remove it immediately rather than undergo the hassle // of deploying a unit agent purely so it can set itself to Dead. if responsible && !d.deployed.Contains(unitName) { if life == state.Alive { return d.deploy(unit) } else if unit != nil { return d.remove(unit) } } return nil }
// ServerError returns an error suitable for returning to an API // client, with an error code suitable for various kinds of errors // generated in packages outside the API. func ServerError(err error) *params.Error { if err == nil { return nil } code := singletonErrorCodes[err] switch { case code != "": case errors.IsUnauthorizedError(err): code = params.CodeUnauthorized case errors.IsNotFoundError(err): code = params.CodeNotFound case state.IsNotAssigned(err): code = params.CodeNotAssigned case state.IsHasAssignedUnitsError(err): code = params.CodeHasAssignedUnits default: code = params.ErrCode(err) } return ¶ms.Error{ Message: err.Error(), Code: code, } }
// unitsChanged responds to changes to the assigned units. func (fw *Firewaller) unitsChanged(change *unitsChange) error { changed := []*unitData{} for _, name := range change.units { unit, err := fw.st.Unit(name) if err != nil && !errors.IsNotFoundError(err) { return err } var machineId string if unit != nil { machineId, err = unit.AssignedMachineId() if errors.IsNotFoundError(err) { continue } else if err != nil && !state.IsNotAssigned(err) { return err } } if unitd, known := fw.unitds[name]; known { knownMachineId := fw.unitds[name].machined.id if unit == nil || unit.Life() == state.Dead || machineId != knownMachineId { fw.forgetUnit(unitd) changed = append(changed, unitd) log.Debugf("worker/firewaller: stopped watching unit %s", name) } } else if unit != nil && unit.Life() != state.Dead && fw.machineds[machineId] != nil { err = fw.startUnit(unit, machineId) if err != nil { return err } changed = append(changed, fw.unitds[name]) log.Debugf("worker/firewaller: started watching unit %s", name) } } if err := fw.flushUnits(changed); err != nil { return fmt.Errorf("cannot change firewall ports: %v", err) } return nil }