github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/agent/bootstrap_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package agent_test
     5  
     6  import (
     7  	"github.com/juju/names"
     8  	gitjujutesting "github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	"github.com/juju/utils"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/agent"
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/constraints"
    16  	"github.com/juju/juju/environs"
    17  	"github.com/juju/juju/environs/config"
    18  	"github.com/juju/juju/instance"
    19  	"github.com/juju/juju/mongo"
    20  	"github.com/juju/juju/network"
    21  	"github.com/juju/juju/provider/dummy"
    22  	"github.com/juju/juju/state"
    23  	"github.com/juju/juju/state/multiwatcher"
    24  	"github.com/juju/juju/testing"
    25  	"github.com/juju/juju/version"
    26  )
    27  
    28  type bootstrapSuite struct {
    29  	testing.BaseSuite
    30  	mgoInst gitjujutesting.MgoInstance
    31  }
    32  
    33  var _ = gc.Suite(&bootstrapSuite{})
    34  
    35  func (s *bootstrapSuite) SetUpTest(c *gc.C) {
    36  	s.BaseSuite.SetUpTest(c)
    37  	// Don't use MgoSuite, because we need to ensure
    38  	// we have a fresh mongo for each test case.
    39  	s.mgoInst.EnableAuth = true
    40  	err := s.mgoInst.Start(testing.Certs)
    41  	c.Assert(err, jc.ErrorIsNil)
    42  }
    43  
    44  func (s *bootstrapSuite) TearDownTest(c *gc.C) {
    45  	s.mgoInst.Destroy()
    46  	s.BaseSuite.TearDownTest(c)
    47  }
    48  
    49  func (s *bootstrapSuite) TestInitializeState(c *gc.C) {
    50  	dataDir := c.MkDir()
    51  
    52  	pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt)
    53  	configParams := agent.AgentConfigParams{
    54  		DataDir:           dataDir,
    55  		Tag:               names.NewMachineTag("0"),
    56  		UpgradedToVersion: version.Current.Number,
    57  		StateAddresses:    []string{s.mgoInst.Addr()},
    58  		CACert:            testing.CACert,
    59  		Password:          pwHash,
    60  		Environment:       testing.EnvironmentTag,
    61  	}
    62  	servingInfo := params.StateServingInfo{
    63  		Cert:           testing.ServerCert,
    64  		PrivateKey:     testing.ServerKey,
    65  		CAPrivateKey:   testing.CAKey,
    66  		APIPort:        1234,
    67  		StatePort:      s.mgoInst.Port(),
    68  		SystemIdentity: "def456",
    69  	}
    70  
    71  	cfg, err := agent.NewStateMachineConfig(configParams, servingInfo)
    72  	c.Assert(err, jc.ErrorIsNil)
    73  
    74  	_, available := cfg.StateServingInfo()
    75  	c.Assert(available, jc.IsTrue)
    76  	expectConstraints := constraints.MustParse("mem=1024M")
    77  	expectHW := instance.MustParseHardware("mem=2048M")
    78  	mcfg := agent.BootstrapMachineConfig{
    79  		Addresses:       network.NewAddresses("zeroonetwothree", "0.1.2.3"),
    80  		Constraints:     expectConstraints,
    81  		Jobs:            []multiwatcher.MachineJob{multiwatcher.JobManageEnviron},
    82  		InstanceId:      "i-bootstrap",
    83  		Characteristics: expectHW,
    84  		SharedSecret:    "abc123",
    85  	}
    86  	envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{
    87  		"agent-version": version.Current.Number.String(),
    88  		"state-id":      "1", // needed so policy can Open config
    89  	})
    90  	envCfg, err := config.New(config.NoDefaults, envAttrs)
    91  	c.Assert(err, jc.ErrorIsNil)
    92  
    93  	adminUser := names.NewLocalUserTag("agent-admin")
    94  	st, m, err := agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy())
    95  	c.Assert(err, jc.ErrorIsNil)
    96  	defer st.Close()
    97  
    98  	err = cfg.Write()
    99  	c.Assert(err, jc.ErrorIsNil)
   100  
   101  	// Check that the environment has been set up.
   102  	env, err := st.Environment()
   103  	c.Assert(err, jc.ErrorIsNil)
   104  	uuid, ok := envCfg.UUID()
   105  	c.Assert(ok, jc.IsTrue)
   106  	c.Assert(env.UUID(), gc.Equals, uuid)
   107  
   108  	// Check that initial admin user has been set up correctly.
   109  	s.assertCanLogInAsAdmin(c, pwHash)
   110  	user, err := st.User(env.Owner())
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	c.Assert(user.PasswordValid(testing.DefaultMongoPassword), jc.IsTrue)
   113  
   114  	// Check that environment configuration has been added.
   115  	newEnvCfg, err := st.EnvironConfig()
   116  	c.Assert(err, jc.ErrorIsNil)
   117  	c.Assert(newEnvCfg.AllAttrs(), gc.DeepEquals, envCfg.AllAttrs())
   118  
   119  	// Check that the bootstrap machine looks correct.
   120  	c.Assert(m.Id(), gc.Equals, "0")
   121  	c.Assert(m.Jobs(), gc.DeepEquals, []state.MachineJob{state.JobManageEnviron})
   122  	c.Assert(m.Series(), gc.Equals, version.Current.Series)
   123  	c.Assert(m.CheckProvisioned(agent.BootstrapNonce), jc.IsTrue)
   124  	c.Assert(m.Addresses(), gc.DeepEquals, mcfg.Addresses)
   125  	gotConstraints, err := m.Constraints()
   126  	c.Assert(err, jc.ErrorIsNil)
   127  	c.Assert(gotConstraints, gc.DeepEquals, expectConstraints)
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	gotHW, err := m.HardwareCharacteristics()
   130  	c.Assert(err, jc.ErrorIsNil)
   131  	c.Assert(*gotHW, gc.DeepEquals, expectHW)
   132  	gotAddrs := m.Addresses()
   133  	c.Assert(gotAddrs, gc.DeepEquals, mcfg.Addresses)
   134  
   135  	// Check that the API host ports are initialised correctly.
   136  	apiHostPorts, err := st.APIHostPorts()
   137  	c.Assert(err, jc.ErrorIsNil)
   138  	c.Assert(apiHostPorts, jc.DeepEquals, [][]network.HostPort{
   139  		network.NewHostPorts(1234, "zeroonetwothree", "0.1.2.3"),
   140  	})
   141  
   142  	// Check that the state serving info is initialised correctly.
   143  	stateServingInfo, err := st.StateServingInfo()
   144  	c.Assert(err, jc.ErrorIsNil)
   145  	c.Assert(stateServingInfo, jc.DeepEquals, state.StateServingInfo{
   146  		APIPort:        1234,
   147  		StatePort:      s.mgoInst.Port(),
   148  		Cert:           testing.ServerCert,
   149  		PrivateKey:     testing.ServerKey,
   150  		CAPrivateKey:   testing.CAKey,
   151  		SharedSecret:   "abc123",
   152  		SystemIdentity: "def456",
   153  	})
   154  
   155  	// Check that the machine agent's config has been written
   156  	// and that we can use it to connect to the state.
   157  	machine0 := names.NewMachineTag("0")
   158  	newCfg, err := agent.ReadConfig(agent.ConfigPath(dataDir, machine0))
   159  	c.Assert(err, jc.ErrorIsNil)
   160  	c.Assert(newCfg.Tag(), gc.Equals, machine0)
   161  	c.Assert(agent.Password(newCfg), gc.Not(gc.Equals), pwHash)
   162  	c.Assert(agent.Password(newCfg), gc.Not(gc.Equals), testing.DefaultMongoPassword)
   163  	info, ok := cfg.MongoInfo()
   164  	c.Assert(ok, jc.IsTrue)
   165  	st1, err := state.Open(info, mongo.DialOpts{}, environs.NewStatePolicy())
   166  	c.Assert(err, jc.ErrorIsNil)
   167  	defer st1.Close()
   168  }
   169  
   170  func (s *bootstrapSuite) TestInitializeStateWithStateServingInfoNotAvailable(c *gc.C) {
   171  	configParams := agent.AgentConfigParams{
   172  		DataDir:           c.MkDir(),
   173  		Tag:               names.NewMachineTag("0"),
   174  		UpgradedToVersion: version.Current.Number,
   175  		StateAddresses:    []string{s.mgoInst.Addr()},
   176  		CACert:            testing.CACert,
   177  		Password:          "fake",
   178  		Environment:       testing.EnvironmentTag,
   179  	}
   180  	cfg, err := agent.NewAgentConfig(configParams)
   181  	c.Assert(err, jc.ErrorIsNil)
   182  
   183  	_, available := cfg.StateServingInfo()
   184  	c.Assert(available, jc.IsFalse)
   185  
   186  	adminUser := names.NewLocalUserTag("agent-admin")
   187  	_, _, err = agent.InitializeState(adminUser, cfg, nil, agent.BootstrapMachineConfig{}, mongo.DialOpts{}, environs.NewStatePolicy())
   188  	// InitializeState will fail attempting to get the api port information
   189  	c.Assert(err, gc.ErrorMatches, "state serving information not available")
   190  }
   191  
   192  func (s *bootstrapSuite) TestInitializeStateFailsSecondTime(c *gc.C) {
   193  	dataDir := c.MkDir()
   194  
   195  	pwHash := utils.UserPasswordHash(testing.DefaultMongoPassword, utils.CompatSalt)
   196  	configParams := agent.AgentConfigParams{
   197  		DataDir:           dataDir,
   198  		Tag:               names.NewMachineTag("0"),
   199  		UpgradedToVersion: version.Current.Number,
   200  		StateAddresses:    []string{s.mgoInst.Addr()},
   201  		CACert:            testing.CACert,
   202  		Password:          pwHash,
   203  		Environment:       testing.EnvironmentTag,
   204  	}
   205  	cfg, err := agent.NewAgentConfig(configParams)
   206  	c.Assert(err, jc.ErrorIsNil)
   207  	cfg.SetStateServingInfo(params.StateServingInfo{
   208  		APIPort:        5555,
   209  		StatePort:      s.mgoInst.Port(),
   210  		Cert:           "foo",
   211  		PrivateKey:     "bar",
   212  		SharedSecret:   "baz",
   213  		SystemIdentity: "qux",
   214  	})
   215  	expectConstraints := constraints.MustParse("mem=1024M")
   216  	expectHW := instance.MustParseHardware("mem=2048M")
   217  	mcfg := agent.BootstrapMachineConfig{
   218  		Constraints:     expectConstraints,
   219  		Jobs:            []multiwatcher.MachineJob{multiwatcher.JobManageEnviron},
   220  		InstanceId:      "i-bootstrap",
   221  		Characteristics: expectHW,
   222  	}
   223  	envAttrs := dummy.SampleConfig().Delete("admin-secret").Merge(testing.Attrs{
   224  		"agent-version": version.Current.Number.String(),
   225  		"state-id":      "1", // needed so policy can Open config
   226  	})
   227  	envCfg, err := config.New(config.NoDefaults, envAttrs)
   228  	c.Assert(err, jc.ErrorIsNil)
   229  
   230  	adminUser := names.NewLocalUserTag("agent-admin")
   231  	st, _, err := agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy())
   232  	c.Assert(err, jc.ErrorIsNil)
   233  	st.Close()
   234  
   235  	st, _, err = agent.InitializeState(adminUser, cfg, envCfg, mcfg, mongo.DialOpts{}, environs.NewStatePolicy())
   236  	if err == nil {
   237  		st.Close()
   238  	}
   239  	c.Assert(err, gc.ErrorMatches, "failed to initialize mongo admin user: cannot set admin password: not authorized .*")
   240  }
   241  
   242  func (s *bootstrapSuite) TestMachineJobFromParams(c *gc.C) {
   243  	var tests = []struct {
   244  		name multiwatcher.MachineJob
   245  		want state.MachineJob
   246  		err  string
   247  	}{{
   248  		name: multiwatcher.JobHostUnits,
   249  		want: state.JobHostUnits,
   250  	}, {
   251  		name: multiwatcher.JobManageEnviron,
   252  		want: state.JobManageEnviron,
   253  	}, {
   254  		name: multiwatcher.JobManageNetworking,
   255  		want: state.JobManageNetworking,
   256  	}, {
   257  		name: multiwatcher.JobManageStateDeprecated,
   258  		want: state.JobManageStateDeprecated,
   259  	}, {
   260  		name: "invalid",
   261  		want: -1,
   262  		err:  `invalid machine job "invalid"`,
   263  	}}
   264  	for _, test := range tests {
   265  		got, err := agent.MachineJobFromParams(test.name)
   266  		if err != nil {
   267  			c.Check(err, gc.ErrorMatches, test.err)
   268  		}
   269  		c.Check(got, gc.Equals, test.want)
   270  	}
   271  }
   272  
   273  func (s *bootstrapSuite) assertCanLogInAsAdmin(c *gc.C, password string) {
   274  	info := &mongo.MongoInfo{
   275  		Info: mongo.Info{
   276  			Addrs:  []string{s.mgoInst.Addr()},
   277  			CACert: testing.CACert,
   278  		},
   279  		Tag:      nil, // admin user
   280  		Password: password,
   281  	}
   282  	st, err := state.Open(info, mongo.DialOpts{}, environs.NewStatePolicy())
   283  	c.Assert(err, jc.ErrorIsNil)
   284  	defer st.Close()
   285  	_, err = st.Machine("0")
   286  	c.Assert(err, jc.ErrorIsNil)
   287  }