Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CircleCI Configuration #11

Merged
merged 13 commits into from
May 30, 2019
163 changes: 163 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
version: 2.1

references:
images:
go: &GOLANG_IMAGE circleci/golang:1.12.4
consul-current: &CONSUL_IMAGE_CURRENT consul:1.4.4
consul-previous: &CONSUL_IMAGE_PREVIOUS consul:1.4.3

# reusable 'executor' object for jobs
executors:
go:
docker:
- image: *GOLANG_IMAGE
environment:
- TEST_RESULTS: /tmp/test-results # path to where test results are saved

jobs:
go-fmt-and-vet:
executor: go
steps:
- checkout

# Restore go module cache if there is one
- restore_cache:
keys:
- consul-aws-modcache-v1-{{ checksum "go.mod" }}

- run: go mod download

# Save go module cache if the go.mod file has changed
- save_cache:
key: consul-aws-modcache-v1-{{ checksum "go.mod" }}
paths:
- "/go/pkg/mod"

# check go fmt output because it does not report non-zero when there are fmt changes
- run:
name: check go fmt
command: |
files=$(go fmt ./...)
if [ -n "$files" ]; then
echo "The following file(s) do not conform to go fmt:"
echo "$files"
exit 1
fi
- run: go vet ./...

test:
parameters:
consul-version:
description: What version of Consul to test against
type: string
executor: go
environment:
NAMESPACEID: ns-btldyxsz7rymvf4x # AWS Cloud Map Namespace for CI
NAMESPACEIDHTTP: ns-dhshakmjzetizgi2 # AWS Cloud Map Namespace for CI
docker: # the docker stanza will overwrite the executor so we need to define GOLANG_IMAGE again here
- image: *GOLANG_IMAGE
- image: << parameters.consul-version >>
parallelism: 1 # make this explicit in case we need to parallelize in the future
steps:
- checkout
- run: mkdir -p $TEST_RESULTS

# Restore go module cache if there is one
- restore_cache:
keys:
- consul-aws-modcache-v1-{{ checksum "go.mod" }}

# run go tests with gotestsum
- run: |
PACKAGE_NAMES=$(go list ./...)
gotestsum --format=short-verbose --junitfile $TEST_RESULTS/gotestsum-report.xml -- $PACKAGE_NAMES
- store_test_results:
path: /tmp/test-results
- store_artifacts:
path: /tmp/test-results

build-distros:
executor: go
environment:
GOXPARALLEL: 2 # CircleCI containers are 2 CPU x 4GB RAM
steps:
- checkout

# Restore go module cache if there is one
- restore_cache:
keys:
- consul-aws-modcache-v1-{{ checksum "go.mod" }}

- run: make tools
- run: ./build-support/scripts/build-local.sh

# save dev build to CircleCI
- store_artifacts:
path: ./pkg/bin

# Lints all *.dockerfile but don't fail at this time
dockerfile-lint:
docker:
- image: hadolint/hadolint:latest-debian
steps:
- run: apt-get -qq update; apt-get -y install git # the hadolint container doesn't have git
- checkout
- run:
name: Dockefile lint
command: |
for file in $(find . -type f -name *.dockerfile); do
hadolint $file || true
done

# Builds and publishes Docker Container to Dockerhub for tagged releases
docker-build:
executor: go
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: true
- run:
name: wait for release package
command: |
CONSUL_AWS_VERSION=$(echo ${CIRCLE_TAG} | sed 's/v\(.*\)/\1/')
echo "curl-ing https://releases.hashicorp.com/${CIRCLE_PROJECT_REPONAME}/${CONSUL_AWS_VERSION}/${CIRCLE_PROJECT_REPONAME}_${CONSUL_AWS_VERSION}_linux_amd64.zip"
until [ $SECONDS -ge 300 ] && exit 1; do
curl -o /dev/null --fail --silent "https://releases.hashicorp.com/${CIRCLE_PROJECT_REPONAME}/${CONSUL_AWS_VERSION}/${CIRCLE_PROJECT_REPONAME}_${CONSUL_AWS_VERSION}_linux_amd64.zip" && exit
echo -n "."
sleep 2
done
- run: make docker-publish
workflows:
version: 2
test-and-build:
jobs:
- go-fmt-and-vet
- test:
name: test-previous-consul-version
consul-version: *CONSUL_IMAGE_PREVIOUS
requires:
- go-fmt-and-vet
- test:
name: test-current-consul-version
consul-version: *CONSUL_IMAGE_CURRENT
# The resources created in the tests with the two consul versions are the same
# This can be changed to run in parallel once a prefix/uniqueness is added to the tests
requires:
- test-previous-consul-version
- build-distros:
requires:
- test-current-consul-version
docker-build-and-publish:
jobs:
- dockerfile-lint:
filters:
tags:
only: /^v\d+\.\d+\.\d+$/
- docker-build:
requires:
- dockerfile-lint
filters:
tags:
only: /^v\d+\.\d+\.\d+$/
branches:
ignore: /.*/
16 changes: 12 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ GOTOOLS = \
github.com/magiconair/vendorfmt/cmd/vendorfmt \
github.com/mitchellh/gox \
golang.org/x/tools/cmd/cover \
golang.org/x/tools/cmd/stringer \
github.com/axw/gocov/gocov \
gopkg.in/matm/v1/gocov-html
golang.org/x/tools/cmd/stringer

DEV_IMAGE?=consul-aws-dev
GO_BUILD_TAG?=consul-aws-build-go
Expand All @@ -20,6 +18,12 @@ GIT_DESCRIBE?=$(shell git describe --tags --always)
GIT_IMPORT=github.com/hashicorp/consul-aws/version
GOLDFLAGS=-X $(GIT_IMPORT).GitCommit=$(GIT_COMMIT)$(GIT_DIRTY) -X $(GIT_IMPORT).GitDescribe=$(GIT_DESCRIBE)

# Docker Image publishing variables
DOCKER_IMAGE_NAME=consul-aws
DOCKER_ORG=hashicorp
export DOCKER_IMAGE_NAME
export DOCKER_ORG

export GIT_COMMIT
export GIT_DIRTY
export GIT_DESCRIBE
Expand Down Expand Up @@ -105,10 +109,14 @@ go-build-image:
@echo "Building Golang build container"
@docker build $(NOCACHE) $(QUIET) --build-arg 'GOTOOLS=$(GOTOOLS)' -t $(GO_BUILD_TAG) - < build-support/docker/Build-Go.dockerfile

docker-publish:
@echo "Building Docker Image"
@$(SHELL) $(CURDIR)/build-support/scripts/publish-docker.sh

clean:
@rm -rf \
$(CURDIR)/bin \
$(CURDIR)/pkg


.PHONY: all bin clean dev dist docker-images go-build-image test tools
.PHONY: all bin clean dev dist docker-images go-build-image test tools docker-publish
5 changes: 4 additions & 1 deletion build-support/docker/Release.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ ENV VERSION=$VERSION
# This is the location of the releases.
ENV HASHICORP_RELEASES=https://releases.hashicorp.com

# Add a label for introspection of version
LABEL consul-aws.version=$VERSION

# Create a non-root user to run the software.
RUN addgroup ${NAME} && \
adduser -S -G ${NAME} ${NAME}
Expand Down Expand Up @@ -59,4 +62,4 @@ RUN set -eux && \
rm -rf /root/.gnupg

USER ${NAME}
CMD /bin/${NAME}
ENTRYPOINT /bin/${NAME}
111 changes: 111 additions & 0 deletions build-support/scripts/publish-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/bin/bash

# Description:
# This script will publish consul-aws containers to Dockerhub. It should only run on tagged
# branches within CI and all the variables needed are populated either by CircleCI or the Makefile.

# To publish a new container, make sure the following environment variables are set:
# * CIRCLE_TAG - the version of the consul-aws binary you want to build an image for
# * DOCKER_ORG - to the organization of the docker image
# * DOCKER_IMAGE_NAME - to the name of the docker image

function get_latest_docker_version {
# Arguments:
# $1 - Docker Org
# $2 - Docker Image Name
#
#
# Returns:
# 0 - success (version in the 'latest' container echoed)
# 1 - 'latest' tag does not exist or label could not be found

docker_latest=$(docker inspect --format='{{ index .Config.Labels "consul-aws.version" }}' "$1"/"$2":latest 2> /dev/null)

if [ -z "$docker_latest" ]; then
return 1
else
echo "$docker_latest"
return 0
fi
}

function get_latest_docker_minor_version {
# Arguments:
# $1 - Docker Org
# $2 - Docker Image Name
# $3 - Minor Version Tag
#
# Returns:
# 0 - success (version in the latest minor version container echoed)
# 1 - tag does not exist or label could not be found
docker_latest_minor=$(docker inspect --format='{{ index .Config.Labels "consul-aws.version" }}' "$1"/"$2":"$3" 2> /dev/null)

if [ -z "$docker_latest_minor" ]; then
return 1
else
echo "$docker_latest_minor"
return 0
fi
}

function higher_version {
# Arguments:
# $1 - first version to compare
# $2 - second version to compare
#
# Returns:
# higher version of two arguments

higher_version=$(echo -e "$1\n$2" | sort -rV | head -n 1)
echo "$higher_version"
}
function main() {
# check for necessary variables
: "${CIRCLE_TAG?"Need to set CIRCLE_TAG"}"
: "${DOCKER_ORG?"Need to set DOCKER_ORG"}"
: "${DOCKER_IMAGE_NAME?"Need to set DOCKER_IMAGE_NAME"}"

# trims v from version, ex: v1.2.3 -> 1.2.3; this maps to releases.hashicorp.com
CURRENT_TAG_VERSION=$(echo "$CIRCLE_TAG" | sed 's/v\(.*\)/\1/')

# trims the patch part of the git tag to compare
MINOR_VERSION=${CIRCLE_TAG%.[0-9]*}
DOCKER_MINOR_TAG="${MINOR_VERSION#v}-latest"

LATEST_DOCKER_MINOR_VERSION=$(get_latest_docker_minor_version "$DOCKER_ORG" "$DOCKER_IMAGE_NAME" "$DOCKER_MINOR_TAG")
LATEST_DOCKER_VERSION=$(get_latest_docker_version "$DOCKER_ORG" "$DOCKER_IMAGE_NAME")

# Login to Dockerhub
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS"

# build current branch tag image
docker build -t "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$CURRENT_TAG_VERSION" --build-arg NAME="$DOCKER_IMAGE_NAME" --build-arg VERSION="$CURRENT_TAG_VERSION" -f "$(pwd)"/build-support/docker/Release.dockerfile "$(pwd)"/build-support/docker
docker push "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$CURRENT_TAG_VERSION"

# check to see if the current tag is higher than the latest minor version on dockerhub
HIGHER_MINOR_VERSION=$(higher_version "$CURRENT_TAG_VERSION" "$LATEST_DOCKER_MINOR_VERSION")

# if the higher version is the current tag, we tag the current image with the minor tag
if [ "$HIGHER_MINOR_VERSION" = "$CURRENT_TAG_VERSION" ]; then
echo "Tagging a new minor latest image"
docker tag "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$CURRENT_TAG_VERSION" "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$DOCKER_MINOR_TAG"
docker push "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$DOCKER_MINOR_TAG"
fi

# check to see if the current tag is higher than the latest version on dockerhub
HIGHER_LATEST_VERSION=$(higher_version "$CURRENT_TAG_VERSION" "$LATEST_DOCKER_VERSION")

# if:
# * we didn't find a version from the 'latest' image, it means it doesn't exist
# * or if the current tag version is higher than the latest docker one
# we build latest
if [ -z "$LATEST_DOCKER_VERSION" ] || [ "$HIGHER_LATEST_VERSION" = "$CURRENT_TAG_VERSION" ]; then
echo "Tagging a new latest docker image"
docker tag "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$CURRENT_TAG_VERSION" "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":latest
docker push "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":latest
fi

return 0
}
main "$@"
exit $?
4 changes: 2 additions & 2 deletions catalog/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

func TestSync(t *testing.T) {
if len(os.Getenv("INTTEST")) == 0 {
t.Skip("no int test env")
t.Skip("Set INTTEST=1 to enable integration tests")
}
namespaceID := os.Getenv("NAMESPACEID")
if len(namespaceID) == 0 {
Expand Down Expand Up @@ -42,7 +42,7 @@ func runSyncTest(t *testing.T, namespaceID string) {

err = createServiceInConsul(c, cID, cName)
if err != nil {
t.Fatalf("error creating service in aws: %s", err)
t.Fatalf("error creating service in Consul: %s", err)
}

aID, err := createServiceInAWS(a, namespaceID, aName)
Expand Down
Loading