github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/container/broker/kvm-broker.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package broker
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/names/v5"
    10  
    11  	"github.com/juju/juju/agent"
    12  	"github.com/juju/juju/cloudconfig/instancecfg"
    13  	"github.com/juju/juju/container"
    14  	"github.com/juju/juju/core/instance"
    15  	"github.com/juju/juju/environs"
    16  	"github.com/juju/juju/environs/context"
    17  	"github.com/juju/juju/environs/instances"
    18  )
    19  
    20  var kvmLogger = loggo.GetLogger("juju.container.broker.kvm")
    21  
    22  // NewKVMBroker creates a Broker that can be used to start KVM guests in a
    23  // similar fashion to normal StartInstance requests.
    24  // prepareHost is a callback that will be called when a new container is about
    25  // to be started. It provides the intersection point where the host can update
    26  // itself to be ready for whatever changes are necessary to have a functioning
    27  // container. (such as bridging host devices.)
    28  // manager is the infrastructure to actually launch the container.
    29  // agentConfig is currently only used to find out the 'default' bridge to use
    30  // when a specific network device is not specified in StartInstanceParams. This
    31  // should be deprecated. And hopefully removed in the future.
    32  func NewKVMBroker(
    33  	prepareHost PrepareHostFunc,
    34  	api APICalls,
    35  	manager container.Manager,
    36  	agentConfig agent.Config,
    37  ) (environs.InstanceBroker, error) {
    38  	return &kvmBroker{
    39  		prepareHost: prepareHost,
    40  		manager:     manager,
    41  		api:         api,
    42  		agentConfig: agentConfig,
    43  	}, nil
    44  }
    45  
    46  type kvmBroker struct {
    47  	prepareHost PrepareHostFunc
    48  	manager     container.Manager
    49  	api         APICalls
    50  	agentConfig agent.Config
    51  }
    52  
    53  // StartInstance is specified in the Broker interface.
    54  func (broker *kvmBroker) StartInstance(ctx context.ProviderCallContext, args environs.StartInstanceParams) (*environs.StartInstanceResult, error) {
    55  	// TODO: refactor common code out of the container brokers.
    56  	containerMachineID := args.InstanceConfig.MachineId
    57  	kvmLogger.Infof("starting kvm container for containerMachineID: %s", containerMachineID)
    58  
    59  	config, err := broker.api.ContainerConfig()
    60  	if err != nil {
    61  		kvmLogger.Errorf("failed to get container config: %v", err)
    62  		return nil, err
    63  	}
    64  
    65  	err = broker.prepareHost(names.NewMachineTag(containerMachineID), kvmLogger, args.Abort)
    66  	if err != nil {
    67  		return nil, errors.Trace(err)
    68  	}
    69  
    70  	preparedInfo, err := prepareContainerInterfaceInfo(broker.api, containerMachineID, kvmLogger)
    71  	if err != nil {
    72  		return nil, errors.Trace(err)
    73  	}
    74  
    75  	interfaces, err := finishNetworkConfig(preparedInfo)
    76  	if err != nil {
    77  		return nil, errors.Trace(err)
    78  	}
    79  	net := container.BridgeNetworkConfig(0, interfaces)
    80  
    81  	// The provisioner worker will provide all tools it knows about
    82  	// (after applying explicitly specified constraints), which may
    83  	// include tools for architectures other than the host's.
    84  	//
    85  	// container/kvm only allows running container==host arch, so
    86  	// we constrain the tools to host arch here regardless of the
    87  	// constraints specified.
    88  	archTools, err := matchHostArchTools(args.Tools)
    89  	if err != nil {
    90  		return nil, errors.Trace(err)
    91  	}
    92  
    93  	args.InstanceConfig.MachineContainerType = instance.KVM
    94  	if err := args.InstanceConfig.SetTools(archTools); err != nil {
    95  		return nil, errors.Trace(err)
    96  	}
    97  
    98  	cloudInitUserData, err := combinedCloudInitData(
    99  		config.CloudInitUserData,
   100  		config.ContainerInheritProperties,
   101  		args.InstanceConfig.Base, kvmLogger)
   102  	if err != nil {
   103  		return nil, errors.Trace(err)
   104  	}
   105  
   106  	if err := instancecfg.PopulateInstanceConfig(
   107  		args.InstanceConfig,
   108  		config.ProviderType,
   109  		config.AuthorizedKeys,
   110  		config.SSLHostnameVerification,
   111  		proxyConfigurationFromContainerCfg(config),
   112  		config.EnableOSRefreshUpdate,
   113  		config.EnableOSUpgrade,
   114  		cloudInitUserData,
   115  		nil,
   116  	); err != nil {
   117  		kvmLogger.Errorf("failed to populate machine config: %v", err)
   118  		return nil, err
   119  	}
   120  
   121  	storageConfig := &container.StorageConfig{
   122  		AllowMount: true,
   123  	}
   124  	inst, hardware, err := broker.manager.CreateContainer(
   125  		ctx, args.InstanceConfig, args.Constraints, args.InstanceConfig.Base, net, storageConfig, args.StatusCallback,
   126  	)
   127  	if err != nil {
   128  		kvmLogger.Errorf("failed to start container: %v", err)
   129  		return nil, err
   130  	}
   131  	kvmLogger.Infof("started kvm container for containerMachineID: %s, %s, %s", containerMachineID, inst.Id(), hardware.String())
   132  	return &environs.StartInstanceResult{
   133  		Instance: inst,
   134  		Hardware: hardware,
   135  	}, nil
   136  }
   137  
   138  // StopInstances shuts down the given instances.
   139  func (broker *kvmBroker) StopInstances(ctx context.ProviderCallContext, ids ...instance.Id) error {
   140  	for _, id := range ids {
   141  		kvmLogger.Infof("stopping kvm container for instance: %s", id)
   142  		if err := broker.manager.DestroyContainer(id); err != nil {
   143  			kvmLogger.Errorf("container did not stop: %v", err)
   144  			return err
   145  		}
   146  		releaseContainerAddresses(broker.api, id, broker.manager.Namespace(), kvmLogger)
   147  	}
   148  	return nil
   149  }
   150  
   151  // AllInstances returns all containers.
   152  func (broker *kvmBroker) AllInstances(ctx context.ProviderCallContext) (result []instances.Instance, err error) {
   153  	return broker.manager.ListContainers()
   154  }
   155  
   156  // AllRunningInstances only returns running containers.
   157  func (broker *kvmBroker) AllRunningInstances(ctx context.ProviderCallContext) (result []instances.Instance, err error) {
   158  	return broker.manager.ListContainers()
   159  }