Example #1
0
func processDeadEnv(client apiundertaker.UndertakerClient, clock uc.Clock, tod time.Time, stopCh <-chan struct{}) error {
	timeDead := clock.Now().Sub(tod)
	wait := ripTime - timeDead
	if wait < 0 {
		wait = 0
	}

	select {
	case <-clock.After(wait):
		err := client.RemoveEnviron()
		return errors.Annotate(err, "could not remove all docs for dead environment")
	case <-stopCh:
		return tomb.ErrDying
	}
}
Example #2
0
// New returns a worker which periodically prunes the data for
// completed transactions.
func New(tp TransactionPruner, interval time.Duration, clock clock.Clock) worker.Worker {
	return worker.NewSimpleWorker(func(stopCh <-chan struct{}) error {
		for {
			select {
			case <-clock.After(interval):
				err := tp.MaybePruneTransactions()
				if err != nil {
					return errors.Annotate(err, "pruning failed, txnpruner stopping")
				}
			case <-stopCh:
				return nil
			}
		}
	})
}
Example #3
0
// newTimedStatusUpdater returns a function which waits a given period of time
// before querying the apiserver for updated data.
func newTimedStatusUpdater(ctx *cmd.Context, api destroyControllerAPI, controllerModelUUID string, clock clock.Clock) func(time.Duration) (ctrData, []modelData) {
	return func(wait time.Duration) (ctrData, []modelData) {
		if wait > 0 {
			<-clock.After(wait)
		}

		// If we hit an error, status.HostedModelCount will be 0, the polling
		// loop will stop and we'll go directly to destroying the model.
		ctrStatus, modelsStatus, err := newData(api, controllerModelUUID)
		if err != nil {
			ctx.Infof("Unable to get the controller summary from the API: %s.", err)
		}

		return ctrStatus, modelsStatus
	}
}
Example #4
0
// runCommandsWithTimeout is a helper to abstract common code between run commands and
// juju-run as an action
func (runner *runner) runCommandsWithTimeout(commands string, timeout time.Duration, clock clock.Clock) (*utilexec.ExecResponse, error) {
	srv, err := runner.startJujucServer()
	if err != nil {
		return nil, err
	}
	defer srv.Close()

	env, err := runner.context.HookVars(runner.paths)
	if err != nil {
		return nil, errors.Trace(err)
	}
	command := utilexec.RunParams{
		Commands:    commands,
		WorkingDir:  runner.paths.GetCharmDir(),
		Environment: env,
		Clock:       clock,
	}

	err = command.Run()
	if err != nil {
		return nil, err
	}
	runner.context.SetProcess(hookProcess{command.Process()})

	var cancel chan struct{}
	if timeout != 0 {
		cancel = make(chan struct{})
		go func() {
			<-clock.After(timeout)
			close(cancel)
		}()
	}

	// Block and wait for process to finish
	return command.WaitWithCancel(cancel)
}
Example #5
0
// GetTriggers returns the signal channels for state transitions based on the current state.
// It controls the transitions of the inactive meter status worker.
//
// In a simple case, the transitions are trivial:
//
// D------------------A----------------------R--------------------->
//
// D - disconnect time
// A - amber status triggered
// R - red status triggered
//
// The problem arises from the fact that the lifetime of the worker can
// be interrupted, possibly with significant portions of the duration missing.
func GetTriggers(
	wst WorkerState,
	status string,
	disconnectedAt time.Time,
	clk clock.Clock,
	amberGracePeriod time.Duration,
	redGracePeriod time.Duration) (<-chan time.Time, <-chan time.Time) {

	now := clk.Now()

	if wst == Done {
		return nil, nil
	}

	if wst <= WaitingAmber && status == "RED" {
		// If the current status is already RED, we don't want to deescalate.
		wst = WaitingRed
		//	} else if wst <= WaitingAmber && now.Sub(disconnectedAt) >= amberGracePeriod {
		// If we missed the transition to amber, activate it.
		//		wst = WaitingRed
	} else if wst < Done && now.Sub(disconnectedAt) >= redGracePeriod {
		// If we missed the transition to amber and it's time to transition to RED, go straight to RED.
		wst = WaitingRed
	}

	if wst == WaitingRed {
		redSignal := clk.After(redGracePeriod - now.Sub(disconnectedAt))
		return nil, redSignal
	}
	if wst == WaitingAmber || wst == Uninitialized {
		amberSignal := clk.After(amberGracePeriod - now.Sub(disconnectedAt))
		redSignal := clk.After(redGracePeriod - now.Sub(disconnectedAt))
		return amberSignal, redSignal
	}
	return nil, nil
}
Example #6
0
File: updater.go Project: bac/juju
func machineLoop(context machineContext, m machine, lifeChanged <-chan struct{}, clock clock.Clock) error {
	// Use a short poll interval when initially waiting for
	// a machine's address and machine agent to start, and a long one when it already
	// has an address and the machine agent is started.
	pollInterval := ShortPoll
	pollInstance := func() error {
		instInfo, err := pollInstanceInfo(context, m)
		if err != nil {
			return err
		}

		machineStatus := status.Pending
		if err == nil {
			if statusInfo, err := m.Status(); err != nil {
				logger.Warningf("cannot get current machine status for machine %v: %v", m.Id(), err)
			} else {
				// TODO(perrito666) add status validation.
				machineStatus = status.Status(statusInfo.Status)
			}
		}

		// the extra condition below (checking allocating/pending) is here to improve user experience
		// without it the instance status will say "pending" for +10 minutes after the agent comes up to "started"
		if instInfo.status.Status != status.Allocating && instInfo.status.Status != status.Pending {
			if len(instInfo.addresses) > 0 && machineStatus == status.Started {
				// We've got at least one address and a status and instance is started, so poll infrequently.
				pollInterval = LongPoll
			} else if pollInterval < LongPoll {
				// We have no addresses or not started - poll increasingly rarely
				// until we do.
				pollInterval = time.Duration(float64(pollInterval) * ShortPollBackoff)
			}
		}
		return nil
	}

	shouldPollInstance := true
	for {
		if shouldPollInstance {
			if err := pollInstance(); err != nil {
				if !params.IsCodeNotProvisioned(err) {
					return errors.Trace(err)
				}
			}
			shouldPollInstance = false
		}
		select {
		case <-context.dying():
			return context.errDying()
		case <-clock.After(pollInterval):
			shouldPollInstance = true
		case <-lifeChanged:
			if err := m.Refresh(); err != nil {
				return err
			}
			if m.Life() == params.Dead {
				return nil
			}
		}
	}
}