github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/jujud/agent/agenttest/agent.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package agenttest
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/juju/clock"
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/cmd/cmdtesting"
    13  	"github.com/juju/errors"
    14  	"github.com/juju/os/series"
    15  	"github.com/juju/replicaset"
    16  	gitjujutesting "github.com/juju/testing"
    17  	jc "github.com/juju/testing/checkers"
    18  	"github.com/juju/utils/arch"
    19  	"github.com/juju/version"
    20  	gc "gopkg.in/check.v1"
    21  	"gopkg.in/juju/names.v2"
    22  	"gopkg.in/mgo.v2"
    23  
    24  	"github.com/juju/juju/agent"
    25  	agenttools "github.com/juju/juju/agent/tools"
    26  	"github.com/juju/juju/apiserver/params"
    27  	cmdutil "github.com/juju/juju/cmd/jujud/util"
    28  	"github.com/juju/juju/controller"
    29  	"github.com/juju/juju/environs/filestorage"
    30  	envtesting "github.com/juju/juju/environs/testing"
    31  	envtools "github.com/juju/juju/environs/tools"
    32  	"github.com/juju/juju/juju/testing"
    33  	"github.com/juju/juju/mongo"
    34  	"github.com/juju/juju/mongo/mongotest"
    35  	"github.com/juju/juju/network"
    36  	"github.com/juju/juju/state"
    37  	"github.com/juju/juju/state/stateenvirons"
    38  	coretesting "github.com/juju/juju/testing"
    39  	coretools "github.com/juju/juju/tools"
    40  	jujuversion "github.com/juju/juju/version"
    41  	"github.com/juju/juju/worker/peergrouper"
    42  )
    43  
    44  type patchingSuite interface {
    45  	PatchValue(interface{}, interface{})
    46  }
    47  
    48  // InstallFakeEnsureMongo creates a new FakeEnsureMongo, patching
    49  // out replicaset.CurrentConfig and cmdutil.EnsureMongoServer.
    50  func InstallFakeEnsureMongo(suite patchingSuite) *FakeEnsureMongo {
    51  	f := &FakeEnsureMongo{
    52  		ServiceInstalled: true,
    53  	}
    54  	suite.PatchValue(&mongo.IsServiceInstalled, f.IsServiceInstalled)
    55  	suite.PatchValue(&replicaset.CurrentConfig, f.CurrentConfig)
    56  	suite.PatchValue(&cmdutil.EnsureMongoServer, f.EnsureMongo)
    57  	return f
    58  }
    59  
    60  // FakeEnsureMongo provides test fakes for the functions used to
    61  // initialise MongoDB.
    62  type FakeEnsureMongo struct {
    63  	EnsureCount      int
    64  	InitiateCount    int
    65  	DataDir          string
    66  	OplogSize        int
    67  	Info             state.StateServingInfo
    68  	InitiateParams   peergrouper.InitiateMongoParams
    69  	Err              error
    70  	ServiceInstalled bool
    71  }
    72  
    73  func (f *FakeEnsureMongo) IsServiceInstalled() (bool, error) {
    74  	return f.ServiceInstalled, nil
    75  }
    76  
    77  func (f *FakeEnsureMongo) CurrentConfig(*mgo.Session) (*replicaset.Config, error) {
    78  	// Return a dummy replicaset config that's good enough to
    79  	// indicate that the replicaset is initiated.
    80  	return &replicaset.Config{
    81  		Members: []replicaset.Member{{}},
    82  	}, nil
    83  }
    84  
    85  func (f *FakeEnsureMongo) EnsureMongo(args mongo.EnsureServerParams) (mongo.Version, error) {
    86  	f.EnsureCount++
    87  	f.DataDir, f.OplogSize = args.DataDir, args.OplogSize
    88  	f.Info = state.StateServingInfo{
    89  		APIPort:        args.APIPort,
    90  		StatePort:      args.StatePort,
    91  		Cert:           args.Cert,
    92  		PrivateKey:     args.PrivateKey,
    93  		CAPrivateKey:   args.CAPrivateKey,
    94  		SharedSecret:   args.SharedSecret,
    95  		SystemIdentity: args.SystemIdentity,
    96  	}
    97  	v, err := gitjujutesting.MongodVersion()
    98  	if err != nil {
    99  		return mongo.Version{}, errors.Trace(err)
   100  	}
   101  	return mongo.Version{
   102  		Major: v.Major,
   103  		Minor: v.Minor,
   104  		Patch: fmt.Sprint(v.Patch),
   105  	}, f.Err
   106  }
   107  
   108  func (f *FakeEnsureMongo) InitiateMongo(p peergrouper.InitiateMongoParams) error {
   109  	f.InitiateCount++
   110  	f.InitiateParams = p
   111  	return nil
   112  }
   113  
   114  // agentSuite is a fixture to be used by agent test suites.
   115  type AgentSuite struct {
   116  	oldRestartDelay time.Duration
   117  	testing.JujuConnSuite
   118  }
   119  
   120  // PrimeAgent writes the configuration file and tools for an agent
   121  // with the given entity name. It returns the agent's configuration and the
   122  // current tools.
   123  func (s *AgentSuite) PrimeAgent(c *gc.C, tag names.Tag, password string) (agent.ConfigSetterWriter, *coretools.Tools) {
   124  	vers := version.Binary{
   125  		Number: jujuversion.Current,
   126  		Arch:   arch.HostArch(),
   127  		Series: series.MustHostSeries(),
   128  	}
   129  	return s.PrimeAgentVersion(c, tag, password, vers)
   130  }
   131  
   132  // PrimeAgentVersion writes the configuration file and tools with version
   133  // vers for an agent with the given entity name. It returns the agent's
   134  // configuration and the current tools.
   135  func (s *AgentSuite) PrimeAgentVersion(c *gc.C, tag names.Tag, password string, vers version.Binary) (agent.ConfigSetterWriter, *coretools.Tools) {
   136  	c.Logf("priming agent %s", tag.String())
   137  	stor, err := filestorage.NewFileStorageWriter(c.MkDir())
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	agentTools := envtesting.PrimeTools(c, stor, s.DataDir(), "released", vers)
   140  	err = envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{agentTools}, envtools.DoNotWriteMirrors)
   141  	tools1, err := agenttools.ChangeAgentTools(s.DataDir(), tag.String(), vers)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	c.Assert(tools1, gc.DeepEquals, agentTools)
   144  
   145  	stateInfo := s.MongoInfo(c)
   146  	apiInfo := s.APIInfo(c)
   147  	paths := agent.DefaultPaths
   148  	paths.DataDir = s.DataDir()
   149  	paths.LogDir = s.LogDir
   150  	paths.MetricsSpoolDir = c.MkDir()
   151  	conf, err := agent.NewAgentConfig(
   152  		agent.AgentConfigParams{
   153  			Paths:             paths,
   154  			Tag:               tag,
   155  			UpgradedToVersion: vers.Number,
   156  			Password:          password,
   157  			Nonce:             agent.BootstrapNonce,
   158  			APIAddresses:      apiInfo.Addrs,
   159  			CACert:            stateInfo.CACert,
   160  			Controller:        coretesting.ControllerTag,
   161  			Model:             apiInfo.ModelTag,
   162  		})
   163  	c.Assert(err, jc.ErrorIsNil)
   164  	conf.SetPassword(password)
   165  	c.Assert(conf.Write(), gc.IsNil)
   166  	s.primeAPIHostPorts(c)
   167  	return conf, agentTools
   168  }
   169  
   170  // PrimeStateAgent writes the configuration file and tools for
   171  // a state agent with the given entity name. It returns the agent's
   172  // configuration and the current tools.
   173  func (s *AgentSuite) PrimeStateAgent(c *gc.C, tag names.Tag, password string) (agent.ConfigSetterWriter, *coretools.Tools) {
   174  	vers := version.Binary{
   175  		Number: jujuversion.Current,
   176  		Arch:   arch.HostArch(),
   177  		Series: series.MustHostSeries(),
   178  	}
   179  	return s.PrimeStateAgentVersion(c, tag, password, vers)
   180  }
   181  
   182  // PrimeStateAgentVersion writes the configuration file and tools with
   183  // version vers for a state agent with the given entity name. It
   184  // returns the agent's configuration and the current tools.
   185  func (s *AgentSuite) PrimeStateAgentVersion(c *gc.C, tag names.Tag, password string, vers version.Binary) (
   186  	agent.ConfigSetterWriter, *coretools.Tools,
   187  ) {
   188  	stor, err := filestorage.NewFileStorageWriter(c.MkDir())
   189  	c.Assert(err, jc.ErrorIsNil)
   190  	agentTools := envtesting.PrimeTools(c, stor, s.DataDir(), "released", vers)
   191  	tools1, err := agenttools.ChangeAgentTools(s.DataDir(), tag.String(), vers)
   192  	c.Assert(err, jc.ErrorIsNil)
   193  	c.Assert(tools1, gc.DeepEquals, agentTools)
   194  
   195  	model, err := s.State.Model()
   196  	c.Assert(err, jc.ErrorIsNil)
   197  
   198  	conf := s.WriteStateAgentConfig(c, tag, password, vers, model.ModelTag())
   199  	s.primeAPIHostPorts(c)
   200  	return conf, agentTools
   201  }
   202  
   203  // WriteStateAgentConfig creates and writes a state agent config.
   204  func (s *AgentSuite) WriteStateAgentConfig(
   205  	c *gc.C,
   206  	tag names.Tag,
   207  	password string,
   208  	vers version.Binary,
   209  	modelTag names.ModelTag,
   210  ) agent.ConfigSetterWriter {
   211  	stateInfo := s.MongoInfo(c)
   212  	apiPort := gitjujutesting.FindTCPPort()
   213  	s.SetControllerConfigAPIPort(c, apiPort)
   214  	apiAddr := []string{fmt.Sprintf("localhost:%d", apiPort)}
   215  	conf, err := agent.NewStateMachineConfig(
   216  		agent.AgentConfigParams{
   217  			Paths: agent.NewPathsWithDefaults(agent.Paths{
   218  				DataDir: s.DataDir(),
   219  				LogDir:  s.LogDir,
   220  			}),
   221  			Tag:               tag,
   222  			UpgradedToVersion: vers.Number,
   223  			Password:          password,
   224  			Nonce:             agent.BootstrapNonce,
   225  			APIAddresses:      apiAddr,
   226  			CACert:            stateInfo.CACert,
   227  			Controller:        s.State.ControllerTag(),
   228  			Model:             modelTag,
   229  		},
   230  		params.StateServingInfo{
   231  			Cert:         coretesting.ServerCert,
   232  			PrivateKey:   coretesting.ServerKey,
   233  			CAPrivateKey: coretesting.CAKey,
   234  			StatePort:    gitjujutesting.MgoServer.Port(),
   235  			APIPort:      apiPort,
   236  		})
   237  	c.Assert(err, jc.ErrorIsNil)
   238  	conf.SetPassword(password)
   239  	c.Assert(conf.Write(), gc.IsNil)
   240  	return conf
   241  }
   242  
   243  // SetControllerConfigAPIPort resets the API port in controller config
   244  // to the value provided - this is useful in tests that create
   245  // multiple agents and only start one, so that the API port the http
   246  // server listens on matches the one the agent tries to connect to.
   247  func (s *AgentSuite) SetControllerConfigAPIPort(c *gc.C, apiPort int) {
   248  	// Need to update the controller config with this new API port as
   249  	// well - this is a nasty hack but... oh well!
   250  	controller.AllowedUpdateConfigAttributes.Add("api-port")
   251  	defer func() {
   252  		controller.AllowedUpdateConfigAttributes.Remove("api-port")
   253  	}()
   254  	err := s.State.UpdateControllerConfig(map[string]interface{}{
   255  		"api-port": apiPort,
   256  	}, nil)
   257  	c.Assert(err, jc.ErrorIsNil)
   258  	// Ensure that the local controller config is also up to date.
   259  	s.ControllerConfig["api-port"] = apiPort
   260  }
   261  
   262  func (s *AgentSuite) primeAPIHostPorts(c *gc.C) {
   263  	apiInfo := s.APIInfo(c)
   264  
   265  	c.Assert(apiInfo.Addrs, gc.HasLen, 1)
   266  	hostPorts, err := network.ParseHostPorts(apiInfo.Addrs[0])
   267  	c.Assert(err, jc.ErrorIsNil)
   268  
   269  	err = s.State.SetAPIHostPorts([][]network.HostPort{hostPorts})
   270  	c.Assert(err, jc.ErrorIsNil)
   271  
   272  	c.Logf("api host ports primed %#v", hostPorts)
   273  }
   274  
   275  // InitAgent initialises the given agent command with additional
   276  // arguments as provided.
   277  func (s *AgentSuite) InitAgent(c *gc.C, a cmd.Command, args ...string) {
   278  	args = append([]string{"--data-dir", s.DataDir()}, args...)
   279  	err := cmdtesting.InitCommand(a, args)
   280  	c.Assert(err, jc.ErrorIsNil)
   281  }
   282  
   283  func (s *AgentSuite) AssertCanOpenState(c *gc.C, tag names.Tag, dataDir string) {
   284  	config, err := agent.ReadConfig(agent.ConfigPath(dataDir, tag))
   285  	c.Assert(err, jc.ErrorIsNil)
   286  	info, ok := config.MongoInfo()
   287  	c.Assert(ok, jc.IsTrue)
   288  	session, err := mongo.DialWithInfo(*info, mongotest.DialOpts())
   289  	c.Assert(err, jc.ErrorIsNil)
   290  	defer session.Close()
   291  	pool, err := state.OpenStatePool(state.OpenParams{
   292  		Clock:              clock.WallClock,
   293  		ControllerTag:      config.Controller(),
   294  		ControllerModelTag: config.Model(),
   295  		MongoSession:       session,
   296  		NewPolicy:          stateenvirons.GetNewPolicyFunc(),
   297  	})
   298  	c.Assert(err, jc.ErrorIsNil)
   299  	pool.Close()
   300  }
   301  
   302  func (s *AgentSuite) AssertCannotOpenState(c *gc.C, tag names.Tag, dataDir string) {
   303  	config, err := agent.ReadConfig(agent.ConfigPath(dataDir, tag))
   304  	c.Assert(err, jc.ErrorIsNil)
   305  	_, ok := config.MongoInfo()
   306  	c.Assert(ok, jc.IsFalse)
   307  }