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 }