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