Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/25632.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
consul: Add AllocIPv6 option to allow IPv6 address being used for service registration
```
20 changes: 15 additions & 5 deletions client/serviceregistration/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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
}
26 changes: 26 additions & 0 deletions client/serviceregistration/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion client/serviceregistration/checks/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 9 additions & 7 deletions nomad/structs/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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))
}
Expand Down
8 changes: 8 additions & 0 deletions nomad/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion website/content/docs/job-specification/service.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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:

Expand All @@ -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
Expand Down
Loading