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

feat: Application resource watching #43

Merged
merged 15 commits into from
Jan 11, 2024
42 changes: 26 additions & 16 deletions Earthfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
VERSION 0.7

ARG --global USERARCH

test:
BUILD +ci-golang
BUILD +ci-helm
Expand All @@ -22,11 +24,11 @@ release:
BUILD +release-helm

go-deps:
ARG GOLANG_VERSION="1.19.3"
ARG GOLANG_VERSION="1.21"
ARG GOOS=linux
ARG GOARCH=amd64
ARG GOARCH=$USERARCH

FROM --platform=linux/amd64 golang:$GOLANG_VERSION-bullseye
FROM --platform=linux/$USERARCH golang:$GOLANG_VERSION-bullseye

ENV GO111MODULE=on
ENV CGO_ENABLED=0
Expand Down Expand Up @@ -62,20 +64,26 @@ test-golang:

build-binary:
ARG GOOS=linux
ARG GOARCH=amd64
ARG GOARCH=$USERARCH
ARG VARIANT
ARG --required GIT_TAG
ARG --required GIT_COMMIT

FROM --platform=linux/amd64 +go-deps
FROM --platform=linux/$USERARCH +go-deps

WORKDIR /src
COPY . /src
RUN GOARM=${VARIANT#v} go build -ldflags "-X github.com/zapier/kubechecks/pkg.GitCommit=$GIT_COMMIT -X github.com/zapier/kubechecks/pkg.GitTag=$GIT_TAG" -o kubechecks
SAVE ARTIFACT kubechecks

build-debug-binary:
FROM --platform=linux/$USERARCH +go-deps
WORKDIR /src
COPY . /src
RUN go build -gcflags="all=-N -l" -ldflags "-X github.com/zapier/kubechecks/pkg.GitCommit=$GIT_COMMIT -X github.com/zapier/kubechecks/pkg.GitTag=$GIT_TAG" -o kubechecks
SAVE ARTIFACT kubechecks

docker:
ARG --required IMAGE_NAME
ARG TARGETPLATFORM
ARG TARGETARCH
ARG TARGETVARIANT
Expand Down Expand Up @@ -115,29 +123,31 @@ docker:
VOLUME /app/policies
VOLUME /app/schemas

COPY (+build-binary/kubechecks --platform=linux/amd64 --GOARCH=$TARGETARCH --VARIANT=$TARGETVARIANT) .
COPY (+build-binary/kubechecks --platform=linux/$USERARCH --GOARCH=$TARGETARCH --VARIANT=$TARGETVARIANT) .
RUN ./kubechecks help

CMD ["./kubechecks", "controller"]

ARG --required IMAGE_NAME
SAVE IMAGE --push $IMAGE_NAME

dlv:
FROM golang:1.19
FROM golang:1.21-bullseye

RUN apt update && apt install -y ca-certificates curl git
RUN go install github.com/go-delve/delve/cmd/dlv@latest

SAVE ARTIFACT /go/bin/dlv

docker-debug:
ARG IMAGE_NAME="kubechecks:debug"
FROM +docker --GIT_TAG=debug --GIT_COMMIT=abcdef

COPY (+dlv/dlv --GOARCH=$GOARCH --VARIANT=$TARGETVARIANT) /usr/local/bin/dlv
COPY (+build-debug-binary/kubechecks --GOARCH=$USERARCH --VARIANT=$TARGETVARIANT) .

COPY (+dlv/dlv --GOARCH=$USERARCH --VARIANT=$TARGETVARIANT) /usr/local/bin/dlv

CMD ["/usr/local/bin/dlv", "--listen=:2345", "--api-version=2", "--headless=true", "--accept-multiclient", "exec", "--continue", "./kubechecks", "controller"]

ARG IMAGE_NAME="kubechecks:debug"
SAVE IMAGE --push $IMAGE_NAME

fmt-golang:
Expand All @@ -150,13 +160,13 @@ fmt-golang:
&& ./hacks/exit-on-changed-files.sh

lint-golang:
ARG STATICCHECK_VERSION="2023.1.3"
ARG STATICCHECK_VERSION="2023.1.6"

FROM +go-deps

# install staticcheck
RUN FILE=staticcheck.tgz \
&& URL=https://github.com/dominikh/go-tools/releases/download/$STATICCHECK_VERSION/staticcheck_linux_amd64.tar.gz \
&& URL=https://github.com/dominikh/go-tools/releases/download/$STATICCHECK_VERSION/staticcheck_linux_$USERARCH.tar.gz \
&& wget ${URL} \
--output-document ${FILE} \
&& tar \
Expand All @@ -176,9 +186,9 @@ test-helm:
FROM quay.io/helmpack/chart-testing:v${CHART_TESTING_VERSION}

# install kubeconform
ARG KUBECONFORM_VERSION="0.5.0"
ARG KUBECONFORM_VERSION="0.6.4"
RUN FILE=kubeconform.tgz \
&& URL=https://github.com/yannh/kubeconform/releases/download/v${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz \
&& URL=https://github.com/yannh/kubeconform/releases/download/v${KUBECONFORM_VERSION}/kubeconform-linux-${USERARCH}.tar.gz \
&& wget ${URL} \
--output-document ${FILE} \
&& tar \
Expand All @@ -205,7 +215,7 @@ release-helm:

ARG HELM_VERSION="3.8.1"
RUN FILE=helm.tgz \
&& URL=https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz \
&& URL=https://get.helm.sh/helm-v${HELM_VERSION}-linux-${USERARCH}.tar.gz \
&& wget ${URL} \
--output-document ${FILE} \
&& tar \
Expand Down
40 changes: 19 additions & 21 deletions Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ deploy_ngrok(cfg)
# /////////////////////////////////////////////////////////////////////////////

# Load ArgoCD Tiltfile
load('./localdev/argocd/Tiltfile', 'deploy_argo')
load('./localdev/argocd/Tiltfile', 'deploy_argo', 'delete_argocd_apps_on_tilt_down', 'force_argocd_cleanup_on_tilt_down')
# make sure apps get removed (cleanly) before ArgoCD is shutdown
delete_argocd_apps_on_tilt_down()
deploy_argo()

#load('./localdev/reloader/Tiltfile', 'deploy_reloader')
Expand Down Expand Up @@ -135,32 +137,21 @@ test_go(
],
)

arch="arm64" if str(local("uname -m")).strip('\n') == "arm64" else "amd64"

earthly_build(
context='.',
target="+docker-debug",
ref='kubechecks',
image_arg='IMAGE_NAME',
ignore='./dist',
extra_args=[
'--GOARCH={}'.format(arch),
]
)


cmd_button('loc:go mod tidy',
argv=['go', 'mod', 'tidy'],
resource='kubechecks',
icon_name='move_up',
text='go mod tidy',
)
cmd_button('generate-mocks',
argv=['go', 'generate', './...'],
resource='kubechecks',
icon_name='change_circle',
text='go generate',
)

cmd_button('restart-pod',
argv=['kubectl', '-n', 'kubechecks', 'rollout', 'restart', 'deployment/kubechecks'],
resource='kubechecks',
Expand All @@ -173,13 +164,15 @@ k8s_yaml(helm(
namespace='kubechecks',
name='kubechecks',
values='./localdev/kubechecks/values.yaml',
set=['deployment.env.KUBECHECKS_WEBHOOK_URL_BASE=' + get_ngrok_url(cfg), 'deployment.env.NGROK_URL=' + get_ngrok_url(cfg),
'deployment.env.KUBECHECKS_ARGOCD_WEBHOOK_URL='+ get_ngrok_url(cfg) +'/argocd/api/webhook',
'deployment.env.KUBECHECKS_ENABLE_CONFTEST=true',
'deployment.env.KUBECHECKS_VCS_TYPE=' + cfg.get('vcs-type', 'gitlab'),
'secrets.env.KUBECHECKS_VCS_TOKEN=' + (os.getenv('GITLAB_TOKEN') if 'gitlab' in cfg.get('vcs-type', 'gitlab') else os.getenv('GITHUB_TOKEN')),
'secrets.env.KUBECHECKS_WEBHOOK_SECRET=' + (os.getenv('KUBECHECKS_WEBHOOK_SECRET') if os.getenv('KUBECHECKS_WEBHOOK_SECRET') != None else ""),
'secrets.env.KUBECHECKS_OPENAI_API_TOKEN=' + (os.getenv('OPENAI_API_TOKEN') if os.getenv('OPENAI_API_TOKEN') != None else ""),],
set=[
'deployment.env[15].name=KUBECHECKS_WEBHOOK_URL_BASE', 'deployment.env[15].value=' + get_ngrok_url(cfg),
'deployment.env[16].name=NGROK_URL', 'deployment.env[16].value=' + get_ngrok_url(cfg),
'deployment.env[17].name=KUBECHECKS_ARGOCD_WEBHOOK_URL', 'deployment.env[17].value=' + get_ngrok_url(cfg) +'/argocd/api/webhook',
'deployment.env[18].name=KUBECHECKS_VCS_TYPE', 'deployment.env[18].value=' + cfg.get('vcs-type', 'gitlab'),
'secrets.env.KUBECHECKS_VCS_TOKEN=' + (os.getenv('GITLAB_TOKEN') if 'gitlab' in cfg.get('vcs-type', 'gitlab') else os.getenv('GITHUB_TOKEN')),
'secrets.env.KUBECHECKS_WEBHOOK_SECRET=' + (os.getenv('KUBECHECKS_WEBHOOK_SECRET') if os.getenv('KUBECHECKS_WEBHOOK_SECRET') != None else ""),
'secrets.env.KUBECHECKS_OPENAI_API_TOKEN=' + (os.getenv('OPENAI_API_TOKEN') if os.getenv('OPENAI_API_TOKEN') != None else ""),
],
))

k8s_resource(
Expand All @@ -188,7 +181,9 @@ k8s_resource(
resource_deps=[
# 'go-build',
'go-test',
'k8s:namespace'
'k8s:namespace',
'argocd',
'argocd-crds',
],
labels=["kubechecks"]
)
Expand Down Expand Up @@ -218,3 +213,6 @@ install_test_apps(cfg)

load("localdev/test_appsets/Tiltfile", "install_test_appsets")
install_test_appsets(cfg)


force_argocd_cleanup_on_tilt_down()
2 changes: 1 addition & 1 deletion charts/kubechecks/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: v2
name: kubechecks
description: A Helm chart for kubechecks
version: 0.4.1
version: 0.4.2
appVersion: "1.3.3"
type: application
maintainers:
Expand Down
8 changes: 8 additions & 0 deletions charts/kubechecks/templates/clusterrole.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "kubechecks.fullname" . }}
rules:
- apiGroups: ['*']
resources: ['applications', 'appprojects', 'services']
verbs: ['*']
12 changes: 12 additions & 0 deletions charts/kubechecks/templates/clusterrolebinding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "kubechecks.fullname" . }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "kubechecks.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "kubechecks.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
15 changes: 7 additions & 8 deletions cmd/controller_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ var ControllerCmd = &cobra.Command{
}

fmt.Println("Starting KubeChecks:", pkg.GitTag, pkg.GitCommit)
server := server.NewServer(&cfg)

ctx := context.Background()
server := server.NewServer(ctx, &cfg)

go server.Start(ctx)

// graceful termination handler.
Expand Down Expand Up @@ -88,12 +88,11 @@ func init() {
RootCmd.AddCommand(ControllerCmd)

flags := ControllerCmd.Flags()
stringFlag(flags, "fallback-k8s-version", "Fallback target Kubernetes version for schema / upgrade checks.",
newStringOpts().
withDefault("1.23.0"))
boolFlag(flags, "show-debug-info", "Set to true to print debug info to the footer of MR comments.")
boolFlag(flags, "enable-conftest", "Set to true to enable conftest policy checking of manifests.")
stringFlag(flags, "label-filter", `(Optional) If set, The label that must be set on an MR (as "kubechecks:<value>") for kubechecks to process the merge request webhook.`)
stringFlag(flags, "fallback-k8s-version", "Fallback target Kubernetes version for schema / upgrade checks (KUBECHECKS_FALLBACK_K8S_VERSION).",
newStringOpts().withDefault("1.23.0"))
boolFlag(flags, "show-debug-info", "Set to true to print debug info to the footer of MR comments (KUBECHECKS_SHOW_DEBUG_INFO).")
boolFlag(flags, "enable-conftest", "Set to true to enable conftest policy checking of manifests (KUBECHECKS_ENABLE_CONFTEST).")
stringFlag(flags, "label-filter", `(Optional) If set, The label that must be set on an MR (as "kubechecks:<value>") for kubechecks to process the merge request webhook (KUBECHECKS_LABEL_FILTER).`)
stringFlag(flags, "openai-api-token", "OpenAI API Token.")
stringFlag(flags, "webhook-url-base", "The endpoint to listen on for incoming PR/MR event webhooks. For example, 'https://checker.mycompany.com'.")
stringFlag(flags, "webhook-url-prefix", "If your application is running behind a proxy that uses path based routing, set this value to match the path prefix. For example, '/hello/world'.")
Expand Down
2 changes: 1 addition & 1 deletion docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ Click the Detailed view button at the top, and click the refresh button next to

#### Minikube

If you're using minikube with Tilt we recommend following this [guide](https://github.com/tilt-dev/minikube-local) to setup a local registry that Tilt can push to automatically. Without this Tilt will attempt to push up to Docker Hub by default.
If you're using minikube with Tilt we recommend following this [guide](https://github.com/tilt-dev/ctlptl) to setup a local registry that Tilt can push to automatically. Without this Tilt will attempt to push up to Docker Hub by default.

### Code Changes

Expand Down
10 changes: 10 additions & 0 deletions localdev/argocd/Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,13 @@ def deploy_argo():
labels=["argocd"],
resource_deps=['k8s:namespace']
)

def delete_argocd_apps_on_tilt_down():
if config.tilt_subcommand == 'down':
# delete Apps
local("./localdev/argocd/delete-apps.sh")

def force_argocd_cleanup_on_tilt_down():
if config.tilt_subcommand == 'down':
# force cleanup of Apps and CRD on tilt down
local("./localdev/argocd/force-cleanup-apps.sh")
15 changes: 15 additions & 0 deletions localdev/argocd/delete-apps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash

echo "Deleting ArgoCD test Applications & AppSets (gracefully)..."

# Delete ApplicationSets
for a in $(kubectl get ApplicationSet -n kubechecks -o=jsonpath='{.items[*].metadata.name}'); do
kubectl delete ApplicationSet $a -n kubechecks --timeout=10s;
done;

# Delete Applications
for a in $(kubectl get application -n kubechecks -o=jsonpath='{.items[*].metadata.name}'); do
kubectl delete application $a -n kubechecks --timeout=10s;
done;

exit 0;
27 changes: 27 additions & 0 deletions localdev/argocd/force-cleanup-apps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash

# check if Applications CRD still exists
exists=$(kubectl get crd | grep "applications.argoproj.io" | wc -l)
if [ "$exists" -eq 0 ]; then
echo "Applications CRD doesn't exist. Exiting..."
exit 0;
fi

# give time for other processes to cleanup properly
echo "ArgoCD Cleanup: waiting 20 seconds..."
sleep 20
echo "Cleaning up ArgoCD test Applications and CRDs..."

# Cleanup Applications
for a in $(kubectl get application -n kubechecks -o=jsonpath='{.items[*].metadata.name}'); do
# remove finalizer from Applications (ArgoCD is probably shutdown by now and deleting apps will hang)
kubectl patch application $a -n kubechecks --type json -p='[{"op": "remove", "path": "/metadata/finalizers"}]';
kubectl delete application $a -n kubechecks;
done;

# Cleanup ArgoCD CRDs
for crd in applications.argoproj.io applicationsets.argoproj.io appprojects.argoproj.io; do
kubectl delete crd $crd;
done;

exit 0;
Loading
Loading