github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/meterstatus/manifold.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // Package meterstatus provides a worker that executes the meter-status-changed hook
     5  // periodically.
     6  package meterstatus
     7  
     8  import (
     9  	"path"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/loggo"
    13  	"github.com/juju/utils/clock"
    14  	"gopkg.in/juju/names.v2"
    15  
    16  	"github.com/juju/juju/agent"
    17  	"github.com/juju/juju/api/base"
    18  	"github.com/juju/juju/api/meterstatus"
    19  	"github.com/juju/juju/worker"
    20  	"github.com/juju/juju/worker/dependency"
    21  )
    22  
    23  var (
    24  	logger = loggo.GetLogger("juju.worker.meterstatus")
    25  )
    26  
    27  // ManifoldConfig identifies the resource names upon which the status manifold depends.
    28  type ManifoldConfig struct {
    29  	AgentName       string
    30  	APICallerName   string
    31  	MachineLockName string
    32  	Clock           clock.Clock
    33  
    34  	NewHookRunner           func(names.UnitTag, string, agent.Config, clock.Clock) HookRunner
    35  	NewMeterStatusAPIClient func(base.APICaller, names.UnitTag) meterstatus.MeterStatusClient
    36  
    37  	NewConnectedStatusWorker func(ConnectedConfig) (worker.Worker, error)
    38  	NewIsolatedStatusWorker  func(IsolatedConfig) (worker.Worker, error)
    39  }
    40  
    41  // Manifold returns a status manifold.
    42  func Manifold(config ManifoldConfig) dependency.Manifold {
    43  	return dependency.Manifold{
    44  		Inputs: []string{
    45  			config.AgentName,
    46  			config.APICallerName,
    47  		},
    48  		Start: func(context dependency.Context) (worker.Worker, error) {
    49  			if config.Clock == nil {
    50  				return nil, errors.NotValidf("missing Clock")
    51  			}
    52  			if config.MachineLockName == "" {
    53  				return nil, errors.NotValidf("missing MachineLockName")
    54  			}
    55  			return newStatusWorker(config, context)
    56  		},
    57  	}
    58  }
    59  
    60  func newStatusWorker(config ManifoldConfig, context dependency.Context) (worker.Worker, error) {
    61  	var agent agent.Agent
    62  	if err := context.Get(config.AgentName, &agent); err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	tag := agent.CurrentConfig().Tag()
    67  	unitTag, ok := tag.(names.UnitTag)
    68  	if !ok {
    69  		return nil, errors.Errorf("expected unit tag, got %v", tag)
    70  	}
    71  
    72  	agentConfig := agent.CurrentConfig()
    73  	stateFile := NewStateFile(path.Join(agentConfig.DataDir(), "meter-status.yaml"))
    74  	runner := config.NewHookRunner(unitTag, config.MachineLockName, agentConfig, config.Clock)
    75  
    76  	// If we don't have a valid APICaller, start a meter status
    77  	// worker that works without an API connection.
    78  	var apiCaller base.APICaller
    79  	err := context.Get(config.APICallerName, &apiCaller)
    80  	if errors.Cause(err) == dependency.ErrMissing {
    81  		logger.Tracef("API caller dependency not available, starting isolated meter status worker.")
    82  		cfg := IsolatedConfig{
    83  			Runner:           runner,
    84  			StateFile:        stateFile,
    85  			Clock:            config.Clock,
    86  			AmberGracePeriod: defaultAmberGracePeriod,
    87  			RedGracePeriod:   defaultRedGracePeriod,
    88  			TriggerFactory:   GetTriggers,
    89  		}
    90  		return config.NewIsolatedStatusWorker(cfg)
    91  	} else if err != nil {
    92  		return nil, err
    93  	}
    94  	logger.Tracef("Starting connected meter status worker.")
    95  	status := config.NewMeterStatusAPIClient(apiCaller, unitTag)
    96  
    97  	cfg := ConnectedConfig{
    98  		Runner:    runner,
    99  		StateFile: stateFile,
   100  		Status:    status,
   101  	}
   102  	return config.NewConnectedStatusWorker(cfg)
   103  }