Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 19 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ jobs:
name: Subcommands on Kubernetes
script: make test-subcommand

# Build and test go
# Build and test go for legacy project layouts
- <<: *test
name: Go on Kubernetes
name: Go for legacy project layouts on Kubernetes
before_script:
- (cd / && go get github.com/mattn/goveralls)
script:
Expand All @@ -143,6 +143,23 @@ jobs:
- make test-e2e-go
- make test-integration

# Build and test go for new project layouts
- name: Go e2e tests for new project layouts
before_install:
# hack/ci/check-doc-only-update.sh needs to be sourced so
# that it can properly exit the test early with success
- source hack/ci/check-doc-only-update.sh
script:
- make test-e2e-go-new
after_success:
- echo "E2E tests passed"
after_failure:
- echo "E2E tests failed"
- kubectl get all --all-namespaces
- kubectl get events --all-namespaces --field-selector=type=Warning
services:
- docker

# Build and test helm
- <<: *test
name: Helm on Kubernetes
Expand Down
14 changes: 10 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,17 @@ test-subcommand-scorecard:
test-subcommand-olm-install:
./hack/tests/subcommand-olm-install.sh

# E2E and integration tests.
.PHONY: test-e2e test-e2e-go test-e2e-ansible test-e2e-ansible-molecule test-e2e-helm test-integration
# E2E tests.
.PHONY: test-e2e test-e2e-go test-e2e-go-new test-e2e-ansible test-e2e-ansible-molecule test-e2e-helm

test-e2e: test-e2e-go test-e2e-ansible test-e2e-ansible-molecule test-e2e-helm ## Run the e2e tests
test-e2e: test-e2e-go test-e2e-go-new test-e2e-ansible test-e2e-ansible-molecule test-e2e-helm ## Run the e2e tests

test-e2e-go:
./hack/tests/e2e-go.sh $(ARGS)

test-e2e-go-new:
K8S_VERSION=$(K8S_VERSION) ./hack/tests/e2e-go-new.sh

test-e2e-ansible: image-build-ansible
./hack/tests/e2e-ansible.sh

Expand All @@ -271,5 +274,8 @@ test-e2e-ansible-molecule: image-build-ansible
test-e2e-helm: image-build-helm
./hack/tests/e2e-helm.sh

test-integration:
# Integration tests.
.PHONY: test-integration

test-integration: ## Run integration tests
./hack/tests/integration.sh
102 changes: 98 additions & 4 deletions hack/lib/common.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
#!/usr/bin/env bash

function log() { printf '%s\n' "$*"; }
function error() { error_text "ERROR:" $* >&2; }
function fatal() { error "$@"; exit 1; }

# Skip fetching and untaring the tools by setting the SKIP_FETCH_TOOLS variable
# in your environment to any value:
#
# $ SKIP_FETCH_TOOLS=1 ./test.sh
#
# If you skip fetching tools, this script will use the tools already on your
# machine, but rebuild the operator-sdk binary.
SKIP_FETCH_TOOLS=${SKIP_FETCH_TOOLS:-""}
# Current version of the 'kind' binary. Update this when a new breaking release
# is made for a docker.io/kindest/node:${K8S_VERSION} image.
KIND_VERSION="v0.8.1"
# ENVTEST_TOOLS_VERSION is the version of k8s server tarballs used for envtest.
# TODO: use K8S_VERSION once we start building our own server binary tarballs.
ENVTEST_TOOLS_VERSION="1.16.4"
# Turn colors in this script off by setting the NO_COLOR variable in your
# environment to any value:
NO_COLOR=${NO_COLOR:-""}
Expand All @@ -17,6 +27,14 @@ else
reset_color=''
fi

# Roots used by tests.
tmp_root=/tmp
tmp_sdk_root=$tmp_root/operator-sdk

function log() { printf '%s\n' "$*"; }
function error() { error_text "ERROR:" $* >&2; }
function fatal() { error "$@"; exit 1; }

function header_text {
echo "$header_color$*$reset_color"
}
Expand All @@ -37,3 +55,79 @@ function is_installed {
function install_service_monitor_crd {
kubectl apply -f https://raw.githubusercontent.com/coreos/prometheus-operator/release-0.35/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml
}

# prepare the e2e test staging dir, containing test tools (SKIP_FETCH_TOOLS aware).
function prepare_staging_dir {

header_text "preparing staging dir $1"

if [[ -z "$SKIP_FETCH_TOOLS" ]]; then
rm -rf "$1"
else
rm -f "$1/bin/operator-sdk"
fi

mkdir -p "$1"
}

# Fetch k8s API gen tools and make it available under $1/bin.
function fetch_tools {
if [[ -z "$SKIP_FETCH_TOOLS" ]]; then
fetch_envtest_tools $@
install_kind $@
fi
}

# Fetch tools required for envtest.
function fetch_envtest_tools {

# TODO: make our own tarball containing envtest binaries: etcd, kubectl, kube-apiserver
#
# To get k8s server binaries:
# server_tar="kubernetes-server-$(go env GOOS)-$(go env GOARCH).tar.gz"
# url=https://dl.k8s.io/$K8S_VERSION/$server_tar
# curl -fL --retry 3 --keepalive-time 2 "${url}" -o "${tmp_sdk_root}/${server_tar}"
# tar -zxvf "${tmp_sdk_root}/${server_tar}"

local tools_archive_name="kubebuilder-tools-${ENVTEST_TOOLS_VERSION}-$(go env GOOS)-$(go env GOARCH).tar.gz"
local tools_download_url="https://storage.googleapis.com/kubebuilder-tools/$tools_archive_name"

local tools_archive_path="$1/$tools_archive_name"
if [[ ! -f $tools_archive_path ]]; then
header_text "fetching envtest tools"
curl -sSLo "$tools_archive_path" $tools_download_url
else
header_text "using existing envtest tools in $tools_archive_path"
fi
tar -zvxf "$tools_archive_path" -C "$1/" --strip-components=1
}

# Set up test and envtest vars
function setup_envs {
header_text "setting up env vars"

export PATH="$1"/bin:$PATH
export TEST_ASSET_KUBECTL="$1"/bin/kubectl
export TEST_ASSET_KUBE_APISERVER="$1"/bin/kube-apiserver
export TEST_ASSET_ETCD="$1"/bin/etcd
}

# Build the operator-sdk binary.
function build_sdk {
header_text "building operator-sdk"

GO111MODULE=on make build/operator-sdk
mv ./build/operator-sdk "$1"/bin/operator-sdk
}

# Install the 'kind' binary at version $KIND_VERSION.
function install_kind {

local kind_path="${1}/bin/kind"

header_text "installing kind $KIND_VERSION"
local kind_binary="kind-$(go env GOOS)-$(go env GOARCH)"
local kind_url="https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/$kind_binary"
curl -sSLo "$kind_path" $kind_url
chmod +x "$kind_path"
}
2 changes: 1 addition & 1 deletion hack/lib/image_lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function is_latest_tag() {
#
function load_image_if_kind() {
if [[ "$(kubectl config current-context)" == "kind-kind" ]]; then
if which kind 2>/dev/null; then
if is_installed kind; then
kind load docker-image "$1"
fi
fi
Expand Down
43 changes: 43 additions & 0 deletions hack/tests/e2e-go-new.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash

# remove running containers on exit
function cleanup() {
kind delete cluster
}

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

source ./hack/lib/common.sh
source ./hack/lib/test_lib.sh

test_dir=./test
tests=$test_dir/e2e-new

export TRACE=1
export GO111MODULE=on

: ${K8S_VERSION:?"must be set"}

prepare_staging_dir $tmp_sdk_root
fetch_tools $tmp_sdk_root
# These envtest environment variables are required for the default unit tests
# scaffolded in the test operator project. No e2e tests currently use envtest.
setup_envs $tmp_sdk_root
build_sdk $tmp_sdk_root

# Create a cluster of version $K8S_VERSION.
kind create cluster -v 4 --retain --wait=1m \
--config $test_dir/kind-config.yaml \
--image=kindest/node:$K8S_VERSION

kind export kubeconfig

kubectl cluster-info

docker pull gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
kind load docker-image gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0

trap_add cleanup EXIT
go test -v $tests
139 changes: 139 additions & 0 deletions test/e2e-new/e2e_suite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright 2020 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.

// Modified from https://github.com/kubernetes-sigs/kubebuilder/tree/39224f0/test/e2e/v3

package e2e

import (
"fmt"
"path/filepath"
"strings"
"time"

. "github.com/onsi/ginkgo" //nolint:golint
. "github.com/onsi/gomega" //nolint:golint

"github.com/operator-framework/operator-sdk/test/e2e-new/utils"
)

var _ = Describe("operator-sdk", func() {
Context("with the new project layout", func() {
var tc *utils.TestContext
BeforeEach(func() {

By("creating a new test context")
var err error
tc, err = utils.NewTestContext("operator-sdk", "GO111MODULE=on")
Expect(err).NotTo(HaveOccurred())
Expect(tc.Prepare()).To(Succeed())
})

AfterEach(func() {
By("cleaning up created API objects during test process")
tc.CleanupManifests(filepath.Join("config", "default"))

By("removing container image and work dir")
tc.Destroy()
})

It("should generate a runnable project", func() {
var controllerPodName string
By("initializing a project")
err := tc.Init(
"--project-version", "3-alpha",
"--domain", tc.Domain,
"--fetch-deps=false")
Expect(err).Should(Succeed())

By("creating an API definition")
err = tc.CreateAPI(
"--group", tc.Group,
"--version", tc.Version,
"--kind", tc.Kind,
"--namespaced",
"--resource",
"--controller",
"--make=false")
Expect(err).Should(Succeed())

By("implementing the API")
Expect(utils.InsertCode(
filepath.Join(tc.Dir, "api", tc.Version, fmt.Sprintf("%s_types.go", strings.ToLower(tc.Kind))),
fmt.Sprintf(`type %sSpec struct {
`, tc.Kind),
` // +optional
Count int `+"`"+`json:"count,omitempty"`+"`"+`
`)).Should(Succeed())

By("building the operator image")
err = tc.Make("docker-build", "IMG="+tc.ImageName)
Expect(err).Should(Succeed())

By("loading the operator image into the test cluster")
err = tc.LoadImageToKindCluster()
Expect(err).Should(Succeed())

By("deploying the controller manager")
err = tc.Make("deploy", "IMG="+tc.ImageName)
Expect(err).Should(Succeed())

By("ensuring the controller-manager pod is running as expected")
verifyControllerUp := func() error {
// Get pod name
podOutput, err := tc.Kubectl.Get(
true,
"pods", "-l", "control-plane=controller-manager",
"-o", "go-template={{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ .metadata.name }}"+
"{{ \"\\n\" }}{{ end }}{{ end }}")
Expect(err).NotTo(HaveOccurred())
podNames := utils.GetNonEmptyLines(podOutput)
if len(podNames) != 1 {
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
}
controllerPodName = podNames[0]
Expect(controllerPodName).Should(ContainSubstring("controller-manager"))

// Validate pod status
status, err := tc.Kubectl.Get(
true,
"pods", controllerPodName, "-o", "jsonpath={.status.phase}")
Expect(err).NotTo(HaveOccurred())
if status != "Running" {
return fmt.Errorf("controller pod in %s status", status)
}
return nil
}
Eventually(verifyControllerUp, time.Minute, time.Second).Should(Succeed())

By("creating an instance of CR")
// currently controller-runtime doesn't provide a readiness probe, we retry a few times
// we can change it to probe the readiness endpoint after CR supports it.
sampleFile := filepath.Join("config", "samples",
fmt.Sprintf("%s_%s_%s.yaml", tc.Group, tc.Version, strings.ToLower(tc.Kind)))
Eventually(func() error {
_, err = tc.Kubectl.Apply(true, "-f", sampleFile)
return err
}, time.Minute, time.Second).Should(Succeed())

By("ensuring the created resource object gets reconciled in controller")
managerContainerLogs := func() string {
logOutput, err := tc.Kubectl.Logs(controllerPodName, "-c", "manager")
Expect(err).NotTo(HaveOccurred())
return logOutput
}
Eventually(managerContainerLogs, time.Minute, time.Second).Should(ContainSubstring("Successfully Reconciled"))
})
})
})
Loading