github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/equinix/instance.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package equinix 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 "github.com/packethost/packngo" 11 12 "github.com/juju/juju/core/instance" 13 "github.com/juju/juju/core/network" 14 corenetwork "github.com/juju/juju/core/network" 15 "github.com/juju/juju/core/network/firewall" 16 "github.com/juju/juju/core/status" 17 "github.com/juju/juju/environs/context" 18 "github.com/juju/juju/environs/instances" 19 "github.com/juju/juju/provider/common" 20 ) 21 22 type equinixDevice struct { 23 e *environ 24 25 *packngo.Device 26 newInstanceConfigurator func(string) common.InstanceConfigurator 27 } 28 29 var ( 30 _ instances.Instance = (*equinixDevice)(nil) 31 _ instances.InstanceFirewaller = (*equinixDevice)(nil) 32 ) 33 34 // newInstance returns a new equinixDevice 35 func newInstance(raw *packngo.Device, env *environ) *equinixDevice { 36 return &equinixDevice{ 37 Device: raw, 38 e: env, 39 newInstanceConfigurator: common.NewSshInstanceConfigurator, 40 } 41 } 42 43 func (device *equinixDevice) String() string { 44 return device.ID 45 } 46 47 func (device *equinixDevice) Id() instance.Id { 48 return instance.Id(device.ID) 49 } 50 51 func (device *equinixDevice) Status(ctx context.ProviderCallContext) instance.Status { 52 var jujuStatus status.Status 53 54 switch device.State { 55 case Active: 56 jujuStatus = status.Running 57 case Provisioning: 58 jujuStatus = status.Pending 59 case ShuttingDown, Stopped, Stopping, Terminated: 60 jujuStatus = status.Empty 61 default: 62 jujuStatus = status.Empty 63 } 64 65 return instance.Status{ 66 Status: jujuStatus, 67 Message: device.State, 68 } 69 } 70 71 // Addresses implements network.Addresses() returning generic address 72 // details for the instance, and requerying the equinix api if required. 73 func (device *equinixDevice) Addresses(ctx context.ProviderCallContext) (corenetwork.ProviderAddresses, error) { 74 var addresses []corenetwork.ProviderAddress 75 76 for _, netw := range device.Network { 77 address := corenetwork.ProviderAddress{} 78 address.Value = netw.Address 79 address.CIDR = fmt.Sprintf("%s/%d", netw.Network, netw.CIDR) 80 81 if netw.Public { 82 address.Scope = corenetwork.ScopePublic 83 } else { 84 address.Scope = corenetwork.ScopeCloudLocal 85 } 86 87 if netw.AddressFamily == 4 { 88 address.Type = network.IPv4Address 89 } else { 90 address.Type = network.IPv6Address 91 logger.Infof("skipping IPv6 Address %s", netw.Address) 92 93 continue 94 } 95 96 addresses = append(addresses, address) 97 } 98 99 return addresses, nil 100 } 101 102 // OpenPorts (InstanceFirewaller) ensures that the input ingress rule is 103 // permitted for machine with the input ID. 104 func (device *equinixDevice) OpenPorts(ctx context.ProviderCallContext, _ string, rules firewall.IngressRules) error { 105 client, err := device.getInstanceConfigurator(ctx) 106 if err != nil { 107 return errors.Trace(err) 108 } 109 return errors.Trace(client.ChangeIngressRules("", true, rules)) 110 } 111 112 // OpenPorts (InstanceFirewaller) ensures that the input ingress rule is 113 // restricted for machine with the input ID. 114 func (device *equinixDevice) ClosePorts(ctx context.ProviderCallContext, _ string, rules firewall.IngressRules) error { 115 client, err := device.getInstanceConfigurator(ctx) 116 if err != nil { 117 return errors.Trace(err) 118 } 119 return errors.Trace(client.ChangeIngressRules("", false, rules)) 120 } 121 122 // IngressRules (InstanceFirewaller) returns the ingress rules that have been 123 // applied to the input machine ID. 124 func (device *equinixDevice) IngressRules(ctx context.ProviderCallContext, _ string) (firewall.IngressRules, error) { 125 client, err := device.getInstanceConfigurator(ctx) 126 if err != nil { 127 return nil, errors.Trace(err) 128 } 129 130 rules, err := client.FindIngressRules() 131 return rules, errors.Trace(err) 132 } 133 134 func (device *equinixDevice) getInstanceConfigurator( 135 ctx context.ProviderCallContext, 136 ) (common.InstanceConfigurator, error) { 137 addresses, err := device.Addresses(ctx) 138 if err != nil { 139 return nil, errors.Trace(err) 140 } 141 142 // Try to find a public address. 143 // Different models use different VCNs (and therefore subnets), 144 // so the cloud-local IPs are no good if a controller is trying to 145 // configure an instance in another model. 146 for _, addr := range addresses { 147 if addr.Scope == corenetwork.ScopePublic { 148 return device.newInstanceConfigurator(addr.Value), nil 149 } 150 } 151 152 return nil, errors.NotFoundf("public address for instance %q", device.Id()) 153 }