github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/cmd/jujud/agent/testing/agent.go (about)

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