github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/apiserver/common/tools_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common_test
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/names"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/apiserver/params"
    16  	apiservertesting "github.com/juju/juju/apiserver/testing"
    17  	"github.com/juju/juju/environs"
    18  	"github.com/juju/juju/juju/testing"
    19  	"github.com/juju/juju/network"
    20  	"github.com/juju/juju/state"
    21  	"github.com/juju/juju/state/toolstorage"
    22  	coretools "github.com/juju/juju/tools"
    23  	"github.com/juju/juju/version"
    24  )
    25  
    26  type toolsSuite struct {
    27  	testing.JujuConnSuite
    28  	machine0 *state.Machine
    29  }
    30  
    31  var _ = gc.Suite(&toolsSuite{})
    32  
    33  func (s *toolsSuite) SetUpTest(c *gc.C) {
    34  	s.JujuConnSuite.SetUpTest(c)
    35  	var err error
    36  	s.machine0, err = s.State.AddMachine("series", state.JobHostUnits)
    37  	c.Assert(err, jc.ErrorIsNil)
    38  	s.AddDefaultToolsToState(c)
    39  }
    40  
    41  func (s *toolsSuite) TestTools(c *gc.C) {
    42  	getCanRead := func() (common.AuthFunc, error) {
    43  		return func(tag names.Tag) bool {
    44  			return tag == names.NewMachineTag("0") || tag == names.NewMachineTag("42")
    45  		}, nil
    46  	}
    47  	tg := common.NewToolsGetter(s.State, s.State, s.State, sprintfURLGetter("tools:%s"), getCanRead)
    48  	c.Assert(tg, gc.NotNil)
    49  
    50  	err := s.machine0.SetAgentVersion(version.Current)
    51  	c.Assert(err, jc.ErrorIsNil)
    52  
    53  	args := params.Entities{
    54  		Entities: []params.Entity{
    55  			{Tag: "machine-0"},
    56  			{Tag: "machine-1"},
    57  			{Tag: "machine-42"},
    58  		}}
    59  	result, err := tg.Tools(args)
    60  	c.Assert(err, jc.ErrorIsNil)
    61  	c.Assert(result.Results, gc.HasLen, 3)
    62  	c.Assert(result.Results[0].Error, gc.IsNil)
    63  	c.Assert(result.Results[0].Tools, gc.NotNil)
    64  	c.Assert(result.Results[0].Tools.Version, gc.DeepEquals, version.Current)
    65  	c.Assert(result.Results[0].Tools.URL, gc.Equals, "tools:"+version.Current.String())
    66  	c.Assert(result.Results[0].DisableSSLHostnameVerification, jc.IsTrue)
    67  	c.Assert(result.Results[1].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized)
    68  	c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.NotFoundError("machine 42"))
    69  }
    70  
    71  func (s *toolsSuite) TestToolsError(c *gc.C) {
    72  	getCanRead := func() (common.AuthFunc, error) {
    73  		return nil, fmt.Errorf("splat")
    74  	}
    75  	tg := common.NewToolsGetter(s.State, s.State, s.State, sprintfURLGetter("%s"), getCanRead)
    76  	args := params.Entities{
    77  		Entities: []params.Entity{{Tag: "machine-42"}},
    78  	}
    79  	result, err := tg.Tools(args)
    80  	c.Assert(err, gc.ErrorMatches, "splat")
    81  	c.Assert(result.Results, gc.HasLen, 1)
    82  }
    83  
    84  func (s *toolsSuite) TestSetTools(c *gc.C) {
    85  	getCanWrite := func() (common.AuthFunc, error) {
    86  		return func(tag names.Tag) bool {
    87  			return tag == names.NewMachineTag("0") || tag == names.NewMachineTag("42")
    88  		}, nil
    89  	}
    90  	ts := common.NewToolsSetter(s.State, getCanWrite)
    91  	c.Assert(ts, gc.NotNil)
    92  
    93  	err := s.machine0.SetAgentVersion(version.Current)
    94  	c.Assert(err, jc.ErrorIsNil)
    95  
    96  	args := params.EntitiesVersion{
    97  		AgentTools: []params.EntityVersion{{
    98  			Tag: "machine-0",
    99  			Tools: &params.Version{
   100  				Version: version.Current,
   101  			},
   102  		}, {
   103  			Tag: "machine-1",
   104  			Tools: &params.Version{
   105  				Version: version.Current,
   106  			},
   107  		}, {
   108  			Tag: "machine-42",
   109  			Tools: &params.Version{
   110  				Version: version.Current,
   111  			},
   112  		}},
   113  	}
   114  	result, err := ts.SetTools(args)
   115  	c.Assert(err, jc.ErrorIsNil)
   116  	c.Assert(result.Results, gc.HasLen, 3)
   117  	c.Assert(result.Results[0].Error, gc.IsNil)
   118  	agentTools, err := s.machine0.AgentTools()
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	c.Assert(agentTools.Version, gc.DeepEquals, version.Current)
   121  	c.Assert(result.Results[1].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized)
   122  	c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.NotFoundError("machine 42"))
   123  }
   124  
   125  func (s *toolsSuite) TestToolsSetError(c *gc.C) {
   126  	getCanWrite := func() (common.AuthFunc, error) {
   127  		return nil, fmt.Errorf("splat")
   128  	}
   129  	ts := common.NewToolsSetter(s.State, getCanWrite)
   130  	args := params.EntitiesVersion{
   131  		AgentTools: []params.EntityVersion{{
   132  			Tag: "machine-42",
   133  			Tools: &params.Version{
   134  				Version: version.Current,
   135  			},
   136  		}},
   137  	}
   138  	result, err := ts.SetTools(args)
   139  	c.Assert(err, gc.ErrorMatches, "splat")
   140  	c.Assert(result.Results, gc.HasLen, 1)
   141  }
   142  
   143  func (s *toolsSuite) TestFindTools(c *gc.C) {
   144  	envtoolsList := coretools.List{
   145  		&coretools.Tools{
   146  			Version: version.MustParseBinary("123.456.0-win81-alpha"),
   147  			Size:    2048,
   148  			SHA256:  "badf00d",
   149  		},
   150  		&coretools.Tools{
   151  			Version: version.MustParseBinary("123.456.1-win81-alpha"),
   152  		},
   153  	}
   154  	storageMetadata := []toolstorage.Metadata{{
   155  		Version: version.MustParseBinary("123.456.0-win81-alpha"),
   156  		Size:    1024,
   157  		SHA256:  "feedface",
   158  	}}
   159  
   160  	s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, filter coretools.Filter) (coretools.List, error) {
   161  		c.Assert(major, gc.Equals, 123)
   162  		c.Assert(minor, gc.Equals, 456)
   163  		c.Assert(filter.Series, gc.Equals, "win81")
   164  		c.Assert(filter.Arch, gc.Equals, "alpha")
   165  		return envtoolsList, nil
   166  	})
   167  	toolsFinder := common.NewToolsFinder(s.State, &mockToolsStorage{metadata: storageMetadata}, sprintfURLGetter("tools:%s"))
   168  	result, err := toolsFinder.FindTools(params.FindToolsParams{
   169  		MajorVersion: 123,
   170  		MinorVersion: 456,
   171  		Series:       "win81",
   172  		Arch:         "alpha",
   173  	})
   174  	c.Assert(err, jc.ErrorIsNil)
   175  	c.Assert(result.Error, gc.IsNil)
   176  	c.Assert(result.List, gc.DeepEquals, coretools.List{
   177  		&coretools.Tools{
   178  			Version: storageMetadata[0].Version,
   179  			Size:    storageMetadata[0].Size,
   180  			SHA256:  storageMetadata[0].SHA256,
   181  			URL:     "tools:" + storageMetadata[0].Version.String(),
   182  		},
   183  		envtoolsList[1],
   184  	})
   185  }
   186  
   187  func (s *toolsSuite) TestFindToolsNotFound(c *gc.C) {
   188  	s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, filter coretools.Filter) (list coretools.List, err error) {
   189  		return nil, errors.NotFoundf("tools")
   190  	})
   191  	toolsFinder := common.NewToolsFinder(s.State, s.State, sprintfURLGetter("%s"))
   192  	result, err := toolsFinder.FindTools(params.FindToolsParams{})
   193  	c.Assert(err, jc.ErrorIsNil)
   194  	c.Assert(result.Error, jc.Satisfies, params.IsCodeNotFound)
   195  }
   196  
   197  func (s *toolsSuite) TestFindToolsExactInStorage(c *gc.C) {
   198  	mockToolsStorage := &mockToolsStorage{
   199  		metadata: []toolstorage.Metadata{{Version: version.Current}},
   200  	}
   201  	s.testFindToolsExact(c, mockToolsStorage, true)
   202  }
   203  
   204  func (s *toolsSuite) TestFindToolsExactNotInStorage(c *gc.C) {
   205  	mockToolsStorage := &mockToolsStorage{}
   206  	s.testFindToolsExact(c, mockToolsStorage, false)
   207  }
   208  
   209  func (s *toolsSuite) testFindToolsExact(c *gc.C, t common.ToolsStorageGetter, inStorage bool) {
   210  	var called bool
   211  	s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, filter coretools.Filter) (list coretools.List, err error) {
   212  		called = true
   213  		c.Assert(filter.Number, gc.Equals, version.Current.Number)
   214  		c.Assert(filter.Series, gc.Equals, version.Current.Series)
   215  		c.Assert(filter.Arch, gc.Equals, version.Current.Arch)
   216  		return nil, errors.NotFoundf("tools")
   217  	})
   218  	toolsFinder := common.NewToolsFinder(s.State, t, sprintfURLGetter("tools:%s"))
   219  	result, err := toolsFinder.FindTools(params.FindToolsParams{
   220  		Number:       version.Current.Number,
   221  		MajorVersion: -1,
   222  		MinorVersion: -1,
   223  		Series:       version.Current.Series,
   224  		Arch:         version.Current.Arch,
   225  	})
   226  	c.Assert(err, jc.ErrorIsNil)
   227  	if inStorage {
   228  		c.Assert(result.Error, gc.IsNil)
   229  		c.Assert(called, jc.IsFalse)
   230  	} else {
   231  		c.Assert(result.Error, gc.ErrorMatches, "tools not found")
   232  		c.Assert(called, jc.IsTrue)
   233  	}
   234  }
   235  
   236  func (s *toolsSuite) TestFindToolsToolsStorageError(c *gc.C) {
   237  	var called bool
   238  	s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, filter coretools.Filter) (list coretools.List, err error) {
   239  		called = true
   240  		return nil, errors.NotFoundf("tools")
   241  	})
   242  	toolsFinder := common.NewToolsFinder(s.State, &mockToolsStorage{
   243  		err: errors.New("AllMetadata failed"),
   244  	}, sprintfURLGetter("tools:%s"))
   245  	result, err := toolsFinder.FindTools(params.FindToolsParams{
   246  		MajorVersion: 1,
   247  		MinorVersion: -1,
   248  	})
   249  	c.Assert(err, jc.ErrorIsNil)
   250  	// ToolsStorage errors always cause FindTools to bail. Only
   251  	// if AllMetadata succeeds but returns nothing that matches
   252  	// do we continue on to searching simplestreams.
   253  	c.Assert(result.Error, gc.ErrorMatches, "AllMetadata failed")
   254  	c.Assert(called, jc.IsFalse)
   255  }
   256  
   257  func (s *toolsSuite) TestToolsURLGetterNoAPIHostPorts(c *gc.C) {
   258  	g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{})
   259  	_, err := g.ToolsURL(version.Current)
   260  	c.Assert(err, gc.ErrorMatches, "no API host ports")
   261  }
   262  
   263  func (s *toolsSuite) TestToolsURLGetterAPIHostPortsError(c *gc.C) {
   264  	g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{err: errors.New("oh noes")})
   265  	_, err := g.ToolsURL(version.Current)
   266  	c.Assert(err, gc.ErrorMatches, "oh noes")
   267  }
   268  
   269  func (s *toolsSuite) TestToolsURLGetter(c *gc.C) {
   270  	g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{
   271  		hostPorts: [][]network.HostPort{
   272  			network.NewHostPorts(1234, "0.1.2.3"),
   273  		},
   274  	})
   275  	url, err := g.ToolsURL(version.Current)
   276  	c.Assert(err, jc.ErrorIsNil)
   277  	c.Assert(url, gc.Equals, "https://0.1.2.3:1234/environment/my-uuid/tools/"+version.Current.String())
   278  }
   279  
   280  type sprintfURLGetter string
   281  
   282  func (s sprintfURLGetter) ToolsURL(v version.Binary) (string, error) {
   283  	return fmt.Sprintf(string(s), v), nil
   284  }
   285  
   286  type mockAPIHostPortsGetter struct {
   287  	hostPorts [][]network.HostPort
   288  	err       error
   289  }
   290  
   291  func (g mockAPIHostPortsGetter) APIHostPorts() ([][]network.HostPort, error) {
   292  	return g.hostPorts, g.err
   293  }
   294  
   295  type mockToolsStorage struct {
   296  	toolstorage.Storage
   297  	metadata []toolstorage.Metadata
   298  	err      error
   299  }
   300  
   301  func (s *mockToolsStorage) ToolsStorage() (toolstorage.StorageCloser, error) {
   302  	return s, nil
   303  }
   304  
   305  func (s *mockToolsStorage) Close() error {
   306  	return nil
   307  }
   308  
   309  func (s *mockToolsStorage) AllMetadata() ([]toolstorage.Metadata, error) {
   310  	return s.metadata, s.err
   311  }