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

hack,test: initial e2e test for helm operator #53

Merged
merged 11 commits into from
Oct 23, 2018
Merged
24 changes: 21 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
language: go
go_import_path: github.com/operator-framework/helm-app-operator-kit
sudo: required
language: bash

services:
- docker
script:
- docker build -t quay.io/operatorframework/helm-app-operator-ci:$(git rev-parse --short HEAD) .

jobs:
include:
- before_script: helm-app-operator/hack/ci/setup-openshift.sh
env: CLUSTER=openshift
script: make -C helm-app-operator test/e2e
name: Helm on OpenShift

install:
- curl -Lo dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && chmod +x dep && sudo mv dep /usr/local/bin/
- make -C helm-app-operator dep test/sanity test/unit build


after_success:
- echo "Build succeeded, operator was generated, memcached operator is running on $CLUSTER, and unit/integration tests passed"

after_failure:
- echo "Build failed, operator failed to generate, memcached operator is not running on $CLUSTER, and unit/integration tests failed"
1 change: 0 additions & 1 deletion helm-app-operator/Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 76 additions & 0 deletions helm-app-operator/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# kernel-style V=1 build verbosity
ifeq ("$(origin V)", "command line")
BUILD_VERBOSE = $(V)
endif

ifeq ($(BUILD_VERBOSE),1)
Q =
else
Q = @
endif

VERSION = $(shell git describe --dirty --tags --always)
REPO = github.com/operator-framework/helm-app-operator-kit/helm-app-operator
BUILD_PATH = $(REPO)/cmd/manager
PKGS = $(shell go list ./... | grep -v /vendor/)

export CGO_ENABLED:=0

all: format test build

format:
$(Q)go fmt $(PKGS)

dep:
$(Q)dep ensure -v

clean:
$(Q)rm -rf build/_output

.PHONY: all test format dep clean

build:
./build/build.sh

release_x86_64 := \
build/_output/bin/helm-app-operator-$(VERSION)-x86_64-linux-gnu \
build/_output/bin/helm-app-operator-$(VERSION)-x86_64-apple-darwin

release: clean $(release_x86_64)

build/_output/bin/helm-app-operator-%-x86_64-linux-gnu: GOARGS = GOOS=linux GOARCH=amd64
build/_output/bin/helm-app-operator-%-x86_64-apple-darwin: GOARGS = GOOS=darwin GOARCH=amd64

build/%:
$(Q)$(GOARGS) go build -o $@ $(BUILD_PATH)

DEFAULT_KEY = $(shell gpgconf --list-options gpg \
| awk -F: '$$1 == "default-key" { gsub(/"/,""); print toupper($$10)}')
GIT_KEY = $(shell git config --get user.signingkey | awk '{ print toupper($$0) }')
build/%.asc:
ifeq ("$(DEFAULT_KEY)","$(GIT_KEY)")
$(Q)gpg --output $@ --detach-sig build/$*
$(Q)gpg --verify $@ build/$*
else
@echo "git and/or gpg are not configured to have default signing key ${DEFAULT_KEY}"
@exit 1
endif

.PHONY: build release

test: dep test/sanity test/unit build test/e2e

test/ci-helm: test/e2e/helm

test/sanity:
./hack/tests/sanity-check.sh

test/unit:
./hack/tests/unit.sh

test/e2e: test/e2e/helm

test/e2e/helm:
./hack/tests/e2e-helm.sh

.PHONY: test test/sanity test/unit test/e2e test/e2e/helm test/ci-helm
16 changes: 15 additions & 1 deletion helm-app-operator/cmd/manager/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2018 The Operator-SDK Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
Expand Down Expand Up @@ -30,7 +44,7 @@ func main() {

namespace, err := k8sutil.GetWatchNamespace()
if err != nil {
logrus.Fatalf("Failed to get watch namespace: %v", err)
logrus.Fatalf("failed to get watch namespace: %v", err)
}

// TODO: Expose metrics port after SDK uses controller-runtime's dynamic client
Expand Down
15 changes: 15 additions & 0 deletions helm-app-operator/hack/check_error_case.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

set -o nounset
set -o pipefail

source "hack/lib/test_lib.sh"

echo "Checking case of error messages..."
allfiles=$(listFiles)
output=$(grep -Rn 'Fatalf("[[:upper:]]\|Errorf("[[:upper:]]\|errors.New("[[:upper:]]' $allfiles)
if [ -n "${output}" ]; then
echo "Error messages in wrong case:"
echo "${output}"
exit 255
fi
20 changes: 20 additions & 0 deletions helm-app-operator/hack/check_license.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash

set -o errexit
set -o nounset
set -o pipefail

source "hack/lib/test_lib.sh"

echo "Checking for license header..."
allfiles=$(listFiles)
licRes=""
for file in $allfiles; do
if ! head -n3 "${file}" | grep -Eq "(Copyright|generated|GENERATED)" ; then
licRes="${licRes}\n"$(echo -e " ${file}")
fi
done
if [ -n "${licRes}" ]; then
echo -e "license header checking failed:\n${licRes}"
exit 255
fi
15 changes: 15 additions & 0 deletions helm-app-operator/hack/ci/setup-openshift.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Configure insecure docker registry for openshift
sudo service docker stop
sudo sed -i 's/DOCKER_OPTS=\"/DOCKER_OPTS=\"--insecure-registry 172.30.0.0\/16 /' /etc/default/docker
sudo service docker start
# Download oc to spin up openshift on local docker instance
curl -Lo oc.tar.gz https://github.com/openshift/origin/releases/download/v3.11.0/openshift-origin-client-tools-v3.11.0-0cbc58b-linux-64bit.tar.gz
# Put oc binary in path
tar xvzOf oc.tar.gz openshift-origin-client-tools-v3.11.0-0cbc58b-linux-64bit/oc > oc && chmod +x oc && sudo mv oc /usr/local/bin/
# Start oc cluster
oc cluster up
# Become cluster admin
oc login -u system:admin

# kubectl is needed for the single namespace local test and the ansible tests
curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/v1.11.3/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
8 changes: 8 additions & 0 deletions helm-app-operator/hack/lib/test_lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function listPkgs() {
go list ./... | grep -v generated
}

function listFiles() {
# pipeline is much faster than for loop
listPkgs | xargs -I {} find "${GOPATH}/src/{}" -name '*.go' | grep -v generated
}
103 changes: 103 additions & 0 deletions helm-app-operator/hack/tests/e2e-helm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env bash

#===================================================================
# FUNCTION trap_add ()
#
# Purpose: prepends a command to a trap
#
# - 1st arg: code to add
# - remaining args: names of traps to modify
#
# Example: trap_add 'echo "in trap DEBUG"' DEBUG
#
# See: http://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal
#===================================================================
trap_add() {
trap_add_cmd=$1; shift || fatal "${FUNCNAME} usage error"
new_cmd=
for trap_add_name in "$@"; do
# Grab the currently defined trap commands for this trap
existing_cmd=`trap -p "${trap_add_name}" | awk -F"'" '{print $2}'`

# Define default command
[ -z "${existing_cmd}" ] && existing_cmd="echo exiting @ `date`"

# Generate the new command
new_cmd="${trap_add_cmd};${existing_cmd}"

# Assign the test
trap "${new_cmd}" "${trap_add_name}" || \
fatal "unable to add to trap ${trap_add_name}"
done
}

set -ex

TAG=$(git rev-parse --short HEAD)
BASE_IMAGE=quay.io/example/helm-app-operator:${TAG}
MEMCACHED_IMAGE=quay.io/example/memcached-operator:${TAG}

# switch to the "default" namespace if on openshift, to match the minikube test
if which oc 2>/dev/null; then oc project default; fi

# build operator base image
docker build -t ${BASE_IMAGE} -f build/Dockerfile .

# build a memcached operator
pushd test
pushd memcached-operator
DIR1=$(pwd)

mkdir chart && wget -qO- https://storage.googleapis.com/kubernetes-charts/memcached-2.3.1.tgz | tar -xzv --strip-components=1 -C ./chart
trap_add 'rm -rf ${DIR1}/chart' EXIT

docker build --build-arg BASE_IMAGE=${BASE_IMAGE} -t ${MEMCACHED_IMAGE} .
sed "s|REPLACE_IMAGE|${MEMCACHED_IMAGE}|g" deploy/operator.yaml.tmpl > deploy/operator.yaml
sed -i "s|Always|Never|g" deploy/operator.yaml
trap_add 'rm ${DIR1}/deploy/operator.yaml' EXIT

# deploy the operator
kubectl create -f deploy/rbac.yaml
trap_add 'kubectl delete -f ${DIR1}/deploy/rbac.yaml' EXIT

kubectl create -f deploy/crd.yaml
trap_add 'kubectl delete -f ${DIR1}/deploy/crd.yaml' EXIT

kubectl create -f deploy/operator.yaml
trap_add 'kubectl delete -f ${DIR1}/deploy/operator.yaml' EXIT


# wait for operator pod to run
if ! timeout 1m kubectl rollout status deployment/memcached-operator;
then
kubectl describe deployment memcached-operator
kubectl logs deployment/memcached-operator
exit 1
fi

# create CR
kubectl create -f deploy/cr.yaml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw this is fine for now but just a heads up when we move this test into the SDK the project layout is a little different after the controller-runtime refactor:
https://github.com/operator-framework/operator-sdk-samples/tree/master/memcached-operator/deploy

trap_add 'kubectl delete --ignore-not-found -f ${DIR1}/deploy/cr.yaml' EXIT
if ! timeout 1m bash -c -- 'until kubectl get memcacheds.helm.example.com my-test-app -o jsonpath="{..status.release.info.status.code}" | grep 1; do sleep 1; done';
then
kubectl describe crds
kubectl logs deployment/memcached-operator
exit 1
fi

release_name=$(kubectl get memcacheds.helm.example.com my-test-app -o jsonpath="{..status.release.name}")
memcached_statefulset=$(kubectl get statefulset -l release=${release_name} -o jsonpath="{..metadata.name}")
kubectl patch statefulset ${memcached_statefulset} -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
if ! timeout 1m kubectl rollout status statefulset/${memcached_statefulset};
then
kubectl describe pods -l release=${release_name}
kubectl describe statefulsets ${memcached_statefulset}
kubectl logs statefulset/${memcached_statefulset}
exit 1
fi

kubectl delete -f deploy/cr.yaml --wait=true
kubectl logs deployment/memcached-operator | grep "Uninstalled release for apiVersion=helm.example.com/v1alpha1 kind=Memcached name=default/my-test-app"

popd
popd
10 changes: 10 additions & 0 deletions helm-app-operator/hack/tests/sanity-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -ex

go vet ./...

./hack/check_license.sh
./hack/check_error_case.sh

# Make sure repo is in clean state
git diff --exit-code
4 changes: 4 additions & 0 deletions helm-app-operator/hack/tests/unit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -ex

go test ./...
14 changes: 14 additions & 0 deletions helm-app-operator/pkg/apis/app/v1alpha1/doc.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2018 The Operator-SDK Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +k8s:deepcopy-gen=package
// +groupName=app.coreos.com
package v1alpha1
14 changes: 14 additions & 0 deletions helm-app-operator/pkg/apis/app/v1alpha1/types.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2018 The Operator-SDK Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha1

import (
Expand Down
14 changes: 14 additions & 0 deletions helm-app-operator/pkg/apis/app/v1alpha1/types_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2018 The Operator-SDK Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha1

import (
Expand Down
14 changes: 14 additions & 0 deletions helm-app-operator/pkg/helm/client.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2018 The Operator-SDK Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package helm

import (
Expand Down
Loading