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  }