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 }