github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/environs/cloudinit_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package environs_test 5 6 import ( 7 "time" 8 9 gc "launchpad.net/gocheck" 10 "launchpad.net/goyaml" 11 12 "launchpad.net/juju-core/agent" 13 "launchpad.net/juju-core/cert" 14 "launchpad.net/juju-core/constraints" 15 "launchpad.net/juju-core/environs" 16 "launchpad.net/juju-core/environs/cloudinit" 17 "launchpad.net/juju-core/environs/config" 18 "launchpad.net/juju-core/juju/osenv" 19 "launchpad.net/juju-core/provider/dummy" 20 "launchpad.net/juju-core/state" 21 "launchpad.net/juju-core/state/api" 22 "launchpad.net/juju-core/state/api/params" 23 "launchpad.net/juju-core/testing" 24 jc "launchpad.net/juju-core/testing/checkers" 25 "launchpad.net/juju-core/testing/testbase" 26 "launchpad.net/juju-core/tools" 27 "launchpad.net/juju-core/utils" 28 "launchpad.net/juju-core/version" 29 ) 30 31 // dummySampleConfig returns the dummy sample config without 32 // the state server configured. 33 // will not run a state server. 34 func dummySampleConfig() testing.Attrs { 35 return dummy.SampleConfig().Merge(testing.Attrs{ 36 "state-server": false, 37 }) 38 } 39 40 type CloudInitSuite struct { 41 testbase.LoggingSuite 42 } 43 44 var _ = gc.Suite(&CloudInitSuite{}) 45 46 func (s *CloudInitSuite) TestFinishInstanceConfig(c *gc.C) { 47 attrs := dummySampleConfig().Merge(testing.Attrs{ 48 "authorized-keys": "we-are-the-keys", 49 }) 50 cfg, err := config.New(config.NoDefaults, attrs) 51 c.Assert(err, gc.IsNil) 52 mcfg := &cloudinit.MachineConfig{ 53 StateInfo: &state.Info{Tag: "not touched"}, 54 APIInfo: &api.Info{Tag: "not touched"}, 55 } 56 err = environs.FinishMachineConfig(mcfg, cfg, constraints.Value{}) 57 c.Assert(err, gc.IsNil) 58 c.Assert(mcfg, gc.DeepEquals, &cloudinit.MachineConfig{ 59 AuthorizedKeys: "we-are-the-keys", 60 AgentEnvironment: map[string]string{ 61 agent.ProviderType: "dummy", 62 agent.ContainerType: "", 63 }, 64 StateInfo: &state.Info{Tag: "not touched"}, 65 APIInfo: &api.Info{Tag: "not touched"}, 66 DisableSSLHostnameVerification: false, 67 }) 68 } 69 70 func (s *CloudInitSuite) TestFinishMachineConfigNonDefault(c *gc.C) { 71 attrs := dummySampleConfig().Merge(testing.Attrs{ 72 "authorized-keys": "we-are-the-keys", 73 "ssl-hostname-verification": false, 74 }) 75 cfg, err := config.New(config.NoDefaults, attrs) 76 c.Assert(err, gc.IsNil) 77 mcfg := &cloudinit.MachineConfig{ 78 StateInfo: &state.Info{Tag: "not touched"}, 79 APIInfo: &api.Info{Tag: "not touched"}, 80 } 81 err = environs.FinishMachineConfig(mcfg, cfg, constraints.Value{}) 82 c.Assert(err, gc.IsNil) 83 c.Assert(mcfg, gc.DeepEquals, &cloudinit.MachineConfig{ 84 AuthorizedKeys: "we-are-the-keys", 85 AgentEnvironment: map[string]string{ 86 agent.ProviderType: "dummy", 87 agent.ContainerType: "", 88 }, 89 StateInfo: &state.Info{Tag: "not touched"}, 90 APIInfo: &api.Info{Tag: "not touched"}, 91 DisableSSLHostnameVerification: true, 92 }) 93 } 94 95 func (s *CloudInitSuite) TestFinishBootstrapConfig(c *gc.C) { 96 attrs := dummySampleConfig().Merge(testing.Attrs{ 97 "authorized-keys": "we-are-the-keys", 98 "admin-secret": "lisboan-pork", 99 "agent-version": "1.2.3", 100 "state-server": false, 101 }) 102 cfg, err := config.New(config.NoDefaults, attrs) 103 c.Assert(err, gc.IsNil) 104 oldAttrs := cfg.AllAttrs() 105 mcfg := &cloudinit.MachineConfig{ 106 StateServer: true, 107 } 108 cons := constraints.MustParse("mem=1T cpu-power=999999999") 109 err = environs.FinishMachineConfig(mcfg, cfg, cons) 110 c.Assert(err, gc.IsNil) 111 c.Check(mcfg.AuthorizedKeys, gc.Equals, "we-are-the-keys") 112 c.Check(mcfg.DisableSSLHostnameVerification, jc.IsFalse) 113 password := utils.UserPasswordHash("lisboan-pork", utils.CompatSalt) 114 c.Check(mcfg.APIInfo, gc.DeepEquals, &api.Info{ 115 Password: password, CACert: []byte(testing.CACert), 116 }) 117 c.Check(mcfg.StateInfo, gc.DeepEquals, &state.Info{ 118 Password: password, CACert: []byte(testing.CACert), 119 }) 120 c.Check(mcfg.StatePort, gc.Equals, cfg.StatePort()) 121 c.Check(mcfg.APIPort, gc.Equals, cfg.APIPort()) 122 c.Check(mcfg.Constraints, gc.DeepEquals, cons) 123 124 oldAttrs["ca-private-key"] = "" 125 oldAttrs["admin-secret"] = "" 126 c.Check(mcfg.Config.AllAttrs(), gc.DeepEquals, oldAttrs) 127 srvCertPEM := mcfg.StateServerCert 128 srvKeyPEM := mcfg.StateServerKey 129 _, _, err = cert.ParseCertAndKey(srvCertPEM, srvKeyPEM) 130 c.Check(err, gc.IsNil) 131 132 err = cert.Verify(srvCertPEM, []byte(testing.CACert), time.Now()) 133 c.Assert(err, gc.IsNil) 134 err = cert.Verify(srvCertPEM, []byte(testing.CACert), time.Now().AddDate(9, 0, 0)) 135 c.Assert(err, gc.IsNil) 136 err = cert.Verify(srvCertPEM, []byte(testing.CACert), time.Now().AddDate(10, 0, 1)) 137 c.Assert(err, gc.NotNil) 138 } 139 140 func (s *CloudInitSuite) TestUserData(c *gc.C) { 141 s.testUserData(c, false) 142 } 143 144 func (s *CloudInitSuite) TestStateServerUserData(c *gc.C) { 145 s.testUserData(c, true) 146 } 147 148 func (*CloudInitSuite) testUserData(c *gc.C, stateServer bool) { 149 testJujuHome := c.MkDir() 150 defer osenv.SetJujuHome(osenv.SetJujuHome(testJujuHome)) 151 tools := &tools.Tools{ 152 URL: "http://foo.com/tools/releases/juju1.2.3-linux-amd64.tgz", 153 Version: version.MustParseBinary("1.2.3-linux-amd64"), 154 } 155 envConfig, err := config.New(config.NoDefaults, dummySampleConfig()) 156 c.Assert(err, gc.IsNil) 157 158 allJobs := []params.MachineJob{ 159 params.JobManageEnviron, 160 params.JobHostUnits, 161 } 162 cfg := &cloudinit.MachineConfig{ 163 MachineId: "10", 164 MachineNonce: "5432", 165 Tools: tools, 166 StateServerCert: []byte(testing.ServerCert), 167 StateServerKey: []byte(testing.ServerKey), 168 StateInfo: &state.Info{ 169 Addrs: []string{"127.0.0.1:1234"}, 170 Password: "pw1", 171 CACert: []byte("CA CERT\n" + testing.CACert), 172 Tag: "machine-10", 173 }, 174 APIInfo: &api.Info{ 175 Addrs: []string{"127.0.0.1:1234"}, 176 Password: "pw2", 177 CACert: []byte("CA CERT\n" + testing.CACert), 178 Tag: "machine-10", 179 }, 180 DataDir: environs.DataDir, 181 LogDir: agent.DefaultLogDir, 182 Jobs: allJobs, 183 CloudInitOutputLog: environs.CloudInitOutputLog, 184 Config: envConfig, 185 StatePort: envConfig.StatePort(), 186 APIPort: envConfig.APIPort(), 187 StateServer: stateServer, 188 AgentEnvironment: map[string]string{agent.ProviderType: "dummy"}, 189 AuthorizedKeys: "wheredidileavemykeys", 190 MachineAgentServiceName: "jujud-machine-10", 191 } 192 script1 := "script1" 193 script2 := "script2" 194 scripts := []string{script1, script2} 195 result, err := environs.ComposeUserData(cfg, scripts...) 196 c.Assert(err, gc.IsNil) 197 198 unzipped, err := utils.Gunzip(result) 199 c.Assert(err, gc.IsNil) 200 201 config := make(map[interface{}]interface{}) 202 err = goyaml.Unmarshal(unzipped, &config) 203 c.Assert(err, gc.IsNil) 204 205 // The scripts given to userData where added as the first 206 // commands to be run. 207 runCmd := config["runcmd"].([]interface{}) 208 c.Check(runCmd[0], gc.Equals, script1) 209 c.Check(runCmd[1], gc.Equals, script2) 210 211 if stateServer { 212 // The cloudinit config should have nothing but the basics: 213 // SSH authorized keys, the additional runcmds, and log output. 214 // 215 // Note: the additional runcmds *do* belong here, at least 216 // for MAAS. MAAS needs to configure and then bounce the 217 // network interfaces, which would sever the SSH connection 218 // in the synchronous bootstrap phase. 219 c.Check(config, gc.DeepEquals, map[interface{}]interface{}{ 220 "output": map[interface{}]interface{}{ 221 "all": "| tee -a /var/log/cloud-init-output.log", 222 }, 223 "runcmd": []interface{}{ 224 "script1", "script2", 225 "set -xe", 226 "install -D -m 644 /dev/null '/var/lib/juju/nonce.txt'", 227 "printf '%s\\n' '5432' > '/var/lib/juju/nonce.txt'", 228 }, 229 "ssh_authorized_keys": []interface{}{"wheredidileavemykeys"}, 230 }) 231 } else { 232 // Just check that the cloudinit config looks good, 233 // and that there are more runcmds than the additional 234 // ones we passed into ComposeUserData. 235 c.Check(config["apt_upgrade"], gc.Equals, true) 236 c.Check(len(runCmd) > 2, jc.IsTrue) 237 } 238 }