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  }