func machineLoop(context machineContext, m machine, changed <-chan struct{}) 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 := true for { if pollInstance { instInfo, err := pollInstanceInfo(context, m) if err != nil && !state.IsNotProvisionedError(err) { // If the provider doesn't implement Addresses/Status now, // it never will until we're upgraded, so don't bother // asking any more. We could use less resources // by taking down the entire worker, but this is easier for now // (and hopefully the local provider will implement // Addresses/Status in the not-too-distant future), // so we won't need to worry about this case at all. if errors.IsNotImplemented(err) { pollInterval = 365 * 24 * time.Hour } else { return err } } machineStatus := params.StatusPending if err == nil { if machineStatus, _, _, err = m.Status(); err != nil { logger.Warningf("cannot get current machine status for machine %v: %v", m.Id(), err) } } if len(instInfo.addresses) > 0 && instInfo.status != "" && machineStatus == params.StatusStarted { // 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) } pollInstance = false } select { case <-time.After(pollInterval): pollInstance = true case <-context.dying(): return nil case <-changed: if err := m.Refresh(); err != nil { return err } if m.Life() == state.Dead { return nil } } } }
// validate calls the state's assigned policy, if non-nil, to obtain // a ConfigValidator, and calls Validate if a non-nil ConfigValidator is // returned. func (st *State) validate(cfg, old *config.Config) (valid *config.Config, err error) { if st.policy == nil { return cfg, nil } configValidator, err := st.policy.ConfigValidator(cfg.Type()) if errors.IsNotImplemented(err) { return cfg, nil } else if err != nil { return nil, err } if configValidator == nil { return nil, fmt.Errorf("policy returned nil configValidator without an error") } return configValidator.Validate(cfg, old) }
// precheckInstance calls the state's assigned policy, if non-nil, to obtain // a Prechecker, and calls PrecheckInstance if a non-nil Prechecker is returned. func (st *State) precheckInstance(series string, cons constraints.Value, placement string) error { if st.policy == nil { return nil } cfg, err := st.EnvironConfig() if err != nil { return err } prechecker, err := st.policy.Prechecker(cfg) if errors.IsNotImplemented(err) { return nil } else if err != nil { return err } if prechecker == nil { return fmt.Errorf("policy returned nil prechecker without an error") } return prechecker.PrecheckInstance(series, cons, placement) }
// supportsUnitPlacement calls the state's assigned policy, if non-nil, // to obtain an EnvironCapability, and calls SupportsUnitPlacement if a // non-nil EnvironCapability is returned. func (st *State) supportsUnitPlacement() error { if st.policy == nil { return nil } cfg, err := st.EnvironConfig() if err != nil { return err } capability, err := st.policy.EnvironCapability(cfg) if errors.IsNotImplemented(err) { return nil } else if err != nil { return err } if capability == nil { return fmt.Errorf("policy returned nil EnvironCapability without an error") } return capability.SupportsUnitPlacement() }
// getStartTask creates a new worker for the provisioner, func (p *provisioner) getStartTask(safeMode bool) (ProvisionerTask, error) { auth, err := environs.NewAPIAuthenticator(p.st) if err != nil { return nil, err } // Start responding to changes in machines, and to any further updates // to the environment config. machineWatcher, err := p.getMachineWatcher() if err != nil { return nil, err } retryWatcher, err := p.getRetryWatcher() if err != nil && !errors.IsNotImplemented(err) { return nil, err } task := NewProvisionerTask( p.agentConfig.Tag(), safeMode, p.st, machineWatcher, retryWatcher, p.broker, auth) return task, nil }
// pollInstanceInfo checks the current provider addresses and status // for the given machine's instance, and sets them on the machine if they've changed. func pollInstanceInfo(context machineContext, m machine) (instInfo instanceInfo, err error) { instInfo = instanceInfo{} instId, err := m.InstanceId() // We can't ask the machine for its addresses if it isn't provisioned yet. if state.IsNotProvisionedError(err) { return instInfo, err } if err != nil { return instInfo, fmt.Errorf("cannot get machine's instance id: %v", err) } instInfo, err = context.instanceInfo(instId) if err != nil { if errors.IsNotImplemented(err) { return instInfo, err } logger.Warningf("cannot get instance info for instance %q: %v", instId, err) return instInfo, nil } currentInstStatus, err := m.InstanceStatus() if err != nil { // This should never occur since the machine is provisioned. // But just in case, we reset polled status so we try again next time. logger.Warningf("cannot get current instance status for machine %v: %v", m.Id(), err) instInfo.status = "" } else { if instInfo.status != currentInstStatus { logger.Infof("machine %q has new instance status: %v", m.Id(), instInfo.status) if err = m.SetInstanceStatus(instInfo.status); err != nil { logger.Errorf("cannot set instance status on %q: %v", m, err) } } } if !addressesEqual(m.Addresses(), instInfo.addresses) { logger.Infof("machine %q has new addresses: %v", m.Id(), instInfo.addresses) if err = m.SetAddresses(instInfo.addresses...); err != nil { logger.Errorf("cannot set addresses on %q: %v", m, err) } } return instInfo, err }
func (st *State) constraintsValidator() (constraints.Validator, error) { // Default behaviour is to simply use a standard validator with // no environment specific behaviour built in. defaultValidator := constraints.NewValidator() if st.policy == nil { return defaultValidator, nil } cfg, err := st.EnvironConfig() if err != nil { return nil, err } validator, err := st.policy.ConstraintsValidator(cfg) if errors.IsNotImplemented(err) { return defaultValidator, nil } else if err != nil { return nil, err } if validator == nil { return nil, fmt.Errorf("policy returned nil constraints validator without an error") } return validator, nil }