Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRD Controller #353

Merged
merged 37 commits into from
Oct 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
688d36d
push latest image for crd-controller-base branch (#307)
alvin-huang Aug 13, 2020
04f04cb
fix ifelse in makefile (#308)
alvin-huang Aug 13, 2020
e656c46
Update kubernetes and golang dependencies
hashicorp-ci Aug 10, 2020
85c7713
Apply suggestions from code review
Aug 13, 2020
2790a9c
Remove unnecessary dep on prometheus logging (#311)
kschoche Aug 19, 2020
55bd0f5
Merge POC into consul-k8s (#309)
Aug 27, 2020
c89e4d2
Remove patch for validating webhook (#314)
lkysow Aug 28, 2020
3059542
Update docs for CRDs (#318)
lkysow Aug 31, 2020
3a61dfe
Add -create-controller-token flag
lkysow Aug 31, 2020
e78313c
Update ACLs for consul ent and controller (#322)
lkysow Sep 14, 2020
2092f5d
Support Consul Ent NS's for CRDs (#323)
lkysow Sep 14, 2020
9cf39f6
Add defaults and validation for ServiceDefaults (#320)
Sep 15, 2020
767a5cf
Provision webhooks with self-generated certs (#316)
Sep 15, 2020
cc1d16d
Ensure system recovers quickly from failures or drift in state (#326)
Sep 22, 2020
b333e0b
ServiceResolver controller and webhook (#325)
lkysow Sep 22, 2020
1e9a70b
Fix bug with service-resolver validation (#330)
lkysow Sep 23, 2020
aa64895
Pass down path through validators (#331)
lkysow Sep 23, 2020
1b33c49
Implement webhook support for consul ent (#329)
lkysow Sep 24, 2020
c77a9f5
Add -enable-webhooks flag (#336)
lkysow Sep 25, 2020
092fc5f
ProxyDefaults CRD (#328)
Sep 25, 2020
bc9ae7a
Ignore ProxyDefaultsValidator from deepcopy (#338)
Sep 25, 2020
bd17a55
Remove metrics flag since we're not using it (#337)
lkysow Sep 25, 2020
90b9c80
ServiceRouter support (#332)
lkysow Sep 29, 2020
9f994ed
Update to latest serviceresolver code (#335)
lkysow Sep 29, 2020
33a9810
Clarify cookie docs (#341)
lkysow Sep 29, 2020
423cbac
Add support for ServiceSplitter (#339)
ishustava Sep 29, 2020
3a97323
Replace reflect.DeepEqual with gocmp.Equal (#340)
Sep 29, 2020
7aaa508
Refactor ent controller tests (#342)
Sep 30, 2020
6f37b01
Pull consul dev images (#344)
alvin-huang Oct 1, 2020
40d03ab
Use metadata field from configEntry (#343)
Oct 1, 2020
5ecc0d4
Support split weights that have a value of 0 (#349)
Oct 5, 2020
46baf63
Crd controller service intentions (#346)
Oct 7, 2020
e9cc25b
Add -log-level flag to controller (#348)
lkysow Oct 7, 2020
fc52045
L7 intentions (#352)
Oct 7, 2020
5213536
Merge remote-tracking branch 'origin/master' into crd-controller-base
lkysow Oct 7, 2020
704ca54
Tidy up go.sum
Oct 7, 2020
b7f17e1
Bump commit sha's for Consul
lkysow Oct 8, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 57 additions & 11 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,54 @@
version: 2.1

# reusable 'executor' object for jobs
executors:
go:
docker:
- image: circleci/golang:1.14
environment:
- TEST_RESULTS: /tmp/test-results # path to where test results are saved
- CONSUL_VERSION: 1.8.2 # Consul's OSS version to use in tests
- CONSUL_ENT_VERSION: 1.8.2+ent # Consul's enterprise version to use in tests
- CONSUL_VERSION: 71ba8300a3d25b335aff0de9f9dd2a82fc2e58f1 # Consul's OSS version to use in tests
- CONSUL_ENT_VERSION: 9fb10787b1ec44d6a7c42c3a5f326953943fc39e # Consul's enterprise version to use in tests

commands:
get-aws-cli:
steps:
- run:
name: download and install AWS CLI
command: |
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
echo -e "${AWS_CLI_GPG_KEY}" | gpg --import
curl -o awscliv2.sig https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip.sig
gpg --verify awscliv2.sig awscliv2.zip
unzip awscliv2.zip
sudo ./aws/install
aws-assume-role:
steps:
- run:
name: assume-role aws creds
command: |
# assume role has duration of 15 min (the minimum allowed)
CREDENTIALS="$(aws sts assume-role --duration-seconds 900 --role-arn ${ROLE_ARN} --role-session-name build-${CIRCLE_SHA1} | jq '.Credentials')"
echo "export AWS_ACCESS_KEY_ID=$(echo $CREDENTIALS | jq -r '.AccessKeyId')" >> $BASH_ENV
echo "export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.SecretAccessKey')" >> $BASH_ENV
echo "export AWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r '.SessionToken')" >> $BASH_ENV
install-dev-consul:
description: "Pull a dev version of consul/consul-enterprise for testing"
parameters:
bucket:
type: env_var_name
default: CONSUL_DEV_ARTIFACT_BUCKET # we use the same bucket for oss/ent dev builds (at different paths)
path:
type: env_var_name
sha:
type: env_var_name
steps:
- run:
name: download and install dev consul/consul-enterprise
command: |
aws s3 cp s3://${<< parameters.bucket >>}/${<< parameters.path >>}/${<< parameters.sha >>}.tar.gz /tmp
sudo tar -xzvf /tmp/${<< parameters.sha >>}.tar.gz -C /usr/local/bin
consul version
jobs:
go-fmt-and-vet:
Expand Down Expand Up @@ -61,12 +102,15 @@ jobs:
keys:
- consul-k8s-modcache-v1-{{ checksum "go.mod" }}

# pull a dev build of consul oss from s3
- get-aws-cli
- aws-assume-role
- install-dev-consul:
path: CONSUL_DEV_ARTIFACT_PATH
sha: CONSUL_VERSION

# run go tests with gotestsum
- run: |
# download and install the consul binary
wget https://releases.hashicorp.com/consul/"${CONSUL_VERSION}"/consul_"${CONSUL_VERSION}"_linux_amd64.zip && \
unzip consul_"${CONSUL_VERSION}"_linux_amd64.zip -d /home/circleci/bin &&
rm consul_"${CONSUL_VERSION}"_linux_amd64.zip
PACKAGE_NAMES=$(go list ./...)
gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES
Expand All @@ -89,12 +133,14 @@ jobs:
keys:
- consul-k8s-modcache-v1-{{ checksum "go.mod" }}

# pull a dev build of consul ent from s3
- get-aws-cli
- aws-assume-role
- install-dev-consul:
path: CONSUL_ENT_DEV_ARTIFACT_PATH
sha: CONSUL_ENT_VERSION

# run go tests with gotestsum
- run: |
# download and install the consul binary
wget https://releases.hashicorp.com/consul/"${CONSUL_ENT_VERSION}"/consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip && \
unzip consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip -d /home/circleci/bin &&
rm consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip
- run: |
PACKAGE_NAMES=$(go list ./...)
gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES
Expand Down
59 changes: 57 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export GIT_DESCRIBE
export GOLDFLAGS
export GOTAGS


CRD_OPTIONS ?= "crd:trivialVersions=true,allowDangerousTypes=true,crdVersions=v1beta1"

################
# CI Variables #
Expand Down Expand Up @@ -79,7 +79,7 @@ else
DEV_PUSH_ARG=--no-push
endif

all: bin
all: bin ctrl-generate

bin:
@$(SHELL) $(CURDIR)/build-support/scripts/build-local.sh
Expand Down Expand Up @@ -128,6 +128,57 @@ clean:
$(CURDIR)/bin \
$(CURDIR)/pkg

# Run controller tests
ENVTEST_ASSETS_DIR=$(shell pwd)/testbin
ctrl-test: ctrl-generate ctrl-manifests
mkdir -p ${ENVTEST_ASSETS_DIR}
test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/master/hack/setup-envtest.sh
source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./...

# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
ctrl-deploy: ctrl-manifests kustomize
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | kubectl apply -f -

# Generate manifests e.g. CRD, RBAC etc.
ctrl-manifests: controller-gen
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases

# Generate code
ctrl-generate: controller-gen
$(CONTROLLER_GEN) object:headerFile="build-support/controller/boilerplate.go.txt" paths="./..."

# find or download controller-gen
# download controller-gen if necessary
controller-gen:
ifeq (, $(shell which controller-gen))
@{ \
set -e ;\
CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$CONTROLLER_GEN_TMP_DIR ;\
go mod init tmp ;\
go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.4.0 ;\
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
}
CONTROLLER_GEN=$(GOBIN)/controller-gen
else
CONTROLLER_GEN=$(shell which controller-gen)
endif

kustomize:
ifeq (, $(shell which kustomize))
@{ \
set -e ;\
KUSTOMIZE_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$KUSTOMIZE_GEN_TMP_DIR ;\
go mod init tmp ;\
go get sigs.k8s.io/kustomize/kustomize/v3@v3.5.4 ;\
rm -rf $$KUSTOMIZE_GEN_TMP_DIR ;\
}
KUSTOMIZE=$(GOBIN)/kustomize
else
KUSTOMIZE=$(shell which kustomize)
endif

# In CircleCI, the linux binary will be attached from a previous step at pkg/bin/linux_amd64/. This make target
# should only run in CI and not locally.
Expand All @@ -148,5 +199,9 @@ ifeq ($(CIRCLE_BRANCH), master)
@docker tag $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest
@docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest
endif
ifeq ($(CIRCLE_BRANCH), crd-controller-base)
@docker tag $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):crd-controller-base-latest
@docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):crd-controller-base-latest
endif

.PHONY: all bin clean dev dist docker-images go-build-image test tools ci.dev-docker
7 changes: 7 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# this is a generated file used for operator sdk during code generation of CRDs, Controllers and webhooks
domain: hashicorp.com
layout: go.kubebuilder.io/v2
repo: github.com/hashicorp/consul-k8s
version: 3-alpha
plugins:
go.operator-sdk.io/v2-alpha: {}
19 changes: 19 additions & 0 deletions api/common/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Package common holds code that isn't tied to a particular CRD version or type.
package common

const (
ServiceDefaults string = "servicedefaults"
ProxyDefaults string = "proxydefaults"
ServiceResolver string = "serviceresolver"
ServiceRouter string = "servicerouter"
ServiceSplitter string = "servicesplitter"
ServiceIntentions string = "serviceintentions"

Global string = "global"
DefaultConsulNamespace string = "default"
WildcardNamespace string = "*"

SourceKey string = "external-source"
DatacenterKey string = "consul.hashicorp.com/source-datacenter"
SourceValue string = "kubernetes"
)
60 changes: 60 additions & 0 deletions api/common/configentry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package common

import (
"github.com/hashicorp/consul/api"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)

// ConfigEntryResource is a generic config entry custom resource. It is implemented
// by each config entry type so that they can be acted upon generically.
// It is not tied to a specific CRD version.
type ConfigEntryResource interface {
// GetObjectMeta returns object meta.
GetObjectMeta() metav1.ObjectMeta
// AddFinalizer adds a finalizer to the list of finalizers.
AddFinalizer(name string)
// RemoveFinalizer removes this finalizer from the list.
RemoveFinalizer(name string)
// Finalizers returns the list of finalizers for this object.
Finalizers() []string
// ConsulKind returns the Consul config entry kind, i.e. service-defaults, not
// servicedefaults.
ConsulKind() string
// ConsulGlobalResource returns if the resource exists in the default
// Consul namespace only.
ConsulGlobalResource() bool
// ConsulMirroringNS returns the Consul namespace that the config entry should
// be created in if namespaces and mirroring are enabled.
ConsulMirroringNS() string
// KubeKind returns the Kube config entry kind, i.e. servicedefaults, not
// service-defaults.
KubeKind() string
// ConsulName returns the name of the config entry as saved in Consul.
// This may be different than KubernetesName() in the case of a ServiceIntentions
// config entry.
ConsulName() string
// KubernetesName returns the name of the Kubernetes resource.
KubernetesName() string
// SetSyncedCondition updates the synced condition.
SetSyncedCondition(status corev1.ConditionStatus, reason, message string)
// SyncedCondition gets the synced condition.
SyncedCondition() (status corev1.ConditionStatus, reason, message string)
// SyncedConditionStatus returns the status of the synced condition.
SyncedConditionStatus() corev1.ConditionStatus
// ToConsul converts the resource to the corresponding Consul API definition.
// Its return type is the generic ConfigEntry but a specific config entry
// type should be constructed e.g. ServiceConfigEntry.
ToConsul(datacenter string) api.ConfigEntry
// MatchesConsul returns true if the resource has the same fields as the Consul
// config entry.
MatchesConsul(candidate api.ConfigEntry) bool
// GetObjectKind should be implemented by the generated code.
GetObjectKind() schema.ObjectKind
// DeepCopyObject should be implemented by the generated code.
DeepCopyObject() runtime.Object
// Validate returns an error if the resource is invalid.
Validate() error
}
60 changes: 60 additions & 0 deletions api/common/configentry_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package common

import (
"context"
"fmt"
"net/http"

"github.com/go-logr/logr"
"k8s.io/api/admission/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

// ConfigEntryLister is implemented by CRD-specific webhooks.
type ConfigEntryLister interface {
// List returns all resources of this type across all namespaces in a
// Kubernetes cluster.
List(ctx context.Context) ([]ConfigEntryResource, error)
}

// ValidateConfigEntry validates cfgEntry. It is a generic method that
// can be used by all CRD-specific validators.
// Callers should pass themselves as validator and kind should be the custom
// resource name, e.g. "ServiceDefaults".
func ValidateConfigEntry(
ctx context.Context,
req admission.Request,
logger logr.Logger,
configEntryLister ConfigEntryLister,
cfgEntry ConfigEntryResource,
enableConsulNamespaces bool,
nsMirroring bool) admission.Response {

// On create we need to validate that there isn't already a resource with
// the same name in a different namespace if we're need to mapping all Kube
// resources to a single Consul namespace. The only case where we're not
// mapping all kube resources to a single Consul namespace is when we
// are running Consul enterprise with namespace mirroring.
singleConsulDestNS := !(enableConsulNamespaces && nsMirroring)
if req.Operation == v1beta1.Create && singleConsulDestNS {
logger.Info("validate create", "name", cfgEntry.KubernetesName())

list, err := configEntryLister.List(ctx)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}
for _, item := range list {
if item.KubernetesName() == cfgEntry.KubernetesName() {
return admission.Errored(http.StatusBadRequest,
fmt.Errorf("%s resource with name %q is already defined – all %s resources must have unique names across namespaces",
cfgEntry.KubeKind(),
cfgEntry.KubernetesName(),
cfgEntry.KubeKind()))
}
}
}
if err := cfgEntry.Validate(); err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
return admission.Allowed(fmt.Sprintf("valid %s request", cfgEntry.KubeKind()))
}
Loading