github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/uniter/runner/util_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package runner_test
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strings"
    12  
    13  	"github.com/juju/names"
    14  	jc "github.com/juju/testing/checkers"
    15  	"github.com/juju/utils"
    16  	"github.com/juju/utils/fs"
    17  	gc "gopkg.in/check.v1"
    18  
    19  	"github.com/juju/juju/api"
    20  	"github.com/juju/juju/api/uniter"
    21  	"github.com/juju/juju/instance"
    22  	"github.com/juju/juju/juju/testing"
    23  	"github.com/juju/juju/network"
    24  	"github.com/juju/juju/state"
    25  	"github.com/juju/juju/storage"
    26  	"github.com/juju/juju/testcharms"
    27  	"github.com/juju/juju/worker/uniter/runner"
    28  	"github.com/juju/juju/worker/uniter/runner/context"
    29  	runnertesting "github.com/juju/juju/worker/uniter/runner/testing"
    30  )
    31  
    32  var apiAddrs = []string{"a1:123", "a2:123"}
    33  
    34  type ContextSuite struct {
    35  	testing.JujuConnSuite
    36  
    37  	paths          runnertesting.RealPaths
    38  	factory        runner.Factory
    39  	contextFactory context.ContextFactory
    40  	membership     map[int][]string
    41  
    42  	st      api.Connection
    43  	service *state.Service
    44  	machine *state.Machine
    45  	unit    *state.Unit
    46  	uniter  *uniter.State
    47  	apiUnit *uniter.Unit
    48  	storage *runnertesting.StorageContextAccessor
    49  
    50  	apiRelunits map[int]*uniter.RelationUnit
    51  	relch       *state.Charm
    52  	relunits    map[int]*state.RelationUnit
    53  }
    54  
    55  func (s *ContextSuite) SetUpTest(c *gc.C) {
    56  	s.JujuConnSuite.SetUpTest(c)
    57  
    58  	s.machine = nil
    59  
    60  	ch := s.AddTestingCharm(c, "wordpress")
    61  	s.service = s.AddTestingService(c, "u", ch)
    62  	s.unit = s.AddUnit(c, s.service)
    63  
    64  	storageData0 := names.NewStorageTag("data/0")
    65  	s.storage = &runnertesting.StorageContextAccessor{
    66  		map[names.StorageTag]*runnertesting.ContextStorage{
    67  			storageData0: &runnertesting.ContextStorage{
    68  				storageData0,
    69  				storage.StorageKindBlock,
    70  				"/dev/sdb",
    71  			},
    72  		},
    73  	}
    74  
    75  	password, err := utils.RandomPassword()
    76  	err = s.unit.SetPassword(password)
    77  	c.Assert(err, jc.ErrorIsNil)
    78  	s.st = s.OpenAPIAs(c, s.unit.Tag(), password)
    79  	s.uniter, err = s.st.Uniter()
    80  	c.Assert(err, jc.ErrorIsNil)
    81  	c.Assert(s.uniter, gc.NotNil)
    82  	s.apiUnit, err = s.uniter.Unit(s.unit.Tag().(names.UnitTag))
    83  	c.Assert(err, jc.ErrorIsNil)
    84  
    85  	s.paths = runnertesting.NewRealPaths(c)
    86  	s.membership = map[int][]string{}
    87  
    88  	// Note: The unit must always have a charm URL set, because this
    89  	// happens as part of the installation process (that happens
    90  	// before the initial install hook).
    91  	err = s.unit.SetCharmURL(ch.URL())
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	s.relch = s.AddTestingCharm(c, "mysql")
    94  	s.relunits = map[int]*state.RelationUnit{}
    95  	s.apiRelunits = map[int]*uniter.RelationUnit{}
    96  	s.AddContextRelation(c, "db0")
    97  	s.AddContextRelation(c, "db1")
    98  
    99  	s.contextFactory, err = context.NewContextFactory(
   100  		s.uniter,
   101  		s.unit.Tag().(names.UnitTag),
   102  		runnertesting.FakeTracker{},
   103  		s.getRelationInfos,
   104  		s.storage,
   105  		s.paths,
   106  	)
   107  	c.Assert(err, jc.ErrorIsNil)
   108  
   109  	factory, err := runner.NewFactory(
   110  		s.uniter,
   111  		s.paths,
   112  		s.contextFactory,
   113  	)
   114  	c.Assert(err, jc.ErrorIsNil)
   115  	s.factory = factory
   116  }
   117  
   118  func (s *ContextSuite) AddContextRelation(c *gc.C, name string) {
   119  	s.AddTestingService(c, name, s.relch)
   120  	eps, err := s.State.InferEndpoints("u", name)
   121  	c.Assert(err, jc.ErrorIsNil)
   122  	rel, err := s.State.AddRelation(eps...)
   123  	c.Assert(err, jc.ErrorIsNil)
   124  	ru, err := rel.Unit(s.unit)
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	err = ru.EnterScope(map[string]interface{}{"relation-name": name})
   127  	c.Assert(err, jc.ErrorIsNil)
   128  	s.relunits[rel.Id()] = ru
   129  	apiRel, err := s.uniter.Relation(rel.Tag().(names.RelationTag))
   130  	c.Assert(err, jc.ErrorIsNil)
   131  	apiRelUnit, err := apiRel.Unit(s.apiUnit)
   132  	c.Assert(err, jc.ErrorIsNil)
   133  	s.apiRelunits[rel.Id()] = apiRelUnit
   134  }
   135  
   136  func (s *ContextSuite) AddUnit(c *gc.C, svc *state.Service) *state.Unit {
   137  	unit, err := svc.AddUnit()
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	if s.machine != nil {
   140  		err = unit.AssignToMachine(s.machine)
   141  		c.Assert(err, jc.ErrorIsNil)
   142  		return unit
   143  	}
   144  
   145  	err = s.State.AssignUnit(unit, state.AssignCleanEmpty)
   146  	c.Assert(err, jc.ErrorIsNil)
   147  	machineId, err := unit.AssignedMachineId()
   148  	c.Assert(err, jc.ErrorIsNil)
   149  	s.machine, err = s.State.Machine(machineId)
   150  	c.Assert(err, jc.ErrorIsNil)
   151  	zone := "a-zone"
   152  	hwc := instance.HardwareCharacteristics{
   153  		AvailabilityZone: &zone,
   154  	}
   155  	err = s.machine.SetProvisioned("i-exist", "fake_nonce", &hwc)
   156  	c.Assert(err, jc.ErrorIsNil)
   157  
   158  	name := strings.Replace(unit.Name(), "/", "-", 1)
   159  	privateAddr := network.NewScopedAddress(name+".testing.invalid", network.ScopeCloudLocal)
   160  	err = s.machine.SetProviderAddresses(privateAddr)
   161  	c.Assert(err, jc.ErrorIsNil)
   162  	return unit
   163  }
   164  
   165  func (s *ContextSuite) SetCharm(c *gc.C, name string) {
   166  	err := os.RemoveAll(s.paths.GetCharmDir())
   167  	c.Assert(err, jc.ErrorIsNil)
   168  	err = fs.Copy(testcharms.Repo.CharmDirPath(name), s.paths.GetCharmDir())
   169  	c.Assert(err, jc.ErrorIsNil)
   170  }
   171  
   172  func (s *ContextSuite) getRelationInfos() map[int]*context.RelationInfo {
   173  	info := map[int]*context.RelationInfo{}
   174  	for relId, relUnit := range s.apiRelunits {
   175  		info[relId] = &context.RelationInfo{
   176  			RelationUnit: relUnit,
   177  			MemberNames:  s.membership[relId],
   178  		}
   179  	}
   180  	return info
   181  }
   182  
   183  // hookSpec supports makeCharm.
   184  type hookSpec struct {
   185  	// dir is the directory to create the hook in.
   186  	dir string
   187  	// name is the name of the hook.
   188  	name string
   189  	// perm is the file permissions of the hook.
   190  	perm os.FileMode
   191  	// code is the exit status of the hook.
   192  	code int
   193  	// stdout holds a string to print to stdout
   194  	stdout string
   195  	// stderr holds a string to print to stderr
   196  	stderr string
   197  	// background holds a string to print in the background after 0.2s.
   198  	background string
   199  }
   200  
   201  // makeCharm constructs a fake charm dir containing a single named hook
   202  // with permissions perm and exit code code. If output is non-empty,
   203  // the charm will write it to stdout and stderr, with each one prefixed
   204  // by name of the stream.
   205  func makeCharm(c *gc.C, spec hookSpec, charmDir string) {
   206  	dir := charmDir
   207  	if spec.dir != "" {
   208  		dir = filepath.Join(dir, spec.dir)
   209  		err := os.Mkdir(dir, 0755)
   210  		c.Assert(err, jc.ErrorIsNil)
   211  	}
   212  	c.Logf("openfile perm %v", spec.perm)
   213  	hook, err := os.OpenFile(
   214  		filepath.Join(dir, spec.name), os.O_CREATE|os.O_WRONLY, spec.perm,
   215  	)
   216  	c.Assert(err, jc.ErrorIsNil)
   217  	defer func() {
   218  		c.Assert(hook.Close(), gc.IsNil)
   219  	}()
   220  
   221  	printf := func(f string, a ...interface{}) {
   222  		_, err := fmt.Fprintf(hook, f+"\n", a...)
   223  		c.Assert(err, jc.ErrorIsNil)
   224  	}
   225  	if runtime.GOOS != "windows" {
   226  		printf("#!/bin/bash")
   227  	}
   228  	printf(echoPidScript)
   229  	if spec.stdout != "" {
   230  		printf("echo %s", spec.stdout)
   231  	}
   232  	if spec.stderr != "" {
   233  		printf("echo %s >&2", spec.stderr)
   234  	}
   235  	if spec.background != "" {
   236  		// Print something fairly quickly, then sleep for
   237  		// quite a long time - if the hook execution is
   238  		// blocking because of the background process,
   239  		// the hook execution will take much longer than
   240  		// expected.
   241  		printf("(sleep 0.2; echo %s; sleep 10) &", spec.background)
   242  	}
   243  	printf("exit %d", spec.code)
   244  }