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  }