open-nomad/nomad/structs/job.go
Seth Hoenig 1593963cd1
servicedisco: implicit constraint for nomad v1.4 when using nsd checks (#14868)
This PR adds a jobspec mutator to constrain jobs making use of checks
in the nomad service provider to nomad clients of at least v1.4.0.

Before, in a mixed client version cluster it was possible to submit
an NSD job making use of checks and for that job to land on an older,
incompatible client node.

Closes #14862
2022-10-11 08:21:42 -05:00

117 lines
3.7 KiB
Go

package structs
import (
"github.com/hashicorp/go-set"
)
const (
// JobServiceRegistrationsRPCMethod is the RPC method for listing all
// service registrations assigned to a specific namespaced job.
//
// Args: JobServiceRegistrationsRequest
// Reply: JobServiceRegistrationsResponse
JobServiceRegistrationsRPCMethod = "Job.GetServiceRegistrations"
)
// JobServiceRegistrationsRequest is the request object used to list all
// service registrations belonging to the specified Job.ID.
type JobServiceRegistrationsRequest struct {
JobID string
QueryOptions
}
// JobServiceRegistrationsResponse is the response object when performing a
// listing of services belonging to a namespaced job.
type JobServiceRegistrationsResponse struct {
Services []*ServiceRegistration
QueryMeta
}
// NativeServiceDiscoveryUsage tracks which groups make use of the nomad service
// discovery provider, and also which of those groups make use of checks. This
// information will be used to configure implicit constraints on the job.
type NativeServiceDiscoveryUsage struct {
Basic *set.Set[string] // implies v1.3.0 + ${attr.nomad.service_discovery}
Checks *set.Set[string] // implies v1.4.0
}
// Empty returns true if no groups are using native service discovery.
func (u *NativeServiceDiscoveryUsage) Empty() bool {
return u.Basic.Size() == 0 && u.Checks.Size() == 0
}
// RequiredNativeServiceDiscovery identifies which task groups, if any, within
// the job are utilising Nomad native service discovery.
func (j *Job) RequiredNativeServiceDiscovery() *NativeServiceDiscoveryUsage {
basic := set.New[string](10)
checks := set.New[string](10)
for _, tg := range j.TaskGroups {
// It is possible for services using the Nomad provider to be
// configured at the group level, so check here first.
requiresNativeServiceDiscovery(tg.Name, tg.Services, basic, checks)
// Iterate the tasks within the task group to check the services
// configured at this more traditional level.
for _, task := range tg.Tasks {
requiresNativeServiceDiscovery(tg.Name, task.Services, basic, checks)
}
}
return &NativeServiceDiscoveryUsage{
Basic: basic,
Checks: checks,
}
}
// requiresNativeServiceDiscovery identifies whether any of the services passed
// to the function are utilising Nomad native service discovery.
func requiresNativeServiceDiscovery(group string, services []*Service, basic, checks *set.Set[string]) {
for _, tgService := range services {
if tgService.Provider == ServiceProviderNomad {
basic.Insert(group)
if len(tgService.Checks) > 0 {
checks.Insert(group)
}
}
}
}
// RequiredConsulServiceDiscovery identifies which task groups, if any, within
// the job are utilising Consul service discovery.
func (j *Job) RequiredConsulServiceDiscovery() map[string]bool {
groups := make(map[string]bool)
for _, tg := range j.TaskGroups {
// It is possible for services using the Consul provider to be
// configured at the task group level, so check here first. This is
// a requirement for Consul Connect services.
if requiresConsulServiceDiscovery(tg.Services) {
groups[tg.Name] = true
continue
}
// Iterate the tasks within the task group to check the services
// configured at this more traditional level.
for _, task := range tg.Tasks {
if requiresConsulServiceDiscovery(task.Services) {
groups[tg.Name] = true
continue
}
}
}
return groups
}
// requiresConsulServiceDiscovery identifies whether any of the services passed
// to the function are utilising Consul service discovery.
func requiresConsulServiceDiscovery(services []*Service) bool {
for _, tgService := range services {
if tgService.Provider == ServiceProviderConsul || tgService.Provider == "" {
return true
}
}
return false
}