github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/jujud/agent/agent.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 /* 5 agent contains jujud's machine agent. 6 */ 7 package agent 8 9 import ( 10 "sync" 11 "time" 12 13 "github.com/juju/clock" 14 "github.com/juju/cmd" 15 "github.com/juju/errors" 16 "github.com/juju/gnuflag" 17 "github.com/juju/loggo" 18 "github.com/juju/utils/featureflag" 19 "github.com/juju/version" 20 "gopkg.in/juju/names.v2" 21 "gopkg.in/juju/worker.v1/dependency" 22 23 "github.com/juju/juju/agent" 24 "github.com/juju/juju/cmd/jujud/util" 25 ) 26 27 // AgentConf is a terribly confused interface. 28 // 29 // Parts of it are a mixin for cmd.Command implementations; others are a mixin 30 // for agent.Agent implementations; others bridge the two. We should be aiming 31 // to separate the cmd responsibilities from the agent responsibilities. 32 type AgentConf interface { 33 34 // AddFlags injects common agent flags into f. 35 AddFlags(f *gnuflag.FlagSet) 36 37 // CheckArgs reports whether the given args are valid for this agent. 38 CheckArgs(args []string) error 39 40 // DataDir returns the directory where this agent should store its data. 41 DataDir() string 42 43 // ReadConfig reads the agent's config from its config file. 44 ReadConfig(tag string) error 45 46 // CurrentConfig returns the agent config for this agent. 47 CurrentConfig() agent.Config 48 49 // ChangeConfig modifies this configuration using the given mutator. 50 ChangeConfig(change agent.ConfigMutator) error 51 } 52 53 // NewAgentConf returns a new value that satisfies AgentConf 54 func NewAgentConf(dataDir string) AgentConf { 55 return &agentConf{dataDir: dataDir} 56 } 57 58 // agentConf handles command-line flags shared by all agents. 59 type agentConf struct { 60 dataDir string 61 mu sync.Mutex 62 _config agent.ConfigSetterWriter 63 } 64 65 // AddFlags injects common agent flags into f. 66 func (c *agentConf) AddFlags(f *gnuflag.FlagSet) { 67 // TODO(dimitern) 2014-02-19 bug 1282025 68 // We need to pass a config location here instead and 69 // use it to locate the conf and the infer the data-dir 70 // from there instead of passing it like that. 71 f.StringVar(&c.dataDir, "data-dir", util.DataDir, "directory for juju data") 72 } 73 74 // CheckArgs reports whether the given args are valid for this agent. 75 func (c *agentConf) CheckArgs(args []string) error { 76 if c.dataDir == "" { 77 return util.RequiredError("data-dir") 78 } 79 return cmd.CheckEmpty(args) 80 } 81 82 // DataDir returns the directory where this agent should store its data. 83 func (c *agentConf) DataDir() string { 84 return c.dataDir 85 } 86 87 // ReadConfig reads the agent's config from its config file. 88 func (c *agentConf) ReadConfig(tag string) error { 89 t, err := names.ParseTag(tag) 90 if err != nil { 91 return err 92 } 93 c.mu.Lock() 94 defer c.mu.Unlock() 95 conf, err := agent.ReadConfig(agent.ConfigPath(c.dataDir, t)) 96 if err != nil { 97 return err 98 } 99 c._config = conf 100 return nil 101 } 102 103 // ChangeConfig modifies this configuration using the given mutator. 104 func (ch *agentConf) ChangeConfig(change agent.ConfigMutator) error { 105 ch.mu.Lock() 106 defer ch.mu.Unlock() 107 if err := change(ch._config); err != nil { 108 return errors.Trace(err) 109 } 110 if err := ch._config.Write(); err != nil { 111 return errors.Annotate(err, "cannot write agent configuration") 112 } 113 return nil 114 } 115 116 // CurrentConfig returns the agent config for this agent. 117 func (ch *agentConf) CurrentConfig() agent.Config { 118 ch.mu.Lock() 119 defer ch.mu.Unlock() 120 return ch._config.Clone() 121 } 122 123 func setupAgentLogging(config agent.Config) { 124 125 if loggingOverride := config.Value(agent.LoggingOverride); loggingOverride != "" { 126 logger.Infof("logging override set for this agent: %q", loggingOverride) 127 loggo.DefaultContext().ResetLoggerLevels() 128 err := loggo.ConfigureLoggers(loggingOverride) 129 if err != nil { 130 logger.Errorf("setting logging override %v", err) 131 } 132 } else if loggingConfig := config.LoggingConfig(); loggingConfig != "" { 133 logger.Infof("setting logging config to %q", loggingConfig) 134 // There should only be valid logging configuration strings saved 135 // in the logging config section in the agent.conf file. 136 loggo.DefaultContext().ResetLoggerLevels() 137 err := loggo.ConfigureLoggers(loggingConfig) 138 if err != nil { 139 logger.Errorf("problem setting logging config %v", err) 140 } 141 } 142 143 if flags := featureflag.String(); flags != "" { 144 logger.Warningf("developer feature flags enabled: %s", flags) 145 } 146 } 147 148 // GetJujuVersion gets the version of the agent from agent's config file 149 func GetJujuVersion(machineAgent string, dataDir string) (version.Number, error) { 150 agentConf := NewAgentConf(dataDir) 151 if err := agentConf.ReadConfig(machineAgent); err != nil { 152 err = errors.Annotate(err, "failed to read agent config file.") 153 return version.Number{}, err 154 } 155 config := agentConf.CurrentConfig() 156 if config == nil { 157 return version.Number{}, errors.Errorf("%s agent conf is not found", machineAgent) 158 } 159 return config.UpgradedToVersion(), nil 160 } 161 162 func dependencyEngineConfig() dependency.EngineConfig { 163 return dependency.EngineConfig{ 164 IsFatal: util.IsFatal, 165 WorstError: util.MoreImportantError, 166 ErrorDelay: 3 * time.Second, 167 BounceDelay: 10 * time.Millisecond, 168 BackoffFactor: 1.2, 169 MaxDelay: 2 * time.Minute, 170 Clock: clock.WallClock, 171 Logger: loggo.GetLogger("juju.worker.dependency"), 172 } 173 }