diff --git a/.travis.yml b/.travis.yml index 6bfaebef..2139f9f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,10 +8,9 @@ git: depth: 1 install: true before_script: -- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ${GOPATH}/bin v1.20.0 -- go get github.com/mitchellh/gox@v1.0.1 +- make ci-setup script: -- make fmt check build-cross +- make ci-tests ci-dist deploy: provider: releases skip_cleanup: true diff --git a/Dockerfile b/Dockerfile index 87b4589c..07d8716c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,4 +4,10 @@ COPY . . RUN make build && bin/k3d --version FROM docker:19.03-dind + +# TODO: we could create a different stage for e2e tests +RUN apk add bash curl sudo +RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl && \ + chmod +x ./kubectl && \ + mv ./kubectl /usr/local/bin/kubectl COPY --from=builder /app/bin/k3d /bin/k3d diff --git a/Makefile b/Makefile index 84cf5c1b..570c0052 100644 --- a/Makefile +++ b/Makefile @@ -32,10 +32,12 @@ GOFLAGS := BINDIR := $(CURDIR)/bin BINARIES := k3d +K3D_IMAGE_TAG := $(GIT_TAG) # Go Package required PKG_GOX := github.com/mitchellh/gox@v1.0.1 PKG_GOLANGCI_LINT_VERSION := 1.22.2 +PKG_GOLANGCI_LINT_SCRIPT := https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh PKG_GOLANGCI_LINT := github.com/golangci/golangci-lint/cmd/golangci-lint@v${PKG_GOLANGCI_LINT_VERSION} # configuration adjustments for golangci-lint @@ -62,12 +64,16 @@ LINT_DIRS := $(DIRS) $(foreach dir,$(REC_DIRS),$(dir)/...) all: clean fmt check build build: - CGO_ENABLED=0 $(GO) build -i $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o '$(BINDIR)/$(BINARIES)' + CGO_ENABLED=0 $(GO) build $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o '$(BINDIR)/$(BINARIES)' build-cross: LDFLAGS += -extldflags "-static" build-cross: CGO_ENABLED=0 gox -parallel=3 -output="_dist/$(BINARIES)-{{.OS}}-{{.Arch}}" -osarch='$(TARGETS)' $(GOFLAGS) $(if $(TAGS),-tags '$(TAGS)',) -ldflags '$(LDFLAGS)' +build-dockerfile: Dockerfile + @echo "Building Docker image k3d:$(K3D_IMAGE_TAG)" + docker build -t k3d:$(K3D_IMAGE_TAG) . + clean: @rm -rf $(BINDIR) _dist/ @@ -79,6 +85,19 @@ extra-clean: clean fmt: @gofmt -s -l -w $(GO_SRC) +e2e: build + EXE='$(BINDIR)/$(BINARIES)' ./tests/runner.sh + +e2e-dind: build-dockerfile + @echo "Running e2e tests in k3d:$(K3D_IMAGE_TAG)" + docker run -ti --rm \ + -v `pwd`/tests:/tests \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e EXE="/bin/k3d" \ + -e CI="true" \ + k3d:$(K3D_IMAGE_TAG) \ + /bin/bash /tests/runner.sh + # check-fmt returns an error code if any source code contains format error. check-fmt: @test -z $(shell gofmt -s -l $(GO_SRC) | tee /dev/stderr) || echo "[WARN] Fix formatting issues with 'make fmt'" @@ -98,15 +117,31 @@ ifndef HAS_GOX ($(GO) get $(PKG_GOX)) endif ifndef HAS_GOLANGCI - (curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b ${GOPATH}/bin v${PKG_GOLANGCI_LINT_VERSION}) + (curl -sfL $(PKG_GOLANGCI_LINT_SCRIPT) | sh -s -- -b ${GOPATH}/bin v${PKG_GOLANGCI_LINT_VERSION}) endif ifdef HAS_GOLANGCI ifeq ($(HAS_GOLANGCI_VERSION),) ifdef INTERACTIVE @echo "Warning: Your installed version of golangci-lint (interactive: ${INTERACTIVE}) differs from what we'd like to use. Switch to v${PKG_GOLANGCI_LINT_VERSION}? [Y/n]" - @read line; if [ $$line == "y" ]; then (curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b ${GOPATH}/bin v${PKG_GOLANGCI_LINT_VERSION}); fi + @read line; if [ $$line == "y" ]; then (curl -sfL $(PKG_GOLANGCI_LINT_SCRIPT) | sh -s -- -b ${GOPATH}/bin v${PKG_GOLANGCI_LINT_VERSION}); fi else @echo "Warning: you're not using the same version of golangci-lint as us (v${PKG_GOLANGCI_LINT_VERSION})" endif endif endif + +ci-setup: + @echo "Installing Go tools..." + curl -sfL $(PKG_GOLANGCI_LINT_SCRIPT) | sh -s -- -b ${GOPATH}/bin v$(PKG_GOLANGCI_LINT_VERSION) + go get $(PKG_GOX) + + @echo "Installing kubectl..." + curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + +ci-tests: fmt check e2e + +ci-dist: build-cross + +ci-tests-dind: fmt check e2e-dind diff --git a/tests/01-basic.sh b/tests/01-basic.sh new file mode 100755 index 00000000..c296b064 --- /dev/null +++ b/tests/01-basic.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +CURR_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +[ -d "$CURR_DIR" ] || { echo "FATAL: no current dir (maybe running in zsh?)"; exit 1; } + +# shellcheck source=./common.sh +source "$CURR_DIR/common.sh" + +######################################################################################### + +info "Creating two clusters..." +$EXE create --wait 60 --name "c1" --api-port 6443 || failed "could not create cluster c1" +$EXE create --wait 60 --name "c2" --api-port 6444 || failed "could not create cluster c2" + +info "Checking we have access to both clusters..." +check_k3d_clusters "c1" "c2" || failed "error checking cluster" + +info "Deleting clusters..." +$EXE delete --name "c1" || failed "could not delete the cluster c1" +$EXE delete --name "c2" || failed "could not delete the cluster c2" + +exit 0 + + diff --git a/tests/common.sh b/tests/common.sh new file mode 100644 index 00000000..fc726144 --- /dev/null +++ b/tests/common.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +RED='\033[1;31m' +GRN='\033[1;32m' +YEL='\033[1;33m' +BLU='\033[1;34m' +WHT='\033[1;37m' +MGT='\033[1;95m' +CYA='\033[1;96m' +END='\033[0m' +BLOCK='\033[1;37m' + +PATH=/usr/local/bin:$PATH +export PATH + +log() { >&2 printf "${BLOCK}>>>${END} $1\n"; } + +info() { log "${BLU}$1${END}"; } +highlight() { log "${MGT}$1${END}"; } + +bye() { + log "${BLU}$1... exiting${END}" + exit 0 +} + +warn() { log "${RED}!!! WARNING !!! $1 ${END}"; } + +abort() { + log "${RED}FATAL: $1${END}" + exit 1 +} + +command_exists() { + command -v $1 >/dev/null 2>&1 +} + +failed() { + if [ -z "$1" ] ; then + log "${RED}failed!!!${END}" + else + log "${RED}$1${END}" + fi + abort "test failed" +} + +passed() { + if [ -z "$1" ] ; then + log "${GRN}done!${END}" + else + log "${GRN}$1${END}" + fi +} + +# checks that a URL is available, with an optional error message +check_url() { + command_exists curl || abort "curl is not installed" + curl -L --silent -k --output /dev/null --fail "$1" +} + +check_k3d_clusters() { + for c in "c1" "c2" ; do + kc=$($EXE get-kubeconfig --name "$c") + if kubectl --kubeconfig=$kc cluster-info ; then + passed "cluster $c is reachable" + else + warn "could not obtain cluster info for $c with kubeconfig=$kc. Contents:\n$(cat $kc)" + return 1 + fi + done + return 0 +} diff --git a/tests/runner.sh b/tests/runner.sh new file mode 100755 index 00000000..52e8fe4e --- /dev/null +++ b/tests/runner.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +CURR_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +[ -d "$CURR_DIR" ] || { echo "FATAL: no current dir (maybe running in zsh?)"; exit 1; } + +# shellcheck source=./common.sh +source "$CURR_DIR/common.sh" + +######################################################################################### + +[ -n "$EXE" ] || abort "no EXE provided" + +info "Starting e2e tests..." + +for i in $CURR_DIR/[0-9]*.sh ; do + base=$(basename $i .sh) + highlight "***** Running $base *****" + $i || abort "test $base failed" +done + +exit 0 +