mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
Add AllocIPv6 option to allow IPv6 address being used for service registration (#25632)
Fixes #25627 by adding an extra `alloc_advertise_ipv6` option similar to the `AdvertiseIPv6Addr` with the docker driver config. Fixes: https://github.com/hashicorp/nomad/issues/25627
This commit is contained in:
3
.changelog/25632.txt
Normal file
3
.changelog/25632.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
consul: Add AllocIPv6 option to allow IPv6 address being used for service registration
|
||||
```
|
||||
@@ -134,7 +134,7 @@ func GetAddress(
|
||||
|
||||
return driverNet.IP, port, nil
|
||||
|
||||
case structs.AddressModeAlloc:
|
||||
case structs.AddressModeAlloc, structs.AddressModeAllocIPv6:
|
||||
// Cannot use address mode alloc with custom advertise address.
|
||||
if address != "" {
|
||||
return "", 0, fmt.Errorf("cannot use custom advertise address with %q address mode", structs.AddressModeAlloc)
|
||||
@@ -147,16 +147,17 @@ func GetAddress(
|
||||
|
||||
// If no port label is specified just return the IP
|
||||
if portLabel == "" {
|
||||
return netStatus.Address, 0, nil
|
||||
return getAddressPort(addressMode, netStatus, 0)
|
||||
}
|
||||
|
||||
// If port is a label and is found then return it
|
||||
if port, ok := ports.Get(portLabel); ok {
|
||||
// Use port.To value unless not set
|
||||
if port.To > 0 {
|
||||
return netStatus.Address, port.To, nil
|
||||
return getAddressPort(addressMode, netStatus, port.To)
|
||||
}
|
||||
return netStatus.Address, port.Value, nil
|
||||
|
||||
return getAddressPort(addressMode, netStatus, port.Value)
|
||||
}
|
||||
|
||||
// Check if port is a literal number
|
||||
@@ -168,10 +169,19 @@ func GetAddress(
|
||||
if port <= 0 {
|
||||
return "", 0, fmt.Errorf("invalid port: %q: port must be >0", portLabel)
|
||||
}
|
||||
return netStatus.Address, port, nil
|
||||
|
||||
return getAddressPort(addressMode, netStatus, port)
|
||||
default:
|
||||
// Shouldn't happen due to validation, but enforce invariants
|
||||
return "", 0, fmt.Errorf("invalid address mode %q", addressMode)
|
||||
}
|
||||
}
|
||||
|
||||
// getAddressPort is a helper function to return the IPv6 or IPv4 address based on the addressMode
|
||||
func getAddressPort(addressMode string, netStatus *structs.AllocNetworkStatus, port int) (string, int, error) {
|
||||
if addressMode == structs.AddressModeAllocIPv6 {
|
||||
return netStatus.AddressIPv6, port, nil
|
||||
}
|
||||
|
||||
return netStatus.Address, port, nil
|
||||
}
|
||||
|
||||
@@ -298,6 +298,26 @@ func Test_GetAddress(t *testing.T) {
|
||||
expIP: "172.26.0.1",
|
||||
expPort: 6379,
|
||||
},
|
||||
{
|
||||
name: "Alloc",
|
||||
mode: structs.AddressModeAllocIPv6,
|
||||
portLabel: "db",
|
||||
ports: []structs.AllocatedPortMapping{
|
||||
{
|
||||
Label: "db",
|
||||
Value: 12345,
|
||||
To: 6379,
|
||||
HostIP: HostIP,
|
||||
},
|
||||
},
|
||||
status: &structs.AllocNetworkStatus{
|
||||
InterfaceName: "eth0",
|
||||
Address: "172.26.0.1",
|
||||
AddressIPv6: "2001:db8::8a2e:370:7334",
|
||||
},
|
||||
expIP: "2001:db8::8a2e:370:7334",
|
||||
expPort: 6379,
|
||||
},
|
||||
{
|
||||
name: "Alloc no to value",
|
||||
mode: structs.AddressModeAlloc,
|
||||
@@ -383,6 +403,12 @@ func Test_GetAddress(t *testing.T) {
|
||||
advertise: "example.com",
|
||||
expErr: `cannot use custom advertise address with "alloc" address mode`,
|
||||
},
|
||||
{
|
||||
name: "Address with alloc IPv6 mode",
|
||||
mode: structs.AddressModeAllocIPv6,
|
||||
advertise: "example.com",
|
||||
expErr: `cannot use custom advertise address with "alloc" address mode`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
@@ -40,7 +40,7 @@ type Query struct {
|
||||
|
||||
Timeout time.Duration // connection / request timeout
|
||||
|
||||
AddressMode string // host, driver, or alloc
|
||||
AddressMode string // host, driver, alloc or alloc_advertise_ipv6
|
||||
PortLabel string // label or value
|
||||
|
||||
Protocol string // http checks only (http or https)
|
||||
|
||||
@@ -305,7 +305,7 @@ func (sc *ServiceCheck) validateCommon(allowableTypes []string) error {
|
||||
|
||||
// validate address_mode
|
||||
switch sc.AddressMode {
|
||||
case "", AddressModeHost, AddressModeDriver, AddressModeAlloc:
|
||||
case "", AddressModeHost, AddressModeDriver, AddressModeAlloc, AddressModeAllocIPv6:
|
||||
// Ok
|
||||
case AddressModeAuto:
|
||||
return fmt.Errorf("invalid address_mode %q - %s only valid for services", sc.AddressMode, AddressModeAuto)
|
||||
@@ -562,10 +562,11 @@ func hashHeader(h hash.Hash, m map[string][]string) {
|
||||
}
|
||||
|
||||
const (
|
||||
AddressModeAuto = "auto"
|
||||
AddressModeHost = "host"
|
||||
AddressModeDriver = "driver"
|
||||
AddressModeAlloc = "alloc"
|
||||
AddressModeAuto = "auto"
|
||||
AddressModeHost = "host"
|
||||
AddressModeDriver = "driver"
|
||||
AddressModeAlloc = "alloc"
|
||||
AddressModeAllocIPv6 = "alloc_ipv6"
|
||||
|
||||
// ServiceProviderConsul is the default service provider and the way Nomad
|
||||
// worked before native service discovery.
|
||||
@@ -597,7 +598,8 @@ type Service struct {
|
||||
PortLabel string
|
||||
|
||||
// AddressMode specifies how the address in service registration is
|
||||
// determined. Must be "auto" (default), "host", "driver", or "alloc".
|
||||
// determined. Must be "auto" (default), "host", "driver", "alloc" or
|
||||
// "alloc_ipv6".
|
||||
AddressMode string
|
||||
|
||||
// Address enables explicitly setting a custom address to use in service
|
||||
@@ -768,7 +770,7 @@ func (s *Service) Validate() error {
|
||||
|
||||
switch s.AddressMode {
|
||||
case "", AddressModeAuto:
|
||||
case AddressModeHost, AddressModeDriver, AddressModeAlloc:
|
||||
case AddressModeHost, AddressModeDriver, AddressModeAlloc, AddressModeAllocIPv6:
|
||||
if s.Address != "" {
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("Service address_mode must be %q if address is set", AddressModeAuto))
|
||||
}
|
||||
|
||||
@@ -8313,6 +8313,10 @@ func validateServices(t *Task, tgNetworks Networks) error {
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("service %q cannot use address_mode=\"alloc\", only services defined in a \"group\" block can use this mode", service.Name))
|
||||
}
|
||||
|
||||
if service.AddressMode == AddressModeAllocIPv6 {
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("service %q cannot use address_mode=\"alloc_ipv6\", only services defined in a \"group\" block can use this mode", service.Name))
|
||||
}
|
||||
|
||||
// Ensure that services with the same name are not being registered for
|
||||
// the same port
|
||||
if _, ok := knownServices[service.Name+service.PortLabel]; ok {
|
||||
@@ -8350,6 +8354,10 @@ func validateServices(t *Task, tgNetworks Networks) error {
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("check %q cannot use address_mode=\"alloc\", only checks defined in a \"group\" service block can use this mode", service.Name))
|
||||
}
|
||||
|
||||
if check.AddressMode == AddressModeAllocIPv6 {
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("check %q cannot use address_mode=\"alloc_ipv6\", only checks defined in a \"group\" service block can use this mode", service.Name))
|
||||
}
|
||||
|
||||
if !check.RequiresPort() {
|
||||
// No need to continue validating check if it doesn't need a port
|
||||
continue
|
||||
|
||||
@@ -150,6 +150,8 @@ service mesh][connect] integration.
|
||||
If a `to` value is not set, the port falls back to using the allocated host port. The `port`
|
||||
field may be a numeric port or a port label specified in the same group's network block.
|
||||
|
||||
- `alloc_ipv6` - Same as `alloc` but use the IPv6 address in case of dual-stack or IPv6-only.
|
||||
|
||||
- `driver` - Advertise the port determined by the driver (e.g. Docker).
|
||||
The `port` may be a numeric port or a port label specified in the driver's
|
||||
`ports` field.
|
||||
@@ -190,7 +192,7 @@ service mesh][connect] integration.
|
||||
- `tagged_addresses` `(map<string|string>` - Specifies custom [tagged addresses][tagged_addresses] to
|
||||
advertise in the Consul service registration. Only available where `provider = "consul"`.
|
||||
|
||||
- `address_mode` `(string: "auto")` - Specifies which address (host, alloc or
|
||||
- `address_mode` `(string: "auto")` - Specifies which address (host, alloc, alloc_ipv6 or
|
||||
driver-specific) this service should advertise. See [below for
|
||||
examples.](#using-driver-address-mode) Valid options are:
|
||||
|
||||
@@ -200,6 +202,8 @@ service mesh][connect] integration.
|
||||
where no port mapping is necessary. This mode can only be set for services which
|
||||
are defined in a "group" block.
|
||||
|
||||
- `alloc_ipv6` - Same as `alloc` but use the IPv6 address in case of dual-stack or IPv6-only.
|
||||
|
||||
- `auto` - Allows the driver to determine whether the host or driver address
|
||||
should be used. Defaults to `host` and only implemented by Docker. If you
|
||||
use a Docker network plugin such as weave, Docker will automatically use
|
||||
|
||||
Reference in New Issue
Block a user