github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/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 stdcontext "context" 8 "errors" 9 "os" 10 11 "github.com/juju/collections/set" 12 "github.com/juju/gomaasapi/v2" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils/v3" 15 gc "gopkg.in/check.v1" 16 "gopkg.in/yaml.v2" 17 18 "github.com/juju/juju/cloud" 19 "github.com/juju/juju/environs" 20 environscloudspec "github.com/juju/juju/environs/cloudspec" 21 "github.com/juju/juju/environs/config" 22 "github.com/juju/juju/environs/context" 23 "github.com/juju/juju/testing" 24 ) 25 26 type EnvironProviderSuite struct { 27 maasSuite 28 } 29 30 var _ = gc.Suite(&EnvironProviderSuite{}) 31 32 func (s *EnvironProviderSuite) cloudSpec() environscloudspec.CloudSpec { 33 credential := oauthCredential("aa:bb:cc") 34 return environscloudspec.CloudSpec{ 35 Type: "maas", 36 Name: "maas", 37 Endpoint: "http://maas.testing.invalid/maas/", 38 Credential: &credential, 39 } 40 } 41 42 func oauthCredential(token string) cloud.Credential { 43 return cloud.NewCredential( 44 cloud.OAuth1AuthType, 45 map[string]string{ 46 "maas-oauth": token, 47 }, 48 ) 49 } 50 51 func (s *EnvironProviderSuite) TestPrepareConfig(c *gc.C) { 52 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 53 config, err := config.New(config.NoDefaults, attrs) 54 c.Assert(err, jc.ErrorIsNil) 55 _, err = providerInstance.PrepareConfig(environs.PrepareConfigParams{ 56 Config: config, 57 Cloud: s.cloudSpec(), 58 }) 59 c.Assert(err, jc.ErrorIsNil) 60 } 61 62 func (s *EnvironProviderSuite) TestPrepareConfigInvalidOAuth(c *gc.C) { 63 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 64 config, err := config.New(config.NoDefaults, attrs) 65 c.Assert(err, jc.ErrorIsNil) 66 spec := s.cloudSpec() 67 cred := oauthCredential("wrongly-formatted-oauth-string") 68 spec.Credential = &cred 69 _, err = providerInstance.PrepareConfig(environs.PrepareConfigParams{ 70 Config: config, 71 Cloud: spec, 72 }) 73 c.Assert(err, gc.ErrorMatches, ".*malformed maas-oauth.*") 74 } 75 76 func (s *EnvironProviderSuite) TestPrepareConfigInvalidEndpoint(c *gc.C) { 77 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 78 config, err := config.New(config.NoDefaults, attrs) 79 c.Assert(err, jc.ErrorIsNil) 80 spec := s.cloudSpec() 81 spec.Endpoint = "This should have been a URL or host." 82 _, err = providerInstance.PrepareConfig(environs.PrepareConfigParams{ 83 Config: config, 84 Cloud: spec, 85 }) 86 c.Assert(err, gc.ErrorMatches, 87 `validating cloud spec: validating endpoint: endpoint "This should have been a URL or host." not valid`, 88 ) 89 } 90 91 func (s *EnvironProviderSuite) TestPrepareConfigSetsDefaults(c *gc.C) { 92 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 93 config, err := config.New(config.NoDefaults, attrs) 94 c.Assert(err, jc.ErrorIsNil) 95 cfg, err := providerInstance.PrepareConfig(environs.PrepareConfigParams{ 96 Config: config, 97 Cloud: s.cloudSpec(), 98 }) 99 c.Assert(err, jc.ErrorIsNil) 100 src, _ := cfg.StorageDefaultBlockSource() 101 c.Assert(src, gc.Equals, "maas") 102 } 103 104 // create a temporary file with the given content. The file will be cleaned 105 // up at the end of the test calling this method. 106 func createTempFile(c *gc.C, content []byte) string { 107 file, err := os.CreateTemp(c.MkDir(), "") 108 defer file.Close() 109 c.Assert(err, jc.ErrorIsNil) 110 filename := file.Name() 111 err = os.WriteFile(filename, content, 0644) 112 c.Assert(err, jc.ErrorIsNil) 113 return filename 114 } 115 116 func (s *EnvironProviderSuite) TestOpenReturnsNilInterfaceUponFailure(c *gc.C) { 117 attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) 118 config, err := config.New(config.NoDefaults, attrs) 119 c.Assert(err, jc.ErrorIsNil) 120 spec := s.cloudSpec() 121 cred := oauthCredential("wrongly-formatted-oauth-string") 122 spec.Credential = &cred 123 env, err := providerInstance.Open(stdcontext.TODO(), environs.OpenParams{ 124 Cloud: spec, 125 Config: config, 126 }) 127 // When Open() fails (i.e. returns a non-nil error), it returns an 128 // environs.Environ interface object with a nil value and a nil 129 // type. 130 c.Check(env, gc.Equals, nil) 131 c.Check(err, gc.ErrorMatches, ".*malformed maas-oauth.*") 132 } 133 134 func (s *EnvironProviderSuite) TestSchema(c *gc.C) { 135 y := []byte(` 136 auth-types: [oauth1] 137 endpoint: http://foo.com/openstack 138 `[1:]) 139 var v interface{} 140 err := yaml.Unmarshal(y, &v) 141 c.Assert(err, jc.ErrorIsNil) 142 v, err = utils.ConformYAML(v) 143 c.Assert(err, jc.ErrorIsNil) 144 145 p, err := environs.Provider("maas") 146 c.Assert(err, jc.ErrorIsNil) 147 err = p.CloudSchema().Validate(v) 148 c.Assert(err, jc.ErrorIsNil) 149 } 150 151 type MaasPingSuite struct { 152 testing.BaseSuite 153 154 callCtx context.ProviderCallContext 155 } 156 157 var _ = gc.Suite(&MaasPingSuite{}) 158 159 func (s *MaasPingSuite) SetUpTest(c *gc.C) { 160 s.BaseSuite.SetUpTest(c) 161 s.callCtx = context.NewEmptyCloudCallContext() 162 } 163 164 func (s *MaasPingSuite) TestPingNoEndpoint(c *gc.C) { 165 endpoint := "https://foo.com/MAAS" 166 var serverURLs []string 167 err := ping(c, s.callCtx, endpoint, 168 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 169 serverURLs = append(serverURLs, client.URL().String()) 170 c.Assert(serverURL, gc.Equals, endpoint) 171 return nil, errors.New("nope") 172 }, 173 ) 174 c.Assert(err, gc.ErrorMatches, "No MAAS server running at "+endpoint+": nope") 175 c.Assert(serverURLs, gc.DeepEquals, []string{ 176 "https://foo.com/MAAS/api/2.0/", 177 }) 178 } 179 180 func (s *MaasPingSuite) TestPingOK(c *gc.C) { 181 endpoint := "https://foo.com/MAAS" 182 var serverURLs []string 183 err := ping(c, s.callCtx, endpoint, 184 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 185 serverURLs = append(serverURLs, client.URL().String()) 186 c.Assert(serverURL, gc.Equals, endpoint) 187 return set.NewStrings("network-deployment-ubuntu"), nil 188 }, 189 ) 190 c.Assert(err, jc.ErrorIsNil) 191 c.Assert(serverURLs, gc.DeepEquals, []string{ 192 "https://foo.com/MAAS/api/2.0/", 193 }) 194 } 195 196 func (s *MaasPingSuite) TestPingVersionURLOK(c *gc.C) { 197 endpoint := "https://foo.com/MAAS/api/10.1/" 198 var serverURLs []string 199 err := ping(c, s.callCtx, endpoint, 200 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 201 serverURLs = append(serverURLs, client.URL().String()) 202 c.Assert(serverURL, gc.Equals, "https://foo.com/MAAS/") 203 return set.NewStrings("network-deployment-ubuntu"), nil 204 }, 205 ) 206 c.Assert(err, jc.ErrorIsNil) 207 c.Assert(serverURLs, gc.DeepEquals, []string{ 208 "https://foo.com/MAAS/api/10.1/", 209 }) 210 } 211 212 func (s *MaasPingSuite) TestPingVersionURLBad(c *gc.C) { 213 endpoint := "https://foo.com/MAAS/api/10.1/" 214 var serverURLs []string 215 err := ping(c, s.callCtx, endpoint, 216 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 217 serverURLs = append(serverURLs, client.URL().String()) 218 c.Assert(serverURL, gc.Equals, "https://foo.com/MAAS/") 219 return nil, errors.New("nope") 220 }, 221 ) 222 c.Assert(err, gc.ErrorMatches, "No MAAS server running at "+endpoint+": nope") 223 c.Assert(serverURLs, gc.DeepEquals, []string{ 224 "https://foo.com/MAAS/api/10.1/", 225 }) 226 } 227 228 func ping(c *gc.C, callCtx context.ProviderCallContext, endpoint string, getCapabilities Capabilities) error { 229 p, err := environs.Provider("maas") 230 c.Assert(err, jc.ErrorIsNil) 231 m, ok := p.(EnvironProvider) 232 c.Assert(ok, jc.IsTrue) 233 m.GetCapabilities = getCapabilities 234 return m.Ping(callCtx, endpoint) 235 }