Skip to content

Commit

Permalink
Merge pull request #231 from vshn/add/diff_script
Browse files Browse the repository at this point in the history
Add script to generate diffs between a cluster and the local branch
  • Loading branch information
Kidswiss authored Sep 24, 2024
2 parents 01fa5b4 + f96303a commit b2194fb
Show file tree
Hide file tree
Showing 7 changed files with 412 additions and 195 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/diff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Diff
on:
pull_request: {}

jobs:
render-diff:
runs-on: ubuntu-latest
steps:

- name: Wait on Workflow
uses: lucasssvaz/wait-on-workflow@v1
with:
workflow: pr.yml
max-wait: 3
timeout: 60
sha: ${{ github.event.pull_request.head.sha || github.sha }}

- name: Extract branch name
shell: bash
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
id: extract_branch

- name: Trigger diff on internal gitlab
run: |
curl -X POST \
--fail \
-F token=${{ secrets.GITLAB_CI_TOKEN }} \
-F ref=add/pipeline \
-F "variables[BRANCH]=${{ steps.extract_branch.outputs.branch }}" \
https://git.vshn.net/api/v4/projects/58084/trigger/pipeline
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ __debug_bin*

# Ignore crossplane packages
*.xpkg

hack/res
hack/tmp
hack/diff/function.yaml
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,11 @@ bootstrap: api-bootstrap generate ## API bootstrapping, create a new claim/compo
.PHONY: install-proxy
install-proxy:
kubectl apply -f hack/functionproxy

.PHONY: render-diff
render-diff: export IMG_TAG=$(shell git rev-parse --abbrev-ref HEAD | sed 's/\//_/g')
render-diff: ## Render diff between the cluster in KUBECONF and the local branch
# We check if the image is pullable, if so we pull it, otherwise we build the image
# this will speed up the compare in CI/CD environments.
if ! docker pull $(IMG); then $(MAKE) docker-build-branchtag; fi
hack/diff/compare.sh
146 changes: 146 additions & 0 deletions hack/diff/compare.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/bin/bash

set -e

[ -z "${KUBECONFIG}" ] && echo "Please export KUBECONFIG" && exit 1

# get the state and all objects from each composite
function get_state() {
type="$1"
name="$2"
dir_name="hack/tmp/$type-$name"

echo "getting state of $type/$name"

mkdir -p "$dir_name"

while read -r res_type res_name
do
kubectl get "$res_type" "$res_name" -oyaml > "$dir_name/$res_type-$res_name.yaml"
done <<< "$(kubectl get "$type" "$name" -oyaml | yq -r '.spec.resourceRefs | .[] | .kind + " " + .name')"

}

# also get the claim namespace
function get_claim_namespace() {
type="$1"
name="$2"
dir_name="hack/tmp/$type-$name"

ns=$(kubectl get "$type" "$name" -oyaml | yq -r '.metadata.labels["crossplane.io/claim-namespace"]')
kubectl get ns "$ns" -oyaml > "$dir_name/namespace.yaml"

}

function run_single_diff() {
type="$1"
name="$2"
dir_name="hack/tmp/$type-$name"
res_dir_name="hack/res/$type/$name"

mkdir -p "$res_dir_name"

kubectl get "$type" "$name" -oyaml > hack/tmp/xr.yaml
comp=$(kubectl get "$type" "$name" -oyaml | yq -r '.spec.compositionRef.name')
echo "composition: $comp $type/$name"
kubectl get compositions.apiextensions.crossplane.io "$comp" -oyaml > hack/tmp/composition.yaml
crank_func render hack/tmp/xr.yaml hack/tmp/composition.yaml hack/diff/function.yaml -o "$dir_name" > "$res_dir_name/$3.yaml"
}

function crank_func() {
mkdir -p .work/bin
[ ! -f .work/bin/crank ] && curl -s https://releases.crossplane.io/stable/v1.17.0/bin/linux_amd64/crank -o .work/bin/crank
chmod +x .work/bin/crank
if .work/bin/crank -h > /dev/null 2>&1; then .work/bin/crank "$@";
else go run github.com/crossplane/crossplane/cmd/[email protected] "$@"; fi
}

function get_running_func_version() {
version=$(kubectl get function function-appcat -oyaml | yq -r '.spec.package' | cut -d ":" -f2)
echo "${version%"-func"}"
}
function get_pnt_func_version() {
kubectl get function function-patch-and-transform -oyaml | yq -r '.spec.package' | cut -d ":" -f2
}
function template_func_file() {
export PNT_VERSION=$1
export APPCAT_VERSION=$2
cat "$(dirname "$0")/function.yaml.tmpl" | envsubst > "$(dirname "$0")/function.yaml"
}
function diff_func() {
while read -r type name rest
do
# we only get the state on the first run for two reasons:
# speed things up
# avoid any diffs that could come from actual changes on the cluster
[ "first" == "$1" ] && get_state "$type" "$name"
get_claim_namespace "$type" "$name"
run_single_diff "$type" "$name" "$1"
done <<< "$(kubectl get composite --no-headers | sed 's/\// /g' )"
}
# do the diff
function first_diff() {
diff_func "first"
}
function second_diff() {
diff_func "second"
}
function compare() {
for f in hack/res/*/*;
do
echo "comparing $f"
# enable color
# ignore changed array order
# exclude nested managedFields in kube objects
# exclude nested resourceVersion
# don't print the huge dyff header
dyff between \
--color=on \
-i \
--exclude-regexp "spec.forProvider.manifest.metadata.managedFields.*" \
--exclude "spec.forProvider.manifest.metadata.resourceVersion" \
--omit-header \
"$f/first.yaml" "$f/second.yaml"
# diff "$f/first.yaml" "$f/second.yaml"
done
}
function dyff() {
mkdir -p .work/bin
[ ! -f .work/bin/dyff ] && curl -sL https://github.com/homeport/dyff/releases/download/v1.9.1/dyff_1.9.1_linux_amd64.tar.gz -o .work/bin/dyff.tar.gz && \
tar xvfz .work/bin/dyff.tar.gz -C .work/bin > /dev/null 2>&1
chmod +x .work/bin/dyff
if .work/bin/dyff version > /dev/null 2>&1 ; then .work/bin/dyff "$@";
else go run github.com/homeport/dyff/cmd/[email protected] "$@"; fi
}
function clean() {
rm -rf hack/tmp
rm -rf hack/res
rm -rf "$(dirname "$0")/function.yaml"
}
clean
trap clean EXIT
template_func_file "$(get_pnt_func_version)" "$(get_running_func_version)"
echo "Render live manifests"
first_diff
template_func_file "$(get_pnt_func_version)" "$(git rev-parse --abbrev-ref HEAD | sed 's/\//_/g')"
echo "Render against branch"
second_diff
echo "Comparing"
compare
17 changes: 17 additions & 0 deletions hack/diff/function.yaml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: function-appcat
annotations:
render.crossplane.io/runtime-docker-cleanup: Stop
spec:
package: ghcr.io/vshn/appcat:$APPCAT_VERSION
---
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-patch-and-transform
annotations:
render.crossplane.io/runtime-docker-cleanup: Stop
spec:
package: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:$PNT_VERSION
12 changes: 12 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/vshn/appcat/v4/cmd"
)
Expand All @@ -22,6 +23,16 @@ func init() {

func main() {

cmd, _, err := rootCmd.Find(os.Args[1:])

// default to functions if no cmd is given
// necessary to properly support `crank render`
// from https://github.com/spf13/cobra/issues/823#issuecomment-870027246
if err == nil && cmd.Use == rootCmd.Use && cmd.Flags().Parse(os.Args[1:]) != pflag.ErrHelp {
args := append([]string{"functions"}, os.Args[1:]...)
rootCmd.SetArgs(args)
}

if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
Expand All @@ -35,6 +46,7 @@ var (
Short: "AppCat",
Long: "AppCat controllers, api servers, grpc servers and probers",
PersistentPreRunE: setupLogging,
Use: "appcat",
}
)

Expand Down
Loading

0 comments on commit b2194fb

Please sign in to comment.