github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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/names"
    14  	"github.com/juju/utils/clock"
    15  	"github.com/juju/utils/fslock"
    16  
    17  	"github.com/juju/juju/agent"
    18  	"github.com/juju/juju/api/base"
    19  	"github.com/juju/juju/api/meterstatus"
    20  	"github.com/juju/juju/worker"
    21  	"github.com/juju/juju/worker/dependency"
    22  )
    23  
    24  var (
    25  	logger = loggo.GetLogger("juju.worker.meterstatus")
    26  )
    27  
    28  // ManifoldConfig identifies the resource names upon which the status manifold depends.
    29  type ManifoldConfig struct {
    30  	AgentName       string
    31  	APICallerName   string
    32  	MachineLockName string
    33  
    34  	NewHookRunner           func(names.UnitTag, *fslock.Lock, agent.Config) 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  			config.MachineLockName,
    48  		},
    49  		Start: func(context dependency.Context) (worker.Worker, error) {
    50  			return newStatusWorker(config, context)
    51  		},
    52  	}
    53  }
    54  
    55  func newStatusWorker(config ManifoldConfig, context dependency.Context) (worker.Worker, error) {
    56  	var agent agent.Agent
    57  	if err := context.Get(config.AgentName, &agent); err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	var machineLock *fslock.Lock
    62  	if err := context.Get(config.MachineLockName, &machineLock); 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, machineLock, agentConfig)
    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:            clock.WallClock,
    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  }