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