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