diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..903fc59 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +* @slok @ese + diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..c6105d6 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,48 @@ +name: CI + +on: [push] + +jobs: + check: + name: Check + runs-on: ubuntu-latest + # Execute the checks inside the container instead the VM. + container: golangci/golangci-lint:v1.28.3-alpine + steps: + - uses: actions/checkout@v1 + - run: ./scripts/check/check.sh + + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-go@v2-beta + with: + go-version: 1.14 + - run: make ci-test + + # release-image: + # if: startsWith(github.ref, 'refs/tags/') + # env: + # TAG_IMAGE_LATEST: "true" + # PROD_IMAGE_NAME: quay.com/${GITHUB_REPOSITORY} + # needs: [check, test] + # name: Release image + # runs-on: ubuntu-latest + # # Only run in master and when has a tag. + # steps: + # - name: Set tag on VERSION env var + # run: echo ::set-env name=VERSION::$(echo ${GITHUB_REF:10}) + # - uses: actions/checkout@v1 + # - name: Build image + # run: make build-image + # - name: Docker login + # run: docker login ${DOCKER_HOST} -u ${DOCKER_USER} -p ${DOCKER_TOKEN} + # env: + # DOCKER_HOST: "" + # DOCKER_USER: slok + # DOCKER_TOKEN: ${{secrets.DOCKER_HUB_TOKEN}} + + # - name: Publish image + # run: make publish-image diff --git a/.gitignore b/.gitignore index 4d12af4..baf7e5c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,5 @@ # Binary bin/ -# vendor -vendor/ \ No newline at end of file +# Coverage. +.test_coverage.txt \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..70ef460 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,5 @@ +--- + +run: + skip-dirs: + - pkg/k8sautogen \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 87358ef..0000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: go -sudo: required -services: - - docker -go: - - "1.13" - -before_install: - # Upgrade default docker - - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" - - sudo apt-get update - - sudo apt-get -y install docker-ce - -script: - - make ci - -deploy: - - provider: script - script: docker login -u="${DOCKER_USER}" -p="${DOCKER_PASSWORD}" quay.io && make push - on: - tags: true - -env: - global: - - GO111MODULE: on - - DOCKER_USER: spotahome+serviceleveloperator - # DOCKER_PASSWORD - - secure: "smTgGZsms3W3cjA2aw34Rr1rNjVIHj9N0CwgpOLWuw3j1Nwb4OdRPdHN8qSc4HpCeIVWUU/rdVr2gsXherok+6vQR5y4Wh4dxTODM/4mVxdY67k7URJra4Vktei0K1hD5E4AYAvUb/YZTlBcex83tIkMaeGSYc+w2PzQHa1R1p4PVVEnsu6+O1Qg4i7xErXLmnSVc5tcqpXRhM/cp/XMNiJPKezRVHD5j73ZzN36xJSkNS/xiHw5nA/B/kpzb/NL/sAvknXNqx8+/S0Y3mIsXId4r8LK3YBjV5ALYZvq0mWc/0vZIZ8Fmcf6J+1LQzT+7O9lUuAFKt9LXMsZbiQuG0YEcqix732IqIXicUSOLA/w9TajLNYXQh05L5mAiejHsFZmtDwCDzRi/wvc4d3NkxJt4YsuUu+2Lsd5DGyyuoz2zlzaVoVRSCYwKTIfLU0XdiQ8ilHpI31BN7TK3z+Eh27MfkbJTldyHB2eV0B6mLWxpYICYf5TzlwHtvLg8FUrJ+W7j9Wk63+0W4pY0gzNMSaZunSEuymHjdn94U01aIjqAjMat6HqvjdAs5mYgLmLqC8clOjMW4fJmhdiSXk0NDEAjG35G3OJ9dsImXgaQrHGMM3SZJAhxPEF+MpH0iUuaqC4ExBQtJFz9sQTOue10zOMVRSOoqZQuGmmj2Uy+zk=" diff --git a/Makefile b/Makefile index f71fe35..6df3dd8 100644 --- a/Makefile +++ b/Makefile @@ -1,138 +1,83 @@ -# Name of this service/application -SERVICE_NAME := service-level-operator -# Shell to use for running scripts SHELL := $(shell which bash) - -# Get docker path or an empty string +OSTYPE := $(shell uname) DOCKER := $(shell command -v docker) +GID := $(shell id -g) +UID := $(shell id -u) +VERSION ?= $(shell git describe --tags --always) -# Get docker-compose path or an empty string -DOCKER_COMPOSE := $(shell command -v docker-compose) +UNIT_TEST_CMD := ./scripts/check/unit-test.sh +INTEGRATION_TEST_CMD := ./scripts/check/integration-test.sh +CHECK_CMD := ./scripts/check/check.sh -# Get the main unix group for the user running make (to be used by docker-compose later) -GID := $(shell id -g) +DEV_IMAGE_NAME := spotahome/service-level-operator-dev +PROD_IMAGE_NAME ?= spotahome/service-level-operator -# Get the unix user id for the user running make (to be used by docker-compose later) -UID := $(shell id -u) +DOCKER_RUN_CMD := docker run --env ostype=$(OSTYPE) -v ${PWD}:/src --rm -it ${DEV_IMAGE_NAME} +BUILD_BINARY_CMD := VERSION=${VERSION} ./scripts/build/build.sh +BUILD_DEV_IMAGE_CMD := IMAGE=${DEV_IMAGE_NAME} DOCKER_FILE_PATH=./docker/dev/Dockerfile VERSION=latest ./scripts/build/build-image.sh +BUILD_PROD_IMAGE_CMD := IMAGE=${PROD_IMAGE_NAME} DOCKER_FILE_PATH=./docker/prod/Dockerfile VERSION=${VERSION} ./scripts/build/build-image.sh +PUBLISH_PROD_IMAGE_CMD := IMAGE=${PROD_IMAGE_NAME} VERSION=${VERSION} ./scripts/build/publish-image.sh -# Bash history file for container shell -HISTORY_FILE := ~/.bash_history.$(SERVICE_NAME) - -# Version from Git. -VERSION=$(shell git describe --tags --always) - -# Dev direcotry has all the required dev files. -DEV_DIR := ./docker/dev - -# cmds -UNIT_TEST_CMD := ./hack/scripts/unit-test.sh -INTEGRATION_TEST_CMD := ./hack/scripts/integration-test.sh -TEST_ALERTS_CMD := ./hack/scripts/test-alerts.sh -MOCKS_CMD := ./hack/scripts/mockgen.sh -DOCKER_RUN_CMD := docker run \ - -v ${PWD}:/src \ - --rm -it $(SERVICE_NAME) -DOCKER_ALERTS_TEST_RUN_CMD := docker run \ - -v ${PWD}:/prometheus \ - --entrypoint=${TEST_ALERTS_CMD} \ - --rm -it prom/prometheus -BUILD_BINARY_CMD := VERSION=${VERSION} ./hack/scripts/build-binary.sh -BUILD_IMAGE_CMD := VERSION=${VERSION} ./hack/scripts/build-image.sh -DEBUG_CMD := go run ./cmd/service-level-operator/* --debug -DEV_CMD := $(DEBUG_CMD) --development -FAKE_CMD := $(DEV_CMD) --fake -K8S_CODE_GEN_CMD := ./hack/scripts/k8scodegen.sh -OPENAPI_CODE_GEN_CMD := ./hack/scripts/openapicodegen.sh -DEPS_CMD := GO111MODULE=on go mod tidy && GO111MODULE=on go mod vendor -K8S_VERSION := 1.13.12 -SET_K8S_DEPS_CMD := GO111MODULE=on go mod edit \ - -require=k8s.io/apiextensions-apiserver@kubernetes-${K8S_VERSION} \ - -require=k8s.io/client-go@kubernetes-${K8S_VERSION} \ - -require=k8s.io/apimachinery@kubernetes-${K8S_VERSION} \ - -require=k8s.io/api@kubernetes-${K8S_VERSION} \ - -require=k8s.io/kubernetes@v${K8S_VERSION} && \ - $(DEPS_CMD) - - -# The default action of this Makefile is to build the development docker image -default: build - -# Test if the dependencies we need to run this Makefile are installed -.PHONY: deps-development -deps-development: -ifndef DOCKER - @echo "Docker is not available. Please install docker" - @exit 1 -endif -ifndef DOCKER_COMPOSE - @echo "docker-compose is not available. Please install docker-compose" - @exit 1 -endif - -# Build the development docker images -.PHONY: build -build: - docker build -t $(SERVICE_NAME) --build-arg uid=$(UID) --build-arg gid=$(GID) -f $(DEV_DIR)/Dockerfile . -# run the development stack. -.PHONY: stack -stack: deps-development - cd $(DEV_DIR) && \ - ( docker-compose -p $(SERVICE_NAME) up --build; \ - docker-compose -p $(SERVICE_NAME) stop; \ - docker-compose -p $(SERVICE_NAME) rm -f; ) +help: ## Show this help + @echo "Help" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[93m %s\n", $$1, $$2}' -# Build production stuff. -build-binary: build - $(DOCKER_RUN_CMD) /bin/sh -c '$(BUILD_BINARY_CMD)' +.PHONY: default +default: help .PHONY: build-image -build-image: - $(BUILD_IMAGE_CMD) +build-image: ## Builds the production docker image. + @$(BUILD_PROD_IMAGE_CMD) -# Dependencies stuff. -.PHONY: set-k8s-deps -set-k8s-deps: - $(SET_K8S_DEPS_CMD) +.PHONY: publish-image +publish-image: ## Publishes the production docker image. + @$(PUBLISH_PROD_IMAGE_CMD) + +.PHONY: build-dev-image +build-dev-image: ## Builds the development docker image. + @$(BUILD_DEV_IMAGE_CMD) + +.PHONY: build +build: build-dev-image ## Builds the production binary. + @$(DOCKER_RUN_CMD) /bin/sh -c '$(BUILD_BINARY_CMD)' -.PHONY: deps -deps: - $(DEPS_CMD) - -k8s-code-gen: - $(K8S_CODE_GEN_CMD) - -openapi-code-gen: - $(OPENAPI_CODE_GEN_CMD) - -# Test stuff in dev -.PHONY: test-alerts -test-alerts: - $(DOCKER_ALERTS_TEST_RUN_CMD) -.PHONY: unit-test -unit-test: build - $(DOCKER_RUN_CMD) /bin/sh -c '$(UNIT_TEST_CMD)' -.PHONY: integration-test -integration-test: build - $(DOCKER_RUN_CMD) /bin/sh -c '$(INTEGRATION_TEST_CMD)' -.PHONY: test -test: integration-test .PHONY: test -ci: test test-alerts +test: build-dev-image ## Runs unit test. + @$(DOCKER_RUN_CMD) /bin/sh -c '$(UNIT_TEST_CMD)' + +.PHONY: check +check: build-dev-image ## Runs checks. + @$(DOCKER_RUN_CMD) /bin/sh -c '$(CHECK_CMD)' + +.PHONY: integration +integration: build-dev-image ## Runs integration test. + @$(DOCKER_RUN_CMD) /bin/sh -c '$(INTEGRATION_TEST_CMD)' -# Mocks stuff in dev -.PHONY: mocks -mocks: build - # FIX: Problem using go mod with vektra/mockery. - #$(DOCKER_RUN_CMD) /bin/sh -c '$(MOCKS_CMD)' - $(MOCKS_CMD) +.PHONY: go-gen +go-gen: build-dev-image ## Generates go based code. + @$(DOCKER_RUN_CMD) /bin/sh -c './scripts/gogen.sh' + +.PHONY: kube-gen +kube-gen: ## Generates Kubernetes based code. + /bin/sh -c './scripts/kubegen.sh' + +.PHONY: gen +gen: go-gen kube-gen ## Generates all. + +.PHONY: deps +deps: ## Fixes the dependencies + @$(DOCKER_RUN_CMD) /bin/sh -c './scripts/deps.sh' -.PHONY: dev -dev: - $(DEV_CMD) +.PHONY: ci-unit-test +ci-test: ## Runs unit test in CI environment (without docker). + @$(UNIT_TEST_CMD) +.PHONY: ci-check +ci-check: ## Runs checks in CI environment (without docker). + @$(CHECK_CMD) -.PHONY: push -push: export PUSH_IMAGE=true -push: build-image +.PHONY: ci-integration-test +ci-integration: ## Runs integraton test in CI environment (without docker). + @$(INTEGRATION_TEST_CMD) diff --git a/cmd/service-level-operator/flags.go b/cmd/service-level-operator/flags.go index f2cb066..7c702d9 100644 --- a/cmd/service-level-operator/flags.go +++ b/cmd/service-level-operator/flags.go @@ -22,29 +22,33 @@ const ( type cmdFlags struct { fs *flag.FlagSet - kubeConfig string - resyncSeconds int - workers int - metricsPath string - listenAddress string - labelSelector string - namespace string + kubeConfig string + resyncSeconds int + workers int + metricsPath string + listenAddress string + labelSelector string + namespace string defSLISourcePath string - debug bool - development bool - fake bool + debug bool + development bool + fake bool } -func newCmdFlags() *cmdFlags { +func newCmdFlags() (*cmdFlags, error) { c := &cmdFlags{ fs: flag.NewFlagSet(os.Args[0], flag.ExitOnError), } - c.init() - return c + err := c.init() + if err != nil { + return nil, err + } + + return c, nil } -func (c *cmdFlags) init() { +func (c *cmdFlags) init() error { kubehome := filepath.Join(homedir.HomeDir(), ".kube", "config") // register flags @@ -60,8 +64,7 @@ func (c *cmdFlags) init() { c.fs.BoolVar(&c.debug, "debug", false, "enable debug mode") c.fs.BoolVar(&c.fake, "fake", false, "enable faked mode, in faked node external services/dependencies are not needed") - // Parse flags - c.fs.Parse(os.Args[1:]) + return c.fs.Parse(os.Args[1:]) } func (c *cmdFlags) toOperatorConfig() operator.Config { diff --git a/cmd/service-level-operator/main.go b/cmd/service-level-operator/main.go index c0d8ceb..3320b2c 100644 --- a/cmd/service-level-operator/main.go +++ b/cmd/service-level-operator/main.go @@ -42,6 +42,12 @@ type Main struct { // Run runs the main program. func (m *Main) Run() error { + flags, err := newCmdFlags() + if err != nil { + return err + } + m.flags = flags + // Prepare the logger with the correct settings. jsonLog := true if m.flags.development { @@ -49,7 +55,10 @@ func (m *Main) Run() error { } m.logger = log.Base(jsonLog) if m.flags.debug { - m.logger.Set("debug") + err := m.logger.Set("debug") + if err != nil { + return err + } } if m.flags.fake { @@ -236,7 +245,7 @@ func (m *Main) createHTTPServer(promReg *prometheus.Registry) http.Server { mux := http.NewServeMux() mux.Handle(m.flags.metricsPath, h) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(` + _, _ = w.Write([]byte(` Service level operator

Service level operator

@@ -244,8 +253,8 @@ func (m *Main) createHTTPServer(promReg *prometheus.Registry) http.Server { `)) }) - mux.HandleFunc("/healthz/ready", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`ready`)) }) - mux.HandleFunc("/healthz/live", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`live`)) }) + mux.HandleFunc("/healthz/ready", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`ready`)) }) + mux.HandleFunc("/healthz/live", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(`live`)) }) return http.Server{ Handler: mux, @@ -254,7 +263,7 @@ func (m *Main) createHTTPServer(promReg *prometheus.Registry) http.Server { } func main() { - m := &Main{flags: newCmdFlags()} + m := &Main{} // Party time! err := m.Run() diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 68fe857..234e5f9 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -1,32 +1,39 @@ -FROM golang:1.13-alpine +FROM golang:1.14 -RUN apk --no-cache add \ - bash \ +ARG GOLANGCI_LINT_VERSION="1.27.0" +ARG MOCKERY_VERSION="2.0.0-alpha.2" +ARG ostype=Linux + +RUN apt-get update && apt-get install -y \ git \ - g++ \ - curl \ - openssl \ - openssh-client + bash \ + zip -# Mock creator -RUN go get -u github.com/vektra/mockery/.../ -RUN mkdir /src +RUN wget https://github.com/golangci/golangci-lint/releases/download/v${GOLANGCI_LINT_VERSION}/golangci-lint-${GOLANGCI_LINT_VERSION}-linux-amd64.tar.gz && \ + tar zxvf golangci-lint-${GOLANGCI_LINT_VERSION}-linux-amd64.tar.gz --strip 1 -C /usr/local/bin/ && \ + rm golangci-lint-${GOLANGCI_LINT_VERSION}-linux-amd64.tar.gz && \ + \ + wget https://github.com/vektra/mockery/releases/download/v${MOCKERY_VERSION}/mockery_${MOCKERY_VERSION}_Linux_x86_64.tar.gz && \ + tar zxvf mockery_${MOCKERY_VERSION}_Linux_x86_64.tar.gz -C /tmp && \ + mv /tmp/mockery /usr/local/bin/ && \ + rm mockery_${MOCKERY_VERSION}_Linux_x86_64.tar.gz -# Create user +# Create user. ARG uid=1000 ARG gid=1000 -RUN addgroup -g $gid service-level-operator && \ - adduser -D -u $uid -G service-level-operator service-level-operator && \ - chown service-level-operator:service-level-operator -R /src && \ - chown service-level-operator:service-level-operator -R /go -USER service-level-operator + +RUN bash -c 'if [ ${ostype} == Linux ]; then addgroup -gid $gid app; else addgroup app; fi && \ + adduser --disabled-password -uid $uid --ingroup app --gecos "" app && \ + chown app:app -R /go' # Fill go mod cache. RUN mkdir /tmp/cache COPY go.mod /tmp/cache COPY go.sum /tmp/cache +RUN chown app:app -R /tmp/cache +USER app RUN cd /tmp/cache && \ go mod download -WORKDIR /src +WORKDIR /src \ No newline at end of file diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index 28ed737..1e1ce3b 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -1,19 +1,21 @@ -FROM golang:1.13-alpine AS build-stage +FROM golang:1.14-alpine as build-stage RUN apk --no-cache add \ g++ \ git \ - make + make \ + bash ARG VERSION ENV VERSION=${VERSION} + WORKDIR /src COPY . . -RUN ./hack/scripts/build-binary.sh +RUN ./scripts/build/build.sh # Final image. FROM alpine:latest RUN apk --no-cache add \ ca-certificates COPY --from=build-stage /src/bin/service-level-operator /usr/local/bin/service-level-operator -ENTRYPOINT ["/usr/local/bin/service-level-operator"] +ENTRYPOINT ["/usr/local/bin/service-level-operator"] \ No newline at end of file diff --git a/go.mod b/go.mod index 34e860f..447fe65 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/sirupsen/logrus v1.4.2 github.com/spotahome/kooper v0.6.1-0.20190926114429-1c6a0cfab9a5 github.com/stretchr/testify v1.4.0 - golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 + golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 k8s.io/api v0.0.0-20191004102255-dacd7df5a50b // indirect k8s.io/apiextensions-apiserver v0.0.0-20191004105443-a7d558db75c6 k8s.io/apimachinery v0.0.0-20191004074956-01f8b7d1121a @@ -16,4 +16,4 @@ require ( k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d ) -go 1.13 +go 1.14 diff --git a/go.sum b/go.sum index 1bc422f..3eb37d6 100644 --- a/go.sum +++ b/go.sum @@ -190,6 +190,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/hack/scripts/build-binary.sh b/hack/scripts/build-binary.sh deleted file mode 100755 index a198e0a..0000000 --- a/hack/scripts/build-binary.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env sh - -set -o errexit -set -o nounset - -goos=linux -goarch=amd64 -src=./cmd/service-level-operator -out=./bin/service-level-operator -ldf_cmp="-w -extldflags '-static'" -f_ver="-X main.Version=${VERSION:-dev}" - -echo "Building binary at ${out}" - -GOOS=${goos} GOARCH=${goarch} CGO_ENABLED=0 go build -o ${out} --ldflags "${ldf_cmp} ${f_ver}" ${src} \ No newline at end of file diff --git a/hack/scripts/build-image.sh b/hack/scripts/build-image.sh deleted file mode 100755 index 77959c2..0000000 --- a/hack/scripts/build-image.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env sh - -set -e - -if [ -z ${VERSION} ]; then - echo "VERSION env var needs to be set" - exit 1 -fi - -REPOSITORY="quay.io/spotahome/" -IMAGE="service-level-operator" -TARGET_IMAGE=${REPOSITORY}${IMAGE} - - -docker build \ - --build-arg VERSION=${VERSION} \ - -t ${TARGET_IMAGE}:${VERSION} \ - -t ${TARGET_IMAGE}:latest \ - -f ./docker/prod/Dockerfile . - -if [ -n "${PUSH_IMAGE}" ]; then - echo "pushing ${TARGET_IMAGE} images..." - docker push ${TARGET_IMAGE} -fi \ No newline at end of file diff --git a/hack/scripts/integration-test.sh b/hack/scripts/integration-test.sh deleted file mode 100755 index 797a2a1..0000000 --- a/hack/scripts/integration-test.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env sh - -set -o errexit -set -o nounset - -go test `go list ./... | grep -v vendor` -v -tags='integration' \ No newline at end of file diff --git a/hack/scripts/k8scodegen.sh b/hack/scripts/k8scodegen.sh deleted file mode 100755 index 75a3378..0000000 --- a/hack/scripts/k8scodegen.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env sh - -CODE_GENERATOR_IMAGE=quay.io/slok/kube-code-generator:v1.13.5 -DIRECTORY=${PWD} -CODE_GENERATOR_PACKAGE=github.com/spotahome/service-level-operator - -docker run --rm -it \ - -v ${DIRECTORY}:/go/src/${CODE_GENERATOR_PACKAGE} \ - -e PROJECT_PACKAGE=${CODE_GENERATOR_PACKAGE} \ - -e CLIENT_GENERATOR_OUT=${CODE_GENERATOR_PACKAGE}/pkg/k8sautogen/client \ - -e APIS_ROOT=${CODE_GENERATOR_PACKAGE}/pkg/apis \ - -e GROUPS_VERSION="monitoring:v1alpha1" \ - -e GENERATION_TARGETS="deepcopy,client" \ - ${CODE_GENERATOR_IMAGE} \ No newline at end of file diff --git a/hack/scripts/openapicodegen.sh b/hack/scripts/openapicodegen.sh deleted file mode 100755 index e29b893..0000000 --- a/hack/scripts/openapicodegen.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env sh - -DIR="$( cd "$( dirname "${0}" )" && pwd )" -ROOT_DIR=${DIR}/../.. - -PROJECT_PACKAGE=github.com/spotahome/service-level-operator -IMAGE=quay.io/slok/kube-code-generator:v1.11.3 - -# Execute once per package because we want independent output specs per kind/version. -docker run -it --rm \ - -v ${ROOT_DIR}:/go/src/${PROJECT_PACKAGE} \ - -e CRD_PACKAGES=${PROJECT_PACKAGE}/pkg/apis/monitoring/v1alpha1 \ - -e OPENAPI_OUTPUT_PACKAGE=${PROJECT_PACKAGE}/pkg/apis/monitoring/v1alpha1 \ - ${IMAGE} ./update-openapi.sh \ No newline at end of file diff --git a/pkg/service/client/prometheus/factory_test.go b/pkg/service/client/prometheus/factory_test.go index 2d1b8c9..3ea10cc 100644 --- a/pkg/service/client/prometheus/factory_test.go +++ b/pkg/service/client/prometheus/factory_test.go @@ -32,7 +32,7 @@ func TestBaseFactoryV1Client(t *testing.T) { "Getting a missing address client with a default client it should not error.": { cli: func() *prometheus.BaseFactory { f := prometheus.NewBaseFactory() - f.WithDefaultV1APIClient("http://127.0.0.1:9090") + _ = f.WithDefaultV1APIClient("http://127.0.0.1:9090") return f }, address: "", diff --git a/pkg/service/configuration/configuration.go b/pkg/service/configuration/configuration.go index 4947c53..e0106b8 100644 --- a/pkg/service/configuration/configuration.go +++ b/pkg/service/configuration/configuration.go @@ -18,7 +18,6 @@ type PrometheusSLISource struct { Address string `json:"address,omitempty"` } - // Loader knows how to load configuration based on different formats. // At this moment configuration is not versioned, the configuration // is so simple that if it grows we could refactor and add version, diff --git a/pkg/service/output/prometheus_test.go b/pkg/service/output/prometheus_test.go index 868bd59..73d6b9d 100644 --- a/pkg/service/output/prometheus_test.go +++ b/pkg/service/output/prometheus_test.go @@ -76,7 +76,7 @@ func TestPrometheusOutput(t *testing.T) { { name: "Creating a output result should expose all the required metrics", createResults: func(output output.Output) { - output.Create(sl0, slo00, &sli.Result{ + _ = output.Create(sl0, slo00, &sli.Result{ TotalQ: 1000000, ErrorQ: 122, }) @@ -93,7 +93,7 @@ func TestPrometheusOutput(t *testing.T) { ExpireDuration: 500 * time.Microsecond, }, createResults: func(output output.Output) { - output.Create(sl0, slo00, &sli.Result{ + _ = output.Create(sl0, slo00, &sli.Result{ TotalQ: 1000000, ErrorQ: 122, }) @@ -109,17 +109,17 @@ func TestPrometheusOutput(t *testing.T) { name: "Creating a output result should expose all the required metrics (multiple adds on same SLO).", createResults: func(output output.Output) { slis := []*sli.Result{ - &sli.Result{TotalQ: 1000000, ErrorQ: 122}, - &sli.Result{TotalQ: 999, ErrorQ: 1}, - &sli.Result{TotalQ: 812392, ErrorQ: 94}, - &sli.Result{TotalQ: 83, ErrorQ: 83}, - &sli.Result{TotalQ: 11223, ErrorQ: 11222}, - &sli.Result{TotalQ: 9999999999, ErrorQ: 2}, - &sli.Result{TotalQ: 1245, ErrorQ: 0}, - &sli.Result{TotalQ: 9019, ErrorQ: 1001}, + {TotalQ: 1000000, ErrorQ: 122}, + {TotalQ: 999, ErrorQ: 1}, + {TotalQ: 812392, ErrorQ: 94}, + {TotalQ: 83, ErrorQ: 83}, + {TotalQ: 11223, ErrorQ: 11222}, + {TotalQ: 9999999999, ErrorQ: 2}, + {TotalQ: 1245, ErrorQ: 0}, + {TotalQ: 9019, ErrorQ: 1001}, } for _, sli := range slis { - output.Create(sl0, slo00, sli) + _ = output.Create(sl0, slo00, sli) } }, expMetrics: []string{ @@ -131,23 +131,23 @@ func TestPrometheusOutput(t *testing.T) { { name: "Creating a output result should expose all the required metrics (multiple SLOs).", createResults: func(output output.Output) { - output.Create(sl0, slo00, &sli.Result{ + _ = output.Create(sl0, slo00, &sli.Result{ TotalQ: 1000000, ErrorQ: 122, }) - output.Create(sl0, slo01, &sli.Result{ + _ = output.Create(sl0, slo01, &sli.Result{ TotalQ: 1011, ErrorQ: 340, }) - output.Create(sl1, slo10, &sli.Result{ + _ = output.Create(sl1, slo10, &sli.Result{ TotalQ: 9212, ErrorQ: 1, }) - output.Create(sl1, slo10, &sli.Result{ + _ = output.Create(sl1, slo10, &sli.Result{ TotalQ: 3456, ErrorQ: 3, }) - output.Create(sl1, slo11, &sli.Result{ + _ = output.Create(sl1, slo11, &sli.Result{ TotalQ: 998, ErrorQ: 7, }) diff --git a/pkg/service/sli/prometheus.go b/pkg/service/sli/prometheus.go index 3d0f463..5acfa83 100644 --- a/pkg/service/sli/prometheus.go +++ b/pkg/service/sli/prometheus.go @@ -47,11 +47,13 @@ func (p *prometheus) Retrieve(sli *monitoringv1alpha1.SLI) (Result, error) { // Make queries concurrently. g, ctx := errgroup.WithContext(promclictx) g.Go(func() error { - res.TotalQ, err = p.getVectorMetric(ctx, cli, sli.Prometheus.TotalQuery) + result, err := p.getVectorMetric(ctx, cli, sli.Prometheus.TotalQuery) + res.TotalQ = result return err }) g.Go(func() error { - res.ErrorQ, err = p.getVectorMetric(ctx, cli, sli.Prometheus.ErrorQuery) + result, err := p.getVectorMetric(ctx, cli, sli.Prometheus.ErrorQuery) + res.ErrorQ = result return err }) diff --git a/scripts/build/build-image.sh b/scripts/build/build-image.sh new file mode 100755 index 0000000..90e9d35 --- /dev/null +++ b/scripts/build/build-image.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env sh + +set -e + +if [ -z ${VERSION} ]; then + echo "IMAGE_VERSION env var needs to be set" + exit 1 +fi + +if [ -z ${IMAGE} ]; then + echo "IMAGE env var needs to be set" + exit 1 +fi + +if [ -z ${DOCKER_FILE_PATH} ]; then + echo "DOCKER_FILE_PATH env var needs to be set" + exit 1 +fi + +echo "Building image ${IMAGE}:${VERSION}..." +docker build \ + --build-arg VERSION=${VERSION} \ + -t ${IMAGE}:${VERSION} \ + -f ${DOCKER_FILE_PATH} . + +if [ ! -z ${TAG_IMAGE_LATEST} ]; then + echo "Tagged image ${IMAGE}:${VERSION} with ${IMAGE}:latest" + docker tag ${IMAGE}:${VERSION} ${IMAGE}:latest +fi \ No newline at end of file diff --git a/scripts/build/build.sh b/scripts/build/build.sh new file mode 100755 index 0000000..5b0bbe4 --- /dev/null +++ b/scripts/build/build.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset + +src=./cmd/service-level-operator +out=./bin/service-level-operator + +ostype=${ostype:-"native"} +binary_ext="" + +if [ $ostype == 'Linux' ]; then + echo "Building linux release..." + export GOOS=linux + export GOARCH=amd64 + binary_ext=-linux-amd64 +elif [ $ostype == 'Darwin' ]; then + echo "Building darwin release..." + export GOOS=darwin + export GOARCH=amd64 + binary_ext=-darwin-amd64 +elif [ $ostype == 'Windows' ]; then + echo "Building windows release..." + export GOOS=windows + export GOARCH=amd64 + binary_ext=-windows-amd64.exe +elif [ $ostype == 'ARM64' ]; then + echo "Building ARM64 release..." + export GOOS=linux + export GOARCH=arm64 + binary_ext=-linux-arm64 +elif [ $ostype == 'ARM' ]; then + echo "Building ARM release..." + export GOOS=linux + export GOARCH=arm + export GOARM=7 + binary_ext=-linux-arm-v7 +else + echo "Building native release..." +fi + +final_out=${out}${binary_ext} +ldf_cmp="-w -extldflags '-static'" +f_ver="-X main.Version=${VERSION:-dev}" + +echo "Building binary at ${final_out}" +CGO_ENABLED=0 go build -o ${final_out} --ldflags "${ldf_cmp} ${f_ver}" ${src} \ No newline at end of file diff --git a/scripts/build/publish-image.sh b/scripts/build/publish-image.sh new file mode 100755 index 0000000..76fbbdc --- /dev/null +++ b/scripts/build/publish-image.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env sh + +set -e + +if [ -z ${VERSION} ]; then + echo "IMAGE_VERSION env var needs to be set" + exit 1 +fi + +if [ -z ${IMAGE} ]; then + echo "IMAGE env var needs to be set" + exit 1 +fi + +echo "Pushing image ${IMAGE}:${VERSION}..." +docker push ${IMAGE}:${VERSION} + +if [ ! -z ${TAG_IMAGE_LATEST} ]; then + echo "Pushing image ${IMAGE}:latest..." + docker push ${IMAGE}:latest +fi \ No newline at end of file diff --git a/hack/scripts/unit-test.sh b/scripts/check/check.sh similarity index 53% rename from hack/scripts/unit-test.sh rename to scripts/check/check.sh index fc01664..532753e 100755 --- a/hack/scripts/unit-test.sh +++ b/scripts/check/check.sh @@ -3,4 +3,4 @@ set -o errexit set -o nounset -go test `go list ./... | grep -v vendor` -v \ No newline at end of file +golangci-lint run -E goimports --timeout 3m \ No newline at end of file diff --git a/scripts/check/integration-test.sh b/scripts/check/integration-test.sh new file mode 100755 index 0000000..d2f1b77 --- /dev/null +++ b/scripts/check/integration-test.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +set -o errexit +set -o nounset + +go test -race -v -tags='integration' ./... \ No newline at end of file diff --git a/hack/scripts/test-alerts.sh b/scripts/check/test-alerts.sh similarity index 72% rename from hack/scripts/test-alerts.sh rename to scripts/check/test-alerts.sh index 7f9f2b8..b4031ac 100755 --- a/hack/scripts/test-alerts.sh +++ b/scripts/check/test-alerts.sh @@ -1,4 +1,7 @@ -#!/bin/sh +#!/usr/bin/env sh + +set -o errexit +set -o nounset DIR="$(dirname "$(readlink -f $0)")" ROOT_DIR="${DIR}/../.." diff --git a/scripts/check/unit-test.sh b/scripts/check/unit-test.sh new file mode 100755 index 0000000..b3b3a08 --- /dev/null +++ b/scripts/check/unit-test.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +set -o errexit +set -o nounset + +go test -race -coverprofile=.test_coverage.txt ./... +go tool cover -func=.test_coverage.txt | tail -n1 | awk '{print "Total test coverage: " $3}' \ No newline at end of file diff --git a/hack/scripts/mockgen.sh b/scripts/deps.sh similarity index 72% rename from hack/scripts/mockgen.sh rename to scripts/deps.sh index b332aaf..f112039 100755 --- a/hack/scripts/mockgen.sh +++ b/scripts/deps.sh @@ -3,4 +3,4 @@ set -o errexit set -o nounset -go generate ./mocks \ No newline at end of file +go mod tidy \ No newline at end of file diff --git a/scripts/gogen.sh b/scripts/gogen.sh new file mode 100755 index 0000000..803ac8a --- /dev/null +++ b/scripts/gogen.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +set -o errexit +set -o nounset + +go generate ./... \ No newline at end of file diff --git a/scripts/kubegen.sh b/scripts/kubegen.sh new file mode 100755 index 0000000..aeb7362 --- /dev/null +++ b/scripts/kubegen.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env sh + +set -o errexit +set -o nounset + +IMAGE_CLI_GEN=quay.io/slok/kube-code-generator:v1.17.3 +IMAGE_CRD_GEN=quay.io/slok/kube-code-generator:v1.18.0 +ROOT_DIRECTORY=$(dirname "$(readlink -f "$0")")/../ +PROJECT_PACKAGE="github.com/spotahome/service-level-operator" + +echo "Generating Kubernetes CRD clients..." +docker run -it --rm \ + -v ${ROOT_DIRECTORY}:/go/src/${PROJECT_PACKAGE} \ + -e PROJECT_PACKAGE=${PROJECT_PACKAGE} \ + -e CLIENT_GENERATOR_OUT=${PROJECT_PACKAGE}/pkg/kubernetes/gen \ + -e APIS_ROOT=${PROJECT_PACKAGE}/pkg/apis \ + -e GROUPS_VERSION="monitoring:v1alpha1" \ + -e GENERATION_TARGETS="deepcopy,client" \ + ${IMAGE_CLI_GEN} + +echo "Generating Kubernetes CRD manifests..." +docker run -it --rm \ + -v ${ROOT_DIRECTORY}:/src \ + -e GO_PROJECT_ROOT=/src \ + -e CRD_TYPES_PATH=/src/pkg/apis \ + -e CRD_OUT_PATH=/src/manifests/crd \ + ${IMAGE_CRD_GEN} update-crd.sh \ No newline at end of file