github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/jujud/unit.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package main 5 6 import ( 7 "fmt" 8 "path/filepath" 9 "runtime" 10 11 "github.com/juju/cmd" 12 "github.com/juju/errors" 13 "github.com/juju/loggo" 14 "github.com/juju/names" 15 "github.com/juju/utils/featureflag" 16 "gopkg.in/natefinch/lumberjack.v2" 17 "launchpad.net/gnuflag" 18 "launchpad.net/tomb" 19 20 "github.com/juju/juju/agent" 21 agentcmd "github.com/juju/juju/cmd/jujud/agent" 22 cmdutil "github.com/juju/juju/cmd/jujud/util" 23 "github.com/juju/juju/network" 24 "github.com/juju/juju/storage" 25 "github.com/juju/juju/tools" 26 "github.com/juju/juju/version" 27 "github.com/juju/juju/worker" 28 "github.com/juju/juju/worker/apiaddressupdater" 29 "github.com/juju/juju/worker/diskformatter" 30 workerlogger "github.com/juju/juju/worker/logger" 31 "github.com/juju/juju/worker/proxyupdater" 32 "github.com/juju/juju/worker/rsyslog" 33 "github.com/juju/juju/worker/uniter" 34 "github.com/juju/juju/worker/upgrader" 35 ) 36 37 var agentLogger = loggo.GetLogger("juju.jujud") 38 39 // UnitAgent is a cmd.Command responsible for running a unit agent. 40 type UnitAgent struct { 41 cmd.CommandBase 42 tomb tomb.Tomb 43 agentcmd.AgentConf 44 UnitName string 45 runner worker.Runner 46 setupLogging func(agent.Config) error 47 logToStdErr bool 48 } 49 50 // Info returns usage information for the command. 51 func (a *UnitAgent) Info() *cmd.Info { 52 return &cmd.Info{ 53 Name: "unit", 54 Purpose: "run a juju unit agent", 55 } 56 } 57 58 func (a *UnitAgent) SetFlags(f *gnuflag.FlagSet) { 59 a.AgentConf.AddFlags(f) 60 f.StringVar(&a.UnitName, "unit-name", "", "name of the unit to run") 61 f.BoolVar(&a.logToStdErr, "log-to-stderr", false, "whether to log to standard error instead of log files") 62 } 63 64 // Init initializes the command for running. 65 func (a *UnitAgent) Init(args []string) error { 66 if a.UnitName == "" { 67 return cmdutil.RequiredError("unit-name") 68 } 69 if !names.IsValidUnit(a.UnitName) { 70 return fmt.Errorf(`--unit-name option expects "<service>/<n>" argument`) 71 } 72 if err := a.AgentConf.CheckArgs(args); err != nil { 73 return err 74 } 75 a.runner = worker.NewRunner(cmdutil.IsFatal, cmdutil.MoreImportant) 76 return nil 77 } 78 79 // Stop stops the unit agent. 80 func (a *UnitAgent) Stop() error { 81 a.runner.Kill() 82 return a.tomb.Wait() 83 } 84 85 // Run runs a unit agent. 86 func (a *UnitAgent) Run(ctx *cmd.Context) error { 87 defer a.tomb.Done() 88 if err := a.ReadConfig(a.Tag().String()); err != nil { 89 return err 90 } 91 agentConfig := a.CurrentConfig() 92 93 if !a.logToStdErr { 94 filename := filepath.Join(agentConfig.LogDir(), agentConfig.Tag().String()+".log") 95 96 log := &lumberjack.Logger{ 97 Filename: filename, 98 MaxSize: 300, // megabytes 99 MaxBackups: 2, 100 } 101 102 if err := cmdutil.SwitchProcessToRollingLogs(log); err != nil { 103 return err 104 } 105 } 106 agentLogger.Infof("unit agent %v start (%s [%s])", a.Tag().String(), version.Current, runtime.Compiler) 107 if flags := featureflag.String(); flags != "" { 108 logger.Warningf("developer feature flags enabled: %s", flags) 109 } 110 111 network.InitializeFromConfig(agentConfig) 112 a.runner.StartWorker("api", a.APIWorkers) 113 err := cmdutil.AgentDone(logger, a.runner.Wait()) 114 a.tomb.Kill(err) 115 return err 116 } 117 118 func (a *UnitAgent) APIWorkers() (worker.Worker, error) { 119 agentConfig := a.CurrentConfig() 120 dataDir := agentConfig.DataDir() 121 hookLock, err := cmdutil.HookExecutionLock(dataDir) 122 if err != nil { 123 return nil, err 124 } 125 st, entity, err := agentcmd.OpenAPIState(agentConfig, a) 126 if err != nil { 127 return nil, err 128 } 129 unitTag, err := names.ParseUnitTag(entity.Tag()) 130 if err != nil { 131 return nil, errors.Trace(err) 132 } 133 // Ensure that the environment uuid is stored in the agent config. 134 // Luckily the API has it recorded for us after we connect. 135 if agentConfig.Environment().Id() == "" { 136 err := a.ChangeConfig(func(setter agent.ConfigSetter) error { 137 environTag, err := st.EnvironTag() 138 if err != nil { 139 return errors.Annotate(err, "no environment uuid set on api") 140 } 141 142 return setter.Migrate(agent.MigrateParams{ 143 Environment: environTag, 144 }) 145 }) 146 if err != nil { 147 logger.Warningf("unable to save environment uuid: %v", err) 148 // Not really fatal, just annoying. 149 } 150 } 151 152 // Before starting any workers, ensure we record the Juju version this unit 153 // agent is running. 154 currentTools := &tools.Tools{Version: version.Current} 155 if err := st.Upgrader().SetVersion(agentConfig.Tag().String(), currentTools.Version); err != nil { 156 return nil, errors.Annotate(err, "cannot set unit agent version") 157 } 158 159 runner := worker.NewRunner(cmdutil.ConnectionIsFatal(logger, st), cmdutil.MoreImportant) 160 // start proxyupdater first to ensure proxy settings are correct 161 runner.StartWorker("proxyupdater", func() (worker.Worker, error) { 162 return proxyupdater.New(st.Environment(), false), nil 163 }) 164 runner.StartWorker("upgrader", func() (worker.Worker, error) { 165 return upgrader.NewUpgrader( 166 st.Upgrader(), 167 agentConfig, 168 agentConfig.UpgradedToVersion(), 169 func() bool { return false }, 170 ), nil 171 }) 172 runner.StartWorker("logger", func() (worker.Worker, error) { 173 return workerlogger.NewLogger(st.Logger(), agentConfig), nil 174 }) 175 runner.StartWorker("uniter", func() (worker.Worker, error) { 176 uniterFacade, err := st.Uniter() 177 if err != nil { 178 return nil, errors.Trace(err) 179 } 180 return uniter.NewUniter(uniterFacade, unitTag, dataDir, hookLock), nil 181 }) 182 183 runner.StartWorker("apiaddressupdater", func() (worker.Worker, error) { 184 uniterFacade, err := st.Uniter() 185 if err != nil { 186 return nil, errors.Trace(err) 187 } 188 return apiaddressupdater.NewAPIAddressUpdater(uniterFacade, a), nil 189 }) 190 runner.StartWorker("rsyslog", func() (worker.Worker, error) { 191 return cmdutil.NewRsyslogConfigWorker(st.Rsyslog(), agentConfig, rsyslog.RsyslogModeForwarding) 192 }) 193 // TODO(axw) stop checking feature flag once storage has graduated. 194 if featureflag.Enabled(storage.FeatureFlag) { 195 runner.StartWorker("diskformatter", func() (worker.Worker, error) { 196 api, err := st.DiskFormatter() 197 if err != nil { 198 return nil, err 199 } 200 return diskformatter.NewWorker(api), nil 201 }) 202 } 203 return cmdutil.NewCloseWorker(logger, runner, st), nil 204 } 205 206 func (a *UnitAgent) Tag() names.Tag { 207 return names.NewUnitTag(a.UnitName) 208 }