github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/environs/bootstrap/tools_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package bootstrap_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	jc "github.com/juju/testing/checkers"
     9  	"github.com/juju/utils/arch"
    10  	"github.com/juju/utils/os"
    11  	"github.com/juju/utils/series"
    12  	"github.com/juju/version"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/environs"
    16  	"github.com/juju/juju/environs/bootstrap"
    17  	coretesting "github.com/juju/juju/testing"
    18  	"github.com/juju/juju/tools"
    19  	jujuversion "github.com/juju/juju/version"
    20  )
    21  
    22  type toolsSuite struct {
    23  	coretesting.BaseSuite
    24  }
    25  
    26  var _ = gc.Suite(&toolsSuite{})
    27  
    28  func (s *toolsSuite) TestValidateUploadAllowedIncompatibleHostArch(c *gc.C) {
    29  	// Host runs amd64, want ppc64 tools.
    30  	s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 })
    31  	// Force a dev version by having a non zero build number.
    32  	// This is because we have not uploaded any tools and auto
    33  	// upload is only enabled for dev versions.
    34  	devVersion := jujuversion.Current
    35  	devVersion.Build = 1234
    36  	s.PatchValue(&jujuversion.Current, devVersion)
    37  	env := newEnviron("foo", useDefaultKeys, nil)
    38  	arch := arch.PPC64EL
    39  	err := bootstrap.ValidateUploadAllowed(env, &arch, nil)
    40  	c.Assert(err, gc.ErrorMatches, `cannot build tools for "ppc64el" using a machine running on "amd64"`)
    41  }
    42  
    43  func (s *toolsSuite) TestValidateUploadAllowedIncompatibleHostOS(c *gc.C) {
    44  	// Host runs Ubuntu, want win2012 tools.
    45  	s.PatchValue(&os.HostOS, func() os.OSType { return os.Ubuntu })
    46  	env := newEnviron("foo", useDefaultKeys, nil)
    47  	series := "win2012"
    48  	err := bootstrap.ValidateUploadAllowed(env, nil, &series)
    49  	c.Assert(err, gc.ErrorMatches, `cannot build tools for "win2012" using a machine running "Ubuntu"`)
    50  }
    51  
    52  func (s *toolsSuite) TestValidateUploadAllowedIncompatibleTargetArch(c *gc.C) {
    53  	// Host runs ppc64el, environment only supports amd64, arm64.
    54  	s.PatchValue(&arch.HostArch, func() string { return arch.PPC64EL })
    55  	// Force a dev version by having a non zero build number.
    56  	// This is because we have not uploaded any tools and auto
    57  	// upload is only enabled for dev versions.
    58  	devVersion := jujuversion.Current
    59  	devVersion.Build = 1234
    60  	s.PatchValue(&jujuversion.Current, devVersion)
    61  	env := newEnviron("foo", useDefaultKeys, nil)
    62  	err := bootstrap.ValidateUploadAllowed(env, nil, nil)
    63  	c.Assert(err, gc.ErrorMatches, `model "foo" of type dummy does not support instances running on "ppc64el"`)
    64  }
    65  
    66  func (s *toolsSuite) TestValidateUploadAllowed(c *gc.C) {
    67  	env := newEnviron("foo", useDefaultKeys, nil)
    68  	// Host runs arm64, environment supports arm64.
    69  	arm64 := "arm64"
    70  	centos7 := "centos7"
    71  	s.PatchValue(&arch.HostArch, func() string { return arm64 })
    72  	s.PatchValue(&os.HostOS, func() os.OSType { return os.CentOS })
    73  	err := bootstrap.ValidateUploadAllowed(env, &arm64, &centos7)
    74  	c.Assert(err, jc.ErrorIsNil)
    75  }
    76  
    77  func (s *toolsSuite) TestFindBootstrapTools(c *gc.C) {
    78  	var called int
    79  	var filter tools.Filter
    80  	var findStream string
    81  	s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) {
    82  		called++
    83  		c.Check(major, gc.Equals, jujuversion.Current.Major)
    84  		c.Check(minor, gc.Equals, jujuversion.Current.Minor)
    85  		findStream = stream
    86  		filter = f
    87  		return nil, nil
    88  	})
    89  
    90  	vers := version.MustParse("1.2.1")
    91  	devVers := version.MustParse("1.2-beta1")
    92  	arm64 := "arm64"
    93  
    94  	type test struct {
    95  		version *version.Number
    96  		arch    *string
    97  		series  *string
    98  		dev     bool
    99  		filter  tools.Filter
   100  		stream  string
   101  	}
   102  	tests := []test{{
   103  		version: nil,
   104  		arch:    nil,
   105  		series:  nil,
   106  		dev:     true,
   107  		filter:  tools.Filter{},
   108  	}, {
   109  		version: &vers,
   110  		arch:    nil,
   111  		series:  nil,
   112  		dev:     false,
   113  		filter:  tools.Filter{Number: vers},
   114  	}, {
   115  		version: &vers,
   116  		arch:    &arm64,
   117  		series:  nil,
   118  		filter:  tools.Filter{Arch: arm64, Number: vers},
   119  	}, {
   120  		version: &vers,
   121  		arch:    &arm64,
   122  		series:  nil,
   123  		dev:     true,
   124  		filter:  tools.Filter{Arch: arm64, Number: vers},
   125  	}, {
   126  		version: &devVers,
   127  		arch:    &arm64,
   128  		series:  nil,
   129  		filter:  tools.Filter{Arch: arm64, Number: devVers},
   130  	}, {
   131  		version: &devVers,
   132  		arch:    &arm64,
   133  		series:  nil,
   134  		filter:  tools.Filter{Arch: arm64, Number: devVers},
   135  		stream:  "devel",
   136  	}}
   137  
   138  	for i, test := range tests {
   139  		c.Logf("test %d: %#v", i, test)
   140  		extra := map[string]interface{}{"development": test.dev}
   141  		if test.stream != "" {
   142  			extra["agent-stream"] = test.stream
   143  		}
   144  		env := newEnviron("foo", useDefaultKeys, extra)
   145  		bootstrap.FindBootstrapTools(env, test.version, test.arch, test.series)
   146  		c.Assert(called, gc.Equals, i+1)
   147  		c.Assert(filter, gc.Equals, test.filter)
   148  		if test.stream != "" {
   149  			c.Check(findStream, gc.Equals, test.stream)
   150  		} else {
   151  			if test.dev || jujuversion.IsDev(*test.version) {
   152  				c.Check(findStream, gc.Equals, "devel")
   153  			} else {
   154  				c.Check(findStream, gc.Equals, "released")
   155  			}
   156  		}
   157  	}
   158  }
   159  
   160  func (s *toolsSuite) TestFindAvailableToolsError(c *gc.C) {
   161  	s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) {
   162  		return nil, errors.New("splat")
   163  	})
   164  	env := newEnviron("foo", useDefaultKeys, nil)
   165  	_, err := bootstrap.FindAvailableTools(env, nil, nil, nil, false, false)
   166  	c.Assert(err, gc.ErrorMatches, "splat")
   167  }
   168  
   169  func (s *toolsSuite) TestFindAvailableToolsNoUpload(c *gc.C) {
   170  	s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) {
   171  		return nil, errors.NotFoundf("tools")
   172  	})
   173  	env := newEnviron("foo", useDefaultKeys, map[string]interface{}{
   174  		"agent-version": "1.17.1",
   175  	})
   176  	_, err := bootstrap.FindAvailableTools(env, nil, nil, nil, false, false)
   177  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   178  }
   179  
   180  func (s *toolsSuite) TestFindAvailableToolsForceUpload(c *gc.C) {
   181  	s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 })
   182  	var findToolsCalled int
   183  	s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) {
   184  		findToolsCalled++
   185  		return nil, errors.NotFoundf("tools")
   186  	})
   187  	env := newEnviron("foo", useDefaultKeys, nil)
   188  	uploadedTools, err := bootstrap.FindAvailableTools(env, nil, nil, nil, true, true)
   189  	c.Assert(err, jc.ErrorIsNil)
   190  	c.Assert(uploadedTools, gc.Not(gc.HasLen), 0)
   191  	c.Assert(findToolsCalled, gc.Equals, 0)
   192  	expectedVersion := jujuversion.Current
   193  	expectedVersion.Build++
   194  	for _, tools := range uploadedTools {
   195  		c.Assert(tools.Version.Number, gc.Equals, expectedVersion)
   196  		c.Assert(tools.URL, gc.Equals, "")
   197  	}
   198  }
   199  
   200  func (s *toolsSuite) TestFindAvailableToolsForceUploadInvalidArch(c *gc.C) {
   201  	s.PatchValue(&arch.HostArch, func() string {
   202  		return arch.I386
   203  	})
   204  	var findToolsCalled int
   205  	s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) {
   206  		findToolsCalled++
   207  		return nil, errors.NotFoundf("tools")
   208  	})
   209  	env := newEnviron("foo", useDefaultKeys, nil)
   210  	_, err := bootstrap.FindAvailableTools(env, nil, nil, nil, true, true)
   211  	c.Assert(err, gc.ErrorMatches, `model "foo" of type dummy does not support instances running on "i386"`)
   212  	c.Assert(findToolsCalled, gc.Equals, 0)
   213  }
   214  
   215  func (s *toolsSuite) TestFindAvailableToolsSpecificVersion(c *gc.C) {
   216  	currentVersion := version.Binary{
   217  		Number: jujuversion.Current,
   218  		Arch:   arch.HostArch(),
   219  		Series: series.HostSeries(),
   220  	}
   221  	currentVersion.Major = 2
   222  	currentVersion.Minor = 3
   223  	s.PatchValue(&jujuversion.Current, currentVersion.Number)
   224  	var findToolsCalled int
   225  	s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) {
   226  		c.Assert(f.Number.Major, gc.Equals, 10)
   227  		c.Assert(f.Number.Minor, gc.Equals, 11)
   228  		c.Assert(f.Number.Patch, gc.Equals, 12)
   229  		c.Assert(stream, gc.Equals, "released")
   230  		findToolsCalled++
   231  		return []*tools.Tools{
   232  			&tools.Tools{
   233  				Version: currentVersion,
   234  				URL:     "http://testing.invalid/tools.tar.gz",
   235  			},
   236  		}, nil
   237  	})
   238  	env := newEnviron("foo", useDefaultKeys, nil)
   239  	toolsVersion := version.MustParse("10.11.12")
   240  	result, err := bootstrap.FindAvailableTools(env, &toolsVersion, nil, nil, false, false)
   241  	c.Assert(err, jc.ErrorIsNil)
   242  	c.Assert(findToolsCalled, gc.Equals, 1)
   243  	c.Assert(result, jc.DeepEquals, tools.List{
   244  		&tools.Tools{
   245  			Version: currentVersion,
   246  			URL:     "http://testing.invalid/tools.tar.gz",
   247  		},
   248  	})
   249  }
   250  
   251  func (s *toolsSuite) TestFindAvailableToolsAutoUpload(c *gc.C) {
   252  	s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 })
   253  	trustyTools := &tools.Tools{
   254  		Version: version.MustParseBinary("1.2.3-trusty-amd64"),
   255  		URL:     "http://testing.invalid/tools.tar.gz",
   256  	}
   257  	s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) {
   258  		return tools.List{trustyTools}, nil
   259  	})
   260  	env := newEnviron("foo", useDefaultKeys, map[string]interface{}{
   261  		"agent-stream": "proposed"})
   262  	availableTools, err := bootstrap.FindAvailableTools(env, nil, nil, nil, false, true)
   263  	c.Assert(err, jc.ErrorIsNil)
   264  	c.Assert(len(availableTools), jc.GreaterThan, 1)
   265  	c.Assert(env.supportedArchitecturesCount, gc.Equals, 1)
   266  	var trustyToolsFound int
   267  	expectedVersion := jujuversion.Current
   268  	expectedVersion.Build++
   269  	for _, tools := range availableTools {
   270  		if tools == trustyTools {
   271  			trustyToolsFound++
   272  		} else {
   273  			c.Assert(tools.Version.Number, gc.Equals, expectedVersion)
   274  			c.Assert(tools.Version.Series, gc.Not(gc.Equals), "trusty")
   275  			c.Assert(tools.URL, gc.Equals, "")
   276  		}
   277  	}
   278  	c.Assert(trustyToolsFound, gc.Equals, 1)
   279  }
   280  
   281  func (s *toolsSuite) TestFindAvailableToolsCompleteNoValidate(c *gc.C) {
   282  	s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 })
   283  
   284  	var allTools tools.List
   285  	for _, series := range series.SupportedSeries() {
   286  		binary := version.Binary{
   287  			Number: jujuversion.Current,
   288  			Series: series,
   289  			Arch:   arch.HostArch(),
   290  		}
   291  		allTools = append(allTools, &tools.Tools{
   292  			Version: binary,
   293  			URL:     "http://testing.invalid/tools.tar.gz",
   294  		})
   295  	}
   296  
   297  	s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) {
   298  		return allTools, nil
   299  	})
   300  	env := newEnviron("foo", useDefaultKeys, nil)
   301  	availableTools, err := bootstrap.FindAvailableTools(env, nil, nil, nil, false, false)
   302  	c.Assert(err, jc.ErrorIsNil)
   303  	c.Assert(availableTools, gc.HasLen, len(allTools))
   304  	c.Assert(env.supportedArchitecturesCount, gc.Equals, 0)
   305  }