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