Skip to content

Commit

Permalink
feat: add helm plugin scaffolding new layout (#3421)
Browse files Browse the repository at this point in the history
**Description of the change:**
This PR adds the helm plugin scaffolding the files with the new layout and using the current sdk helm pkg implementation (image)

- added e2e tests for helm new layout. See:`/test/e2e-helm-new/e2e_suite.go` and `./hack/tests/e2e-helm-new.sh` 
- centralize the method ReplaceInFile in the test/internal/utils.go since it is useful for all tests
- Impl e2e tests in shell for the new layout. See `hack/tests/e2e-helm.sh` 

**Motivation**

SDK is in a process to be integrated with KB which means that its project layouts will be aligned. More info : [Integrating Kubebuilder and Operator SDK](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/integrating-kubebuilder-and-osdk.md). 

This PR adds the Helm Plugin which will provide the Helm project in the new layout by the command `operator-sdk init --plugins=`helm.operator-sdk.io/v1`. For a further understanding see the WIP: #329 and the doc [Extensible CLI and Scaffolding Plugins](https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md).
  • Loading branch information
camilamacedo86 authored Jul 15, 2020
1 parent 96d8bae commit 0fe8cf4
Show file tree
Hide file tree
Showing 54 changed files with 5,284 additions and 378 deletions.
2 changes: 2 additions & 0 deletions cmd/operator-sdk/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/operator-framework/operator-sdk/cmd/operator-sdk/version"
"github.com/operator-framework/operator-sdk/internal/flags"
golangv2 "github.com/operator-framework/operator-sdk/internal/plugins/golang/v2"
helmv1 "github.com/operator-framework/operator-sdk/internal/plugins/helm/v1"
"github.com/operator-framework/operator-sdk/internal/util/projutil"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -64,6 +65,7 @@ func GetPluginsCLIAndRoot() (cli.CLI, *cobra.Command) {
cli.WithCommandName("operator-sdk"),
cli.WithPlugins(
&golangv2.Plugin{},
&helmv1.Plugin{},
),
cli.WithDefaultPlugins(
&golangv2.Plugin{},
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ require (
github.com/go-logr/logr v0.1.0
github.com/go-logr/zapr v0.1.1
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334
github.com/kr/text v0.1.0
github.com/markbates/inflect v1.0.4
github.com/mattn/go-isatty v0.0.12
github.com/mitchellh/go-homedir v1.1.0
Expand All @@ -27,6 +28,7 @@ require (
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.5.1
github.com/xenolf/lego v2.7.2+incompatible
go.uber.org/zap v1.14.1
golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b
gomodules.xyz/jsonpatch/v3 v3.0.1
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -537,8 +537,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365 h1:ECW73yc9MY7935nNYXUkK7Dz17YuSUI9yqRqYS8aBww=
github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
Expand Down Expand Up @@ -927,6 +927,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xenolf/lego v2.7.2+incompatible h1:aGxxYqhnQLQ71HsvEAjJVw6ao14APwPpRk0mpFroPXk=
github.com/xenolf/lego v2.7.2+incompatible/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY=
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
Expand Down
115 changes: 52 additions & 63 deletions hack/tests/e2e-helm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,94 +6,96 @@ source hack/lib/test_lib.sh
source hack/lib/image_lib.sh

DEST_IMAGE="quay.io/example/nginx-operator:v0.0.2"
ROOTDIR="$(pwd)"
TMPDIR="$(mktemp -d)"
trap_add 'rm -rf $TMPDIR' EXIT

setup_envs $tmp_sdk_root

test_namespace="test-e2e-helm"
# kind has an issue with certain image registries (ex. redhat's), so use a
# different test pod image.
METRICS_TEST_IMAGE="fedora:latest"

test_namespace="nginx-cr-system"
operator_namespace="nginx-operator-system"

deploy_operator() {
kubectl create -f "$OPERATORDIR/deploy/crds/helm.example.com_nginxes_crd.yaml"
kubectl create -f "$OPERATORDIR/deploy/service_account.yaml"
kubectl create -f "$OPERATORDIR/deploy/cluster_role.yaml"
kubectl create -f "$OPERATORDIR/deploy/cluster_role_binding.yaml"
kubectl create -f "$OPERATORDIR/deploy/cluster_operator.yaml"
make install
make deploy IMG="$DEST_IMAGE"
kubectl create namespace ${test_namespace}
}

remove_operator() {
kubectl delete --ignore-not-found namespace ${test_namespace}
kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/service_account.yaml"
kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/cluster_role.yaml"
kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/cluster_role_binding.yaml"
kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/crds/helm.example.com_nginxes_crd.yaml"
kubectl delete --ignore-not-found=true -f "$OPERATORDIR/deploy/cluster_operator.yaml"
kubectl delete --ignore-not-found=true clusterrolebinding nginx-operator-system-metrics-reader
kubectl delete --ignore-not-found=true --namespace=${test_namespace} -f "$OPERATORDIR/config/samples/helm.example_v1alpha1_nginx.yaml"
kubectl delete --ignore-not-found=true namespace ${test_namespace}
kubectl delete --ignore-not-found=true namespace ${operator_namespace}
}

operator_logs() {
kubectl get all --namespace=${operator_namespace}
kubectl get events --namespace=${operator_namespace}
kubectl logs deployment/nginx-operator-controller-manager -c manager --namespace=${operator_namespace}
}

test_operator() {
# kind has an issue with certain image registries (ex. redhat's), so use a
# different test pod image.
local metrics_test_image="fedora:latest"
local metrics_test_image="$METRICS_TEST_IMAGE"

# wait for operator pod to run
if ! timeout 1m kubectl rollout status deployment/nginx-operator;
if ! timeout 1m kubectl rollout status deployment/nginx-operator-controller-manager -n ${operator_namespace} ;
then
kubectl logs deployment/nginx-operator
error_text "Failed to rollout status"
operator_logs
exit 1
fi

# verify that metrics service was created
if ! timeout 60s bash -c -- "until kubectl get service/nginx-operator-metrics > /dev/null 2>&1; do sleep 1; done";
if ! timeout 60s bash -c -- "until kubectl get service/nginx-operator-metrics --namespace=${operator_namespace} > /dev/null 2>&1; do sleep 1; done";
then
echo "Failed to get metrics service"
kubectl logs deployment/nginx-operator
error_text "Failed to get metrics service"
operator_logs
exit 1
fi

# give permissions to reach the metrics endpoint
kubectl create clusterrolebinding nginx-operator-system-metrics-reader --clusterrole=nginx-operator-metrics-reader --serviceaccount=nginx-operator-system:default

# verify that the metrics endpoint exists
if ! timeout 1m bash -c -- "until kubectl run --attach --rm --restart=Never test-metrics --image=${metrics_test_image} -- curl -sfo /dev/null http://nginx-operator-metrics:8383/metrics; do sleep 1; done";
if ! kubectl run --attach --rm --restart=Never --namespace=${operator_namespace} test-metrics --image=${metrics_test_image} -- /bin/bash -c 'curl -sfo /dev/null -v -s -k -H "Authorization: Bearer `cat /var/run/secrets/kubernetes.io/serviceaccount/token`" https://nginx-operator-controller-manager-metrics-service:8443/metrics';
then
echo "Failed to verify that metrics endpoint exists"
kubectl logs deployment/nginx-operator
error_text "Failed to verify that metrics endpoint exists"
operator_logs
exit 1
fi

# create CR
kubectl create --namespace=${test_namespace} -f deploy/crds/helm.example.com_v1alpha1_nginx_cr.yaml
trap_add "kubectl delete --namespace=${test_namespace} --ignore-not-found -f ${OPERATORDIR}/deploy/crds/helm.example.com_v1alpha1_nginx_cr.yaml" EXIT
if ! timeout 1m bash -c -- "until kubectl get --namespace=${test_namespace} nginxes.helm.example.com example-nginx -o jsonpath='{..status.deployedRelease.name}' | grep 'example-nginx'; do sleep 1; done";
kubectl create --namespace=${test_namespace} -f config/samples/helm.example_v1alpha1_nginx.yaml
trap_add "kubectl delete --namespace=${test_namespace} --ignore-not-found -f ${OPERATORDIR}/config/samples/helm.example_v1alpha1_nginx.yaml" EXIT
if ! timeout 1m bash -c -- "until kubectl get --namespace=${test_namespace} nginxes.helm.example.com nginx-sample -o jsonpath='{..status.deployedRelease.name}' | grep 'nginx-sample'; do sleep 1; done";
then
kubectl logs deployment/nginx-operator
exit 1
fi

# verify that the custom resource metrics endpoint exists
if ! timeout 1m bash -c -- "until kubectl run --attach --rm --restart=Never test-cr-metrics --image=${metrics_test_image} -- curl -sfo /dev/null http://nginx-operator-metrics:8686/metrics; do sleep 1; done";
then
echo "Failed to verify that custom resource metrics endpoint exists"
kubectl logs deployment/nginx-operator
error_text "Failed to create CR"
operator_logs
exit 1
fi

header_text "verify that the servicemonitor is created"
if ! timeout 1m bash -c -- "until kubectl get servicemonitors/nginx-operator-metrics > /dev/null 2>&1; do sleep 1; done";
if ! timeout 1m bash -c -- "until kubectl get servicemonitors/nginx-operator-metrics --namespace=${operator_namespace} > /dev/null 2>&1; do sleep 1; done";
then
error_text "FAIL: Failed to get service monitor"
operator_logs
exit 1
fi

release_name=$(kubectl get --namespace=${test_namespace} nginxes.helm.example.com example-nginx -o jsonpath="{..status.deployedRelease.name}")
nginx_deployment=$(kubectl get --namespace=${test_namespace} deployment -l "app.kubernetes.io/instance=${release_name}" -o jsonpath="{..metadata.name}")
release_name=$(kubectl get --namespace=${test_namespace} nginxes.helm.example.com nginx-sample -o jsonpath="{..status.deployedRelease.name}")
nginx_deployment=$(kubectl get --namespace=${test_namespace} deployment -l "app.kubernetes.io/instance=${release_name}" -o jsonpath="{..metadata.name}")

if ! timeout 1m kubectl rollout --namespace=${test_namespace} status deployment/${nginx_deployment};
then
error_text "FAIL: kubectl rollout status CR deployment"
kubectl describe --namespace=${test_namespace} pods -l "app.kubernetes.io/instance=${release_name}"
kubectl describe --namespace=${test_namespace} deployments ${nginx_deployment}
kubectl logs deployment/nginx-operator
operator_logs
exit 1
fi

Expand All @@ -107,31 +109,30 @@ test_operator() {
then
kubectl describe --namespace=${test_namespace} pods -l "app.kubernetes.io/instance=${release_name}"
kubectl describe --namespace=${test_namespace} deployments ${nginx_deployment}
kubectl logs deployment/nginx-operator
operator_logs
exit 1
fi

# update CR to replicaCount=2 and verify the deployment
# automatically scales up to 2 replicas.
kubectl patch --namespace=${test_namespace} nginxes.helm.example.com example-nginx -p '[{"op":"replace","path":"/spec/replicaCount","value":2}]' --type=json
kubectl patch --namespace=${test_namespace} nginxes.helm.example.com nginx-sample -p '[{"op":"replace","path":"/spec/replicaCount","value":2}]' --type=json
if ! timeout 1m bash -c -- "until test \$(kubectl get --namespace=${test_namespace} deployment/${nginx_deployment} -o jsonpath='{..spec.replicas}') -eq 2; do sleep 1; done";
then
kubectl describe --namespace=${test_namespace} pods -l "app.kubernetes.io/instance=${release_name}"
kubectl describe --namespace=${test_namespace} deployments ${nginx_deployment}
kubectl logs deployment/nginx-operator
operator_logs
exit 1
fi

kubectl delete --namespace=${test_namespace} -f deploy/crds/helm.example.com_v1alpha1_nginx_cr.yaml --wait=true
kubectl logs deployment/nginx-operator | grep "Uninstalled release" | grep "${release_name}"
kubectl delete --namespace=${test_namespace} -f config/samples/helm.example_v1alpha1_nginx.yaml --wait=true
kubectl logs deployment/nginx-operator-controller-manager -c manager --namespace=${operator_namespace} | grep "Uninstalled release" | grep "${release_name}"
}

# create and build the operator
pushd "$TMPDIR"
log=$(operator-sdk new nginx-operator \
--api-version=helm.example.com/v1alpha1 \
--kind=Nginx \
--type=helm \
mkdir nginx-operator
cd nginx-operator
log=$(operator-sdk init --plugins=helm.operator-sdk.io/v1 \
--domain=com --group=helm.example --version=v1alpha1 --kind=Nginx \
2>&1)
echo $log
if echo $log | grep -q "failed to generate RBAC rules"; then
Expand All @@ -141,21 +142,12 @@ fi

install_service_monitor_crd

pushd nginx-operator
sed -i".bak" -E -e 's/(FROM quay.io\/operator-framework\/helm-operator)(:.*)?/\1:dev/g' build/Dockerfile; rm -f build/Dockerfile.bak
operator-sdk build "$DEST_IMAGE"
sed -i".bak" -E -e 's/(FROM quay.io\/operator-framework\/helm-operator)(:.*)?/\1:dev/g' Dockerfile; rm -f Dockerfile.bak
make docker-build IMG="$DEST_IMAGE"

# If using a kind cluster, load the image into all nodes.
load_image_if_kind "$DEST_IMAGE"
sed -i".bak" -E -e "s|REPLACE_IMAGE|$DEST_IMAGE|g" deploy/operator.yaml; rm -f deploy/operator.yaml.bak
sed -i".bak" -E -e 's|Always|Never|g' deploy/operator.yaml; rm -f deploy/operator.yaml.bak

kubectl create --dry-run -f "deploy/operator.yaml" -o json | jq '((.spec.template.spec.containers[] | select(.name == "nginx-operator").env[]) | select(.name == "WATCH_NAMESPACE")) |= {"name":"WATCH_NAMESPACE", "value":""}' | kubectl create --dry-run -f - -o yaml > deploy/cluster_operator.yaml
kubectl create --dry-run -f "deploy/role.yaml" -o json | jq '.kind = "ClusterRole"' | kubectl create --dry-run -f - -o yaml > deploy/cluster_role.yaml
kubectl create --dry-run -f "deploy/role_binding.yaml" -o json | jq '.subjects[0].namespace= "default"' | jq '.roleRef.kind= "ClusterRole"' | jq '.kind = "ClusterRoleBinding"' | kubectl create --dry-run -f - -o yaml > deploy/cluster_role_binding.yaml

# kind has an issue with certain image registries (ex. redhat's), so use a
# different test pod image.
METRICS_TEST_IMAGE="fedora:latest"
docker pull "$METRICS_TEST_IMAGE"
# If using a kind cluster, load the metrics test image into all nodes.
load_image_if_kind "$METRICS_TEST_IMAGE"
Expand All @@ -166,6 +158,3 @@ deploy_operator
trap_add 'remove_operator' EXIT
test_operator
remove_operator

popd
popd
111 changes: 0 additions & 111 deletions internal/plugins/helm/api.go

This file was deleted.

Loading

0 comments on commit 0fe8cf4

Please sign in to comment.