Exemplo n.º 1
0
Arquivo: manifold.go Projeto: bac/juju
// Manifold returns a dependency manifold that runs an upgrader
// worker, using the resource names defined in the supplied config.
func Manifold(config ManifoldConfig) dependency.Manifold {
	inputs := []string{
		config.AgentName,
		config.APICallerName,
	}
	// The machine agent uses these but the unit agent doesn't.
	if config.UpgradeStepsGateName != "" {
		inputs = append(inputs, config.UpgradeStepsGateName)
	}
	if config.UpgradeCheckGateName != "" {
		inputs = append(inputs, config.UpgradeCheckGateName)
	}

	return dependency.Manifold{
		Inputs: inputs,
		Start: func(context dependency.Context) (worker.Worker, error) {

			var agent agent.Agent
			if err := context.Get(config.AgentName, &agent); err != nil {
				return nil, err
			}
			currentConfig := agent.CurrentConfig()

			var apiCaller base.APICaller
			if err := context.Get(config.APICallerName, &apiCaller); err != nil {
				return nil, err
			}
			upgraderFacade := upgrader.NewState(apiCaller)

			var upgradeStepsWaiter gate.Waiter
			if config.UpgradeStepsGateName == "" {
				upgradeStepsWaiter = gate.NewLock()
			} else {
				if config.PreviousAgentVersion == version.Zero {
					return nil, errors.New("previous agent version not specified")
				}
				if err := context.Get(config.UpgradeStepsGateName, &upgradeStepsWaiter); err != nil {
					return nil, err
				}
			}

			var initialCheckUnlocker gate.Unlocker
			if config.UpgradeCheckGateName == "" {
				initialCheckUnlocker = gate.NewLock()
			} else {
				if err := context.Get(config.UpgradeCheckGateName, &initialCheckUnlocker); err != nil {
					return nil, err
				}
			}

			return NewAgentUpgrader(
				upgraderFacade,
				currentConfig,
				config.PreviousAgentVersion,
				upgradeStepsWaiter,
				initialCheckUnlocker,
			)
		},
	}
}
Exemplo n.º 2
0
func (s *ManifoldSuite) TestOutput(c *gc.C) {
	stepsLock := gate.NewLock()
	checkLock := gate.NewLock()
	getResource := dt.StubGetResource(dt.StubResources{
		"steps-waiter": dt.StubResource{Output: stepsLock},
		"check-waiter": dt.StubResource{Output: checkLock},
	})
	w, err := s.manifold.Start(getResource)
	c.Assert(err, jc.ErrorIsNil)

	// Upgrades not completed yet so output is false.
	s.assertOutputFalse(c, w)

	// Unlock one of the upgrade gates, output should still be false.
	stepsLock.Unlock()
	s.assertOutputFalse(c, w)

	// Unlock the other gate, output should now be true.
	checkLock.Unlock()
	s.assertOutputTrue(c, w)

	// .. and the worker should exit with ErrBounce.
	checkStopWithError(c, w, dependency.ErrBounce)

	// Restarting the worker should result in the output immediately
	// being true.
	w2, err := s.manifold.Start(getResource)
	c.Assert(err, jc.ErrorIsNil)
	s.assertOutputTrue(c, w)
	checkStop(c, w2)
}
Exemplo n.º 3
0
func (s *ManifoldSuite) TestStartSuccess(c *gc.C) {
	getResource := dt.StubGetResource(dt.StubResources{
		"steps-waiter": dt.StubResource{Output: gate.NewLock()},
		"check-waiter": dt.StubResource{Output: gate.NewLock()},
	})
	w, err := s.manifold.Start(getResource)
	c.Assert(err, jc.ErrorIsNil)
	checkStop(c, w)
}
Exemplo n.º 4
0
func (*ManifoldsSuite) TestUpgradeGates(c *gc.C) {
	upgradeStepsLock := gate.NewLock()
	upgradeCheckLock := gate.NewLock()
	manifolds := machine.Manifolds(machine.ManifoldsConfig{
		UpgradeStepsLock: upgradeStepsLock,
		UpgradeCheckLock: upgradeCheckLock,
	})
	assertGate(c, manifolds["upgrade-steps-gate"], upgradeStepsLock)
	assertGate(c, manifolds["upgrade-check-gate"], upgradeCheckLock)
}
Exemplo n.º 5
0
func (s *ManifoldSuite) TestOutputWithWrongType(c *gc.C) {
	getResource := dt.StubGetResource(dt.StubResources{
		"steps-waiter": dt.StubResource{Output: gate.NewLock()},
		"check-waiter": dt.StubResource{Output: gate.NewLock()},
	})
	w, err := s.manifold.Start(getResource)
	c.Assert(err, jc.ErrorIsNil)

	var foo int
	err = s.manifold.Output(w, &foo)
	c.Assert(err, gc.ErrorMatches, `out should be a \*bool;.+`)
}
Exemplo n.º 6
0
func (s *UpgraderSuite) SetUpTest(c *gc.C) {
	s.JujuConnSuite.SetUpTest(c)
	// s.machine needs to have IsManager() so that it can get the actual
	// current revision to upgrade to.
	s.state, s.machine = s.OpenAPIAsNewMachine(c, state.JobManageModel)
	// Capture the value of RetryAfter, and use that captured
	// value in the cleanup lambda.
	oldRetryAfter := *upgrader.RetryAfter
	s.AddCleanup(func(*gc.C) {
		*upgrader.RetryAfter = oldRetryAfter
	})
	s.upgradeStepsComplete = gate.NewLock()
	s.initialCheckComplete = gate.NewLock()
}
Exemplo n.º 7
0
func (s *ManifoldSuite) TestOutputWithWrongWorker(c *gc.C) {
	getResource := dt.StubGetResource(dt.StubResources{
		"steps-waiter": dt.StubResource{Output: gate.NewLock()},
		"check-waiter": dt.StubResource{Output: gate.NewLock()},
	})
	_, err := s.manifold.Start(getResource)
	c.Assert(err, jc.ErrorIsNil)

	type dummyWorker struct {
		worker.Worker
	}
	var foo bool
	err = s.manifold.Output(new(dummyWorker), &foo)
	c.Assert(err, gc.ErrorMatches, `in should be a \*upgradeWaiter;.+`)
}
Exemplo n.º 8
0
Arquivo: worker.go Projeto: bac/juju
// NewLock creates a gate.Lock to be used to synchronise workers which
// need to start after upgrades have completed. If no upgrade steps
// are required the Lock is unlocked and the version in agent's
// configuration is updated to the currently running version.
//
// The returned Lock should be passed to NewWorker.
func NewLock(a agent.Agent) (gate.Lock, error) {
	lock := gate.NewLock()

	if wrench.IsActive("machine-agent", "always-try-upgrade") {
		// Always enter upgrade mode. This allows test of upgrades
		// even when there's actually no upgrade steps to run.
		return lock, nil
	}

	err := a.ChangeConfig(func(agentConfig agent.ConfigSetter) error {
		if !upgrades.AreUpgradesDefined(agentConfig.UpgradedToVersion()) {
			logger.Infof("no upgrade steps required or upgrade steps for %v "+
				"have already been run.", jujuversion.Current)
			lock.Unlock()

			// Even if no upgrade is required the version number in
			// the agent's config still needs to be bumped.
			agentConfig.SetUpgradedToVersion(jujuversion.Current)
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return lock, nil
}
Exemplo n.º 9
0
func (*FlagSuite) TestFlagLocked(c *gc.C) {
	lock := gate.NewLock()
	worker, err := gate.NewFlag(lock)
	c.Assert(err, jc.ErrorIsNil)
	defer workertest.CleanKill(c, worker)
	workertest.CheckAlive(c, worker)
	c.Check(worker.Check(), jc.IsFalse)
}
Exemplo n.º 10
0
func (s *ManifoldSuite) TestStartNoCheckWaiter(c *gc.C) {
	getResource := dt.StubGetResource(dt.StubResources{
		"steps-waiter": dt.StubResource{Output: gate.NewLock()},
		"check-waiter": dt.StubResource{Error: dependency.ErrMissing},
	})
	w, err := s.manifold.Start(getResource)
	c.Assert(w, gc.IsNil)
	c.Assert(err, gc.Equals, dependency.ErrMissing)
}
Exemplo n.º 11
0
func (*FlagSuite) TestFlagUnlockError(c *gc.C) {
	lock := gate.NewLock()
	worker, err := gate.NewFlag(lock)
	c.Assert(err, jc.ErrorIsNil)
	defer workertest.DirtyKill(c, worker)
	workertest.CheckAlive(c, worker)
	lock.Unlock()
	err = workertest.CheckKilled(c, worker)
	c.Check(err, gc.Equals, gate.ErrUnlocked)
}
Exemplo n.º 12
0
// Manifold returns a dependency.Manifold which aggregates the
// upgradesteps lock and the upgrader's "initial check" lock into a
// single boolean output. The output is false until both locks are
// unlocked. To make it easy to depend on this manifold, the
// manifold's worker restarts when the output value changes, causing
// dependent workers to be restarted.
func Manifold(config ManifoldConfig) dependency.Manifold {

	// This lock is unlocked when both the upgradesteps and upgrader
	// locks are unlocked. It exists outside of the start func and
	// worker code so that the state can be maintained beyond restart
	// of the manifold's worker.
	done := gate.NewLock()

	return dependency.Manifold{
		Inputs: []string{
			config.UpgradeStepsWaiterName,
			config.UpgradeCheckWaiterName,
		},
		Start: func(getResource dependency.GetResourceFunc) (worker.Worker, error) {
			var stepsWaiter gate.Waiter
			if err := getResource(config.UpgradeStepsWaiterName, &stepsWaiter); err != nil {
				return nil, err
			}
			var checkWaiter gate.Waiter
			if err := getResource(config.UpgradeCheckWaiterName, &checkWaiter); err != nil {
				return nil, err
			}

			w := &upgradeWaiter{
				done:        done,
				stepsWaiter: stepsWaiter,
				checkWaiter: checkWaiter,
			}
			go func() {
				defer w.tomb.Done()
				w.tomb.Kill(w.wait())
			}()
			return w, nil
		},
		Output: func(in worker.Worker, out interface{}) error {
			inWorker, _ := in.(*upgradeWaiter)
			if inWorker == nil {
				return errors.Errorf("in should be a *upgradeWaiter; is %T", in)
			}
			switch outPointer := out.(type) {
			case *bool:
				*outPointer = done.IsUnlocked()
			default:
				return errors.Errorf("out should be a *bool; is %T", out)
			}
			return nil
		},
	}
}
Exemplo n.º 13
0
func (s *WorkerSuite) startWorker(c *gc.C) (worker.Worker, gate.Lock) {
	// create fresh environ to see any injected broken-ness
	environ, err := stateenvirons.GetNewEnvironFunc(environs.New)(s.State)
	c.Assert(err, jc.ErrorIsNil)

	lock := gate.NewLock()
	worker, err := discoverspaces.NewWorker(discoverspaces.Config{
		Facade:   s.API,
		Environ:  environ,
		NewName:  network.ConvertSpaceName,
		Unlocker: lock,
	})
	c.Assert(err, jc.ErrorIsNil)
	return worker, lock
}
Exemplo n.º 14
0
func (s *ManifoldSuite) TestManifoldEx(c *gc.C) {
	lock := gate.NewLock()

	manifold := gate.ManifoldEx(lock)
	var waiter1 gate.Waiter = lock
	var unlocker1 gate.Unlocker = lock

	worker, err := manifold.Start(nil)
	c.Assert(err, jc.ErrorIsNil)
	defer checkStop(c, worker)
	waiter2 := waiter(c, manifold, worker)

	assertLocked(c, waiter1)
	assertLocked(c, waiter2)

	unlocker1.Unlock()
	assertUnlocked(c, waiter1)
	assertUnlocked(c, waiter2)
}
Exemplo n.º 15
0
// NewMachineAgent instantiates a new MachineAgent.
func NewMachineAgent(
	machineId string,
	agentConfWriter AgentConfigWriter,
	bufferedLogs logsender.LogRecordCh,
	runner worker.Runner,
	loopDeviceManager looputil.LoopDeviceManager,
	rootDir string,
) *MachineAgent {
	return &MachineAgent{
		machineId:                   machineId,
		AgentConfigWriter:           agentConfWriter,
		configChangedVal:            voyeur.NewValue(true),
		bufferedLogs:                bufferedLogs,
		workersStarted:              make(chan struct{}),
		runner:                      runner,
		rootDir:                     rootDir,
		initialUpgradeCheckComplete: gate.NewLock(),
		loopDeviceManager:           loopDeviceManager,
	}
}