Skip to content
This repository has been archived by the owner on Aug 25, 2021. It is now read-only.

Commit

Permalink
TerminatingGateway CRD
Browse files Browse the repository at this point in the history
  • Loading branch information
lkysow committed Nov 27, 2020
1 parent 2c7da0b commit d68fa93
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

FEATURES:
* CRDs: add new CRD `IngressGateway` for configuring Consul's [ingress-gateway](https://www.consul.io/docs/agent/config-entries/ingress-gateway) config entry. [[GH-714](https://github.com/hashicorp/consul-helm/pull/714)]
* CRDs: add new CRD `TerminatingGateway` for configuring Consul's [terminating-gateway](https://www.consul.io/docs/agent/config-entries/terminating-gateway) config entry. [[GH-715](https://github.com/hashicorp/consul-helm/pull/715)]

BUG FIXES:
* CRDs: **(Consul Enterprise only)** change `ServiceResolver` field `failover[].namespaces` to `failover[].namespace`.
Expand Down
2 changes: 2 additions & 0 deletions templates/controller-clusterrole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ rules:
- servicesplitters
- serviceintentions
- ingressgateways
- terminatinggateways
verbs:
- create
- delete
Expand All @@ -38,6 +39,7 @@ rules:
- servicesplitters/status
- serviceintentions/status
- ingressgateways/status
- terminatinggateways/status
verbs:
- get
- patch
Expand Down
22 changes: 22 additions & 0 deletions templates/controller-mutatingwebhookconfiguration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,26 @@ webhooks:
resources:
- ingressgateways
sideEffects: None
- clientConfig:
caBundle: Cg==
service:
name: {{ template "consul.fullname" . }}-controller-webhook
namespace: {{ .Release.Namespace }}
path: /mutate-v1alpha1-terminatinggateway
failurePolicy: Fail
admissionReviewVersions:
- "v1beta1"
- "v1"
name: mutate-terminatinggateway.consul.hashicorp.com
rules:
- apiGroups:
- consul.hashicorp.com
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- terminatinggateways
sideEffects: None
{{- end }}
117 changes: 117 additions & 0 deletions templates/crd-terminatinggateways.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{{- if .Values.controller.enabled }}
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.1
creationTimestamp: null
name: terminatinggateways.consul.hashicorp.com
labels:
app: {{ template "consul.name" . }}
chart: {{ template "consul.chart" . }}
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
component: crd
spec:
additionalPrinterColumns:
- JSONPath: .status.conditions[?(@.type=="Synced")].status
description: The sync status of the resource with Consul
name: Synced
type: string
- JSONPath: .metadata.creationTimestamp
description: The age of the resource
name: Age
type: date
group: consul.hashicorp.com
names:
kind: TerminatingGateway
listKind: TerminatingGatewayList
plural: terminatinggateways
singular: terminatinggateway
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
description: TerminatingGateway is the Schema for the terminatinggateways API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: TerminatingGatewaySpec defines the desired state of TerminatingGateway
properties:
services:
description: Services is a list of service names represented by the terminating gateway.
items:
description: A LinkedService is a service represented by a terminating gateway
properties:
caFile:
description: CAFile is the optional path to a CA certificate to use for TLS connections from the gateway to the linked service.
type: string
certFile:
description: CertFile is the optional path to a client certificate to use for TLS connections from the gateway to the linked service.
type: string
keyFile:
description: KeyFile is the optional path to a private key to use for TLS connections from the gateway to the linked service.
type: string
name:
description: Name is the name of the service, as defined in Consul's catalog.
type: string
namespace:
description: The namespace the service is registered in.
type: string
sni:
description: SNI is the optional name to specify during the TLS handshake with a linked service.
type: string
type: object
type: array
type: object
status:
properties:
conditions:
description: Conditions indicate the latest available observations of a resource's current state.
items:
description: 'Conditions define a readiness condition for a Consul resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties'
properties:
lastTransitionTime:
description: LastTransitionTime is the last time the condition transitioned from one status to another.
format: date-time
type: string
message:
description: A human readable message indicating details about the transition.
type: string
reason:
description: The reason for the condition's last transition.
type: string
status:
description: Status of the condition, one of True, False, Unknown.
type: string
type:
description: Type of condition.
type: string
required:
- status
- type
type: object
type: array
type: object
type: object
version: v1alpha1
versions:
- name: v1alpha1
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
{{- end }}
30 changes: 30 additions & 0 deletions test/acceptance/tests/controller/controller_namespaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,17 @@ func TestControllerNamespaces(t *testing.T) {
require.Len(r, ingressGatewayEntry.Listeners[0].Services, 1)
require.Equal(r, "foo", ingressGatewayEntry.Listeners[0].Services[0].Name)

// terminating-gateway
entry, _, err = consulClient.ConfigEntries().Get(api.TerminatingGateway, "terminating-gateway", queryOpts)
require.NoError(r, err)
terminatingGatewayEntry, ok := entry.(*api.TerminatingGatewayConfigEntry)
require.True(r, ok, "could not cast to TerminatingGatewayConfigEntry")
require.Len(r, terminatingGatewayEntry.Services, 1)
require.Equal(r, "name", terminatingGatewayEntry.Services[0].Name)
require.Equal(r, "caFile", terminatingGatewayEntry.Services[0].CAFile)
require.Equal(r, "certFile", terminatingGatewayEntry.Services[0].CertFile)
require.Equal(r, "keyFile", terminatingGatewayEntry.Services[0].KeyFile)
require.Equal(r, "sni", terminatingGatewayEntry.Services[0].SNI)
})
}

Expand Down Expand Up @@ -216,6 +227,10 @@ func TestControllerNamespaces(t *testing.T) {
patchPort := 9090
k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "ingressgateway", "ingress-gateway", "-p", fmt.Sprintf(`{"spec": {"listeners": [{"port": %d, "protocol": "tcp", "services": [{"name": "foo"}]}]}}`, patchPort), "--type=merge")

logger.Log(t, "patching terminating-gateway custom resource")
patchSNI := "patch-sni"
k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "terminatinggateway", "terminating-gateway", "-p", fmt.Sprintf(`{"spec": {"services": [{"name":"name","caFile":"caFile","certFile":"certFile","keyFile":"keyFile","sni":"%s"}]}}`, patchSNI), "--type=merge")

counter := &retry.Counter{Count: 10, Wait: 500 * time.Millisecond}
retry.RunWith(counter, t, func(r *retry.R) {
// service-defaults
Expand Down Expand Up @@ -268,6 +283,13 @@ func TestControllerNamespaces(t *testing.T) {
ingressGatewayEntry, ok := entry.(*api.IngressGatewayConfigEntry)
require.True(r, ok, "could not cast to IngressGatewayConfigEntry")
require.Equal(r, patchPort, ingressGatewayEntry.Listeners[0].Port)

// terminating-gateway
entry, _, err = consulClient.ConfigEntries().Get(api.TerminatingGateway, "terminating-gateway", queryOpts)
require.NoError(r, err)
terminatingGatewayEntry, ok := entry.(*api.TerminatingGatewayConfigEntry)
require.True(r, ok, "could not cast to TerminatingGatewayConfigEntry")
require.Equal(r, patchSNI, terminatingGatewayEntry.Services[0].SNI)
})
}

Expand All @@ -294,6 +316,9 @@ func TestControllerNamespaces(t *testing.T) {
logger.Log(t, "deleting ingress-gateway custom resource")
k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "ingressgateway", "ingress-gateway")

logger.Log(t, "deleting terminating-gateway custom resource")
k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "terminatinggateway", "terminating-gateway")

counter := &retry.Counter{Count: 10, Wait: 500 * time.Millisecond}
retry.RunWith(counter, t, func(r *retry.R) {
// service-defaults
Expand Down Expand Up @@ -330,6 +355,11 @@ func TestControllerNamespaces(t *testing.T) {
_, _, err = consulClient.ConfigEntries().Get(api.IngressGateway, "ingress-gateway", queryOpts)
require.Error(r, err)
require.Contains(r, err.Error(), "404 (Config entry not found")

// terminating-gateway
_, _, err = consulClient.ConfigEntries().Get(api.IngressGateway, "terminating-gateway", queryOpts)
require.Error(r, err)
require.Contains(r, err.Error(), "404 (Config entry not found")
})
}
})
Expand Down
31 changes: 31 additions & 0 deletions test/acceptance/tests/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,18 @@ func TestController(t *testing.T) {
require.Equal(r, 8080, ingressGatewayEntry.Listeners[0].Port)
require.Len(r, ingressGatewayEntry.Listeners[0].Services, 1)
require.Equal(r, "foo", ingressGatewayEntry.Listeners[0].Services[0].Name)

// terminating-gateway
entry, _, err = consulClient.ConfigEntries().Get(api.TerminatingGateway, "terminating-gateway", nil)
require.NoError(r, err)
terminatingGatewayEntry, ok := entry.(*api.TerminatingGatewayConfigEntry)
require.True(r, ok, "could not cast to TerminatingGatewayConfigEntry")
require.Len(r, terminatingGatewayEntry.Services, 1)
require.Equal(r, "name", terminatingGatewayEntry.Services[0].Name)
require.Equal(r, "caFile", terminatingGatewayEntry.Services[0].CAFile)
require.Equal(r, "certFile", terminatingGatewayEntry.Services[0].CertFile)
require.Equal(r, "keyFile", terminatingGatewayEntry.Services[0].KeyFile)
require.Equal(r, "sni", terminatingGatewayEntry.Services[0].SNI)
})
}

Expand Down Expand Up @@ -156,6 +168,10 @@ func TestController(t *testing.T) {
patchPort := 9090
k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "ingressgateway", "ingress-gateway", "-p", fmt.Sprintf(`{"spec": {"listeners": [{"port": %d, "protocol": "tcp", "services": [{"name": "foo"}]}]}}`, patchPort), "--type=merge")

logger.Log(t, "patching terminating-gateway custom resource")
patchSNI := "patch-sni"
k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "terminatinggateway", "terminating-gateway", "-p", fmt.Sprintf(`{"spec": {"services": [{"name":"name","caFile":"caFile","certFile":"certFile","keyFile":"keyFile","sni":"%s"}]}}`, patchSNI), "--type=merge")

counter := &retry.Counter{Count: 10, Wait: 500 * time.Millisecond}
retry.RunWith(counter, t, func(r *retry.R) {
// service-defaults
Expand Down Expand Up @@ -209,6 +225,13 @@ func TestController(t *testing.T) {
ingressGatewayEntry, ok := entry.(*api.IngressGatewayConfigEntry)
require.True(r, ok, "could not cast to IngressGatewayConfigEntry")
require.Equal(r, patchPort, ingressGatewayEntry.Listeners[0].Port)

// terminating-gateway
entry, _, err = consulClient.ConfigEntries().Get(api.TerminatingGateway, "terminating-gateway", nil)
require.NoError(r, err)
terminatingGatewayEntry, ok := entry.(*api.TerminatingGatewayConfigEntry)
require.True(r, ok, "could not cast to TerminatingGatewayConfigEntry")
require.Equal(r, patchSNI, terminatingGatewayEntry.Services[0].SNI)
})
}

Expand All @@ -235,6 +258,9 @@ func TestController(t *testing.T) {
logger.Log(t, "deleting ingress-gateway custom resource")
k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "ingressgateway", "ingress-gateway")

logger.Log(t, "deleting terminating-gateway custom resource")
k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "terminatinggateway", "terminating-gateway")

counter := &retry.Counter{Count: 10, Wait: 500 * time.Millisecond}
retry.RunWith(counter, t, func(r *retry.R) {
// service-defaults
Expand Down Expand Up @@ -271,6 +297,11 @@ func TestController(t *testing.T) {
_, _, err = consulClient.ConfigEntries().Get(api.IngressGateway, "ingress-gateway", nil)
require.Error(r, err)
require.Contains(r, err.Error(), "404 (Config entry not found")

// terminating-gateway
_, _, err = consulClient.ConfigEntries().Get(api.IngressGateway, "terminating-gateway", nil)
require.Error(r, err)
require.Contains(r, err.Error(), "404 (Config entry not found")
})
}
})
Expand Down
11 changes: 11 additions & 0 deletions test/acceptance/tests/fixtures/crds/terminatinggateway.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: consul.hashicorp.com/v1alpha1
kind: TerminatingGateway
metadata:
name: terminating-gateway
spec:
services:
- name: name
caFile: "caFile"
certFile: "certFile"
keyFile: "keyFile"
sni: "sni"
24 changes: 24 additions & 0 deletions test/unit/crd-terminatinggateway.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bats

load _helpers

@test "terminatingGateway/CustomerResourceDefinition: disabled by default" {
cd `chart_dir`
assert_empty helm template \
-s templates/crd-terminatinggateway.yaml \
.
}

@test "terminatingGateway/CustomerResourceDefinition: enabled with controller.enabled=true" {
cd `chart_dir`
local actual=$(helm template \
-s templates/crd-terminatinggateways.yaml \
--set 'controller.enabled=true' \
. | tee /dev/stderr |
# The generated CRDs have "---" at the top which results in two objects
# being detected by yq, the first of which is null. We must therefore use
# yq -s so that length operates on both objects at once rather than
# individually, which would output false\ntrue and fail the test.
yq -s 'length > 0' | tee /dev/stderr)
[ "${actual}" = "true" ]
}

0 comments on commit d68fa93

Please sign in to comment.