github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/jujud/agent/unit.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package agent
     5  
     6  import (
     7  	"fmt"
     8  	"runtime"
     9  	"time"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/loggo"
    13  	"github.com/juju/names"
    14  	"github.com/juju/utils/featureflag"
    15  	"gopkg.in/natefinch/lumberjack.v2"
    16  	"launchpad.net/gnuflag"
    17  	"launchpad.net/tomb"
    18  
    19  	"github.com/juju/juju/agent"
    20  	"github.com/juju/juju/cmd/jujud/agent/unit"
    21  	cmdutil "github.com/juju/juju/cmd/jujud/util"
    22  	"github.com/juju/juju/network"
    23  	"github.com/juju/juju/version"
    24  	"github.com/juju/juju/worker"
    25  	"github.com/juju/juju/worker/dependency"
    26  	"github.com/juju/juju/worker/logsender"
    27  )
    28  
    29  var (
    30  	agentLogger = loggo.GetLogger("juju.jujud")
    31  )
    32  
    33  // UnitAgent is a cmd.Command responsible for running a unit agent.
    34  type UnitAgent struct {
    35  	cmd.CommandBase
    36  	tomb tomb.Tomb
    37  	AgentConf
    38  	UnitName     string
    39  	runner       worker.Runner
    40  	bufferedLogs logsender.LogRecordCh
    41  	setupLogging func(agent.Config) error
    42  	logToStdErr  bool
    43  	ctx          *cmd.Context
    44  
    45  	// Used to signal that the upgrade worker will not
    46  	// reboot the agent on startup because there are no
    47  	// longer any immediately pending agent upgrades.
    48  	// Channel used as a selectable bool (closed means true).
    49  	initialAgentUpgradeCheckComplete chan struct{}
    50  }
    51  
    52  // NewUnitAgent creates a new UnitAgent value properly initialized.
    53  func NewUnitAgent(ctx *cmd.Context, bufferedLogs logsender.LogRecordCh) *UnitAgent {
    54  	return &UnitAgent{
    55  		AgentConf: NewAgentConf(""),
    56  		ctx:       ctx,
    57  		initialAgentUpgradeCheckComplete: make(chan struct{}),
    58  		bufferedLogs:                     bufferedLogs,
    59  	}
    60  }
    61  
    62  // Info returns usage information for the command.
    63  func (a *UnitAgent) Info() *cmd.Info {
    64  	return &cmd.Info{
    65  		Name:    "unit",
    66  		Purpose: "run a juju unit agent",
    67  	}
    68  }
    69  
    70  func (a *UnitAgent) SetFlags(f *gnuflag.FlagSet) {
    71  	a.AgentConf.AddFlags(f)
    72  	f.StringVar(&a.UnitName, "unit-name", "", "name of the unit to run")
    73  	f.BoolVar(&a.logToStdErr, "log-to-stderr", false, "whether to log to standard error instead of log files")
    74  }
    75  
    76  // Init initializes the command for running.
    77  func (a *UnitAgent) Init(args []string) error {
    78  	if a.UnitName == "" {
    79  		return cmdutil.RequiredError("unit-name")
    80  	}
    81  	if !names.IsValidUnit(a.UnitName) {
    82  		return fmt.Errorf(`--unit-name option expects "<service>/<n>" argument`)
    83  	}
    84  	if err := a.AgentConf.CheckArgs(args); err != nil {
    85  		return err
    86  	}
    87  	a.runner = worker.NewRunner(cmdutil.IsFatal, cmdutil.MoreImportant)
    88  
    89  	if !a.logToStdErr {
    90  		if err := a.ReadConfig(a.Tag().String()); err != nil {
    91  			return err
    92  		}
    93  		agentConfig := a.CurrentConfig()
    94  
    95  		// the writer in ctx.stderr gets set as the loggo writer in github.com/juju/cmd/logging.go
    96  		a.ctx.Stderr = &lumberjack.Logger{
    97  			Filename:   agent.LogFilename(agentConfig),
    98  			MaxSize:    300, // megabytes
    99  			MaxBackups: 2,
   100  		}
   101  
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  // Stop stops the unit agent.
   108  func (a *UnitAgent) Stop() error {
   109  	a.runner.Kill()
   110  	return a.tomb.Wait()
   111  }
   112  
   113  // Run runs a unit agent.
   114  func (a *UnitAgent) Run(ctx *cmd.Context) error {
   115  	defer a.tomb.Done()
   116  	if err := a.ReadConfig(a.Tag().String()); err != nil {
   117  		return err
   118  	}
   119  	agentConfig := a.CurrentConfig()
   120  
   121  	agentLogger.Infof("unit agent %v start (%s [%s])", a.Tag().String(), version.Current, runtime.Compiler)
   122  	if flags := featureflag.String(); flags != "" {
   123  		logger.Warningf("developer feature flags enabled: %s", flags)
   124  	}
   125  
   126  	network.InitializeFromConfig(agentConfig)
   127  	a.runner.StartWorker("api", a.APIWorkers)
   128  	err := cmdutil.AgentDone(logger, a.runner.Wait())
   129  	a.tomb.Kill(err)
   130  	return err
   131  }
   132  
   133  // APIWorkers returns a dependency.Engine running the unit agent's responsibilities.
   134  func (a *UnitAgent) APIWorkers() (worker.Worker, error) {
   135  	manifolds := unit.Manifolds(unit.ManifoldsConfig{
   136  		Agent:               agent.APIHostPortsSetter{a},
   137  		LogSource:           a.bufferedLogs,
   138  		LeadershipGuarantee: 30 * time.Second,
   139  	})
   140  
   141  	config := dependency.EngineConfig{
   142  		IsFatal:       cmdutil.IsFatal,
   143  		MoreImportant: cmdutil.MoreImportantError,
   144  		ErrorDelay:    3 * time.Second,
   145  		BounceDelay:   10 * time.Millisecond,
   146  	}
   147  	engine, err := dependency.NewEngine(config)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	if err := dependency.Install(engine, manifolds); err != nil {
   152  		if err := worker.Stop(engine); err != nil {
   153  			logger.Errorf("while stopping engine with bad manifolds: %v", err)
   154  		}
   155  		return nil, err
   156  	}
   157  	return engine, nil
   158  }
   159  
   160  func (a *UnitAgent) Tag() names.Tag {
   161  	return names.NewUnitTag(a.UnitName)
   162  }