github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/maas/environprovider_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package maas 5 6 import ( 7 "errors" 8 "io/ioutil" 9 "net/http" 10 "net/http/httptest" 11 "net/http/httputil" 12 "net/url" 13 "strings" 14 15 "github.com/juju/collections/set" 16 "github.com/juju/gomaasapi" 17 jc "github.com/juju/testing/checkers" 18 "github.com/juju/utils" 19 gc "gopkg.in/check.v1" 20 "gopkg.in/yaml.v2" 21 22 "github.com/juju/juju/cloud" 23 "github.com/juju/juju/environs" 24 "github.com/juju/juju/environs/config" 25 "github.com/juju/juju/environs/context" 26 "github.com/juju/juju/testing" 27 ) 28 29 type EnvironProviderSuite struct { 30 providerSuite 31 } 32 33 var _ = gc.Suite(&EnvironProviderSuite{}) 34 35 func (s *EnvironProviderSuite) cloudSpec() environs.CloudSpec { 36 credential := oauthCredential("aa:bb:cc") 37 return environs.CloudSpec{ 38 Type: "maas", 39 Name: "maas", 40 Endpoint: "http://maas.testing.invalid/maas/", 41 Credential: &credential, 42 } 43 } 44 45 func oauthCredential(token string) cloud.Credential { 46 return cloud.NewCredential( 47 cloud.OAuth1AuthType, 48 map[string]string{ 49 "maas-oauth": token, 50 }, 51 ) 52 } 53 54 func (suite *EnvironProviderSuite) TestPrepareConfig(c *gc.C) { 55 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 56 config, err := config.New(config.NoDefaults, attrs) 57 c.Assert(err, jc.ErrorIsNil) 58 _, err = providerInstance.PrepareConfig(environs.PrepareConfigParams{ 59 Config: config, 60 Cloud: suite.cloudSpec(), 61 }) 62 c.Assert(err, jc.ErrorIsNil) 63 } 64 65 func (suite *EnvironProviderSuite) TestPrepareConfigInvalidOAuth(c *gc.C) { 66 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 67 config, err := config.New(config.NoDefaults, attrs) 68 c.Assert(err, jc.ErrorIsNil) 69 spec := suite.cloudSpec() 70 cred := oauthCredential("wrongly-formatted-oauth-string") 71 spec.Credential = &cred 72 _, err = providerInstance.PrepareConfig(environs.PrepareConfigParams{ 73 Config: config, 74 Cloud: spec, 75 }) 76 c.Assert(err, gc.ErrorMatches, ".*malformed maas-oauth.*") 77 } 78 79 func (suite *EnvironProviderSuite) TestPrepareConfigInvalidEndpoint(c *gc.C) { 80 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 81 config, err := config.New(config.NoDefaults, attrs) 82 c.Assert(err, jc.ErrorIsNil) 83 spec := suite.cloudSpec() 84 spec.Endpoint = "This should have been a URL or host." 85 _, err = providerInstance.PrepareConfig(environs.PrepareConfigParams{ 86 Config: config, 87 Cloud: spec, 88 }) 89 c.Assert(err, gc.ErrorMatches, 90 `validating cloud spec: validating endpoint: endpoint "This should have been a URL or host." not valid`, 91 ) 92 } 93 94 func (suite *EnvironProviderSuite) TestPrepareConfigSetsDefaults(c *gc.C) { 95 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 96 config, err := config.New(config.NoDefaults, attrs) 97 c.Assert(err, jc.ErrorIsNil) 98 cfg, err := providerInstance.PrepareConfig(environs.PrepareConfigParams{ 99 Config: config, 100 Cloud: suite.cloudSpec(), 101 }) 102 c.Assert(err, jc.ErrorIsNil) 103 src, _ := cfg.StorageDefaultBlockSource() 104 c.Assert(src, gc.Equals, "maas") 105 } 106 107 func (suite *EnvironProviderSuite) TestMAASServerFromEndpointURL(c *gc.C) { 108 suite.testMAASServerFromEndpoint(c, suite.testMAASObject.TestServer.URL) 109 } 110 111 func (suite *EnvironProviderSuite) TestMAASServerFromEndpointHost(c *gc.C) { 112 targetURL, err := url.Parse(suite.testMAASObject.TestServer.URL) 113 c.Assert(err, jc.ErrorIsNil) 114 115 rp := httputil.NewSingleHostReverseProxy(targetURL) 116 rp.Director = func(req *http.Request) { 117 req.URL.Path = strings.TrimPrefix(req.URL.Path, "/MAAS") 118 req.URL.Scheme = targetURL.Scheme 119 req.URL.Host = targetURL.Host 120 } 121 proxy := httptest.NewServer(rp) 122 defer proxy.Close() 123 124 // The proxy's host:port will be formatted into a URL, with a 125 // fixed root path of "/MAAS". 126 proxyURL, err := url.Parse(proxy.URL) 127 c.Assert(err, jc.ErrorIsNil) 128 suite.testMAASServerFromEndpoint(c, proxyURL.Host) 129 } 130 131 func (suite *EnvironProviderSuite) testMAASServerFromEndpoint(c *gc.C, endpoint string) { 132 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 133 config, err := config.New(config.NoDefaults, attrs) 134 c.Assert(err, jc.ErrorIsNil) 135 136 cloudSpec := suite.cloudSpec() 137 cloudSpec.Endpoint = endpoint 138 env, err := providerInstance.Open(environs.OpenParams{ 139 Config: config, 140 Cloud: cloudSpec, 141 }) 142 c.Assert(err, jc.ErrorIsNil) 143 144 suite.addNode(`{"system_id":"test-allocated"}`) 145 _, err = env.AllInstances(suite.callCtx) 146 c.Assert(err, jc.ErrorIsNil) 147 } 148 149 // create a temporary file with the given content. The file will be cleaned 150 // up at the end of the test calling this method. 151 func createTempFile(c *gc.C, content []byte) string { 152 file, err := ioutil.TempFile(c.MkDir(), "") 153 defer file.Close() 154 c.Assert(err, jc.ErrorIsNil) 155 filename := file.Name() 156 err = ioutil.WriteFile(filename, content, 0644) 157 c.Assert(err, jc.ErrorIsNil) 158 return filename 159 } 160 161 func (suite *EnvironProviderSuite) TestOpenReturnsNilInterfaceUponFailure(c *gc.C) { 162 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 163 config, err := config.New(config.NoDefaults, attrs) 164 c.Assert(err, jc.ErrorIsNil) 165 spec := suite.cloudSpec() 166 cred := oauthCredential("wrongly-formatted-oauth-string") 167 spec.Credential = &cred 168 env, err := providerInstance.Open(environs.OpenParams{ 169 Cloud: spec, 170 Config: config, 171 }) 172 // When Open() fails (i.e. returns a non-nil error), it returns an 173 // environs.Environ interface object with a nil value and a nil 174 // type. 175 c.Check(env, gc.Equals, nil) 176 c.Check(err, gc.ErrorMatches, ".*malformed maas-oauth.*") 177 } 178 179 func (suite *EnvironProviderSuite) TestSchema(c *gc.C) { 180 y := []byte(` 181 auth-types: [oauth1] 182 endpoint: http://foo.com/openstack 183 `[1:]) 184 var v interface{} 185 err := yaml.Unmarshal(y, &v) 186 c.Assert(err, jc.ErrorIsNil) 187 v, err = utils.ConformYAML(v) 188 c.Assert(err, jc.ErrorIsNil) 189 190 p, err := environs.Provider("maas") 191 c.Assert(err, jc.ErrorIsNil) 192 err = p.CloudSchema().Validate(v) 193 c.Assert(err, jc.ErrorIsNil) 194 } 195 196 type MaasPingSuite struct { 197 testing.BaseSuite 198 199 callCtx context.ProviderCallContext 200 } 201 202 var _ = gc.Suite(&MaasPingSuite{}) 203 204 func (s *MaasPingSuite) SetUpTest(c *gc.C) { 205 s.BaseSuite.SetUpTest(c) 206 s.callCtx = context.NewCloudCallContext() 207 } 208 209 func (s *MaasPingSuite) TestPingNoEndpoint(c *gc.C) { 210 endpoint := "https://foo.com/MAAS" 211 var serverURLs []string 212 err := ping(c, s.callCtx, endpoint, 213 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 214 serverURLs = append(serverURLs, client.URL().String()) 215 c.Assert(serverURL, gc.Equals, endpoint) 216 return nil, errors.New("nope") 217 }, 218 ) 219 c.Assert(err, gc.ErrorMatches, "No MAAS server running at "+endpoint) 220 c.Assert(serverURLs, gc.DeepEquals, []string{ 221 "https://foo.com/MAAS/api/2.0/", 222 "https://foo.com/MAAS/api/1.0/", 223 }) 224 } 225 226 func (s *MaasPingSuite) TestPingOK(c *gc.C) { 227 endpoint := "https://foo.com/MAAS" 228 var serverURLs []string 229 err := ping(c, s.callCtx, endpoint, 230 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 231 serverURLs = append(serverURLs, client.URL().String()) 232 c.Assert(serverURL, gc.Equals, endpoint) 233 return set.NewStrings("network-deployment-ubuntu"), nil 234 }, 235 ) 236 c.Assert(err, jc.ErrorIsNil) 237 c.Assert(serverURLs, gc.DeepEquals, []string{ 238 "https://foo.com/MAAS/api/2.0/", 239 }) 240 } 241 242 func (s *MaasPingSuite) TestPingVersionURLOK(c *gc.C) { 243 endpoint := "https://foo.com/MAAS/api/10.1/" 244 var serverURLs []string 245 err := ping(c, s.callCtx, endpoint, 246 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 247 serverURLs = append(serverURLs, client.URL().String()) 248 c.Assert(serverURL, gc.Equals, "https://foo.com/MAAS/") 249 return set.NewStrings("network-deployment-ubuntu"), nil 250 }, 251 ) 252 c.Assert(err, jc.ErrorIsNil) 253 c.Assert(serverURLs, gc.DeepEquals, []string{ 254 "https://foo.com/MAAS/api/10.1/", 255 }) 256 } 257 258 func (s *MaasPingSuite) TestPingVersionURLBad(c *gc.C) { 259 endpoint := "https://foo.com/MAAS/api/10.1/" 260 var serverURLs []string 261 err := ping(c, s.callCtx, endpoint, 262 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 263 serverURLs = append(serverURLs, client.URL().String()) 264 c.Assert(serverURL, gc.Equals, "https://foo.com/MAAS/") 265 return nil, errors.New("nope") 266 }, 267 ) 268 c.Assert(err, gc.ErrorMatches, "No MAAS server running at "+endpoint) 269 c.Assert(serverURLs, gc.DeepEquals, []string{ 270 "https://foo.com/MAAS/api/10.1/", 271 }) 272 } 273 274 func ping(c *gc.C, callCtx context.ProviderCallContext, endpoint string, getCapabilities MaasCapabilities) error { 275 p, err := environs.Provider("maas") 276 c.Assert(err, jc.ErrorIsNil) 277 m, ok := p.(MaasEnvironProvider) 278 c.Assert(ok, jc.IsTrue) 279 m.GetCapabilities = getCapabilities 280 return m.Ping(callCtx, endpoint) 281 }