github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/client/serviceregistration/address.go (about) 1 package serviceregistration 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "github.com/hashicorp/nomad/nomad/structs" 8 "github.com/hashicorp/nomad/plugins/drivers" 9 ) 10 11 // GetAddress returns the IP (or custom advertise address) and port to use for a 12 // service or check registration. If no port label is specified (an empty value) 13 // and no custom address is specified, zero values are returned because no address 14 // could be resolved. 15 func GetAddress( 16 address, // custom address, if set 17 addressMode, 18 portLabel string, 19 networks structs.Networks, 20 driverNet *drivers.DriverNetwork, 21 ports structs.AllocatedPorts, 22 netStatus *structs.AllocNetworkStatus, 23 ) (string, int, error) { 24 switch addressMode { 25 case structs.AddressModeAuto: 26 switch { 27 case address != "": 28 // No port no problem, just return the advertise address. 29 if portLabel == "" { 30 return address, 0, nil 31 } 32 // A custom advertise address can be used with a port map; using the 33 // Value and ignoring the IP. The routing from your custom address to 34 // the group network address is DIY. (e.g. EC2 public address) 35 if mapping, exists := ports.Get(portLabel); exists { 36 return address, mapping.Value, nil 37 } 38 // If not a port map we can interpolate a numeric port for you. 39 port, err := strconv.Atoi(portLabel) 40 if err != nil { 41 return "", 0, fmt.Errorf("invalid port: %q: not a valid port mapping or numeric port", portLabel) 42 } 43 return address, port, nil 44 case driverNet.Advertise(): 45 return GetAddress("", structs.AddressModeDriver, portLabel, networks, driverNet, ports, netStatus) 46 default: 47 return GetAddress("", structs.AddressModeHost, portLabel, networks, driverNet, ports, netStatus) 48 } 49 case structs.AddressModeHost: 50 // Cannot use address mode host with custom advertise address. 51 if address != "" { 52 return "", 0, fmt.Errorf("cannot use custom advertise address with %q address mode", structs.AddressModeHost) 53 } 54 55 if portLabel == "" { 56 if len(networks) != 1 { 57 // If no networks are specified return zero 58 // values. Consul will advertise the host IP 59 // with no port. This is the pre-0.7.1 behavior 60 // some people rely on. 61 return "", 0, nil 62 } 63 return networks[0].IP, 0, nil 64 } 65 66 // Default path: use host ip:port 67 // Try finding port in the AllocatedPorts struct first 68 // Check in Networks struct for backwards compatibility if not found 69 mapping, ok := ports.Get(portLabel) 70 if !ok { 71 mapping = networks.Port(portLabel) 72 if mapping.Value > 0 { 73 return mapping.HostIP, mapping.Value, nil 74 } 75 76 // If port isn't a label, try to parse it as a literal port number 77 port, err := strconv.Atoi(portLabel) 78 if err != nil { 79 // Don't include Atoi error message as user likely 80 // never intended it to be a numeric and it creates a 81 // confusing error message 82 return "", 0, fmt.Errorf("invalid port %q: port label not found", portLabel) 83 } 84 if port <= 0 { 85 return "", 0, fmt.Errorf("invalid port: %q: port must be >0", portLabel) 86 } 87 88 // A number was given which will use the Consul agent's address and the given port 89 // Returning a blank string as an address will use the Consul agent's address 90 return "", port, nil 91 } 92 return mapping.HostIP, mapping.Value, nil 93 94 case structs.AddressModeDriver: 95 // Cannot use address mode driver with custom advertise address. 96 if address != "" { 97 return "", 0, fmt.Errorf("cannot use custom advertise address with %q address mode", structs.AddressModeDriver) 98 } 99 100 // Require a driver network if driver address mode is used 101 if driverNet == nil { 102 return "", 0, fmt.Errorf(`cannot use address_mode="driver": no driver network exists`) 103 } 104 105 // If no port label is specified just return the IP 106 if portLabel == "" { 107 return driverNet.IP, 0, nil 108 } 109 110 // If the port is a label, use the driver's port (not the host's) 111 if port, ok := ports.Get(portLabel); ok { 112 return driverNet.IP, port.To, nil 113 } 114 115 // Check if old style driver portmap is used 116 if port, ok := driverNet.PortMap[portLabel]; ok { 117 return driverNet.IP, port, nil 118 } 119 120 // If port isn't a label, try to parse it as a literal port number 121 port, err := strconv.Atoi(portLabel) 122 if err != nil { 123 // Don't include Atoi error message as user likely 124 // never intended it to be a numeric and it creates a 125 // confusing error message 126 return "", 0, fmt.Errorf("invalid port label %q: port labels in driver address_mode must be numeric or in the driver's port map", portLabel) 127 } 128 if port <= 0 { 129 return "", 0, fmt.Errorf("invalid port: %q: port must be >0", portLabel) 130 } 131 132 return driverNet.IP, port, nil 133 134 case structs.AddressModeAlloc: 135 // Cannot use address mode alloc with custom advertise address. 136 if address != "" { 137 return "", 0, fmt.Errorf("cannot use custom advertise address with %q address mode", structs.AddressModeAlloc) 138 } 139 140 // Going to need a network for this. 141 if netStatus == nil { 142 return "", 0, fmt.Errorf(`cannot use address_mode="alloc": no allocation network status reported`) 143 } 144 145 // If no port label is specified just return the IP 146 if portLabel == "" { 147 return netStatus.Address, 0, nil 148 } 149 150 // If port is a label and is found then return it 151 if port, ok := ports.Get(portLabel); ok { 152 // Use port.To value unless not set 153 if port.To > 0 { 154 return netStatus.Address, port.To, nil 155 } 156 return netStatus.Address, port.Value, nil 157 } 158 159 // Check if port is a literal number 160 port, err := strconv.Atoi(portLabel) 161 if err != nil { 162 // User likely specified wrong port label here 163 return "", 0, fmt.Errorf("invalid port %q: port label not found or is not numeric", portLabel) 164 } 165 if port <= 0 { 166 return "", 0, fmt.Errorf("invalid port: %q: port must be >0", portLabel) 167 } 168 return netStatus.Address, port, nil 169 170 default: 171 // Shouldn't happen due to validation, but enforce invariants 172 return "", 0, fmt.Errorf("invalid address mode %q", addressMode) 173 } 174 }