func (s *MachineSuite) TestMachineIdFromTag(c *C) { c.Assert(state.MachineIdFromTag("machine-10"), Equals, "10") // Check a container id. c.Assert(state.MachineIdFromTag("machine-10-lxc-1"), Equals, "10/lxc/1") // Check reversability. nested := "2/kvm/0/lxc/3" c.Assert(state.MachineIdFromTag(state.MachineTag(nested)), Equals, nested) // Try with an invalid tag format. c.Assert(state.MachineIdFromTag("foo"), Equals, "") }
// Watch starts an NotifyWatcher for each given machine. func (m *MachinerAPI) Watch(args params.Entities) (params.NotifyWatchResults, error) { result := params.NotifyWatchResults{ Results: make([]params.NotifyWatchResult, len(args.Entities)), } if len(args.Entities) == 0 { return result, nil } for i, entity := range args.Entities { err := common.ErrPerm if m.auth.AuthOwner(entity.Tag) { var machine *state.Machine machine, err = m.st.Machine(state.MachineIdFromTag(entity.Tag)) if err == nil { watch := machine.Watch() // Consume the initial event. Technically, API // calls to Watch 'transmit' the initial event // in the Watch response. But NotifyWatchers // have no state to transmit. if _, ok := <-watch.Changes(); ok { result.Results[i].NotifyWatcherId = m.resources.Register(watch) } else { err = watcher.MustErr(watch) } } } result.Results[i].Error = common.ServerError(err) } return result, nil }
// getAllUnits returns a list of all principal and subordinate units // assigned to the given machine. func getAllUnits(st *state.State, machineTag string) ([]string, error) { machine, err := st.Machine(state.MachineIdFromTag(machineTag)) if err != nil { return nil, err } // Start a watcher on machine's units, read the initial event and stop it. watch := machine.WatchUnits() defer watch.Stop() if units, ok := <-watch.Changes(); ok { return units, nil } return nil, fmt.Errorf("cannot obtain units of machine %q: %v", machineTag, watch.Err()) }
func (api *AgentAPI) getMachine(tag string) (result params.MachineAgentGetMachinesResult, err error) { // Allow only for the owner agent. // Note: having a bulk API call for this is utter madness, given that // this check means we can only ever return a single object. if !api.auth.AuthOwner(tag) { err = common.ErrPerm return } machine, err := api.st.Machine(state.MachineIdFromTag(tag)) if err != nil { return } result.Life = params.Life(machine.Life().String()) result.Jobs = stateJobsToAPIParamsJobs(machine.Jobs()) return }
// EnsureDead changes the lifecycle of each given machine to Dead if // it's Alive or Dying. It does nothing otherwise. func (m *MachinerAPI) EnsureDead(args params.Entities) (params.ErrorResults, error) { result := params.ErrorResults{ Errors: make([]*params.Error, len(args.Entities)), } if len(args.Entities) == 0 { return result, nil } for i, entity := range args.Entities { err := common.ErrPerm if m.auth.AuthOwner(entity.Tag) { var machine *state.Machine machine, err = m.st.Machine(state.MachineIdFromTag(entity.Tag)) if err == nil { err = machine.EnsureDead() } } result.Errors[i] = common.ServerError(err) } return result, nil }
// SetStatus sets the status of each given machine. func (m *MachinerAPI) SetStatus(args params.MachinesSetStatus) (params.ErrorResults, error) { result := params.ErrorResults{ Errors: make([]*params.Error, len(args.Machines)), } if len(args.Machines) == 0 { return result, nil } for i, arg := range args.Machines { err := common.ErrPerm if m.auth.AuthOwner(arg.Tag) { var machine *state.Machine machine, err = m.st.Machine(state.MachineIdFromTag(arg.Tag)) if err == nil { err = machine.SetStatus(arg.Status, arg.Info) } } result.Errors[i] = common.ServerError(err) } return result, nil }
// EnsureWeHaveLXC checks if we have lxc installed, and installs it if we // don't. Juju 1.11 added the ability to deploy into LXC containers, and uses // functionality from the lxc package in order to do so. Juju 1.10 did not // install lxc, so we ensure it is installed. // See http://bugs.launchpad.net/bug/1199913 // dataDir is the root location where data files are put. It is used to grab // the uniter-hook-execution lock so that we don't try run to apt-get at the // same time that a hook might want to run it. func EnsureWeHaveLXC(dataDir, machineTag string) error { // We need to short circuit this in two places: // 1. if we are running a local provider, then the machines are lxc // containers, and if we install lxc on them, it adds an lxc bridge // network device with the same ip address as the hosts bridge. This // screws up all the networking routes. // 2. if the machine is an lxc container, we need to avoid installing lxc // package for exactly the same reasons. // Later, post-precise LTS, when we have updated lxc, we can bring this // back in to have nested lxc, but until then, we have to avoid it. containerType := state.ContainerTypeFromId(state.MachineIdFromTag(machineTag)) providerType := os.Getenv("JUJU_PROVIDER_TYPE") if providerType == provider.Local || containerType == instance.LXC { return nil } manager := lxc.NewContainerManager(lxc.ManagerConfig{Name: "lxc-test"}) if _, err := manager.ListContainers(); err == nil { validationLogger.Debugf("found lxc, not installing") // We already have it, nothing more to do return nil } validationLogger.Debugf("got error looking for lxc, attempting to install") if dataDir != "" { lock, err := getUniterLock(dataDir, "apt-get install lxc for juju 1.11 upgrade") if err == nil { defer lock.Unlock() } else { validationLogger.Warningf("Failed to acquire lock: %v, will try to install lxc anyway", lock) } // If we got an error trying to acquire the lock, we try to install // lxc anyway. Worst case the install will fail, which is where we // are already } // TODO: This is not platform independent. If jujud is running on // something other than a debian-based Linux, and we are missing // lxc, this call will always fail. However, in juju 1.11+ we // install lxc via cloud-init or whatever bootstrap code we use. // So this is really only upgrade compatibility and juju 1.10 // only supports debian-based anyway return utils.AptGetInstall("lxc") }
func (u *UpgraderAPI) oneAgentTools(entity params.Entity, agentVersion version.Number, env environs.Environ) (params.AgentTools, error) { if !u.authorizer.AuthOwner(entity.Tag) { return nilTools, common.ErrPerm } machine, err := u.st.Machine(state.MachineIdFromTag(entity.Tag)) if err != nil { return nilTools, err } // TODO: Support Unit as well as Machine existingTools, err := machine.AgentTools() if err != nil { return nilTools, err } requested := version.Binary{ Number: agentVersion, Series: existingTools.Series, Arch: existingTools.Arch, } // Note: (jam) We shouldn't have to search the provider // for every machine that wants to upgrade. The // information could just be cached in state, or // even in the API servers tools, err := environs.FindExactTools(env, requested) if err != nil { return nilTools, err } return params.AgentTools{ Tag: entity.Tag, Arch: tools.Arch, Series: tools.Series, URL: tools.URL, Major: tools.Major, Minor: tools.Minor, Patch: tools.Patch, Build: tools.Build, }, nil }
// SetTools updates the recorded tools version for the agents. func (u *UpgraderAPI) SetTools(args params.SetAgentTools) (params.SetAgentToolsResults, error) { results := params.SetAgentToolsResults{ Results: make([]params.SetAgentToolsResult, len(args.AgentTools)), } for i, tools := range args.AgentTools { var err error results.Results[i].Tag = tools.Tag if !u.authorizer.AuthOwner(tools.Tag) { err = common.ErrPerm } else { // TODO: When we get there, we should support setting // Unit agent tools as well as Machine tools. We // can use something like the "AgentState" // interface that cmd/jujud/agent.go had. machine, err := u.st.Machine(state.MachineIdFromTag(tools.Tag)) if err == nil { stTools := state.Tools{ Binary: version.Binary{ Number: version.Number{ Major: tools.Major, Minor: tools.Minor, Patch: tools.Patch, Build: tools.Build, }, Arch: tools.Arch, Series: tools.Series, }, URL: tools.URL, } err = machine.SetAgentTools(&stTools) } } results.Results[i].Error = common.ServerError(err) } return results, nil }
// WatchUnits starts a StringsWatcher to watch all units deployed to // any machine passed in args, in order to track which ones should be // deployed or recalled. func (d *DeployerAPI) WatchUnits(args params.Entities) (params.StringsWatchResults, error) { result := params.StringsWatchResults{ Results: make([]params.StringsWatchResult, len(args.Entities)), } for i, entity := range args.Entities { err := common.ErrPerm if d.authorizer.AuthOwner(entity.Tag) { var machine *state.Machine machine, err = d.st.Machine(state.MachineIdFromTag(entity.Tag)) if err == nil { watch := machine.WatchUnits() // Consume the initial event and forward it to the result. if changes, ok := <-watch.Changes(); ok { result.Results[i].StringsWatcherId = d.resources.Register(watch) result.Results[i].Changes = changes } else { err = watcher.MustErr(watch) } } } result.Results[i].Error = common.ServerError(err) } return result, nil }