github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/environs/testing/tools.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package testing
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils"
    14  	"github.com/juju/utils/set"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	agenttools "github.com/juju/juju/agent/tools"
    18  	"github.com/juju/juju/environs/filestorage"
    19  	"github.com/juju/juju/environs/storage"
    20  	envtools "github.com/juju/juju/environs/tools"
    21  	"github.com/juju/juju/juju/names"
    22  	"github.com/juju/juju/state"
    23  	coretesting "github.com/juju/juju/testing"
    24  	coretools "github.com/juju/juju/tools"
    25  	"github.com/juju/juju/version"
    26  	"github.com/juju/juju/worker/upgrader"
    27  )
    28  
    29  // toolsLtsSeries records the known Ubuntu LTS series.
    30  var toolsLtsSeries = []string{"precise", "trusty"}
    31  
    32  // ToolsFixture is used as a fixture to stub out the default tools URL so we
    33  // don't hit the real internet during tests.
    34  type ToolsFixture struct {
    35  	origDefaultURL string
    36  	DefaultBaseURL string
    37  
    38  	// UploadArches holds the architectures of tools to
    39  	// upload in UploadFakeTools. If empty, it will default
    40  	// to just version.Current.Arch.
    41  	UploadArches []string
    42  }
    43  
    44  func (s *ToolsFixture) SetUpTest(c *gc.C) {
    45  	s.origDefaultURL = envtools.DefaultBaseURL
    46  	envtools.DefaultBaseURL = s.DefaultBaseURL
    47  }
    48  
    49  func (s *ToolsFixture) TearDownTest(c *gc.C) {
    50  	envtools.DefaultBaseURL = s.origDefaultURL
    51  }
    52  
    53  // UploadFakeToolsToDirectory uploads fake tools of the architectures in
    54  // s.UploadArches for each LTS release to the specified directory.
    55  func (s *ToolsFixture) UploadFakeToolsToDirectory(c *gc.C, dir, toolsDir, stream string) {
    56  	stor, err := filestorage.NewFileStorageWriter(dir)
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	s.UploadFakeTools(c, stor, toolsDir, stream)
    59  }
    60  
    61  // UploadFakeTools uploads fake tools of the architectures in
    62  // s.UploadArches for each LTS release to the specified storage.
    63  func (s *ToolsFixture) UploadFakeTools(c *gc.C, stor storage.Storage, toolsDir, stream string) {
    64  	arches := s.UploadArches
    65  	if len(arches) == 0 {
    66  		arches = []string{version.Current.Arch}
    67  	}
    68  	var versions []version.Binary
    69  	for _, arch := range arches {
    70  		v := version.Current
    71  		v.Arch = arch
    72  		for _, series := range toolsLtsSeries {
    73  			v.Series = series
    74  			versions = append(versions, v)
    75  		}
    76  	}
    77  	_, err := UploadFakeToolsVersions(stor, toolsDir, stream, versions...)
    78  	c.Assert(err, jc.ErrorIsNil)
    79  }
    80  
    81  // RemoveFakeToolsMetadata deletes the fake simplestreams tools metadata from the supplied storage.
    82  func RemoveFakeToolsMetadata(c *gc.C, stor storage.Storage) {
    83  	files, err := stor.List("tools/streams")
    84  	c.Assert(err, jc.ErrorIsNil)
    85  	for _, file := range files {
    86  		err = stor.Remove(file)
    87  		c.Check(err, jc.ErrorIsNil)
    88  	}
    89  }
    90  
    91  // CheckTools ensures the obtained and expected tools are equal, allowing for the fact that
    92  // the obtained tools may not have size and checksum set.
    93  func CheckTools(c *gc.C, obtained, expected *coretools.Tools) {
    94  	c.Assert(obtained.Version, gc.Equals, expected.Version)
    95  	// TODO(dimitern) 2013-10-02 bug #1234217
    96  	// Are these used at at all? If not we should drop them.
    97  	if obtained.URL != "" {
    98  		c.Assert(obtained.URL, gc.Equals, expected.URL)
    99  	}
   100  	if obtained.Size > 0 {
   101  		c.Assert(obtained.Size, gc.Equals, expected.Size)
   102  		c.Assert(obtained.SHA256, gc.Equals, expected.SHA256)
   103  	}
   104  }
   105  
   106  // CheckUpgraderReadyError ensures the obtained and expected errors are equal.
   107  func CheckUpgraderReadyError(c *gc.C, obtained error, expected *upgrader.UpgradeReadyError) {
   108  	c.Assert(obtained, gc.FitsTypeOf, &upgrader.UpgradeReadyError{})
   109  	err := obtained.(*upgrader.UpgradeReadyError)
   110  	c.Assert(err.AgentName, gc.Equals, expected.AgentName)
   111  	c.Assert(err.DataDir, gc.Equals, expected.DataDir)
   112  	c.Assert(err.OldTools, gc.Equals, expected.OldTools)
   113  	c.Assert(err.NewTools, gc.Equals, expected.NewTools)
   114  }
   115  
   116  // PrimeTools sets up the current version of the tools to vers and
   117  // makes sure that they're available in the dataDir.
   118  func PrimeTools(c *gc.C, stor storage.Storage, dataDir, toolsDir string, vers version.Binary) *coretools.Tools {
   119  	err := os.RemoveAll(filepath.Join(dataDir, "tools"))
   120  	c.Assert(err, jc.ErrorIsNil)
   121  	agentTools, err := uploadFakeToolsVersion(stor, toolsDir, vers)
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	resp, err := utils.GetValidatingHTTPClient().Get(agentTools.URL)
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	defer resp.Body.Close()
   126  	err = agenttools.UnpackTools(dataDir, agentTools, resp.Body)
   127  	c.Assert(err, jc.ErrorIsNil)
   128  	return agentTools
   129  }
   130  
   131  func uploadFakeToolsVersion(stor storage.Storage, toolsDir string, vers version.Binary) (*coretools.Tools, error) {
   132  	logger.Infof("uploading FAKE tools %s", vers)
   133  	tgz, checksum := makeFakeTools(vers)
   134  	size := int64(len(tgz))
   135  	name := envtools.StorageName(vers, toolsDir)
   136  	if err := stor.Put(name, bytes.NewReader(tgz), size); err != nil {
   137  		return nil, err
   138  	}
   139  	url, err := stor.URL(name)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	return &coretools.Tools{URL: url, Version: vers, Size: size, SHA256: checksum}, nil
   144  }
   145  
   146  // InstallFakeDownloadedTools creates and unpacks fake tools of the
   147  // given version into the data directory specified.
   148  func InstallFakeDownloadedTools(c *gc.C, dataDir string, vers version.Binary) *coretools.Tools {
   149  	tgz, checksum := makeFakeTools(vers)
   150  	agentTools := &coretools.Tools{
   151  		Version: vers,
   152  		Size:    int64(len(tgz)),
   153  		SHA256:  checksum,
   154  	}
   155  	err := agenttools.UnpackTools(dataDir, agentTools, bytes.NewReader(tgz))
   156  	c.Assert(err, jc.ErrorIsNil)
   157  	return agentTools
   158  }
   159  
   160  func makeFakeTools(vers version.Binary) ([]byte, string) {
   161  	return coretesting.TarGz(
   162  		coretesting.NewTarFile(names.Jujud, 0777, "jujud contents "+vers.String()))
   163  }
   164  
   165  // UploadFakeToolsVersions puts fake tools in the supplied storage for the supplied versions.
   166  func UploadFakeToolsVersions(stor storage.Storage, toolsDir, stream string, versions ...version.Binary) ([]*coretools.Tools, error) {
   167  	// Leave existing tools alone.
   168  	existingTools := make(map[version.Binary]*coretools.Tools)
   169  	existing, _ := envtools.ReadList(stor, toolsDir, 1, -1)
   170  	for _, tools := range existing {
   171  		existingTools[tools.Version] = tools
   172  	}
   173  	var agentTools coretools.List = make(coretools.List, len(versions))
   174  	for i, version := range versions {
   175  		if tools, ok := existingTools[version]; ok {
   176  			agentTools[i] = tools
   177  		} else {
   178  			t, err := uploadFakeToolsVersion(stor, toolsDir, version)
   179  			if err != nil {
   180  				return nil, err
   181  			}
   182  			agentTools[i] = t
   183  		}
   184  	}
   185  	if err := envtools.MergeAndWriteMetadata(stor, toolsDir, stream, agentTools, envtools.DoNotWriteMirrors); err != nil {
   186  		return nil, err
   187  	}
   188  	return agentTools, nil
   189  }
   190  
   191  // AssertUploadFakeToolsVersions puts fake tools in the supplied storage for the supplied versions.
   192  func AssertUploadFakeToolsVersions(c *gc.C, stor storage.Storage, toolsDir, stream string, versions ...version.Binary) []*coretools.Tools {
   193  	agentTools, err := UploadFakeToolsVersions(stor, toolsDir, stream, versions...)
   194  	c.Assert(err, jc.ErrorIsNil)
   195  	err = envtools.MergeAndWriteMetadata(stor, toolsDir, stream, agentTools, envtools.DoNotWriteMirrors)
   196  	c.Assert(err, jc.ErrorIsNil)
   197  	return agentTools
   198  }
   199  
   200  // MustUploadFakeToolsVersions acts as UploadFakeToolsVersions, but panics on failure.
   201  func MustUploadFakeToolsVersions(stor storage.Storage, stream string, versions ...version.Binary) []*coretools.Tools {
   202  	var agentTools coretools.List = make(coretools.List, len(versions))
   203  	for i, version := range versions {
   204  		t, err := uploadFakeToolsVersion(stor, stream, version)
   205  		if err != nil {
   206  			panic(err)
   207  		}
   208  		agentTools[i] = t
   209  	}
   210  	err := envtools.MergeAndWriteMetadata(stor, stream, stream, agentTools, envtools.DoNotWriteMirrors)
   211  	if err != nil {
   212  		panic(err)
   213  	}
   214  	return agentTools
   215  }
   216  
   217  func uploadFakeTools(stor storage.Storage, toolsDir, stream string) error {
   218  	toolsSeries := set.NewStrings(toolsLtsSeries...)
   219  	toolsSeries.Add(version.Current.Series)
   220  	var versions []version.Binary
   221  	for _, series := range toolsSeries.Values() {
   222  		vers := version.Current
   223  		vers.Series = series
   224  		versions = append(versions, vers)
   225  	}
   226  	if _, err := UploadFakeToolsVersions(stor, toolsDir, stream, versions...); err != nil {
   227  		return err
   228  	}
   229  	return nil
   230  }
   231  
   232  // UploadFakeTools puts fake tools into the supplied storage with a binary
   233  // version matching version.Current; if version.Current's series is different
   234  // to coretesting.FakeDefaultSeries, matching fake tools will be uploaded for that
   235  // series.  This is useful for tests that are kinda casual about specifying
   236  // their environment.
   237  func UploadFakeTools(c *gc.C, stor storage.Storage, toolsDir, stream string) {
   238  	c.Assert(uploadFakeTools(stor, toolsDir, stream), gc.IsNil)
   239  }
   240  
   241  // MustUploadFakeTools acts as UploadFakeTools, but panics on failure.
   242  func MustUploadFakeTools(stor storage.Storage, toolsDir, stream string) {
   243  	if err := uploadFakeTools(stor, toolsDir, stream); err != nil {
   244  		panic(err)
   245  	}
   246  }
   247  
   248  // RemoveFakeTools deletes the fake tools from the supplied storage.
   249  func RemoveFakeTools(c *gc.C, stor storage.Storage, toolsDir string) {
   250  	c.Logf("removing fake tools")
   251  	toolsVersion := version.Current
   252  	name := envtools.StorageName(toolsVersion, toolsDir)
   253  	err := stor.Remove(name)
   254  	c.Check(err, jc.ErrorIsNil)
   255  	defaultSeries := coretesting.FakeDefaultSeries
   256  	if version.Current.Series != defaultSeries {
   257  		toolsVersion.Series = defaultSeries
   258  		name := envtools.StorageName(toolsVersion, toolsDir)
   259  		err := stor.Remove(name)
   260  		c.Check(err, jc.ErrorIsNil)
   261  	}
   262  	RemoveFakeToolsMetadata(c, stor)
   263  }
   264  
   265  // RemoveTools deletes all tools from the supplied storage.
   266  func RemoveTools(c *gc.C, stor storage.Storage, toolsDir string) {
   267  	names, err := storage.List(stor, fmt.Sprintf("tools/%s/juju-", toolsDir))
   268  	c.Assert(err, jc.ErrorIsNil)
   269  	c.Logf("removing files: %v", names)
   270  	for _, name := range names {
   271  		err = stor.Remove(name)
   272  		c.Check(err, jc.ErrorIsNil)
   273  	}
   274  	RemoveFakeToolsMetadata(c, stor)
   275  }
   276  
   277  var (
   278  	V100    = version.MustParse("1.0.0")
   279  	V100p64 = version.MustParseBinary("1.0.0-precise-amd64")
   280  	V100p32 = version.MustParseBinary("1.0.0-precise-i386")
   281  	V100p   = []version.Binary{V100p64, V100p32}
   282  
   283  	V100q64 = version.MustParseBinary("1.0.0-quantal-amd64")
   284  	V100q32 = version.MustParseBinary("1.0.0-quantal-i386")
   285  	V100q   = []version.Binary{V100q64, V100q32}
   286  	V100all = append(V100p, V100q...)
   287  
   288  	V1001    = version.MustParse("1.0.0.1")
   289  	V1001p64 = version.MustParseBinary("1.0.0.1-precise-amd64")
   290  	V100Xall = append(V100all, V1001p64)
   291  
   292  	V110    = version.MustParse("1.1.0")
   293  	V110p64 = version.MustParseBinary("1.1.0-precise-amd64")
   294  	V110p32 = version.MustParseBinary("1.1.0-precise-i386")
   295  	V110p   = []version.Binary{V110p64, V110p32}
   296  
   297  	V110q64 = version.MustParseBinary("1.1.0-quantal-amd64")
   298  	V110q32 = version.MustParseBinary("1.1.0-quantal-i386")
   299  	V110q   = []version.Binary{V110q64, V110q32}
   300  	V110all = append(V110p, V110q...)
   301  
   302  	V1101p64 = version.MustParseBinary("1.1.0.1-precise-amd64")
   303  	V110Xall = append(V110all, V1101p64)
   304  
   305  	V120    = version.MustParse("1.2.0")
   306  	V120p64 = version.MustParseBinary("1.2.0-precise-amd64")
   307  	V120p32 = version.MustParseBinary("1.2.0-precise-i386")
   308  	V120p   = []version.Binary{V120p64, V120p32}
   309  
   310  	V120q64 = version.MustParseBinary("1.2.0-quantal-amd64")
   311  	V120q32 = version.MustParseBinary("1.2.0-quantal-i386")
   312  	V120q   = []version.Binary{V120q64, V120q32}
   313  
   314  	V120t64 = version.MustParseBinary("1.2.0-trusty-amd64")
   315  	V120t32 = version.MustParseBinary("1.2.0-trusty-i386")
   316  	V120t   = []version.Binary{V120t64, V120t32}
   317  
   318  	V120all = append(append(V120p, V120q...), V120t...)
   319  	V1all   = append(V100Xall, append(V110all, V120all...)...)
   320  
   321  	V220    = version.MustParse("2.2.0")
   322  	V220p32 = version.MustParseBinary("2.2.0-precise-i386")
   323  	V220p64 = version.MustParseBinary("2.2.0-precise-amd64")
   324  	V220q32 = version.MustParseBinary("2.2.0-quantal-i386")
   325  	V220q64 = version.MustParseBinary("2.2.0-quantal-amd64")
   326  	V220all = []version.Binary{V220p64, V220p32, V220q64, V220q32}
   327  	VAll    = append(V1all, V220all...)
   328  
   329  	V31d0qppc64  = version.MustParseBinary("3.1-dev0-quantal-ppc64el")
   330  	V31d01qppc64 = version.MustParseBinary("3.1-dev0.1-quantal-ppc64el")
   331  )
   332  
   333  type BootstrapToolsTest struct {
   334  	Info          string
   335  	Available     []version.Binary
   336  	CliVersion    version.Binary
   337  	DefaultSeries string
   338  	AgentVersion  version.Number
   339  	Development   bool
   340  	Arch          string
   341  	Expect        []version.Binary
   342  	Err           string
   343  }
   344  
   345  var noToolsMessage = "Juju cannot bootstrap because no tools are available for your environment.*"
   346  
   347  var BootstrapToolsTests = []BootstrapToolsTest{
   348  	{
   349  		Info:          "no tools at all",
   350  		CliVersion:    V100p64,
   351  		DefaultSeries: "precise",
   352  		Err:           noToolsMessage,
   353  	}, {
   354  		Info:          "released cli: use newest compatible release version",
   355  		Available:     VAll,
   356  		CliVersion:    V100p64,
   357  		DefaultSeries: "precise",
   358  		Expect:        V100p,
   359  	}, {
   360  		Info:          "released cli: cli Arch ignored",
   361  		Available:     VAll,
   362  		CliVersion:    V100p32,
   363  		DefaultSeries: "precise",
   364  		Expect:        V100p,
   365  	}, {
   366  		Info:          "released cli: cli series ignored",
   367  		Available:     VAll,
   368  		CliVersion:    V100q64,
   369  		DefaultSeries: "precise",
   370  		Expect:        V100p,
   371  	}, {
   372  		Info:          "released cli: series taken from default-series",
   373  		Available:     V120all,
   374  		CliVersion:    V120p64,
   375  		DefaultSeries: "quantal",
   376  		Expect:        V120q,
   377  	}, {
   378  		Info:          "released cli: ignore close dev match",
   379  		Available:     V100Xall,
   380  		CliVersion:    V100p64,
   381  		DefaultSeries: "precise",
   382  		Expect:        V100p,
   383  	}, {
   384  		Info:          "released cli: filter by arch constraints",
   385  		Available:     V120all,
   386  		CliVersion:    V120p64,
   387  		DefaultSeries: "precise",
   388  		Arch:          "i386",
   389  		Expect:        []version.Binary{V120p32},
   390  	}, {
   391  		Info:          "released cli: specific released version",
   392  		Available:     VAll,
   393  		CliVersion:    V100p64,
   394  		AgentVersion:  V100,
   395  		DefaultSeries: "precise",
   396  		Expect:        V100p,
   397  	}, {
   398  		Info:          "released cli: specific dev version",
   399  		Available:     VAll,
   400  		CliVersion:    V110p64,
   401  		AgentVersion:  V110,
   402  		DefaultSeries: "precise",
   403  		Expect:        V110p,
   404  	}, {
   405  		Info:          "released cli: major upgrades bad",
   406  		Available:     V220all,
   407  		CliVersion:    V100p64,
   408  		DefaultSeries: "precise",
   409  		Err:           noToolsMessage,
   410  	}, {
   411  		Info:          "released cli: minor upgrades bad",
   412  		Available:     V120all,
   413  		CliVersion:    V100p64,
   414  		DefaultSeries: "precise",
   415  		Err:           noToolsMessage,
   416  	}, {
   417  		Info:          "released cli: major downgrades bad",
   418  		Available:     V100Xall,
   419  		CliVersion:    V220p64,
   420  		DefaultSeries: "precise",
   421  		Err:           noToolsMessage,
   422  	}, {
   423  		Info:          "released cli: minor downgrades bad",
   424  		Available:     V100Xall,
   425  		CliVersion:    V120p64,
   426  		DefaultSeries: "quantal",
   427  		Err:           noToolsMessage,
   428  	}, {
   429  		Info:          "released cli: no matching series",
   430  		Available:     VAll,
   431  		CliVersion:    V100p64,
   432  		DefaultSeries: "raring",
   433  		Err:           noToolsMessage,
   434  	}, {
   435  		Info:          "released cli: no matching arches",
   436  		Available:     VAll,
   437  		CliVersion:    V100p64,
   438  		DefaultSeries: "precise",
   439  		Arch:          "armhf",
   440  		Err:           noToolsMessage,
   441  	}, {
   442  		Info:          "released cli: specific bad major 1",
   443  		Available:     VAll,
   444  		CliVersion:    V220p64,
   445  		AgentVersion:  V120,
   446  		DefaultSeries: "precise",
   447  		Err:           noToolsMessage,
   448  	}, {
   449  		Info:          "released cli: specific bad major 2",
   450  		Available:     VAll,
   451  		CliVersion:    V120p64,
   452  		AgentVersion:  V220,
   453  		DefaultSeries: "precise",
   454  		Err:           noToolsMessage,
   455  	}, {
   456  		Info:          "released cli: ignore dev tools 1",
   457  		Available:     V110all,
   458  		CliVersion:    V100p64,
   459  		DefaultSeries: "precise",
   460  		Err:           noToolsMessage,
   461  	}, {
   462  		Info:          "released cli: ignore dev tools 2",
   463  		Available:     V110all,
   464  		CliVersion:    V120p64,
   465  		DefaultSeries: "precise",
   466  		Err:           noToolsMessage,
   467  	}, {
   468  		Info:          "released cli: ignore dev tools 3",
   469  		Available:     []version.Binary{V1001p64},
   470  		CliVersion:    V100p64,
   471  		DefaultSeries: "precise",
   472  		Err:           noToolsMessage,
   473  	}, {
   474  		Info:          "released cli with dev setting respects agent-version",
   475  		Available:     VAll,
   476  		CliVersion:    V100q32,
   477  		AgentVersion:  V1001,
   478  		DefaultSeries: "precise",
   479  		Development:   true,
   480  		Expect:        []version.Binary{V1001p64},
   481  	}, {
   482  		Info:          "dev cli respects agent-version",
   483  		Available:     VAll,
   484  		CliVersion:    V100q32,
   485  		AgentVersion:  V1001,
   486  		DefaultSeries: "precise",
   487  		Expect:        []version.Binary{V1001p64},
   488  	}, {
   489  		Info:          "released cli with dev setting respects agent-version",
   490  		Available:     V1all,
   491  		CliVersion:    V100q32,
   492  		AgentVersion:  V1001,
   493  		DefaultSeries: "precise",
   494  		Development:   true,
   495  		Expect:        []version.Binary{V1001p64},
   496  	}, {
   497  		Info:          "dev cli respects agent-version",
   498  		Available:     V1all,
   499  		CliVersion:    V100q32,
   500  		AgentVersion:  V1001,
   501  		DefaultSeries: "precise",
   502  		Expect:        []version.Binary{V1001p64},
   503  	}}
   504  
   505  func SetSSLHostnameVerification(c *gc.C, st *state.State, SSLHostnameVerification bool) {
   506  	err := st.UpdateEnvironConfig(map[string]interface{}{"ssl-hostname-verification": SSLHostnameVerification}, nil, nil)
   507  	c.Assert(err, jc.ErrorIsNil)
   508  }