github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/resumer/manifold.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package resumer
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/utils/clock"
    11  
    12  	"github.com/juju/juju/agent"
    13  	apiagent "github.com/juju/juju/api/agent"
    14  	"github.com/juju/juju/api/base"
    15  	"github.com/juju/juju/cmd/jujud/agent/engine"
    16  	"github.com/juju/juju/state/multiwatcher"
    17  	"github.com/juju/juju/worker"
    18  	"github.com/juju/juju/worker/dependency"
    19  )
    20  
    21  // ManifoldConfig defines the names of the manifolds on which a Manifold
    22  // will depend.
    23  type ManifoldConfig struct {
    24  	AgentName     string
    25  	APICallerName string
    26  	Clock         clock.Clock
    27  	Interval      time.Duration
    28  	NewFacade     func(base.APICaller) (Facade, error)
    29  	NewWorker     func(Config) (worker.Worker, error)
    30  }
    31  
    32  // newWorker is an engine.AgentAPIStartFunc that draws context from the
    33  // ManifoldConfig on which it is defined.
    34  func (config ManifoldConfig) newWorker(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) {
    35  
    36  	// This bit should be encapsulated in another manifold
    37  	// satisfying jujud/agent/engine.Flag, as described in
    38  	// the implementation below. Shouldn't be a concern here.
    39  	if ok, err := isModelManager(a, apiCaller); err != nil {
    40  		return nil, errors.Trace(err)
    41  	} else if !ok {
    42  		// This depends on a job change triggering an agent
    43  		// bounce, which does happen today, but is not ideal;
    44  		// another reason to use a flag.
    45  		return nil, dependency.ErrMissing
    46  	}
    47  
    48  	// Get the API facade.
    49  	if config.NewFacade == nil {
    50  		logger.Errorf("nil NewFacade not valid, uninstalling")
    51  		return nil, dependency.ErrUninstall
    52  	}
    53  	facade, err := config.NewFacade(apiCaller)
    54  	if err != nil {
    55  		return nil, errors.Trace(err)
    56  	}
    57  
    58  	// Start the worker.
    59  	if config.NewWorker == nil {
    60  		logger.Errorf("nil NewWorker not valid, uninstalling")
    61  		return nil, dependency.ErrUninstall
    62  	}
    63  	worker, err := config.NewWorker(Config{
    64  		Facade:   facade,
    65  		Clock:    config.Clock,
    66  		Interval: config.Interval,
    67  	})
    68  	if err != nil {
    69  		return nil, errors.Trace(err)
    70  	}
    71  	return worker, nil
    72  }
    73  
    74  // Manifold returns a dependency manifold that runs a resumer worker,
    75  // using the resources named or defined in the supplied config.
    76  func Manifold(config ManifoldConfig) dependency.Manifold {
    77  	aaConfig := engine.AgentAPIManifoldConfig{
    78  		AgentName:     config.AgentName,
    79  		APICallerName: config.APICallerName,
    80  	}
    81  	return engine.AgentAPIManifold(aaConfig, config.newWorker)
    82  }
    83  
    84  // isModelManager returns whether the agent has JobManageModel,
    85  // or an error.
    86  func isModelManager(a agent.Agent, apiCaller base.APICaller) (bool, error) {
    87  	agentFacade := apiagent.NewState(apiCaller)
    88  	entity, err := agentFacade.Entity(a.CurrentConfig().Tag())
    89  	if err != nil {
    90  		return false, errors.Trace(err)
    91  	}
    92  	for _, job := range entity.Jobs() {
    93  		if job == multiwatcher.JobManageModel {
    94  			return true, nil
    95  		}
    96  	}
    97  	return false, nil
    98  }