github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/maas/environ_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package maas_test
     5  
     6  import (
     7  	stdtesting "testing"
     8  
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  	"launchpad.net/gomaasapi"
    12  
    13  	"github.com/juju/juju/environs/config"
    14  	envtesting "github.com/juju/juju/environs/testing"
    15  	"github.com/juju/juju/feature"
    16  	"github.com/juju/juju/provider/maas"
    17  	coretesting "github.com/juju/juju/testing"
    18  )
    19  
    20  type environSuite struct {
    21  	coretesting.BaseSuite
    22  	envtesting.ToolsFixture
    23  	testMAASObject  *gomaasapi.TestMAASObject
    24  	restoreTimeouts func()
    25  }
    26  
    27  var _ = gc.Suite(&environSuite{})
    28  
    29  func TestMAAS(t *stdtesting.T) {
    30  	gc.TestingT(t)
    31  }
    32  
    33  // TDOO: jam 2013-12-06 This is copied from the providerSuite which is in a
    34  // whitebox package maas. Either move that into a whitebox test so it can be
    35  // shared, or into a 'testing' package so we can use it here.
    36  func (s *environSuite) SetUpSuite(c *gc.C) {
    37  	s.restoreTimeouts = envtesting.PatchAttemptStrategies(maas.ShortAttempt)
    38  	s.BaseSuite.SetUpSuite(c)
    39  	TestMAASObject := gomaasapi.NewTestMAAS("1.0")
    40  	s.testMAASObject = TestMAASObject
    41  }
    42  
    43  func (s *environSuite) SetUpTest(c *gc.C) {
    44  	s.BaseSuite.SetUpTest(c)
    45  	s.ToolsFixture.SetUpTest(c)
    46  	s.SetFeatureFlags(feature.AddressAllocation)
    47  }
    48  
    49  func (s *environSuite) TearDownTest(c *gc.C) {
    50  	s.testMAASObject.TestServer.Clear()
    51  	s.ToolsFixture.TearDownTest(c)
    52  	s.BaseSuite.TearDownTest(c)
    53  }
    54  
    55  func (s *environSuite) TearDownSuite(c *gc.C) {
    56  	s.testMAASObject.Close()
    57  	s.restoreTimeouts()
    58  	s.BaseSuite.TearDownSuite(c)
    59  }
    60  
    61  func getSimpleTestConfig(c *gc.C, extraAttrs coretesting.Attrs) *config.Config {
    62  	attrs := coretesting.FakeConfig()
    63  	attrs["type"] = "maas"
    64  	attrs["maas-server"] = "http://maas.testing.invalid"
    65  	attrs["maas-oauth"] = "a:b:c"
    66  	for k, v := range extraAttrs {
    67  		attrs[k] = v
    68  	}
    69  	cfg, err := config.New(config.NoDefaults, attrs)
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	return cfg
    72  }
    73  
    74  func (*environSuite) TestSetConfigValidatesFirst(c *gc.C) {
    75  	// SetConfig() validates the config change and disallows, for example,
    76  	// changes in the environment name.
    77  	oldCfg := getSimpleTestConfig(c, coretesting.Attrs{"name": "old-name"})
    78  	newCfg := getSimpleTestConfig(c, coretesting.Attrs{"name": "new-name"})
    79  	env, err := maas.NewEnviron(oldCfg)
    80  	c.Assert(err, jc.ErrorIsNil)
    81  
    82  	// SetConfig() fails, even though both the old and the new config are
    83  	// individually valid.
    84  	err = env.SetConfig(newCfg)
    85  	c.Assert(err, gc.NotNil)
    86  	c.Check(err, gc.ErrorMatches, ".*cannot change name.*")
    87  
    88  	// The old config is still in place.  The new config never took effect.
    89  	c.Check(env.Config().Name(), gc.Equals, "old-name")
    90  }
    91  
    92  func (*environSuite) TestSetConfigRefusesChangingAgentName(c *gc.C) {
    93  	oldCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-one"})
    94  	newCfgTwo := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-two"})
    95  	env, err := maas.NewEnviron(oldCfg)
    96  	c.Assert(err, jc.ErrorIsNil)
    97  
    98  	// SetConfig() fails, even though both the old and the new config are
    99  	// individually valid.
   100  	err = env.SetConfig(newCfgTwo)
   101  	c.Assert(err, gc.NotNil)
   102  	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")
   103  
   104  	// The old config is still in place.  The new config never took effect.
   105  	c.Check(maas.MAASAgentName(env), gc.Equals, "agent-one")
   106  
   107  	// It also refuses to set it to the empty string:
   108  	err = env.SetConfig(getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""}))
   109  	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")
   110  
   111  	// And to nil
   112  	err = env.SetConfig(getSimpleTestConfig(c, nil))
   113  	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")
   114  }
   115  
   116  func (*environSuite) TestSetConfigAllowsEmptyFromNilAgentName(c *gc.C) {
   117  	// bug #1256179 is that when using an older version of Juju (<1.16.2)
   118  	// we didn't include maas-agent-name in the database, so it was 'nil'
   119  	// in the OldConfig. However, when setting an environment, we would set
   120  	// it to "" (because maasEnvironConfig.Validate ensures it is a 'valid'
   121  	// string). We can't create that from NewEnviron or newConfig because
   122  	// both of them Validate the contents. 'cmd/juju/environment
   123  	// SetEnvironmentCommand' instead uses conn.State.EnvironConfig() which
   124  	// just reads the content of the database into a map, so we just create
   125  	// the map ourselves.
   126  
   127  	// Even though we use 'nil' here, it actually stores it as "" because
   128  	// 1.16.2 already validates the value
   129  	baseCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""})
   130  	c.Check(baseCfg.UnknownAttrs()["maas-agent-name"], gc.Equals, "")
   131  	env, err := maas.NewEnviron(baseCfg)
   132  	c.Assert(err, jc.ErrorIsNil)
   133  	provider := env.Provider()
   134  
   135  	attrs := coretesting.FakeConfig()
   136  	// These are attrs we need to make it a valid Config, but would usually
   137  	// be set by other infrastructure
   138  	attrs["type"] = "maas"
   139  	nilCfg, err := config.New(config.NoDefaults, attrs)
   140  	c.Assert(err, jc.ErrorIsNil)
   141  	validatedConfig, err := provider.Validate(baseCfg, nilCfg)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	c.Check(validatedConfig.UnknownAttrs()["maas-agent-name"], gc.Equals, "")
   144  	// However, you can't set it to an actual value if you haven't been using a value
   145  	valueCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-name"})
   146  	_, err = provider.Validate(valueCfg, nilCfg)
   147  	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")
   148  }
   149  
   150  func (*environSuite) TestSetConfigAllowsChangingNilAgentNameToEmptyString(c *gc.C) {
   151  	oldCfg := getSimpleTestConfig(c, nil)
   152  	newCfgTwo := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""})
   153  	env, err := maas.NewEnviron(oldCfg)
   154  	c.Assert(err, jc.ErrorIsNil)
   155  
   156  	err = env.SetConfig(newCfgTwo)
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	c.Check(maas.MAASAgentName(env), gc.Equals, "")
   159  }
   160  
   161  func (*environSuite) TestSetConfigUpdatesConfig(c *gc.C) {
   162  	origAttrs := coretesting.Attrs{
   163  		"server-name":  "http://maas2.testing.invalid",
   164  		"maas-oauth":   "a:b:c",
   165  		"admin-secret": "secret",
   166  	}
   167  	cfg := getSimpleTestConfig(c, origAttrs)
   168  	env, err := maas.NewEnviron(cfg)
   169  	c.Check(err, jc.ErrorIsNil)
   170  	c.Check(env.Config().Name(), gc.Equals, "testenv")
   171  
   172  	anotherServer := "http://maas.testing.invalid"
   173  	anotherOauth := "c:d:e"
   174  	anotherSecret := "secret2"
   175  	newAttrs := coretesting.Attrs{
   176  		"server-name":  anotherServer,
   177  		"maas-oauth":   anotherOauth,
   178  		"admin-secret": anotherSecret,
   179  	}
   180  	cfg2 := getSimpleTestConfig(c, newAttrs)
   181  	errSetConfig := env.SetConfig(cfg2)
   182  	c.Check(errSetConfig, gc.IsNil)
   183  	c.Check(env.Config().Name(), gc.Equals, "testenv")
   184  	authClient, _ := gomaasapi.NewAuthenticatedClient(anotherServer, anotherOauth, maas.APIVersion)
   185  	maasClient := gomaasapi.NewMAAS(*authClient)
   186  	MAASServer := maas.GetMAASClient(env)
   187  	c.Check(MAASServer, gc.DeepEquals, maasClient)
   188  }
   189  
   190  func (*environSuite) TestNewEnvironSetsConfig(c *gc.C) {
   191  	cfg := getSimpleTestConfig(c, nil)
   192  
   193  	env, err := maas.NewEnviron(cfg)
   194  
   195  	c.Check(err, jc.ErrorIsNil)
   196  	c.Check(env.Config().Name(), gc.Equals, "testenv")
   197  }
   198  
   199  var expectedCloudinitConfig = []string{
   200  	"set -xe",
   201  	"mkdir -p '/var/lib/juju'\ncat > '/var/lib/juju/MAASmachine.txt' << 'EOF'\n'hostname: testing.invalid\n'\nEOF\nchmod 0755 '/var/lib/juju/MAASmachine.txt'",
   202  }
   203  
   204  var expectedCloudinitConfigWithBridge = []string{
   205  	"set -xe",
   206  	"mkdir -p '/var/lib/juju'\ncat > '/var/lib/juju/MAASmachine.txt' << 'EOF'\n'hostname: testing.invalid\n'\nEOF\nchmod 0755 '/var/lib/juju/MAASmachine.txt'",
   207  	"\n# In case we already created the bridge, don't do it again.\ngrep -q \"iface juju-br0 inet dhcp\" && exit 0\n\n# Discover primary interface at run-time using the default route (if set)\nPRIMARY_IFACE=$(ip route list exact 0/0 | egrep -o 'dev [^ ]+' | cut -b5-)\n\n# If $PRIMARY_IFACE is empty, there's nothing to do.\n[ -z \"$PRIMARY_IFACE\" ] && exit 0\n\n# Change the config to make $PRIMARY_IFACE manual instead of DHCP,\n# then create the bridge and enslave $PRIMARY_IFACE into it.\ngrep -q \"iface ${PRIMARY_IFACE} inet dhcp\" /etc/network/interfaces && \\\nsed -i \"s/iface ${PRIMARY_IFACE} inet dhcp//\" /etc/network/interfaces && \\\ncat >> /etc/network/interfaces << EOF\n\n# Primary interface (defining the default route)\niface ${PRIMARY_IFACE} inet manual\n\n# Bridge to use for LXC/KVM containers\nauto juju-br0\niface juju-br0 inet dhcp\n    bridge_ports ${PRIMARY_IFACE}\nEOF\n\n# Make the primary interface not auto-starting.\ngrep -q \"auto ${PRIMARY_IFACE}\" /etc/network/interfaces && \\\nsed -i \"s/auto ${PRIMARY_IFACE}//\" /etc/network/interfaces\n\n# Stop $PRIMARY_IFACE and start the bridge instead.\nifdown -v ${PRIMARY_IFACE} ; ifup -v juju-br0\n\n# Finally, remove the route using $PRIMARY_IFACE (if any) so it won't\n# clash with the same automatically added route for juju-br0 (except\n# for the device name).\nip route flush dev $PRIMARY_IFACE scope link proto kernel || true\n",
   208  }
   209  
   210  func (*environSuite) TestNewCloudinitConfigWithFeatureFlag(c *gc.C) {
   211  	cfg := getSimpleTestConfig(c, nil)
   212  	env, err := maas.NewEnviron(cfg)
   213  	c.Assert(err, jc.ErrorIsNil)
   214  	cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
   215  	c.Assert(err, jc.ErrorIsNil)
   216  	c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
   217  	c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig)
   218  }
   219  
   220  func (s *environSuite) TestNewCloudinitConfigNoFeatureFlag(c *gc.C) {
   221  	cfg := getSimpleTestConfig(c, nil)
   222  	env, err := maas.NewEnviron(cfg)
   223  	c.Assert(err, jc.ErrorIsNil)
   224  	testCase := func(expectedConfig []string) {
   225  		cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
   226  		c.Assert(err, jc.ErrorIsNil)
   227  		c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
   228  		c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedConfig)
   229  	}
   230  	// First test the default case (address allocation feature flag on).
   231  	testCase(expectedCloudinitConfig)
   232  
   233  	// Now test with the flag off.
   234  	s.SetFeatureFlags() // clear the flags.
   235  	testCase(expectedCloudinitConfigWithBridge)
   236  }
   237  
   238  func (*environSuite) TestNewCloudinitConfigWithDisabledNetworkManagement(c *gc.C) {
   239  	attrs := coretesting.Attrs{
   240  		"disable-network-management": true,
   241  	}
   242  	cfg := getSimpleTestConfig(c, attrs)
   243  	env, err := maas.NewEnviron(cfg)
   244  	c.Assert(err, jc.ErrorIsNil)
   245  	cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
   246  	c.Assert(err, jc.ErrorIsNil)
   247  	c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
   248  	c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig)
   249  }