github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/juju/testing/instance.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package testing
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	jc "github.com/juju/testing/checkers"
     9  	gc "gopkg.in/check.v1"
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/api"
    13  	"github.com/juju/juju/cloudconfig/instancecfg"
    14  	"github.com/juju/juju/constraints"
    15  	"github.com/juju/juju/environs"
    16  	"github.com/juju/juju/environs/config"
    17  	"github.com/juju/juju/environs/imagemetadata"
    18  	"github.com/juju/juju/environs/simplestreams"
    19  	"github.com/juju/juju/environs/tools"
    20  	"github.com/juju/juju/instance"
    21  	"github.com/juju/juju/mongo"
    22  	"github.com/juju/juju/network"
    23  	"github.com/juju/juju/state/multiwatcher"
    24  	"github.com/juju/juju/testing"
    25  	coretools "github.com/juju/juju/tools"
    26  )
    27  
    28  // FakeAPIInfo holds information about no state - it will always
    29  // give an error when connected to.  The machine id gives the machine id
    30  // of the machine to be started.
    31  func FakeAPIInfo(machineId string) *api.Info {
    32  	return &api.Info{
    33  		Addrs:    []string{"0.1.2.3:17777"},
    34  		Tag:      names.NewMachineTag(machineId),
    35  		Password: "unimportant",
    36  		CACert:   testing.CACert,
    37  		ModelTag: testing.ModelTag,
    38  	}
    39  }
    40  
    41  // WaitAddresses waits until the specified instance has addresses, and returns them.
    42  func WaitInstanceAddresses(env environs.Environ, instId instance.Id) ([]network.Address, error) {
    43  	for a := testing.LongAttempt.Start(); a.Next(); {
    44  		insts, err := env.Instances([]instance.Id{instId})
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  		addresses, err := insts[0].Addresses()
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  		if len(addresses) > 0 {
    53  			return addresses, nil
    54  		}
    55  	}
    56  	return nil, errors.Errorf("timed out trying to get addresses for %v", instId)
    57  }
    58  
    59  // AssertStartControllerInstance is a test helper function that starts a
    60  // controller instance with a plausible but invalid configuration, and
    61  // checks that it succeeds.
    62  func AssertStartControllerInstance(
    63  	c *gc.C, env environs.Environ, controllerUUID, machineId string,
    64  ) (
    65  	instance.Instance, *instance.HardwareCharacteristics,
    66  ) {
    67  	params := environs.StartInstanceParams{ControllerUUID: controllerUUID}
    68  	err := fillinStartInstanceParams(env, machineId, true, &params)
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	result, err := env.StartInstance(params)
    71  	c.Assert(err, jc.ErrorIsNil)
    72  	return result.Instance, result.Hardware
    73  }
    74  
    75  // AssertStartInstance is a test helper function that starts an instance with a
    76  // plausible but invalid configuration, and checks that it succeeds.
    77  func AssertStartInstance(
    78  	c *gc.C, env environs.Environ, controllerUUID, machineId string,
    79  ) (
    80  	instance.Instance, *instance.HardwareCharacteristics,
    81  ) {
    82  	inst, hc, _, err := StartInstance(env, controllerUUID, machineId)
    83  	c.Assert(err, jc.ErrorIsNil)
    84  	return inst, hc
    85  }
    86  
    87  // StartInstance is a test helper function that starts an instance with a plausible
    88  // but invalid configuration, and returns the result of Environ.StartInstance.
    89  func StartInstance(
    90  	env environs.Environ, controllerUUID, machineId string,
    91  ) (
    92  	instance.Instance, *instance.HardwareCharacteristics, []network.InterfaceInfo, error,
    93  ) {
    94  	return StartInstanceWithConstraints(env, controllerUUID, machineId, constraints.Value{})
    95  }
    96  
    97  // AssertStartInstanceWithConstraints is a test helper function that starts an instance
    98  // with the given constraints, and a plausible but invalid configuration, and returns
    99  // the result of Environ.StartInstance.
   100  func AssertStartInstanceWithConstraints(
   101  	c *gc.C, env environs.Environ, controllerUUID, machineId string, cons constraints.Value,
   102  ) (
   103  	instance.Instance, *instance.HardwareCharacteristics,
   104  ) {
   105  	inst, hc, _, err := StartInstanceWithConstraints(env, controllerUUID, machineId, cons)
   106  	c.Assert(err, jc.ErrorIsNil)
   107  	return inst, hc
   108  }
   109  
   110  // StartInstanceWithConstraints is a test helper function that starts an instance
   111  // with the given constraints, and a plausible but invalid configuration, and returns
   112  // the result of Environ.StartInstance.
   113  func StartInstanceWithConstraints(
   114  	env environs.Environ, controllerUUID, machineId string, cons constraints.Value,
   115  ) (
   116  	instance.Instance, *instance.HardwareCharacteristics, []network.InterfaceInfo, error,
   117  ) {
   118  	params := environs.StartInstanceParams{ControllerUUID: controllerUUID, Constraints: cons}
   119  	result, err := StartInstanceWithParams(env, machineId, params)
   120  	if err != nil {
   121  		return nil, nil, nil, errors.Trace(err)
   122  	}
   123  	return result.Instance, result.Hardware, result.NetworkInfo, nil
   124  }
   125  
   126  // StartInstanceWithParams is a test helper function that starts an instance
   127  // with the given parameters, and a plausible but invalid configuration, and
   128  // returns the result of Environ.StartInstance. The provided params's
   129  // InstanceConfig and Tools field values will be ignored.
   130  func StartInstanceWithParams(
   131  	env environs.Environ, machineId string,
   132  	params environs.StartInstanceParams,
   133  ) (
   134  	*environs.StartInstanceResult, error,
   135  ) {
   136  	if err := fillinStartInstanceParams(env, machineId, false, &params); err != nil {
   137  		return nil, err
   138  	}
   139  	return env.StartInstance(params)
   140  }
   141  
   142  func fillinStartInstanceParams(env environs.Environ, machineId string, isController bool, params *environs.StartInstanceParams) error {
   143  	if params.ControllerUUID == "" {
   144  		return errors.New("missing controller UUID in start instance parameters")
   145  	}
   146  	preferredSeries := config.PreferredSeries(env.Config())
   147  	agentVersion, ok := env.Config().AgentVersion()
   148  	if !ok {
   149  		return errors.New("missing agent version in model config")
   150  	}
   151  	filter := coretools.Filter{
   152  		Number: agentVersion,
   153  		Series: preferredSeries,
   154  	}
   155  	if params.Constraints.Arch != nil {
   156  		filter.Arch = *params.Constraints.Arch
   157  	}
   158  	stream := tools.PreferredStream(&agentVersion, env.Config().Development(), env.Config().AgentStream())
   159  	possibleTools, err := tools.FindTools(env, -1, -1, stream, filter)
   160  	if err != nil {
   161  		return errors.Trace(err)
   162  	}
   163  
   164  	if params.ImageMetadata == nil {
   165  		if err := SetImageMetadata(
   166  			env,
   167  			possibleTools.AllSeries(),
   168  			possibleTools.Arches(),
   169  			&params.ImageMetadata,
   170  		); err != nil {
   171  			return errors.Trace(err)
   172  		}
   173  	}
   174  
   175  	machineNonce := "fake_nonce"
   176  	apiInfo := FakeAPIInfo(machineId)
   177  	instanceConfig, err := instancecfg.NewInstanceConfig(
   178  		testing.ControllerTag,
   179  		machineId,
   180  		machineNonce,
   181  		imagemetadata.ReleasedStream,
   182  		preferredSeries,
   183  		apiInfo,
   184  	)
   185  	if err != nil {
   186  		return errors.Trace(err)
   187  	}
   188  	if isController {
   189  		instanceConfig.Controller = &instancecfg.ControllerConfig{
   190  			Config: testing.FakeControllerConfig(),
   191  			MongoInfo: &mongo.MongoInfo{
   192  				Info: mongo.Info{
   193  					Addrs:  []string{"127.0.0.1:1234"},
   194  					CACert: "CA CERT\n" + testing.CACert,
   195  				},
   196  				Password: "mongosecret",
   197  				Tag:      names.NewMachineTag(machineId),
   198  			},
   199  		}
   200  		instanceConfig.Jobs = []multiwatcher.MachineJob{multiwatcher.JobHostUnits, multiwatcher.JobManageModel}
   201  	}
   202  	cfg := env.Config()
   203  	instanceConfig.Tags = instancecfg.InstanceTags(env.Config().UUID(), params.ControllerUUID, cfg, nil)
   204  	params.Tools = possibleTools
   205  	params.InstanceConfig = instanceConfig
   206  	return nil
   207  }
   208  
   209  func SetImageMetadata(env environs.Environ, series, arches []string, out *[]*imagemetadata.ImageMetadata) error {
   210  	hasRegion, ok := env.(simplestreams.HasRegion)
   211  	if !ok {
   212  		return nil
   213  	}
   214  	sources, err := environs.ImageMetadataSources(env)
   215  	if err != nil {
   216  		return errors.Trace(err)
   217  	}
   218  	region, err := hasRegion.Region()
   219  	if err != nil {
   220  		return errors.Trace(err)
   221  	}
   222  	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
   223  		CloudSpec: region,
   224  		Series:    series,
   225  		Arches:    arches,
   226  		Stream:    env.Config().ImageStream(),
   227  	})
   228  	imageMetadata, _, err := imagemetadata.Fetch(sources, imageConstraint)
   229  	if err != nil {
   230  		return errors.Trace(err)
   231  	}
   232  	*out = imageMetadata
   233  	return nil
   234  }