github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/vsphere/instance.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package vsphere
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/vmware/govmomi/vim25/mo"
     9  	"github.com/vmware/govmomi/vim25/types"
    10  
    11  	"github.com/juju/juju/core/instance"
    12  	corenetwork "github.com/juju/juju/core/network"
    13  	"github.com/juju/juju/core/network/firewall"
    14  	"github.com/juju/juju/core/status"
    15  	"github.com/juju/juju/environs/context"
    16  	"github.com/juju/juju/environs/instances"
    17  	"github.com/juju/juju/provider/common"
    18  )
    19  
    20  type environInstance struct {
    21  	base *mo.VirtualMachine
    22  	env  *environ
    23  }
    24  
    25  var _ instances.Instance = (*environInstance)(nil)
    26  
    27  func newInstance(base *mo.VirtualMachine, env *environ) *environInstance {
    28  	return &environInstance{
    29  		base: base,
    30  		env:  env,
    31  	}
    32  }
    33  
    34  // Id implements instances.Instance.
    35  func (inst *environInstance) Id() instance.Id {
    36  	return instance.Id(inst.base.Name)
    37  }
    38  
    39  // Status implements instances.Instance.
    40  func (inst *environInstance) Status(ctx context.ProviderCallContext) instance.Status {
    41  	instanceStatus := instance.Status{
    42  		Status:  status.Empty,
    43  		Message: string(inst.base.Runtime.PowerState),
    44  	}
    45  	switch inst.base.Runtime.PowerState {
    46  	case types.VirtualMachinePowerStatePoweredOn:
    47  		instanceStatus.Status = status.Running
    48  	}
    49  	return instanceStatus
    50  }
    51  
    52  // Addresses implements instances.Instance.
    53  func (inst *environInstance) Addresses(ctx context.ProviderCallContext) (corenetwork.ProviderAddresses, error) {
    54  	if inst.base.Guest == nil {
    55  		return nil, nil
    56  	}
    57  	res := make([]corenetwork.ProviderAddress, 0, len(inst.base.Guest.Net))
    58  	for _, net := range inst.base.Guest.Net {
    59  		for _, ip := range net.IpAddress {
    60  			res = append(res, corenetwork.NewMachineAddress(ip).AsProviderAddress())
    61  		}
    62  	}
    63  	return res, nil
    64  }
    65  
    66  // firewall stuff
    67  
    68  // OpenPorts opens the given ports on the instance, which
    69  // should have been started with the given machine id.
    70  func (inst *environInstance) OpenPorts(ctx context.ProviderCallContext, machineID string, rules firewall.IngressRules) error {
    71  	return inst.changeIngressRules(ctx, true, rules)
    72  }
    73  
    74  // ClosePorts closes the given ports on the instance, which
    75  // should have been started with the given machine id.
    76  func (inst *environInstance) ClosePorts(ctx context.ProviderCallContext, machineID string, rules firewall.IngressRules) error {
    77  	return inst.changeIngressRules(ctx, false, rules)
    78  }
    79  
    80  // IngressRules returns the set of ports open on the instance, which
    81  // should have been started with the given machine id.
    82  func (inst *environInstance) IngressRules(ctx context.ProviderCallContext, machineID string) (firewall.IngressRules, error) {
    83  	_, client, err := inst.getInstanceConfigurator(ctx)
    84  	if err != nil {
    85  		return nil, errors.Trace(err)
    86  	}
    87  	return client.FindIngressRules()
    88  }
    89  
    90  func (inst *environInstance) changeIngressRules(ctx context.ProviderCallContext, insert bool, rules firewall.IngressRules) error {
    91  	if inst.env.ecfg.externalNetwork() == "" {
    92  		// Open/Close port without an externalNetwork defined is treated as a no-op.
    93  		// We don't firewall the internal network, and without an external network we don't have any iptables rules
    94  		// to define.
    95  		logger.Warningf("ingress rules changing without an external network defined, no changes will be made")
    96  		return nil
    97  	}
    98  	addresses, client, err := inst.getInstanceConfigurator(ctx)
    99  	if err != nil {
   100  		return errors.Trace(err)
   101  	}
   102  
   103  	for _, addr := range addresses {
   104  		if addr.Type == corenetwork.IPv6Address || addr.Scope != corenetwork.ScopePublic {
   105  			// TODO(axw) support firewalling IPv6
   106  			continue
   107  		}
   108  		if err := client.ChangeIngressRules(addr.Value, insert, rules); err != nil {
   109  			return errors.Trace(err)
   110  		}
   111  	}
   112  	return nil
   113  }
   114  
   115  func (inst *environInstance) getInstanceConfigurator(
   116  	ctx context.ProviderCallContext,
   117  ) ([]corenetwork.ProviderAddress, common.InstanceConfigurator, error) {
   118  	addresses, err := inst.Addresses(ctx)
   119  	if err != nil {
   120  		return nil, nil, errors.Trace(err)
   121  	}
   122  
   123  	var localAddr string
   124  	for _, addr := range addresses {
   125  		if addr.Scope == corenetwork.ScopeCloudLocal {
   126  			localAddr = addr.Value
   127  			break
   128  		}
   129  	}
   130  
   131  	client := common.NewSshInstanceConfigurator(localAddr)
   132  	return addresses, client, err
   133  }