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