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  }