Merge branch v3.0 into master
This commit is contained in:
commit
9d8fd24730
119 changed files with 16917 additions and 500 deletions
|
@ -39,6 +39,9 @@ type Middleware struct {
|
|||
GrpcWeb *GrpcWeb `json:"grpcWeb,omitempty" toml:"grpcWeb,omitempty" yaml:"grpcWeb,omitempty" export:"true"`
|
||||
|
||||
Plugin map[string]PluginConf `json:"plugin,omitempty" toml:"plugin,omitempty" yaml:"plugin,omitempty" export:"true"`
|
||||
|
||||
// Gateway API HTTPRoute filters middlewares.
|
||||
RequestHeaderModifier *RequestHeaderModifier `json:"requestHeaderModifier,omitempty" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
@ -420,11 +423,11 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
|
|||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// IPWhiteList holds the IP whitelist middleware configuration.
|
||||
// This middleware accepts / refuses requests based on the client IP.
|
||||
// This middleware limits allowed requests based on the client IP.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipwhitelist/
|
||||
// Deprecated: please use IPAllowList instead.
|
||||
type IPWhiteList struct {
|
||||
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation).
|
||||
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). Required.
|
||||
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
|
||||
IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||
}
|
||||
|
@ -432,7 +435,7 @@ type IPWhiteList struct {
|
|||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// IPAllowList holds the IP allowlist middleware configuration.
|
||||
// This middleware accepts / refuses requests based on the client IP.
|
||||
// This middleware limits allowed requests based on the client IP.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/
|
||||
type IPAllowList struct {
|
||||
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation).
|
||||
|
@ -673,3 +676,12 @@ type TLSClientCertificateSubjectDNInfo struct {
|
|||
|
||||
// Users holds a list of users.
|
||||
type Users []string
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// RequestHeaderModifier holds the request header modifier configuration.
|
||||
type RequestHeaderModifier struct {
|
||||
Set map[string]string `json:"set,omitempty"`
|
||||
Add map[string]string `json:"add,omitempty"`
|
||||
Remove []string `json:"remove,omitempty"`
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ type TCPIPWhiteList struct {
|
|||
// +k8s:deepcopy-gen=true
|
||||
|
||||
// TCPIPAllowList holds the TCP IPAllowList middleware configuration.
|
||||
// This middleware limits allowed requests based on the client IP.
|
||||
// More info: https://doc.traefik.io/traefik/v3.0/middlewares/tcp/ipallowlist/
|
||||
type TCPIPAllowList struct {
|
||||
// SourceRange defines the allowed IPs (or ranges of allowed IPs by using CIDR notation).
|
||||
SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"`
|
||||
|
|
|
@ -859,6 +859,11 @@ func (in *Middleware) DeepCopyInto(out *Middleware) {
|
|||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
if in.RequestHeaderModifier != nil {
|
||||
in, out := &in.RequestHeaderModifier, &out.RequestHeaderModifier
|
||||
*out = new(RequestHeaderModifier)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1067,6 +1072,41 @@ func (in *ReplacePathRegex) DeepCopy() *ReplacePathRegex {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RequestHeaderModifier) DeepCopyInto(out *RequestHeaderModifier) {
|
||||
*out = *in
|
||||
if in.Set != nil {
|
||||
in, out := &in.Set, &out.Set
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Add != nil {
|
||||
in, out := &in.Add, &out.Add
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Remove != nil {
|
||||
in, out := &in.Remove, &out.Remove
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestHeaderModifier.
|
||||
func (in *RequestHeaderModifier) DeepCopy() *RequestHeaderModifier {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RequestHeaderModifier)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResponseForwarding) DeepCopyInto(out *ResponseForwarding) {
|
||||
*out = *in
|
||||
|
|
|
@ -42,6 +42,9 @@ const (
|
|||
// DefaultIdleTimeout before closing an idle connection.
|
||||
DefaultIdleTimeout = 180 * time.Second
|
||||
|
||||
// DefaultReadTimeout defines the default maximum duration for reading the entire request, including the body.
|
||||
DefaultReadTimeout = 60 * time.Second
|
||||
|
||||
// DefaultAcmeCAServer is the default ACME API endpoint.
|
||||
DefaultAcmeCAServer = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
|
||||
|
@ -164,6 +167,7 @@ type RespondingTimeouts struct {
|
|||
|
||||
// SetDefaults sets the default values.
|
||||
func (a *RespondingTimeouts) SetDefaults() {
|
||||
a.ReadTimeout = ptypes.Duration(DefaultReadTimeout)
|
||||
a.IdleTimeout = ptypes.Duration(DefaultIdleTimeout)
|
||||
}
|
||||
|
||||
|
|
56
pkg/middlewares/headermodifier/request_header_modifier.go
Normal file
56
pkg/middlewares/headermodifier/request_header_modifier.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package headermodifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
const typeName = "RequestHeaderModifier"
|
||||
|
||||
// requestHeaderModifier is a middleware used to modify the headers of an HTTP request.
|
||||
type requestHeaderModifier struct {
|
||||
next http.Handler
|
||||
name string
|
||||
|
||||
set map[string]string
|
||||
add map[string]string
|
||||
remove []string
|
||||
}
|
||||
|
||||
// NewRequestHeaderModifier creates a new request header modifier middleware.
|
||||
func NewRequestHeaderModifier(ctx context.Context, next http.Handler, config dynamic.RequestHeaderModifier, name string) (http.Handler, error) {
|
||||
logger := middlewares.GetLogger(ctx, name, typeName)
|
||||
logger.Debug().Msg("Creating middleware")
|
||||
|
||||
return &requestHeaderModifier{
|
||||
next: next,
|
||||
name: name,
|
||||
set: config.Set,
|
||||
add: config.Add,
|
||||
remove: config.Remove,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *requestHeaderModifier) GetTracingInformation() (string, string, trace.SpanKind) {
|
||||
return r.name, typeName, trace.SpanKindUnspecified
|
||||
}
|
||||
|
||||
func (r *requestHeaderModifier) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
for headerName, headerValue := range r.set {
|
||||
req.Header.Set(headerName, headerValue)
|
||||
}
|
||||
|
||||
for headerName, headerValue := range r.add {
|
||||
req.Header.Add(headerName, headerValue)
|
||||
}
|
||||
|
||||
for _, headerName := range r.remove {
|
||||
req.Header.Del(headerName)
|
||||
}
|
||||
|
||||
r.next.ServeHTTP(rw, req)
|
||||
}
|
121
pkg/middlewares/headermodifier/request_header_modifier_test.go
Normal file
121
pkg/middlewares/headermodifier/request_header_modifier_test.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package headermodifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/testhelpers"
|
||||
)
|
||||
|
||||
func TestRequestHeaderModifier(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
config dynamic.RequestHeaderModifier
|
||||
requestHeaders http.Header
|
||||
expectedHeaders http.Header
|
||||
}{
|
||||
{
|
||||
desc: "no config",
|
||||
config: dynamic.RequestHeaderModifier{},
|
||||
expectedHeaders: map[string][]string{},
|
||||
},
|
||||
{
|
||||
desc: "set header",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Set: map[string]string{"Foo": "Bar"},
|
||||
},
|
||||
expectedHeaders: map[string][]string{"Foo": {"Bar"}},
|
||||
},
|
||||
{
|
||||
desc: "set header with existing headers",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Set: map[string]string{"Foo": "Bar"},
|
||||
},
|
||||
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foo"}},
|
||||
expectedHeaders: map[string][]string{"Foo": {"Bar"}, "Bar": {"Foo"}},
|
||||
},
|
||||
{
|
||||
desc: "set multiple headers with existing headers",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Set: map[string]string{"Foo": "Bar", "Bar": "Foo"},
|
||||
},
|
||||
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foobar"}},
|
||||
expectedHeaders: map[string][]string{"Foo": {"Bar"}, "Bar": {"Foo"}},
|
||||
},
|
||||
{
|
||||
desc: "add header",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Add: map[string]string{"Foo": "Bar"},
|
||||
},
|
||||
expectedHeaders: map[string][]string{"Foo": {"Bar"}},
|
||||
},
|
||||
{
|
||||
desc: "add header with existing headers",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Add: map[string]string{"Foo": "Bar"},
|
||||
},
|
||||
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foo"}},
|
||||
expectedHeaders: map[string][]string{"Foo": {"Baz", "Bar"}, "Bar": {"Foo"}},
|
||||
},
|
||||
{
|
||||
desc: "add multiple headers with existing headers",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Add: map[string]string{"Foo": "Bar", "Bar": "Foo"},
|
||||
},
|
||||
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foobar"}},
|
||||
expectedHeaders: map[string][]string{"Foo": {"Baz", "Bar"}, "Bar": {"Foobar", "Foo"}},
|
||||
},
|
||||
{
|
||||
desc: "remove header",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Remove: []string{"Foo"},
|
||||
},
|
||||
expectedHeaders: map[string][]string{},
|
||||
},
|
||||
{
|
||||
desc: "remove header with existing headers",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Remove: []string{"Foo"},
|
||||
},
|
||||
requestHeaders: map[string][]string{"Foo": {"Baz"}, "Bar": {"Foo"}},
|
||||
expectedHeaders: map[string][]string{"Bar": {"Foo"}},
|
||||
},
|
||||
{
|
||||
desc: "remove multiple headers with existing headers",
|
||||
config: dynamic.RequestHeaderModifier{
|
||||
Remove: []string{"Foo", "Bar"},
|
||||
},
|
||||
requestHeaders: map[string][]string{"Foo": {"Bar"}, "Bar": {"Foo"}, "Baz": {"Bar"}},
|
||||
expectedHeaders: map[string][]string{"Baz": {"Bar"}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var gotHeaders http.Header
|
||||
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotHeaders = r.Header
|
||||
})
|
||||
|
||||
handler, err := NewRequestHeaderModifier(context.Background(), next, test.config, "foo-request-header-modifier")
|
||||
require.NoError(t, err)
|
||||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||
if test.requestHeaders != nil {
|
||||
req.Header = test.requestHeaders
|
||||
}
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
handler.ServeHTTP(resp, req)
|
||||
|
||||
assert.Equal(t, test.expectedHeaders, gotHeaders)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -141,7 +141,7 @@ func newMiddlewareBuilder(ctx context.Context, goPath string, manifest *Manifest
|
|||
case runtimeYaegi, "":
|
||||
i, err := newInterpreter(ctx, goPath, manifest.Import)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to craete Yaegi intepreter: %w", err)
|
||||
return nil, fmt.Errorf("failed to create Yaegi interpreter: %w", err)
|
||||
}
|
||||
|
||||
return newYaegiMiddlewareBuilder(i, manifest.BasePkg, manifest.Import)
|
||||
|
|
|
@ -11,14 +11,15 @@ import (
|
|||
// CheckFile checks file permissions and content size.
|
||||
func CheckFile(name string) (bool, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
f, err = os.Create(name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return false, f.Chmod(0o600)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
nf, err := os.Create(name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer nf.Close()
|
||||
return false, nf.Chmod(0o600)
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
|
|
@ -135,7 +135,7 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
|||
case event := <-eventsc:
|
||||
if event.Action == "start" ||
|
||||
event.Action == "die" ||
|
||||
strings.HasPrefix(event.Action, "health_status") {
|
||||
strings.HasPrefix(string(event.Action), "health_status") {
|
||||
startStopHandle(event)
|
||||
}
|
||||
case err := <-errc:
|
||||
|
|
|
@ -319,7 +319,7 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI
|
|||
}
|
||||
|
||||
var mach *machine
|
||||
if len(task.Attachments) != 0 {
|
||||
if aws.StringValue(taskDef.NetworkMode) == "awsvpc" && len(task.Attachments) != 0 {
|
||||
if len(container.NetworkInterfaces) == 0 {
|
||||
logger.Error().Msgf("Skip container %s: no network interfaces", aws.StringValue(container.Name))
|
||||
continue
|
||||
|
|
|
@ -645,6 +645,10 @@ func createCircuitBreakerMiddleware(circuitBreaker *traefikv1alpha1.CircuitBreak
|
|||
}
|
||||
}
|
||||
|
||||
if circuitBreaker.ResponseCode != 0 {
|
||||
cb.ResponseCode = circuitBreaker.ResponseCode
|
||||
}
|
||||
|
||||
return cb, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ type CircuitBreaker struct {
|
|||
FallbackDuration *intstr.IntOrString `json:"fallbackDuration,omitempty" toml:"fallbackDuration,omitempty" yaml:"fallbackDuration,omitempty" export:"true"`
|
||||
// RecoveryDuration is the duration for which the circuit breaker will try to recover (as soon as it is in recovering state).
|
||||
RecoveryDuration *intstr.IntOrString `json:"recoveryDuration,omitempty" toml:"recoveryDuration,omitempty" yaml:"recoveryDuration,omitempty" export:"true"`
|
||||
// ResponseCode is the status code that the circuit breaker will return while it is in the open state.
|
||||
ResponseCode int `json:"responseCode,omitempty" toml:"responseCode,omitempty" yaml:"responseCode,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen=true
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
kind: GatewayClass
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway-class
|
||||
spec:
|
||||
controllerName: traefik.io/gateway-controller
|
||||
|
||||
---
|
||||
kind: Gateway
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: my-gateway
|
||||
namespace: default
|
||||
spec:
|
||||
gatewayClassName: my-gateway-class
|
||||
listeners: # Use GatewayClass defaults for listener definition.
|
||||
- name: http
|
||||
protocol: HTTP
|
||||
port: 80
|
||||
allowedRoutes:
|
||||
kinds:
|
||||
- kind: HTTPRoute
|
||||
group: gateway.networking.k8s.io
|
||||
namespaces:
|
||||
from: Same
|
||||
|
||||
---
|
||||
kind: HTTPRoute
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
metadata:
|
||||
name: http-app-1
|
||||
namespace: default
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: my-gateway
|
||||
kind: Gateway
|
||||
group: gateway.networking.k8s.io
|
||||
hostnames:
|
||||
- "example.org"
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 1
|
||||
kind: Service
|
||||
group: ""
|
||||
filters:
|
||||
- type: RequestHeaderModifier
|
||||
requestHeaderModifier:
|
||||
set:
|
||||
- name: X-Foo
|
||||
value: Bar
|
||||
add:
|
||||
- name: X-Bar
|
||||
value: Foo
|
||||
remove:
|
||||
- X-Baz
|
|
@ -269,3 +269,16 @@ spec:
|
|||
- protocol: TCP
|
||||
port: 10000
|
||||
name: tcp-2
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: status-address
|
||||
namespace: default
|
||||
|
||||
status:
|
||||
loadBalancer:
|
||||
ingress:
|
||||
- hostname: foo.bar
|
||||
- ip: 1.2.3.4
|
||||
|
|
|
@ -58,6 +58,7 @@ type Provider struct {
|
|||
LabelSelector string `description:"Kubernetes label selector to select specific GatewayClasses." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
|
||||
ThrottleDuration ptypes.Duration `description:"Kubernetes refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
|
||||
ExperimentalChannel bool `description:"Toggles Experimental Channel resources support (TCPRoute, TLSRoute...)." json:"experimentalChannel,omitempty" toml:"experimentalChannel,omitempty" yaml:"experimentalChannel,omitempty" export:"true"`
|
||||
StatusAddress *StatusAddress `description:"Defines the Kubernetes Gateway status address." json:"statusAddress,omitempty" toml:"statusAddress,omitempty" yaml:"statusAddress,omitempty" export:"true"`
|
||||
|
||||
EntryPoints map[string]Entrypoint `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
|
||||
|
||||
|
@ -71,6 +72,19 @@ type Provider struct {
|
|||
routerTransform k8s.RouterTransform
|
||||
}
|
||||
|
||||
// StatusAddress holds the Gateway Status address configuration.
|
||||
type StatusAddress struct {
|
||||
IP string `description:"IP used to set Kubernetes Gateway status address." json:"ip,omitempty" toml:"ip,omitempty" yaml:"ip,omitempty"`
|
||||
Hostname string `description:"Hostname used for Kubernetes Gateway status address." json:"hostname,omitempty" toml:"hostname,omitempty" yaml:"hostname,omitempty"`
|
||||
Service ServiceRef `description:"Published Kubernetes Service to copy status addresses from." json:"service,omitempty" toml:"service,omitempty" yaml:"service,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceRef holds a Kubernetes service reference.
|
||||
type ServiceRef struct {
|
||||
Name string `description:"Name of the Kubernetes service." json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `description:"Namespace of the Kubernetes service." json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// BuildFilterFunc returns the name of the filter and the related dynamic.Middleware if needed.
|
||||
type BuildFilterFunc func(name, namespace string) (string, *dynamic.Middleware, error)
|
||||
|
||||
|
@ -368,9 +382,14 @@ func (p *Provider) createGatewayConf(ctx context.Context, client Client, gateway
|
|||
// and cannot be configured on the Gateway.
|
||||
listenerStatuses := p.fillGatewayConf(ctx, client, gateway, conf, tlsConfigs)
|
||||
|
||||
gatewayStatus, errG := p.makeGatewayStatus(gateway, listenerStatuses)
|
||||
addresses, err := p.gatewayAddresses(client)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get Gateway status addresses: %w", err)
|
||||
}
|
||||
|
||||
err := client.UpdateGatewayStatus(gateway, gatewayStatus)
|
||||
gatewayStatus, errG := p.makeGatewayStatus(gateway, listenerStatuses, addresses)
|
||||
|
||||
err = client.UpdateGatewayStatus(gateway, gatewayStatus)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("an error occurred while updating gateway status: %w", err)
|
||||
}
|
||||
|
@ -618,11 +637,8 @@ func (p *Provider) fillGatewayConf(ctx context.Context, client Client, gateway *
|
|||
return listenerStatuses
|
||||
}
|
||||
|
||||
func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listenerStatuses []gatev1.ListenerStatus) (gatev1.GatewayStatus, error) {
|
||||
// As Status.Addresses are not implemented yet, we initialize an empty array to follow the API expectations.
|
||||
gatewayStatus := gatev1.GatewayStatus{
|
||||
Addresses: []gatev1.GatewayStatusAddress{},
|
||||
}
|
||||
func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listenerStatuses []gatev1.ListenerStatus, addresses []gatev1.GatewayStatusAddress) (gatev1.GatewayStatus, error) {
|
||||
gatewayStatus := gatev1.GatewayStatus{Addresses: addresses}
|
||||
|
||||
var result error
|
||||
for i, listener := range listenerStatuses {
|
||||
|
@ -701,6 +717,57 @@ func (p *Provider) makeGatewayStatus(gateway *gatev1.Gateway, listenerStatuses [
|
|||
return gatewayStatus, nil
|
||||
}
|
||||
|
||||
func (p *Provider) gatewayAddresses(client Client) ([]gatev1.GatewayStatusAddress, error) {
|
||||
if p.StatusAddress == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if p.StatusAddress.IP != "" {
|
||||
return []gatev1.GatewayStatusAddress{{
|
||||
Type: ptr.To(gatev1.IPAddressType),
|
||||
Value: p.StatusAddress.IP,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
if p.StatusAddress.Hostname != "" {
|
||||
return []gatev1.GatewayStatusAddress{{
|
||||
Type: ptr.To(gatev1.HostnameAddressType),
|
||||
Value: p.StatusAddress.Hostname,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
svcRef := p.StatusAddress.Service
|
||||
if svcRef.Name != "" && svcRef.Namespace != "" {
|
||||
svc, exists, err := client.GetService(svcRef.Namespace, svcRef.Name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get service: %w", err)
|
||||
}
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("could not find a service with name %s in namespace %s", svcRef.Name, svcRef.Namespace)
|
||||
}
|
||||
|
||||
var addresses []gatev1.GatewayStatusAddress
|
||||
for _, addr := range svc.Status.LoadBalancer.Ingress {
|
||||
switch {
|
||||
case addr.IP != "":
|
||||
addresses = append(addresses, gatev1.GatewayStatusAddress{
|
||||
Type: ptr.To(gatev1.IPAddressType),
|
||||
Value: addr.IP,
|
||||
})
|
||||
|
||||
case addr.Hostname != "":
|
||||
addresses = append(addresses, gatev1.GatewayStatusAddress{
|
||||
Type: ptr.To(gatev1.HostnameAddressType),
|
||||
Value: addr.Hostname,
|
||||
})
|
||||
}
|
||||
}
|
||||
return addresses, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("empty Gateway status address configuration")
|
||||
}
|
||||
|
||||
func (p *Provider) entryPointName(port gatev1.PortNumber, protocol gatev1.ProtocolType) (string, error) {
|
||||
portStr := strconv.FormatInt(int64(port), 10)
|
||||
|
||||
|
@ -1921,6 +1988,11 @@ func (p *Provider) loadMiddlewares(listener gatev1.Listener, namespace string, p
|
|||
}
|
||||
|
||||
middlewares[name] = middleware
|
||||
|
||||
case gatev1.HTTPRouteFilterRequestHeaderModifier:
|
||||
middlewareName := provider.Normalize(fmt.Sprintf("%s-%s-%d", prefix, strings.ToLower(string(filter.Type)), i))
|
||||
middlewares[middlewareName] = createRequestHeaderModifier(filter.RequestHeaderModifier)
|
||||
|
||||
default:
|
||||
// As per the spec:
|
||||
// https://gateway-api.sigs.k8s.io/api-types/httproute/#filters-optional
|
||||
|
@ -1950,6 +2022,28 @@ func (p *Provider) loadHTTPRouteFilterExtensionRef(namespace string, extensionRe
|
|||
return filterFunc(string(extensionRef.Name), namespace)
|
||||
}
|
||||
|
||||
// createRequestHeaderModifier does not enforce/check the configuration,
|
||||
// as the spec indicates that either the webhook or CEL (since v1.0 GA Release) should enforce that.
|
||||
func createRequestHeaderModifier(filter *gatev1.HTTPHeaderFilter) *dynamic.Middleware {
|
||||
sets := map[string]string{}
|
||||
for _, header := range filter.Set {
|
||||
sets[string(header.Name)] = header.Value
|
||||
}
|
||||
|
||||
adds := map[string]string{}
|
||||
for _, header := range filter.Add {
|
||||
adds[string(header.Name)] = header.Value
|
||||
}
|
||||
|
||||
return &dynamic.Middleware{
|
||||
RequestHeaderModifier: &dynamic.RequestHeaderModifier{
|
||||
Set: sets,
|
||||
Add: adds,
|
||||
Remove: filter.Remove,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createRedirectRegexMiddleware(scheme string, filter *gatev1.HTTPRequestRedirectFilter) (*dynamic.Middleware, error) {
|
||||
// Use the HTTPRequestRedirectFilter scheme if defined.
|
||||
filterScheme := scheme
|
||||
|
|
|
@ -1517,6 +1517,75 @@ func TestLoadHTTPRoutes(t *testing.T) {
|
|||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, request header modifier",
|
||||
paths: []string{"services.yml", "httproute/filter_request_header_modifier.yml"},
|
||||
entryPoints: map[string]Entrypoint{"web": {
|
||||
Address: ":80",
|
||||
}},
|
||||
expected: &dynamic.Configuration{
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr",
|
||||
Rule: "Host(`example.org`) && PathPrefix(`/`)",
|
||||
RuleSyntax: "v3",
|
||||
Middlewares: []string{"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestheadermodifier-0"},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{
|
||||
"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-requestheadermodifier-0": {
|
||||
RequestHeaderModifier: &dynamic.RequestHeaderModifier{
|
||||
Set: map[string]string{"X-Foo": "Bar"},
|
||||
Add: map[string]string{"X-Bar": "Foo"},
|
||||
Remove: []string{"X-Baz"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-364ce6ec04c3d49b19c4-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-80",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default-whoami-80": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.1:80",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.2:80",
|
||||
},
|
||||
},
|
||||
PassHostHeader: ptr.To(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, redirect HTTP to HTTPS",
|
||||
paths: []string{"services.yml", "httproute/filter_http_to_https.yml"},
|
||||
|
@ -6227,30 +6296,6 @@ func Test_makeListenerKey(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func hostnamePtr(hostname gatev1.Hostname) *gatev1.Hostname {
|
||||
return &hostname
|
||||
}
|
||||
|
||||
func groupPtr(group gatev1.Group) *gatev1.Group {
|
||||
return &group
|
||||
}
|
||||
|
||||
func sectionNamePtr(sectionName gatev1.SectionName) *gatev1.SectionName {
|
||||
return §ionName
|
||||
}
|
||||
|
||||
func namespacePtr(namespace gatev1.Namespace) *gatev1.Namespace {
|
||||
return &namespace
|
||||
}
|
||||
|
||||
func kindPtr(kind gatev1.Kind) *gatev1.Kind {
|
||||
return &kind
|
||||
}
|
||||
|
||||
func pathMatchTypePtr(p gatev1.PathMatchType) *gatev1.PathMatchType { return &p }
|
||||
|
||||
func headerMatchTypePtr(h gatev1.HeaderMatchType) *gatev1.HeaderMatchType { return &h }
|
||||
|
||||
func Test_referenceGrantMatchesFrom(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -6489,6 +6534,131 @@ func Test_referenceGrantMatchesTo(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_gatewayAddresses(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
statusAddress *StatusAddress
|
||||
paths []string
|
||||
wantErr require.ErrorAssertionFunc
|
||||
want []gatev1.GatewayStatusAddress
|
||||
}{
|
||||
{
|
||||
desc: "nothing",
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
desc: "empty configuration",
|
||||
statusAddress: &StatusAddress{},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
desc: "IP address",
|
||||
statusAddress: &StatusAddress{
|
||||
IP: "1.2.3.4",
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
want: []gatev1.GatewayStatusAddress{
|
||||
{
|
||||
Type: ptr.To(gatev1.IPAddressType),
|
||||
Value: "1.2.3.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "hostname address",
|
||||
statusAddress: &StatusAddress{
|
||||
Hostname: "foo.bar",
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
want: []gatev1.GatewayStatusAddress{
|
||||
{
|
||||
Type: ptr.To(gatev1.HostnameAddressType),
|
||||
Value: "foo.bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "service",
|
||||
statusAddress: &StatusAddress{
|
||||
Service: ServiceRef{
|
||||
Name: "status-address",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
paths: []string{"services.yml"},
|
||||
wantErr: require.NoError,
|
||||
want: []gatev1.GatewayStatusAddress{
|
||||
{
|
||||
Type: ptr.To(gatev1.HostnameAddressType),
|
||||
Value: "foo.bar",
|
||||
},
|
||||
{
|
||||
Type: ptr.To(gatev1.IPAddressType),
|
||||
Value: "1.2.3.4",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "missing service",
|
||||
statusAddress: &StatusAddress{
|
||||
Service: ServiceRef{
|
||||
Name: "status-address2",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
wantErr: require.Error,
|
||||
},
|
||||
{
|
||||
desc: "service without load-balancer status",
|
||||
statusAddress: &StatusAddress{
|
||||
Service: ServiceRef{
|
||||
Name: "whoamitcp-bar",
|
||||
Namespace: "bar",
|
||||
},
|
||||
},
|
||||
paths: []string{"services.yml"},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
p := Provider{StatusAddress: test.statusAddress}
|
||||
|
||||
got, err := p.gatewayAddresses(newClientMock(test.paths...))
|
||||
test.wantErr(t, err)
|
||||
|
||||
assert.Equal(t, test.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func hostnamePtr(hostname gatev1.Hostname) *gatev1.Hostname {
|
||||
return &hostname
|
||||
}
|
||||
|
||||
func groupPtr(group gatev1.Group) *gatev1.Group {
|
||||
return &group
|
||||
}
|
||||
|
||||
func sectionNamePtr(sectionName gatev1.SectionName) *gatev1.SectionName {
|
||||
return §ionName
|
||||
}
|
||||
|
||||
func namespacePtr(namespace gatev1.Namespace) *gatev1.Namespace {
|
||||
return &namespace
|
||||
}
|
||||
|
||||
func kindPtr(kind gatev1.Kind) *gatev1.Kind {
|
||||
return &kind
|
||||
}
|
||||
|
||||
func pathMatchTypePtr(p gatev1.PathMatchType) *gatev1.PathMatchType { return &p }
|
||||
|
||||
func headerMatchTypePtr(h gatev1.HeaderMatchType) *gatev1.HeaderMatchType { return &h }
|
||||
|
||||
func objectNamePtr(objectName gatev1.ObjectName) *gatev1.ObjectName {
|
||||
return &objectName
|
||||
}
|
||||
|
|
|
@ -97,8 +97,11 @@ func (p *Provider) buildTCPConfig(i item, configuration *dynamic.TCPConfiguratio
|
|||
}
|
||||
|
||||
for _, service := range configuration.Services {
|
||||
if err := p.addServerTCP(i, service.LoadBalancer); err != nil {
|
||||
return err
|
||||
// Leave load balancer empty when no address and allowEmptyServices = true
|
||||
if !(i.Address == "" && p.AllowEmptyServices) {
|
||||
if err := p.addServerTCP(i, service.LoadBalancer); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,8 +118,11 @@ func (p *Provider) buildUDPConfig(i item, configuration *dynamic.UDPConfiguratio
|
|||
}
|
||||
|
||||
for _, service := range configuration.Services {
|
||||
if err := p.addServerUDP(i, service.LoadBalancer); err != nil {
|
||||
return err
|
||||
// Leave load balancer empty when no address and allowEmptyServices = true
|
||||
if !(i.Address == "" && p.AllowEmptyServices) {
|
||||
if err := p.addServerUDP(i, service.LoadBalancer); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,8 +142,11 @@ func (p *Provider) buildServiceConfig(i item, configuration *dynamic.HTTPConfigu
|
|||
}
|
||||
|
||||
for _, service := range configuration.Services {
|
||||
if err := p.addServer(i, service.LoadBalancer); err != nil {
|
||||
return err
|
||||
// Leave load balancer empty when no address and allowEmptyServices = true
|
||||
if !(i.Address == "" && p.AllowEmptyServices) {
|
||||
if err := p.addServer(i, service.LoadBalancer); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -706,6 +706,42 @@ func Test_buildConfig(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "empty service",
|
||||
items: []item{
|
||||
{
|
||||
ID: "id1",
|
||||
Name: "Test",
|
||||
Tags: []string{
|
||||
"traefik.enable=true",
|
||||
},
|
||||
Address: "",
|
||||
Port: -1,
|
||||
ExtraConf: configuration{Enable: true},
|
||||
},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Stores: map[string]tls.Store{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "one service with rule label",
|
||||
items: []item{
|
||||
|
@ -2825,6 +2861,307 @@ func Test_buildConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_buildConfigAllowEmptyServicesTrue(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
items []item
|
||||
constraints string
|
||||
expected *dynamic.Configuration
|
||||
}{
|
||||
{
|
||||
desc: "empty service http",
|
||||
items: []item{
|
||||
{
|
||||
ID: "id1",
|
||||
Name: "Test",
|
||||
Tags: []string{
|
||||
"traefik.enable=true",
|
||||
},
|
||||
Address: "",
|
||||
Port: -1,
|
||||
ExtraConf: configuration{Enable: true},
|
||||
},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"Test": {
|
||||
Service: "Test",
|
||||
Rule: "Host(`Test.traefik.test`)",
|
||||
DefaultRule: true,
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: nil,
|
||||
PassHostHeader: Bool(true),
|
||||
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Stores: map[string]tls.Store{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "empty service tcp",
|
||||
items: []item{
|
||||
{
|
||||
ID: "id1",
|
||||
Name: "Test",
|
||||
Tags: []string{
|
||||
"traefik.tcp.routers.test.rule = HostSNI(`foobar`)",
|
||||
},
|
||||
Address: "",
|
||||
Port: -1,
|
||||
ExtraConf: configuration{Enable: true},
|
||||
},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{
|
||||
"test": {
|
||||
Rule: "HostSNI(`foobar`)",
|
||||
Service: "Test",
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.TCPServersLoadBalancer{},
|
||||
},
|
||||
},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Stores: map[string]tls.Store{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "empty service udp",
|
||||
items: []item{
|
||||
{
|
||||
ID: "id1",
|
||||
Name: "Test",
|
||||
Tags: []string{
|
||||
"traefik.udp.routers.test.entrypoints = udp",
|
||||
},
|
||||
Address: "",
|
||||
Port: -1,
|
||||
ExtraConf: configuration{Enable: true},
|
||||
},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{
|
||||
"test": {
|
||||
EntryPoints: []string{"udp"},
|
||||
Service: "Test",
|
||||
},
|
||||
},
|
||||
Services: map[string]*dynamic.UDPService{
|
||||
"Test": {
|
||||
LoadBalancer: &dynamic.UDPServersLoadBalancer{},
|
||||
},
|
||||
},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Stores: map[string]tls.Store{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.AllowEmptyServices = true
|
||||
p.DefaultRule = "Host(`{{ normalize .Name }}.traefik.test`)"
|
||||
p.Constraints = test.constraints
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.TODO()
|
||||
c := p.buildConfig(ctx, test.items)
|
||||
require.Equal(t, test.expected, c)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_buildConfigAllowEmptyServicesFalseDefault(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
items []item
|
||||
constraints string
|
||||
expected *dynamic.Configuration
|
||||
}{
|
||||
{
|
||||
desc: "empty service http",
|
||||
items: []item{
|
||||
{
|
||||
ID: "id1",
|
||||
Name: "Test",
|
||||
Tags: []string{
|
||||
"traefik.enable=true",
|
||||
},
|
||||
Address: "",
|
||||
Port: -1,
|
||||
ExtraConf: configuration{Enable: true},
|
||||
},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Stores: map[string]tls.Store{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "empty service tcp",
|
||||
items: []item{
|
||||
{
|
||||
ID: "id1",
|
||||
Name: "Test",
|
||||
Tags: []string{
|
||||
"traefik.tcp.routers.test.rule = HostSNI(`foobar`)",
|
||||
},
|
||||
Address: "",
|
||||
Port: -1,
|
||||
ExtraConf: configuration{Enable: true},
|
||||
},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Stores: map[string]tls.Store{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "empty service udp",
|
||||
items: []item{
|
||||
{
|
||||
ID: "id1",
|
||||
Name: "Test",
|
||||
Tags: []string{
|
||||
"traefik.udp.routers.test.entrypoints = udp",
|
||||
},
|
||||
Address: "",
|
||||
Port: -1,
|
||||
ExtraConf: configuration{Enable: true},
|
||||
},
|
||||
},
|
||||
expected: &dynamic.Configuration{
|
||||
TCP: &dynamic.TCPConfiguration{
|
||||
Routers: map[string]*dynamic.TCPRouter{},
|
||||
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||
},
|
||||
UDP: &dynamic.UDPConfiguration{
|
||||
Routers: map[string]*dynamic.UDPRouter{},
|
||||
Services: map[string]*dynamic.UDPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Stores: map[string]tls.Store{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.DefaultRule = "Host(`{{ normalize .Name }}.traefik.test`)"
|
||||
p.Constraints = test.constraints
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.TODO()
|
||||
c := p.buildConfig(ctx, test.items)
|
||||
require.Equal(t, test.expected, c)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_keepItem(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
{
|
||||
"Stop": false,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job1",
|
||||
"ParentID": "",
|
||||
"Name": "job1",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 1,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": {
|
||||
"ID": "654cb8ee-9c81-4fe8-02a0-2aecdea35ae3",
|
||||
"Type": "horizontal",
|
||||
"Target": {
|
||||
"Job": "job1",
|
||||
"Group": "group1",
|
||||
"Namespace": "default"
|
||||
},
|
||||
"Policy": null,
|
||||
"Min": 0,
|
||||
"Max": 3,
|
||||
"Enabled": true,
|
||||
"CreateIndex": 0,
|
||||
"ModifyIndex": 0
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"image": "nginx",
|
||||
"ports": [
|
||||
"http"
|
||||
]
|
||||
},
|
||||
"Env": null,
|
||||
"Services": null,
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job1",
|
||||
"TaskName": "",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 11,
|
||||
"SubmitTime": 1705690395733241600,
|
||||
"CreateIndex": 493,
|
||||
"ModifyIndex": 9961,
|
||||
"JobModifyIndex": 9955
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
{
|
||||
"Stop": false,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job2",
|
||||
"ParentID": "",
|
||||
"Name": "job2",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 0,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": {
|
||||
"ID": "0ae1d8fa-aa84-0b1b-941f-82dc71bc4664",
|
||||
"Type": "horizontal",
|
||||
"Target": {
|
||||
"Group": "group1",
|
||||
"Namespace": "default",
|
||||
"Job": "job2"
|
||||
},
|
||||
"Policy": null,
|
||||
"Min": 0,
|
||||
"Max": 3,
|
||||
"Enabled": true,
|
||||
"CreateIndex": 9975,
|
||||
"ModifyIndex": 9975
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"ports": [
|
||||
"http"
|
||||
],
|
||||
"image": "nginx"
|
||||
},
|
||||
"Env": null,
|
||||
"Services": null,
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job2",
|
||||
"TaskName": "",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "dead",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 10,
|
||||
"SubmitTime": 1705690880440177400,
|
||||
"CreateIndex": 2923,
|
||||
"ModifyIndex": 10048,
|
||||
"JobModifyIndex": 10044
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
{
|
||||
"Stop": false,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job3",
|
||||
"ParentID": "",
|
||||
"Name": "job3",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 1,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": null,
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"ports": [
|
||||
"http"
|
||||
],
|
||||
"image": "nginx"
|
||||
},
|
||||
"Env": null,
|
||||
"Services": null,
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job3",
|
||||
"TaskName": "",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 4,
|
||||
"SubmitTime": 1705690892484556300,
|
||||
"CreateIndex": 2932,
|
||||
"ModifyIndex": 9992,
|
||||
"JobModifyIndex": 9983
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
{
|
||||
"Stop": true,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job4",
|
||||
"ParentID": "",
|
||||
"Name": "job4",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 1,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": null,
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"image": "nginx",
|
||||
"ports": [
|
||||
"http"
|
||||
]
|
||||
},
|
||||
"Env": null,
|
||||
"Services": null,
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job4",
|
||||
"TaskName": "",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "dead",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 11,
|
||||
"SubmitTime": 1705690905317339000,
|
||||
"CreateIndex": 3079,
|
||||
"ModifyIndex": 10054,
|
||||
"JobModifyIndex": 10052
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
{
|
||||
"Stop": false,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job5",
|
||||
"ParentID": "",
|
||||
"Name": "job5",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 1,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": {
|
||||
"ID": "56d57f83-7b9e-fbfa-af96-e2c7f5dc698c",
|
||||
"Type": "horizontal",
|
||||
"Target": {
|
||||
"Namespace": "default",
|
||||
"Job": "job5",
|
||||
"Group": "group1"
|
||||
},
|
||||
"Policy": null,
|
||||
"Min": 0,
|
||||
"Max": 3,
|
||||
"Enabled": true,
|
||||
"CreateIndex": 0,
|
||||
"ModifyIndex": 0
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"image": "nginx",
|
||||
"ports": [
|
||||
"http"
|
||||
]
|
||||
},
|
||||
"Env": null,
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job5task1",
|
||||
"TaskName": "task1",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
},
|
||||
{
|
||||
"Name": "task2",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"ports": [
|
||||
"other"
|
||||
],
|
||||
"image": "nginx"
|
||||
},
|
||||
"Env": null,
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job5task2",
|
||||
"TaskName": "task2",
|
||||
"PortLabel": "other",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
},
|
||||
{
|
||||
"Label": "other",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": null,
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 7,
|
||||
"SubmitTime": 1705690918813110300,
|
||||
"CreateIndex": 3095,
|
||||
"ModifyIndex": 10018,
|
||||
"JobModifyIndex": 10008
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
{
|
||||
"Stop": false,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job6",
|
||||
"ParentID": "",
|
||||
"Name": "job6",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 0,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": {
|
||||
"ID": "d18b02ae-5a68-e635-8100-06b110910b5f",
|
||||
"Type": "horizontal",
|
||||
"Target": {
|
||||
"Job": "job6",
|
||||
"Group": "group1",
|
||||
"Namespace": "default"
|
||||
},
|
||||
"Policy": null,
|
||||
"Min": 0,
|
||||
"Max": 3,
|
||||
"Enabled": true,
|
||||
"CreateIndex": 10020,
|
||||
"ModifyIndex": 10020
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"image": "nginx",
|
||||
"ports": [
|
||||
"http"
|
||||
]
|
||||
},
|
||||
"Env": null,
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job6task1",
|
||||
"TaskName": "task1",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
},
|
||||
{
|
||||
"Name": "task2",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"image": "nginx",
|
||||
"ports": [
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"Env": null,
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job6task2",
|
||||
"TaskName": "task2",
|
||||
"PortLabel": "other",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
},
|
||||
{
|
||||
"Label": "other",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": null,
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "dead",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 3,
|
||||
"SubmitTime": 1705690931854150700,
|
||||
"CreateIndex": 9941,
|
||||
"ModifyIndex": 10078,
|
||||
"JobModifyIndex": 10074
|
||||
}
|
222
pkg/provider/nomad/fixtures/job_job7_TCP.json
Normal file
222
pkg/provider/nomad/fixtures/job_job7_TCP.json
Normal file
|
@ -0,0 +1,222 @@
|
|||
{
|
||||
"Stop": false,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job7",
|
||||
"ParentID": "",
|
||||
"Name": "job7",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 1,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": {
|
||||
"ID": "e3b82307-1b7f-5fc6-901a-d9174418461f",
|
||||
"Type": "horizontal",
|
||||
"Target": {
|
||||
"Namespace": "default",
|
||||
"Job": "job7",
|
||||
"Group": "group1"
|
||||
},
|
||||
"Policy": null,
|
||||
"Min": 0,
|
||||
"Max": 3,
|
||||
"Enabled": true,
|
||||
"CreateIndex": 0,
|
||||
"ModifyIndex": 0
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"image": "nginx",
|
||||
"ports": [
|
||||
"http"
|
||||
]
|
||||
},
|
||||
"Env": null,
|
||||
"Services": null,
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job7",
|
||||
"TaskName": "",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.tcp.routers.job7.rule=HostSNI(`job7`)",
|
||||
"traefik.tcp.routers.job7.tls.passthrough=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 1,
|
||||
"SubmitTime": 1705752438438572000,
|
||||
"CreateIndex": 11221,
|
||||
"ModifyIndex": 11238,
|
||||
"JobModifyIndex": 11232
|
||||
}
|
221
pkg/provider/nomad/fixtures/job_job8_UDP.json
Normal file
221
pkg/provider/nomad/fixtures/job_job8_UDP.json
Normal file
|
@ -0,0 +1,221 @@
|
|||
{
|
||||
"Stop": false,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job8",
|
||||
"ParentID": "",
|
||||
"Name": "job8",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 1,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": {
|
||||
"ID": "3828aaa9-4e16-cde5-cc80-f0cec4a7c82d",
|
||||
"Type": "horizontal",
|
||||
"Target": {
|
||||
"Namespace": "default",
|
||||
"Job": "job8",
|
||||
"Group": "group1"
|
||||
},
|
||||
"Policy": null,
|
||||
"Min": 0,
|
||||
"Max": 3,
|
||||
"Enabled": true,
|
||||
"CreateIndex": 0,
|
||||
"ModifyIndex": 0
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"ports": [
|
||||
"http"
|
||||
],
|
||||
"image": "nginx"
|
||||
},
|
||||
"Env": null,
|
||||
"Services": null,
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job8",
|
||||
"TaskName": "",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.udp.routers.job8.service=job8"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 2,
|
||||
"SubmitTime": 1705753285493029600,
|
||||
"CreateIndex": 11276,
|
||||
"ModifyIndex": 11303,
|
||||
"JobModifyIndex": 11297
|
||||
}
|
220
pkg/provider/nomad/fixtures/job_job9_ScalingEnabled_Stopped.json
Normal file
220
pkg/provider/nomad/fixtures/job_job9_ScalingEnabled_Stopped.json
Normal file
|
@ -0,0 +1,220 @@
|
|||
{
|
||||
"Stop": true,
|
||||
"Region": "global",
|
||||
"Namespace": "default",
|
||||
"ID": "job9",
|
||||
"ParentID": "",
|
||||
"Name": "job9",
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"AllAtOnce": false,
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"TaskGroups": [
|
||||
{
|
||||
"Name": "group1",
|
||||
"Count": 1,
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000,
|
||||
"ProgressDeadline": 600000000000,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Migrate": {
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "checks",
|
||||
"MinHealthyTime": 10000000000,
|
||||
"HealthyDeadline": 300000000000
|
||||
},
|
||||
"Constraints": [
|
||||
{
|
||||
"LTarget": "${attr.nomad.service_discovery}",
|
||||
"RTarget": "true",
|
||||
"Operand": "="
|
||||
}
|
||||
],
|
||||
"Scaling": {
|
||||
"ID": "094d38a7-24cf-d3a4-3a82-cfc50ef7c597",
|
||||
"Type": "horizontal",
|
||||
"Target": {
|
||||
"Group": "group1",
|
||||
"Namespace": "default",
|
||||
"Job": "job9"
|
||||
},
|
||||
"Policy": null,
|
||||
"Min": 0,
|
||||
"Max": 3,
|
||||
"Enabled": true,
|
||||
"CreateIndex": 0,
|
||||
"ModifyIndex": 0
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"Tasks": [
|
||||
{
|
||||
"Name": "task1",
|
||||
"Driver": "docker",
|
||||
"User": "",
|
||||
"Config": {
|
||||
"image": "nginx",
|
||||
"ports": [
|
||||
"http"
|
||||
]
|
||||
},
|
||||
"Env": null,
|
||||
"Services": null,
|
||||
"Vault": null,
|
||||
"Templates": null,
|
||||
"Constraints": null,
|
||||
"Affinities": null,
|
||||
"Resources": {
|
||||
"CPU": 100,
|
||||
"Cores": 0,
|
||||
"MemoryMB": 300,
|
||||
"MemoryMaxMB": 0,
|
||||
"DiskMB": 0,
|
||||
"IOPS": 0,
|
||||
"Networks": null,
|
||||
"Devices": null
|
||||
},
|
||||
"RestartPolicy": {
|
||||
"Attempts": 2,
|
||||
"Interval": 1800000000000,
|
||||
"Delay": 15000000000,
|
||||
"Mode": "fail",
|
||||
"RenderTemplates": false
|
||||
},
|
||||
"DispatchPayload": null,
|
||||
"Lifecycle": null,
|
||||
"Meta": null,
|
||||
"KillTimeout": 5000000000,
|
||||
"LogConfig": {
|
||||
"MaxFiles": 10,
|
||||
"MaxFileSizeMB": 10,
|
||||
"Disabled": false
|
||||
},
|
||||
"Artifacts": null,
|
||||
"Leader": false,
|
||||
"ShutdownDelay": 0,
|
||||
"VolumeMounts": null,
|
||||
"ScalingPolicies": null,
|
||||
"KillSignal": "",
|
||||
"Kind": "",
|
||||
"CSIPluginConfig": null,
|
||||
"Identity": null
|
||||
}
|
||||
],
|
||||
"EphemeralDisk": {
|
||||
"Sticky": false,
|
||||
"SizeMB": 300,
|
||||
"Migrate": false
|
||||
},
|
||||
"Meta": null,
|
||||
"ReschedulePolicy": {
|
||||
"Attempts": 0,
|
||||
"Interval": 0,
|
||||
"Delay": 30000000000,
|
||||
"DelayFunction": "exponential",
|
||||
"MaxDelay": 3600000000000,
|
||||
"Unlimited": true
|
||||
},
|
||||
"Affinities": null,
|
||||
"Spreads": null,
|
||||
"Networks": [
|
||||
{
|
||||
"Mode": "",
|
||||
"Device": "",
|
||||
"CIDR": "",
|
||||
"IP": "",
|
||||
"Hostname": "",
|
||||
"MBits": 0,
|
||||
"DNS": null,
|
||||
"ReservedPorts": null,
|
||||
"DynamicPorts": [
|
||||
{
|
||||
"Label": "http",
|
||||
"Value": 0,
|
||||
"To": 80,
|
||||
"HostNetwork": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Consul": {
|
||||
"Namespace": ""
|
||||
},
|
||||
"Services": [
|
||||
{
|
||||
"Name": "job9",
|
||||
"TaskName": "",
|
||||
"PortLabel": "http",
|
||||
"AddressMode": "auto",
|
||||
"Address": "",
|
||||
"EnableTagOverride": false,
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"CanaryTags": null,
|
||||
"Checks": null,
|
||||
"Connect": null,
|
||||
"Meta": null,
|
||||
"CanaryMeta": null,
|
||||
"TaggedAddresses": null,
|
||||
"Namespace": "default",
|
||||
"OnUpdate": "require_healthy",
|
||||
"Provider": "nomad"
|
||||
}
|
||||
],
|
||||
"Volumes": null,
|
||||
"ShutdownDelay": null,
|
||||
"StopAfterClientDisconnect": null,
|
||||
"MaxClientDisconnect": null
|
||||
}
|
||||
],
|
||||
"Update": {
|
||||
"Stagger": 30000000000,
|
||||
"MaxParallel": 1,
|
||||
"HealthCheck": "",
|
||||
"MinHealthyTime": 0,
|
||||
"HealthyDeadline": 0,
|
||||
"ProgressDeadline": 0,
|
||||
"AutoRevert": false,
|
||||
"AutoPromote": false,
|
||||
"Canary": 0
|
||||
},
|
||||
"Multiregion": null,
|
||||
"Periodic": null,
|
||||
"ParameterizedJob": null,
|
||||
"Dispatched": false,
|
||||
"DispatchIdempotencyToken": "",
|
||||
"Payload": null,
|
||||
"Meta": null,
|
||||
"ConsulToken": "",
|
||||
"ConsulNamespace": "",
|
||||
"VaultToken": "",
|
||||
"VaultNamespace": "",
|
||||
"NomadTokenID": "",
|
||||
"Status": "dead",
|
||||
"StatusDescription": "",
|
||||
"Stable": true,
|
||||
"Version": 3,
|
||||
"SubmitTime": 1705753979676559600,
|
||||
"CreateIndex": 11317,
|
||||
"ModifyIndex": 11346,
|
||||
"JobModifyIndex": 11344
|
||||
}
|
56
pkg/provider/nomad/fixtures/jobs_job1.json
Normal file
56
pkg/provider/nomad/fixtures/jobs_job1.json
Normal file
|
@ -0,0 +1,56 @@
|
|||
[
|
||||
{
|
||||
"ID": "job1",
|
||||
"ParentID": "",
|
||||
"Name": "job1",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": false,
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job1",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"job1": {
|
||||
"Queued": 0,
|
||||
"Complete": 1,
|
||||
"Failed": 0,
|
||||
"Running": 0,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
},
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 6,
|
||||
"Failed": 1,
|
||||
"Running": 1,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 493,
|
||||
"ModifyIndex": 9909
|
||||
},
|
||||
"CreateIndex": 493,
|
||||
"ModifyIndex": 9961,
|
||||
"JobModifyIndex": 9955,
|
||||
"SubmitTime": 1705690395733241600,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
47
pkg/provider/nomad/fixtures/jobs_job2.json
Normal file
47
pkg/provider/nomad/fixtures/jobs_job2.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
[
|
||||
{
|
||||
"ID": "job2",
|
||||
"ParentID": "",
|
||||
"Name": "job2",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": false,
|
||||
"Status": "dead",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job2",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 6,
|
||||
"Failed": 6,
|
||||
"Running": 0,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 2923,
|
||||
"ModifyIndex": 10051
|
||||
},
|
||||
"CreateIndex": 2923,
|
||||
"ModifyIndex": 10048,
|
||||
"JobModifyIndex": 10044,
|
||||
"SubmitTime": 1705690880440177400,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
47
pkg/provider/nomad/fixtures/jobs_job3.json
Normal file
47
pkg/provider/nomad/fixtures/jobs_job3.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
[
|
||||
{
|
||||
"ID": "job3",
|
||||
"ParentID": "",
|
||||
"Name": "job3",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": false,
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job3",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 1,
|
||||
"Failed": 0,
|
||||
"Running": 1,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 2932,
|
||||
"ModifyIndex": 9989
|
||||
},
|
||||
"CreateIndex": 2932,
|
||||
"ModifyIndex": 9992,
|
||||
"JobModifyIndex": 9983,
|
||||
"SubmitTime": 1705690892484556300,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
47
pkg/provider/nomad/fixtures/jobs_job4.json
Normal file
47
pkg/provider/nomad/fixtures/jobs_job4.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
[
|
||||
{
|
||||
"ID": "job4",
|
||||
"ParentID": "",
|
||||
"Name": "job4",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": true,
|
||||
"Status": "dead",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job4",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 6,
|
||||
"Failed": 0,
|
||||
"Running": 0,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 3079,
|
||||
"ModifyIndex": 10057
|
||||
},
|
||||
"CreateIndex": 3079,
|
||||
"ModifyIndex": 10054,
|
||||
"JobModifyIndex": 10052,
|
||||
"SubmitTime": 1705690905317339000,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
56
pkg/provider/nomad/fixtures/jobs_job5.json
Normal file
56
pkg/provider/nomad/fixtures/jobs_job5.json
Normal file
|
@ -0,0 +1,56 @@
|
|||
[
|
||||
{
|
||||
"ID": "job5",
|
||||
"ParentID": "",
|
||||
"Name": "job5",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": false,
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job5",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"job5": {
|
||||
"Queued": 0,
|
||||
"Complete": 2,
|
||||
"Failed": 0,
|
||||
"Running": 0,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
},
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 4,
|
||||
"Failed": 0,
|
||||
"Running": 1,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 3095,
|
||||
"ModifyIndex": 10015
|
||||
},
|
||||
"CreateIndex": 3095,
|
||||
"ModifyIndex": 10018,
|
||||
"JobModifyIndex": 10008,
|
||||
"SubmitTime": 1705690918813110300,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
47
pkg/provider/nomad/fixtures/jobs_job6.json
Normal file
47
pkg/provider/nomad/fixtures/jobs_job6.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
[
|
||||
{
|
||||
"ID": "job6",
|
||||
"ParentID": "",
|
||||
"Name": "job6",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": false,
|
||||
"Status": "dead",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job6",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 3,
|
||||
"Failed": 0,
|
||||
"Running": 0,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 9941,
|
||||
"ModifyIndex": 10082
|
||||
},
|
||||
"CreateIndex": 9941,
|
||||
"ModifyIndex": 10078,
|
||||
"JobModifyIndex": 10074,
|
||||
"SubmitTime": 1705690931854150700,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
47
pkg/provider/nomad/fixtures/jobs_job7.json
Normal file
47
pkg/provider/nomad/fixtures/jobs_job7.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
[
|
||||
{
|
||||
"ID": "job7",
|
||||
"ParentID": "",
|
||||
"Name": "job7",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": false,
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job7",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 0,
|
||||
"Failed": 0,
|
||||
"Running": 1,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 11221,
|
||||
"ModifyIndex": 11225
|
||||
},
|
||||
"CreateIndex": 11221,
|
||||
"ModifyIndex": 11238,
|
||||
"JobModifyIndex": 11232,
|
||||
"SubmitTime": 1705752438438572000,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
47
pkg/provider/nomad/fixtures/jobs_job8.json
Normal file
47
pkg/provider/nomad/fixtures/jobs_job8.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
[
|
||||
{
|
||||
"ID": "job8",
|
||||
"ParentID": "",
|
||||
"Name": "job8",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": false,
|
||||
"Status": "running",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job8",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 0,
|
||||
"Failed": 0,
|
||||
"Running": 1,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 11276,
|
||||
"ModifyIndex": 11281
|
||||
},
|
||||
"CreateIndex": 11276,
|
||||
"ModifyIndex": 11303,
|
||||
"JobModifyIndex": 11297,
|
||||
"SubmitTime": 1705753285493029600,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
47
pkg/provider/nomad/fixtures/jobs_job9.json
Normal file
47
pkg/provider/nomad/fixtures/jobs_job9.json
Normal file
|
@ -0,0 +1,47 @@
|
|||
[
|
||||
{
|
||||
"ID": "job9",
|
||||
"ParentID": "",
|
||||
"Name": "job9",
|
||||
"Namespace": "default",
|
||||
"Datacenters": [
|
||||
"dc1"
|
||||
],
|
||||
"NodePool": "default",
|
||||
"Multiregion": null,
|
||||
"Type": "service",
|
||||
"Priority": 50,
|
||||
"Periodic": false,
|
||||
"ParameterizedJob": false,
|
||||
"Stop": true,
|
||||
"Status": "dead",
|
||||
"StatusDescription": "",
|
||||
"JobSummary": {
|
||||
"JobID": "job9",
|
||||
"Namespace": "default",
|
||||
"Summary": {
|
||||
"group1": {
|
||||
"Queued": 0,
|
||||
"Complete": 1,
|
||||
"Failed": 0,
|
||||
"Running": 0,
|
||||
"Starting": 0,
|
||||
"Lost": 0,
|
||||
"Unknown": 0
|
||||
}
|
||||
},
|
||||
"Children": {
|
||||
"Pending": 0,
|
||||
"Running": 0,
|
||||
"Dead": 0
|
||||
},
|
||||
"CreateIndex": 11317,
|
||||
"ModifyIndex": 11349
|
||||
},
|
||||
"CreateIndex": 11317,
|
||||
"ModifyIndex": 11346,
|
||||
"JobModifyIndex": 11344,
|
||||
"SubmitTime": 1705753979676559600,
|
||||
"Meta": null
|
||||
}
|
||||
]
|
20
pkg/provider/nomad/fixtures/service_hello.json
Normal file
20
pkg/provider/nomad/fixtures/service_hello.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
"Address": "127.0.0.1",
|
||||
"AllocID": "71a63a80-a98a-93ee-4fd7-73b808577c20",
|
||||
"CreateIndex": 18,
|
||||
"Datacenter": "dc1",
|
||||
"ID": "_nomad-task-71a63a80-a98a-93ee-4fd7-73b808577c20-group-hello-nomad-hello-nomad-http",
|
||||
"JobID": "echo",
|
||||
"ModifyIndex": 18,
|
||||
"Namespace": "default",
|
||||
"NodeID": "6d7f412e-e7ff-2e66-d47b-867b0e9d8726",
|
||||
"Port": 20627,
|
||||
"ServiceName": "hello-nomad",
|
||||
"Tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.hellon.entrypoints=web",
|
||||
"traefik.http.routers.hellon.service=hello-nomad"
|
||||
]
|
||||
}
|
||||
]
|
18
pkg/provider/nomad/fixtures/service_job1.json
Normal file
18
pkg/provider/nomad/fixtures/service_job1.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
[
|
||||
{
|
||||
"ID": "_nomad-task-03c7270c-f475-5981-1932-87c0a8a5aa24-group-group1-job1-http",
|
||||
"ServiceName": "job1",
|
||||
"Namespace": "default",
|
||||
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
|
||||
"Datacenter": "dc1",
|
||||
"JobID": "job1",
|
||||
"AllocID": "03c7270c-f475-5981-1932-87c0a8a5aa24",
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"Address": "192.168.1.21",
|
||||
"Port": 29916,
|
||||
"CreateIndex": 5753,
|
||||
"ModifyIndex": 9958
|
||||
}
|
||||
]
|
1
pkg/provider/nomad/fixtures/service_job2.json
Normal file
1
pkg/provider/nomad/fixtures/service_job2.json
Normal file
|
@ -0,0 +1 @@
|
|||
[]
|
18
pkg/provider/nomad/fixtures/service_job3.json
Normal file
18
pkg/provider/nomad/fixtures/service_job3.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
[
|
||||
{
|
||||
"ID": "_nomad-task-dd945b55-70fa-0efc-6512-b88fb55ce33f-group-group1-job3-http",
|
||||
"ServiceName": "job3",
|
||||
"Namespace": "default",
|
||||
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
|
||||
"Datacenter": "dc1",
|
||||
"JobID": "job3",
|
||||
"AllocID": "dd945b55-70fa-0efc-6512-b88fb55ce33f",
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"Address": "192.168.1.21",
|
||||
"Port": 29983,
|
||||
"CreateIndex": 9987,
|
||||
"ModifyIndex": 9987
|
||||
}
|
||||
]
|
1
pkg/provider/nomad/fixtures/service_job4.json
Normal file
1
pkg/provider/nomad/fixtures/service_job4.json
Normal file
|
@ -0,0 +1 @@
|
|||
[]
|
18
pkg/provider/nomad/fixtures/service_job5task1.json
Normal file
18
pkg/provider/nomad/fixtures/service_job5task1.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
[
|
||||
{
|
||||
"ID": "_nomad-task-a98bac3d-5382-3032-1954-57aff58b20c1-task1-job5task1-http",
|
||||
"ServiceName": "job5task1",
|
||||
"Namespace": "default",
|
||||
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
|
||||
"Datacenter": "dc1",
|
||||
"JobID": "job5",
|
||||
"AllocID": "a98bac3d-5382-3032-1954-57aff58b20c1",
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"Address": "192.168.1.21",
|
||||
"Port": 24542,
|
||||
"CreateIndex": 10013,
|
||||
"ModifyIndex": 10013
|
||||
}
|
||||
]
|
18
pkg/provider/nomad/fixtures/service_job5task2.json
Normal file
18
pkg/provider/nomad/fixtures/service_job5task2.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
[
|
||||
{
|
||||
"ID": "_nomad-task-a98bac3d-5382-3032-1954-57aff58b20c1-task2-job5task2-other",
|
||||
"ServiceName": "job5task2",
|
||||
"Namespace": "default",
|
||||
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
|
||||
"Datacenter": "dc1",
|
||||
"JobID": "job5",
|
||||
"AllocID": "a98bac3d-5382-3032-1954-57aff58b20c1",
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
],
|
||||
"Address": "192.168.1.21",
|
||||
"Port": 30165,
|
||||
"CreateIndex": 10014,
|
||||
"ModifyIndex": 10014
|
||||
}
|
||||
]
|
1
pkg/provider/nomad/fixtures/service_job6task1.json
Normal file
1
pkg/provider/nomad/fixtures/service_job6task1.json
Normal file
|
@ -0,0 +1 @@
|
|||
[]
|
1
pkg/provider/nomad/fixtures/service_job6task2.json
Normal file
1
pkg/provider/nomad/fixtures/service_job6task2.json
Normal file
|
@ -0,0 +1 @@
|
|||
[]
|
20
pkg/provider/nomad/fixtures/service_job7.json
Normal file
20
pkg/provider/nomad/fixtures/service_job7.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
"ID": "_nomad-task-3e1cc853-f6b1-2c46-6f20-332a6e91794b-group-group1-job7-http",
|
||||
"ServiceName": "job7",
|
||||
"Namespace": "default",
|
||||
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
|
||||
"Datacenter": "dc1",
|
||||
"JobID": "job7",
|
||||
"AllocID": "3e1cc853-f6b1-2c46-6f20-332a6e91794b",
|
||||
"Tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.tcp.routers.job7.rule=HostSNI(`job7`)",
|
||||
"traefik.tcp.routers.job7.tls.passthrough=true"
|
||||
],
|
||||
"Address": "192.168.1.21",
|
||||
"Port": 22899,
|
||||
"CreateIndex": 11224,
|
||||
"ModifyIndex": 11271
|
||||
}
|
||||
]
|
19
pkg/provider/nomad/fixtures/service_job8.json
Normal file
19
pkg/provider/nomad/fixtures/service_job8.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
[
|
||||
{
|
||||
"ID": "_nomad-task-fffd3d81-66ac-ed6d-d9a1-fc41b2a26d07-group-group1-job8-http",
|
||||
"ServiceName": "job8",
|
||||
"Namespace": "default",
|
||||
"NodeID": "e262ecb6-a7ac-7c3e-4de0-06445559e596",
|
||||
"Datacenter": "dc1",
|
||||
"JobID": "job8",
|
||||
"AllocID": "fffd3d81-66ac-ed6d-d9a1-fc41b2a26d07",
|
||||
"Tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.udp.routers.job8.service=job8"
|
||||
],
|
||||
"Address": "192.168.1.21",
|
||||
"Port": 24268,
|
||||
"CreateIndex": 11279,
|
||||
"ModifyIndex": 11300
|
||||
}
|
||||
]
|
1
pkg/provider/nomad/fixtures/service_job9.json
Normal file
1
pkg/provider/nomad/fixtures/service_job9.json
Normal file
|
@ -0,0 +1 @@
|
|||
[]
|
18
pkg/provider/nomad/fixtures/service_redis.json
Normal file
18
pkg/provider/nomad/fixtures/service_redis.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
[
|
||||
{
|
||||
"Address": "127.0.0.1",
|
||||
"AllocID": "07501480-8175-8071-7da6-133bd1ff890f",
|
||||
"CreateIndex": 46,
|
||||
"Datacenter": "dc1",
|
||||
"ID": "_nomad-task-07501480-8175-8071-7da6-133bd1ff890f-group-redis-redis-redis",
|
||||
"JobID": "echo",
|
||||
"ModifyIndex": 46,
|
||||
"Namespace": "default",
|
||||
"NodeID": "6d7f412e-e7ff-2e66-d47b-867b0e9d8726",
|
||||
"Port": 30826,
|
||||
"ServiceName": "redis",
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
]
|
||||
}
|
||||
]
|
21
pkg/provider/nomad/fixtures/services.json
Normal file
21
pkg/provider/nomad/fixtures/services.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"Namespace": "default",
|
||||
"Services": [
|
||||
{
|
||||
"ServiceName": "redis",
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ServiceName": "hello-nomad",
|
||||
"Tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.hellon.entrypoints=web",
|
||||
"traefik.http.routers.hellon.service=hello-nomad"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -85,13 +85,14 @@ func (p *ProviderBuilder) BuildProviders() []*Provider {
|
|||
|
||||
// Configuration represents the Nomad provider configuration.
|
||||
type Configuration struct {
|
||||
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
|
||||
Constraints string `description:"Constraints is an expression that Traefik matches against the Nomad service's tags to determine whether to create route(s) for that service." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
|
||||
Endpoint *EndpointConfig `description:"Nomad endpoint settings" json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"`
|
||||
Prefix string `description:"Prefix for nomad service tags." json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"`
|
||||
Stale bool `description:"Use stale consistency for catalog reads." json:"stale,omitempty" toml:"stale,omitempty" yaml:"stale,omitempty" export:"true"`
|
||||
ExposedByDefault bool `description:"Expose Nomad services by default." json:"exposedByDefault,omitempty" toml:"exposedByDefault,omitempty" yaml:"exposedByDefault,omitempty" export:"true"`
|
||||
RefreshInterval ptypes.Duration `description:"Interval for polling Nomad API." json:"refreshInterval,omitempty" toml:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty" export:"true"`
|
||||
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
|
||||
Constraints string `description:"Constraints is an expression that Traefik matches against the Nomad service's tags to determine whether to create route(s) for that service." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
|
||||
Endpoint *EndpointConfig `description:"Nomad endpoint settings" json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty" export:"true"`
|
||||
Prefix string `description:"Prefix for nomad service tags." json:"prefix,omitempty" toml:"prefix,omitempty" yaml:"prefix,omitempty" export:"true"`
|
||||
Stale bool `description:"Use stale consistency for catalog reads." json:"stale,omitempty" toml:"stale,omitempty" yaml:"stale,omitempty" export:"true"`
|
||||
ExposedByDefault bool `description:"Expose Nomad services by default." json:"exposedByDefault,omitempty" toml:"exposedByDefault,omitempty" yaml:"exposedByDefault,omitempty" export:"true"`
|
||||
RefreshInterval ptypes.Duration `description:"Interval for polling Nomad API." json:"refreshInterval,omitempty" toml:"refreshInterval,omitempty" yaml:"refreshInterval,omitempty" export:"true"`
|
||||
AllowEmptyServices bool `description:"Allow the creation of services without endpoints." json:"allowEmptyServices,omitempty" toml:"allowEmptyServices,omitempty" yaml:"allowEmptyServices,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// SetDefaults sets the default values for the Nomad Traefik Provider Configuration.
|
||||
|
@ -116,6 +117,7 @@ func (c *Configuration) SetDefaults() {
|
|||
c.ExposedByDefault = true
|
||||
c.RefreshInterval = ptypes.Duration(15 * time.Second)
|
||||
c.DefaultRule = defaultTemplateRule
|
||||
c.AllowEmptyServices = false
|
||||
}
|
||||
|
||||
type EndpointConfig struct {
|
||||
|
@ -222,10 +224,20 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
|
|||
}
|
||||
|
||||
func (p *Provider) loadConfiguration(ctx context.Context, configurationC chan<- dynamic.Message) error {
|
||||
items, err := p.getNomadServiceData(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
var items []item
|
||||
var err error
|
||||
if p.AllowEmptyServices {
|
||||
items, err = p.getNomadServiceDataWithEmptyServices(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
items, err = p.getNomadServiceData(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
configurationC <- dynamic.Message{
|
||||
ProviderName: p.name,
|
||||
Configuration: p.buildConfig(ctx, items),
|
||||
|
@ -291,6 +303,98 @@ func (p *Provider) getNomadServiceData(ctx context.Context) ([]item, error) {
|
|||
return items, nil
|
||||
}
|
||||
|
||||
func (p *Provider) getNomadServiceDataWithEmptyServices(ctx context.Context) ([]item, error) {
|
||||
jobsOpts := &api.QueryOptions{AllowStale: p.Stale}
|
||||
jobsOpts = jobsOpts.WithContext(ctx)
|
||||
|
||||
jobStubs, _, err := p.client.Jobs().List(jobsOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var items []item
|
||||
|
||||
// Get Services even when they are scaled down to zero. Currently the nomad service interface does not support this. https://github.com/hashicorp/nomad/issues/19731
|
||||
for _, jobStub := range jobStubs {
|
||||
jobInfoOpts := &api.QueryOptions{}
|
||||
jobInfoOpts = jobInfoOpts.WithContext(ctx)
|
||||
|
||||
job, _, err := p.client.Jobs().Info(jobStub.ID, jobInfoOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, taskGroup := range job.TaskGroups {
|
||||
services := []*api.Service{}
|
||||
// Get all services in job -> taskgroup
|
||||
services = append(services, taskGroup.Services...)
|
||||
|
||||
// Get all services in job -> taskgroup -> tasks
|
||||
for _, task := range taskGroup.Tasks {
|
||||
services = append(services, task.Services...)
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
logger := log.Ctx(ctx).With().Str("serviceName", service.TaskName).Logger()
|
||||
|
||||
extraConf := p.getExtraConf(service.Tags)
|
||||
if !extraConf.Enable {
|
||||
logger.Debug().Msg("Filter Nomad service that is not enabled")
|
||||
continue
|
||||
}
|
||||
|
||||
matches, err := constraints.MatchTags(service.Tags, p.Constraints)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("Error matching constraint expressions")
|
||||
continue
|
||||
}
|
||||
|
||||
if !matches {
|
||||
logger.Debug().Msgf("Filter Nomad service not matching constraints: %q", p.Constraints)
|
||||
continue
|
||||
}
|
||||
|
||||
if nil != taskGroup.Scaling && *taskGroup.Scaling.Enabled && *taskGroup.Count == 0 {
|
||||
// Add items without address
|
||||
items = append(items, item{
|
||||
// Create a unique id for non registered services
|
||||
ID: fmt.Sprintf("%s-%s-%s-%s-%s", *job.Namespace, *job.Name, *taskGroup.Name, service.TaskName, service.Name),
|
||||
Name: service.Name,
|
||||
Namespace: *job.Namespace,
|
||||
Node: "",
|
||||
Datacenter: "",
|
||||
Address: "",
|
||||
Port: -1,
|
||||
Tags: service.Tags,
|
||||
ExtraConf: p.getExtraConf(service.Tags),
|
||||
})
|
||||
} else {
|
||||
instances, err := p.fetchService(ctx, service.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, i := range instances {
|
||||
items = append(items, item{
|
||||
ID: i.ID,
|
||||
Name: i.ServiceName,
|
||||
Namespace: i.Namespace,
|
||||
Node: i.NodeID,
|
||||
Datacenter: i.Datacenter,
|
||||
Address: i.Address,
|
||||
Port: i.Port,
|
||||
Tags: i.Tags,
|
||||
ExtraConf: p.getExtraConf(i.Tags),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// getExtraConf returns a configuration with settings which are not part of the dynamic configuration (e.g. "<prefix>.enable").
|
||||
func (p *Provider) getExtraConf(tags []string) configuration {
|
||||
labels := tagsToLabels(tags, p.Prefix)
|
||||
|
|
|
@ -2,8 +2,11 @@ package nomad
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -12,6 +15,17 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
)
|
||||
|
||||
var responses = map[string][]byte{}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
err := setup()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func Test_globalConfig(t *testing.T) {
|
||||
cases := []struct {
|
||||
Name string
|
||||
|
@ -131,15 +145,311 @@ func TestProvider_SetDefaults_Endpoint(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_GroupService_Scaling1(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job1"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job1"):
|
||||
_, _ = w.Write(responses["job_job1_WithGroupService_Scaling1"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job1"):
|
||||
_, _ = w.Write(responses["service_job1"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_GroupService_Scaling0(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job2"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job2"):
|
||||
_, _ = w.Write(responses["job_job2_WithGroupService_Scaling0"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job2"):
|
||||
_, _ = w.Write(responses["service_job2"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_GroupService_ScalingDisabled(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job3"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job3"):
|
||||
_, _ = w.Write(responses["job_job3_WithGroupService_ScalingDisabled"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job3"):
|
||||
_, _ = w.Write(responses["service_job3"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_GroupService_ScalingDisabled_Stopped(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job4"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job4"):
|
||||
_, _ = w.Write(responses["job_job4_WithGroupService_ScalingDisabled_Stopped"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job4"):
|
||||
_, _ = w.Write(responses["service_job4"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should not be listed as job is stopped
|
||||
require.Empty(t, items)
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_GroupTaskService_Scaling1(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job5"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job5"):
|
||||
_, _ = w.Write(responses["job_job5_WithGroupTaskService_Scaling1"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job5task1"):
|
||||
_, _ = w.Write(responses["service_job5task1"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job5task2"):
|
||||
_, _ = w.Write(responses["service_job5task2"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 2)
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_GroupTaskService_Scaling0(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job6"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job6"):
|
||||
_, _ = w.Write(responses["job_job6_WithGroupTaskService_Scaling0"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job6task1"):
|
||||
_, _ = w.Write(responses["service_job6task1"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job6task2"):
|
||||
_, _ = w.Write(responses["service_job6task2"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 2)
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_TCP(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job7"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job7"):
|
||||
_, _ = w.Write(responses["job_job7_TCP"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job7"):
|
||||
_, _ = w.Write(responses["service_job7"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_UDP(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job8"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job8"):
|
||||
_, _ = w.Write(responses["job_job8_UDP"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job8"):
|
||||
_, _ = w.Write(responses["service_job8"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
}
|
||||
|
||||
func Test_getNomadServiceDataWithEmptyServices_ScalingEnabled_Stopped(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/jobs"):
|
||||
_, _ = w.Write(responses["jobs_job9"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/job/job9"):
|
||||
_, _ = w.Write(responses["job_job9_ScalingEnabled_Stopped"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/job9"):
|
||||
_, _ = w.Write(responses["service_job9"])
|
||||
}
|
||||
}))
|
||||
|
||||
t.Cleanup(ts.Close)
|
||||
|
||||
p := new(Provider)
|
||||
p.SetDefaults()
|
||||
p.Endpoint.Address = ts.URL
|
||||
err := p.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
// fudge client, avoid starting up via Provide
|
||||
p.client, err = createClient(p.namespace, p.Endpoint)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make the query for services
|
||||
items, err := p.getNomadServiceDataWithEmptyServices(context.TODO())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should not be listed as job is stopped
|
||||
require.Empty(t, items)
|
||||
}
|
||||
|
||||
func setup() error {
|
||||
responsesDir := "./fixtures"
|
||||
files, err := os.ReadDir(responsesDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, file := range files {
|
||||
if !file.IsDir() && filepath.Ext(file.Name()) == ".json" {
|
||||
content, err := os.ReadFile(filepath.Join(responsesDir, file.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
responses[strings.TrimSuffix(filepath.Base(file.Name()), filepath.Ext(file.Name()))] = content
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test_getNomadServiceData(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch {
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/services"):
|
||||
_, _ = w.Write([]byte(services))
|
||||
_, _ = w.Write(responses["services"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/redis"):
|
||||
_, _ = w.Write([]byte(redis))
|
||||
_, _ = w.Write(responses["service_redis"])
|
||||
case strings.HasSuffix(r.RequestURI, "/v1/service/hello-nomad"):
|
||||
_, _ = w.Write([]byte(hello))
|
||||
_, _ = w.Write(responses["service_hello"])
|
||||
}
|
||||
}))
|
||||
t.Cleanup(ts.Close)
|
||||
|
@ -159,71 +469,3 @@ func Test_getNomadServiceData(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Len(t, items, 2)
|
||||
}
|
||||
|
||||
const services = `
|
||||
[
|
||||
{
|
||||
"Namespace": "default",
|
||||
"Services": [
|
||||
{
|
||||
"ServiceName": "redis",
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ServiceName": "hello-nomad",
|
||||
"Tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.hellon.entrypoints=web",
|
||||
"traefik.http.routers.hellon.service=hello-nomad"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
`
|
||||
|
||||
const redis = `
|
||||
[
|
||||
{
|
||||
"Address": "127.0.0.1",
|
||||
"AllocID": "07501480-8175-8071-7da6-133bd1ff890f",
|
||||
"CreateIndex": 46,
|
||||
"Datacenter": "dc1",
|
||||
"ID": "_nomad-task-07501480-8175-8071-7da6-133bd1ff890f-group-redis-redis-redis",
|
||||
"JobID": "echo",
|
||||
"ModifyIndex": 46,
|
||||
"Namespace": "default",
|
||||
"NodeID": "6d7f412e-e7ff-2e66-d47b-867b0e9d8726",
|
||||
"Port": 30826,
|
||||
"ServiceName": "redis",
|
||||
"Tags": [
|
||||
"traefik.enable=true"
|
||||
]
|
||||
}
|
||||
]
|
||||
`
|
||||
|
||||
const hello = `
|
||||
[
|
||||
{
|
||||
"Address": "127.0.0.1",
|
||||
"AllocID": "71a63a80-a98a-93ee-4fd7-73b808577c20",
|
||||
"CreateIndex": 18,
|
||||
"Datacenter": "dc1",
|
||||
"ID": "_nomad-task-71a63a80-a98a-93ee-4fd7-73b808577c20-group-hello-nomad-hello-nomad-http",
|
||||
"JobID": "echo",
|
||||
"ModifyIndex": 18,
|
||||
"Namespace": "default",
|
||||
"NodeID": "6d7f412e-e7ff-2e66-d47b-867b0e9d8726",
|
||||
"Port": 20627,
|
||||
"ServiceName": "hello-nomad",
|
||||
"Tags": [
|
||||
"traefik.enable=true",
|
||||
"traefik.http.routers.hellon.entrypoints=web",
|
||||
"traefik.http.routers.hellon.service=hello-nomad"
|
||||
]
|
||||
}
|
||||
]
|
||||
`
|
||||
|
|
|
@ -511,6 +511,17 @@ func TestDo_staticConfiguration(t *testing.T) {
|
|||
SendAnonymousUsage: true,
|
||||
}
|
||||
|
||||
config.ServersTransport = &static.ServersTransport{
|
||||
InsecureSkipVerify: true,
|
||||
RootCAs: []types.FileOrContent{"root.ca"},
|
||||
MaxIdleConnsPerHost: 42,
|
||||
ForwardingTimeouts: &static.ForwardingTimeouts{
|
||||
DialTimeout: 42,
|
||||
ResponseHeaderTimeout: 42,
|
||||
IdleConnTimeout: 42,
|
||||
},
|
||||
}
|
||||
|
||||
config.EntryPoints = static.EntryPoints{
|
||||
"foobar": &static.EntryPoint{
|
||||
Address: "foo Address",
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/traefik/traefik/v3/pkg/middlewares/contenttype"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/customerrors"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/grpcweb"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/headermodifier"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/headers"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/inflightreq"
|
||||
"github.com/traefik/traefik/v3/pkg/middlewares/ipallowlist"
|
||||
|
@ -384,6 +385,16 @@ func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (
|
|||
}
|
||||
}
|
||||
|
||||
// Gateway API HTTPRoute filters middlewares.
|
||||
if config.RequestHeaderModifier != nil {
|
||||
if middleware != nil {
|
||||
return nil, badConf
|
||||
}
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return headermodifier.NewRequestHeaderModifier(ctx, next, *config.RequestHeaderModifier, middlewareName)
|
||||
}
|
||||
}
|
||||
|
||||
if middleware == nil {
|
||||
return nil, fmt.Errorf("invalid middleware %q configuration: invalid middleware type or middleware does not exist", middlewareName)
|
||||
}
|
||||
|
|
|
@ -100,6 +100,11 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
|
|||
// If there is a handler matching the connection metadata,
|
||||
// we let it handle the connection.
|
||||
if handler != nil {
|
||||
// Remove read/write deadline and delegate this to underlying TCP server.
|
||||
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||
log.Error().Err(err).Msg("Error while setting deadline")
|
||||
}
|
||||
|
||||
handler.ServeTCP(conn)
|
||||
return
|
||||
}
|
||||
|
@ -128,15 +133,9 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
|
|||
return
|
||||
}
|
||||
|
||||
// Remove read/write deadline and delegate this to underlying tcp server (for now only handled by HTTP Server)
|
||||
err = conn.SetReadDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error while setting read deadline")
|
||||
}
|
||||
|
||||
err = conn.SetWriteDeadline(time.Time{})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Error while setting write deadline")
|
||||
// Remove read/write deadline and delegate this to underlying TCP server (for now only handled by HTTP Server)
|
||||
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||
log.Error().Err(err).Msg("Error while setting deadline")
|
||||
}
|
||||
|
||||
connData, err := tcpmuxer.NewConnData(hello.serverName, conn, hello.protos)
|
||||
|
|
|
@ -536,7 +536,7 @@ func (f *fakeSpiffePKI) genSVID(id spiffeid.ID) (*x509svid.SVID, error) {
|
|||
return x509svid.ParseRaw(certDER, keyPKCS8)
|
||||
}
|
||||
|
||||
// fakeSpiffeSource allows retrieving staticly an SVID and its associated bundle.
|
||||
// fakeSpiffeSource allows retrieving statically an SVID and its associated bundle.
|
||||
type fakeSpiffeSource struct {
|
||||
bundle *x509bundle.Bundle
|
||||
svid *x509svid.SVID
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue