Skip to content

Commit

Permalink
Add CircleCI Configuration (#11)
Browse files Browse the repository at this point in the history
* fix go.sum for checksum mismatch

* remove gocov tools

* add circleci config

* fix error statement

* use golang 1.12.4

* add a version label to Dockerfile for introspection in build script

* add make target for publishing a Dockerfile

* add circleci config for dockerfile linting and building on tags

* add docker publishing script

* use an ENTRYPOINT instead of a CMD for published docker

* go.sum updates

* make INTTEST requirement more clear

* use the consul-aws.version LABEL
  • Loading branch information
alvin-huang authored and hanshasselberg committed May 30, 2019
1 parent ad7d8ad commit 69275d6
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 44 deletions.
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

0 comments on commit 69275d6

Please sign in to comment.