From 43bf9fc56c40c0c2e3d57b3b03376be903ae45f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Ecs=C3=A9di?= Date: Mon, 11 Mar 2019 15:04:34 +0100 Subject: [PATCH] Pipeline Kubernetes Engine initial commit --- .gitignore | 7 + Makefile | 33 ++ cmd/pke/app/cmd/cmd.go | 25 + cmd/pke/app/cmd/install.go | 77 +++ cmd/pke/app/cmd/machine-image.go | 30 ++ cmd/pke/app/cmd/token.go | 23 + cmd/pke/app/cmd/version.go | 78 +++ cmd/pke/app/constants/constants.go | 84 +++ .../kubeadm/controlplane/controlplane.go | 473 +++++++++++++++++ .../kubeadm/controlplane/controlplane_test.go | 53 ++ cmd/pke/app/phases/kubeadm/images/pull.go | 99 ++++ cmd/pke/app/phases/kubeadm/node/node.go | 223 ++++++++ cmd/pke/app/phases/kubeadm/node/node_test.go | 23 + cmd/pke/app/phases/kubeadm/reset.go | 22 + .../app/phases/kubeadm/token/create/create.go | 43 ++ cmd/pke/app/phases/kubeadm/token/list/list.go | 42 ++ cmd/pke/app/phases/kubeadm/version/version.go | 83 +++ .../phases/kubeadm/version/version_test.go | 38 ++ cmd/pke/app/phases/phase.go | 78 +++ .../pipeline/certificates/certificates.go | 160 ++++++ cmd/pke/app/phases/pipeline/ready/ready.go | 147 +++++ .../app/phases/runtime/container/container.go | 43 ++ .../runtime/container/containerd_linux.go | 152 ++++++ .../runtime/container/containerd_other.go | 13 + .../phases/runtime/kubernetes/kubernetes.go | 68 +++ .../runtime/kubernetes/kubernetes_linux.go | 102 ++++ .../runtime/kubernetes/kubernetes_other.go | 13 + cmd/pke/app/pke.go | 18 + cmd/pke/app/util/file/download.go | 62 +++ cmd/pke/app/util/file/download_test.go | 50 ++ cmd/pke/app/util/file/tar.go | 74 +++ cmd/pke/app/util/file/tar_test.go | 25 + cmd/pke/app/util/file/write.go | 44 ++ cmd/pke/app/util/file/write_test.go | 36 ++ cmd/pke/app/util/linux/modprobe.go | 23 + cmd/pke/app/util/linux/os_version_linux.go | 50 ++ cmd/pke/app/util/linux/os_version_other.go | 17 + cmd/pke/app/util/linux/swap.go | 28 + cmd/pke/app/util/linux/sysctl.go | 16 + cmd/pke/app/util/linux/systemctl.go | 97 ++++ cmd/pke/app/util/linux/yum.go | 15 + cmd/pke/app/util/network/cidr.go | 27 + cmd/pke/app/util/network/cidr_test.go | 57 ++ cmd/pke/app/util/network/interfaces.go | 45 ++ cmd/pke/app/util/pipeline/client.go | 79 +++ cmd/pke/app/util/pipeline/transport.go | 50 ++ cmd/pke/app/util/runner/command.go | 94 ++++ cmd/pke/app/util/runner/command_test.go | 37 ++ cmd/pke/app/util/validator/parameters.go | 40 ++ cmd/pke/docs/generate.go | 18 + cmd/pke/docs/pke.md | 21 + cmd/pke/docs/pke_install.md | 21 + cmd/pke/docs/pke_install_master.md | 48 ++ .../pke_install_master_container-runtime.md | 22 + ..._install_master_kubernetes-controlplane.md | 37 ++ .../pke_install_master_kubernetes-runtime.md | 23 + .../pke_install_master_kubernetes-version.md | 23 + ...ke_install_master_pipeline-certificates.md | 26 + .../docs/pke_install_master_pipeline-ready.md | 28 + cmd/pke/docs/pke_install_single.md | 48 ++ .../pke_install_single_container-runtime.md | 22 + ..._install_single_kubernetes-controlplane.md | 37 ++ .../pke_install_single_kubernetes-runtime.md | 23 + .../pke_install_single_kubernetes-version.md | 23 + ...ke_install_single_pipeline-certificates.md | 26 + .../docs/pke_install_single_pipeline-ready.md | 28 + cmd/pke/docs/pke_install_worker.md | 38 ++ .../pke_install_worker_container-runtime.md | 22 + .../pke_install_worker_kubernetes-node.md | 31 ++ .../pke_install_worker_kubernetes-runtime.md | 23 + .../pke_install_worker_kubernetes-version.md | 23 + .../docs/pke_install_worker_pipeline-ready.md | 28 + cmd/pke/docs/pke_machine-image.md | 28 + .../pke_machine-image_container-runtime.md | 22 + cmd/pke/docs/pke_machine-image_image-pull.md | 24 + .../pke_machine-image_kubernetes-runtime.md | 23 + .../pke_machine-image_kubernetes-version.md | 23 + cmd/pke/docs/pke_token.md | 20 + cmd/pke/docs/pke_token_create.md | 22 + cmd/pke/docs/pke_token_list.md | 22 + cmd/pke/docs/pke_version.md | 23 + cmd/pke/pke.go | 21 + go.mod | 16 + go.sum | 502 ++++++++++++++++++ 84 files changed, 4601 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 cmd/pke/app/cmd/cmd.go create mode 100644 cmd/pke/app/cmd/install.go create mode 100644 cmd/pke/app/cmd/machine-image.go create mode 100644 cmd/pke/app/cmd/token.go create mode 100644 cmd/pke/app/cmd/version.go create mode 100644 cmd/pke/app/constants/constants.go create mode 100644 cmd/pke/app/phases/kubeadm/controlplane/controlplane.go create mode 100644 cmd/pke/app/phases/kubeadm/controlplane/controlplane_test.go create mode 100644 cmd/pke/app/phases/kubeadm/images/pull.go create mode 100644 cmd/pke/app/phases/kubeadm/node/node.go create mode 100644 cmd/pke/app/phases/kubeadm/node/node_test.go create mode 100644 cmd/pke/app/phases/kubeadm/reset.go create mode 100644 cmd/pke/app/phases/kubeadm/token/create/create.go create mode 100644 cmd/pke/app/phases/kubeadm/token/list/list.go create mode 100644 cmd/pke/app/phases/kubeadm/version/version.go create mode 100644 cmd/pke/app/phases/kubeadm/version/version_test.go create mode 100644 cmd/pke/app/phases/phase.go create mode 100644 cmd/pke/app/phases/pipeline/certificates/certificates.go create mode 100644 cmd/pke/app/phases/pipeline/ready/ready.go create mode 100644 cmd/pke/app/phases/runtime/container/container.go create mode 100644 cmd/pke/app/phases/runtime/container/containerd_linux.go create mode 100644 cmd/pke/app/phases/runtime/container/containerd_other.go create mode 100644 cmd/pke/app/phases/runtime/kubernetes/kubernetes.go create mode 100644 cmd/pke/app/phases/runtime/kubernetes/kubernetes_linux.go create mode 100644 cmd/pke/app/phases/runtime/kubernetes/kubernetes_other.go create mode 100644 cmd/pke/app/pke.go create mode 100644 cmd/pke/app/util/file/download.go create mode 100644 cmd/pke/app/util/file/download_test.go create mode 100644 cmd/pke/app/util/file/tar.go create mode 100644 cmd/pke/app/util/file/tar_test.go create mode 100644 cmd/pke/app/util/file/write.go create mode 100644 cmd/pke/app/util/file/write_test.go create mode 100644 cmd/pke/app/util/linux/modprobe.go create mode 100644 cmd/pke/app/util/linux/os_version_linux.go create mode 100644 cmd/pke/app/util/linux/os_version_other.go create mode 100644 cmd/pke/app/util/linux/swap.go create mode 100644 cmd/pke/app/util/linux/sysctl.go create mode 100644 cmd/pke/app/util/linux/systemctl.go create mode 100644 cmd/pke/app/util/linux/yum.go create mode 100644 cmd/pke/app/util/network/cidr.go create mode 100644 cmd/pke/app/util/network/cidr_test.go create mode 100644 cmd/pke/app/util/network/interfaces.go create mode 100644 cmd/pke/app/util/pipeline/client.go create mode 100644 cmd/pke/app/util/pipeline/transport.go create mode 100644 cmd/pke/app/util/runner/command.go create mode 100644 cmd/pke/app/util/runner/command_test.go create mode 100644 cmd/pke/app/util/validator/parameters.go create mode 100644 cmd/pke/docs/generate.go create mode 100644 cmd/pke/docs/pke.md create mode 100644 cmd/pke/docs/pke_install.md create mode 100644 cmd/pke/docs/pke_install_master.md create mode 100644 cmd/pke/docs/pke_install_master_container-runtime.md create mode 100644 cmd/pke/docs/pke_install_master_kubernetes-controlplane.md create mode 100644 cmd/pke/docs/pke_install_master_kubernetes-runtime.md create mode 100644 cmd/pke/docs/pke_install_master_kubernetes-version.md create mode 100644 cmd/pke/docs/pke_install_master_pipeline-certificates.md create mode 100644 cmd/pke/docs/pke_install_master_pipeline-ready.md create mode 100644 cmd/pke/docs/pke_install_single.md create mode 100644 cmd/pke/docs/pke_install_single_container-runtime.md create mode 100644 cmd/pke/docs/pke_install_single_kubernetes-controlplane.md create mode 100644 cmd/pke/docs/pke_install_single_kubernetes-runtime.md create mode 100644 cmd/pke/docs/pke_install_single_kubernetes-version.md create mode 100644 cmd/pke/docs/pke_install_single_pipeline-certificates.md create mode 100644 cmd/pke/docs/pke_install_single_pipeline-ready.md create mode 100644 cmd/pke/docs/pke_install_worker.md create mode 100644 cmd/pke/docs/pke_install_worker_container-runtime.md create mode 100644 cmd/pke/docs/pke_install_worker_kubernetes-node.md create mode 100644 cmd/pke/docs/pke_install_worker_kubernetes-runtime.md create mode 100644 cmd/pke/docs/pke_install_worker_kubernetes-version.md create mode 100644 cmd/pke/docs/pke_install_worker_pipeline-ready.md create mode 100644 cmd/pke/docs/pke_machine-image.md create mode 100644 cmd/pke/docs/pke_machine-image_container-runtime.md create mode 100644 cmd/pke/docs/pke_machine-image_image-pull.md create mode 100644 cmd/pke/docs/pke_machine-image_kubernetes-runtime.md create mode 100644 cmd/pke/docs/pke_machine-image_kubernetes-version.md create mode 100644 cmd/pke/docs/pke_token.md create mode 100644 cmd/pke/docs/pke_token_create.md create mode 100644 cmd/pke/docs/pke_token_list.md create mode 100644 cmd/pke/docs/pke_version.md create mode 100644 cmd/pke/pke.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a982709e --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +**/.vagrant* +.DS_Store +/.idea/ +/bin/ +/build/ +/test.txt + diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..ce0140de --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +SHELL = /bin/bash + +# Project variables +PACKAGE = github.com/banzaicloud/pke + +# Build variables +BUILD_DIR ?= $(PWD)/build +VERSION ?= $(shell git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD) +COMMIT_HASH ?= $(shell git rev-parse --short HEAD 2>/dev/null) +BUILD_DATE ?= $(shell date +%FT%T%z) +GIT_TREE_STATE ?= $(shell if [[ -z `git status --porcelain 2>/dev/null` ]]; then echo "clean"; else echo "dirty"; fi ) +LDFLAGS += -X main.Version=${VERSION} -X main.CommitHash=${COMMIT_HASH} -X main.BuildDate=${BUILD_DATE} -X main.GitTreeState=${GIT_TREE_STATE} + +.PHONY: pke +pke: GOARGS += -tags "${GOTAGS}" -ldflags "${LDFLAGS}" -o ${BUILD_DIR}/pke +pke: ## Build PKE binary + cd cmd/pke/ && go build ${GOARGS} ${PACKAGE}/cmd/pke + +.PHONY: pke-docs +pke-docs: ## Generate documentation for PKE + rm -rf cmd/pke/docs/*.md + cd cmd/pke/docs/ && go run -v generate.go + +.PHONY: test +test: export CGO_ENABLED = 1 +test: + set -o pipefail; go list ./... | xargs -n1 go test ${GOARGS} -v -parallel 1 2>&1 | tee test.txt + + +.PHONY: help +.DEFAULT_GOAL := help +help: + @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/cmd/pke/app/cmd/cmd.go b/cmd/pke/app/cmd/cmd.go new file mode 100644 index 00000000..40979484 --- /dev/null +++ b/cmd/pke/app/cmd/cmd.go @@ -0,0 +1,25 @@ +package cmd + +import ( + "io" + + "github.com/spf13/cobra" +) + +func NewPKECommand(in io.Reader, out io.Writer, gitVersion, gitCommit, gitTreeState, buildDate string) *cobra.Command { + cmd := &cobra.Command{ + Use: "pke", + Short: "Bootstrap a secure Kubernetes cluster with Banzai Cloud Pipeline Kubernetes Engine (PKE)", + SilenceUsage: true, + DisableAutoGenTag: true, + } + + cmd.ResetFlags() + + cmd.AddCommand(NewCmdInstall(out)) + cmd.AddCommand(NewCmdImage(out)) + cmd.AddCommand(NewCmdToken(out)) + cmd.AddCommand(NewCmdVersion(out, gitVersion, gitCommit, gitTreeState, buildDate)) + + return cmd +} diff --git a/cmd/pke/app/cmd/install.go b/cmd/pke/app/cmd/install.go new file mode 100644 index 00000000..46ed6f9c --- /dev/null +++ b/cmd/pke/app/cmd/install.go @@ -0,0 +1,77 @@ +package cmd + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm/controlplane" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm/node" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm/version" + "github.com/banzaicloud/pke/cmd/pke/app/phases/pipeline/certificates" + "github.com/banzaicloud/pke/cmd/pke/app/phases/pipeline/ready" + "github.com/banzaicloud/pke/cmd/pke/app/phases/runtime/container" + "github.com/banzaicloud/pke/cmd/pke/app/phases/runtime/kubernetes" + "github.com/spf13/cobra" +) + +// NewCmdVersion provides the version information of banzai-cloud-pke. +func NewCmdInstall(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "install", + Short: "Install a single Banzai Cloud Pipeline Kubernetes Engine (PKE) machine", + Args: cobra.NoArgs, + } + + cmd.AddCommand(single(out)) + cmd.AddCommand(master(out)) + cmd.AddCommand(worker(out)) + + return cmd +} + +func master(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "master", + Short: "Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node", + RunE: phases.RunEAllSubcommands, + } + + cmd.AddCommand(version.NewCommand(out)) + cmd.AddCommand(container.NewCommand(out)) + cmd.AddCommand(kubernetes.NewCommand(out)) + cmd.AddCommand(certificates.NewCommand(out)) + cmd.AddCommand(controlplane.NewCommand(out)) + cmd.AddCommand(ready.NewCommand(out, ready.RoleMaster)) + + phases.MakeRunnable(cmd) + + return cmd +} + +func single(out io.Writer) *cobra.Command { + m := master(out) + m.Use = "single" + m.Short = "Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine" + _ = m.Flags().Set(constants.FlagClusterMode, "single") + + return m +} + +func worker(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "worker", + Short: "Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node", + RunE: phases.RunEAllSubcommands, + } + + cmd.AddCommand(version.NewCommand(out)) + cmd.AddCommand(container.NewCommand(out)) + cmd.AddCommand(kubernetes.NewCommand(out)) + cmd.AddCommand(node.NewCommand(out)) + cmd.AddCommand(ready.NewCommand(out, ready.RoleWorker)) + + phases.MakeRunnable(cmd) + + return cmd +} diff --git a/cmd/pke/app/cmd/machine-image.go b/cmd/pke/app/cmd/machine-image.go new file mode 100644 index 00000000..335ae15b --- /dev/null +++ b/cmd/pke/app/cmd/machine-image.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm/images" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm/version" + "github.com/banzaicloud/pke/cmd/pke/app/phases/runtime/container" + "github.com/banzaicloud/pke/cmd/pke/app/phases/runtime/kubernetes" + "github.com/spf13/cobra" +) + +// NewCmdImage . +func NewCmdImage(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "machine-image", + Short: "Machine image build helper for Banzai Cloud Pipeline Kubernetes Engine (PKE)", + RunE: phases.RunEAllSubcommands, + } + + cmd.AddCommand(version.NewCommand(out)) + cmd.AddCommand(container.NewCommand(out)) + cmd.AddCommand(kubernetes.NewCommand(out)) + cmd.AddCommand(images.NewCommand(out)) + + phases.MakeRunnable(cmd) + + return cmd +} diff --git a/cmd/pke/app/cmd/token.go b/cmd/pke/app/cmd/token.go new file mode 100644 index 00000000..ae292f37 --- /dev/null +++ b/cmd/pke/app/cmd/token.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm/token/create" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm/token/list" + "github.com/spf13/cobra" +) + +// NewCmdVersion provides the version information of banzai-cloud-pke. +func NewCmdToken(out io.Writer) *cobra.Command { + cmd := &cobra.Command{ + Use: "token", + Short: "Manage Kubernetes bootstrap tokens", + Args: cobra.NoArgs, + } + + cmd.AddCommand(create.NewCommand(out)) + cmd.AddCommand(list.NewCommand(out)) + + return cmd +} diff --git a/cmd/pke/app/cmd/version.go b/cmd/pke/app/cmd/version.go new file mode 100644 index 00000000..218ff8fb --- /dev/null +++ b/cmd/pke/app/cmd/version.go @@ -0,0 +1,78 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "io" + "runtime" + + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/ghodss/yaml" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +type ClientVersion struct { + GitVersion string `json:"gitVersion"` + GitCommit string `json:"gitCommit"` + GitTreeState string `json:"gitTreeState"` + BuildDate string `json:"buildDate"` + GoVersion string `json:"goVersion"` + Compiler string `json:"compiler"` + Platform string `json:"platform"` +} + +// NewCmdVersion provides the version information of banzai-cloud-pke. +func NewCmdVersion(out io.Writer, gitVersion, gitCommit, gitTreeState, buildDate string) *cobra.Command { + cmd := &cobra.Command{ + Use: "version", + Short: "Print tool version", + RunE: func(cmd *cobra.Command, args []string) error { + return RunVersion(out, cmd, gitVersion, gitCommit, gitTreeState, buildDate) + }, + } + cmd.Flags().StringP(constants.FlagOutput, constants.FlagOutputShort, "", "Output format; available options are 'yaml', 'json' and 'short'") + return cmd +} + +func RunVersion(out io.Writer, cmd *cobra.Command, gitVersion, gitCommit, gitTreeState, buildDate string) error { + of, err := cmd.Flags().GetString(constants.FlagOutput) + if err != nil { + return err + } + + v := struct { + ClientVersion `json:"clientVersion"` + }{ClientVersion{ + GitVersion: gitVersion, + GitCommit: gitCommit, + BuildDate: buildDate, + GitTreeState: gitTreeState, + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + }} + + switch of { + case "": + _, _ = fmt.Fprintf(out, "kubeadm version: %#v\n", v) + case "short": + _, _ = fmt.Fprintf(out, "%s\n", v.GitVersion) + case "yaml": + y, err := yaml.Marshal(&v) + if err != nil { + return err + } + _, _ = fmt.Fprintln(out, string(y)) + case "json": + y, err := json.MarshalIndent(&v, "", " ") + if err != nil { + return err + } + _, _ = fmt.Fprintln(out, string(y)) + default: + return errors.Errorf("invalid output format: %s", of) + } + + return nil +} diff --git a/cmd/pke/app/constants/constants.go b/cmd/pke/app/constants/constants.go new file mode 100644 index 00000000..b47df2eb --- /dev/null +++ b/cmd/pke/app/constants/constants.go @@ -0,0 +1,84 @@ +package constants + +import ( + "github.com/pkg/errors" +) + +const ( + // FlagOutput output formatting. + FlagOutput = "output" + // FlagOutputShort output formatting. + FlagOutputShort = "o" + + // FlagPipelineAPIEndpoint Pipeline API url. + FlagPipelineAPIEndpoint = "pipeline-url" + // FlagPipelineAPIEndpointShort Pipeline API url. + FlagPipelineAPIEndpointShort = "u" + + // FlagPipelineAPIToken token for accessing Pipeline API. + FlagPipelineAPIToken = "pipeline-token" + // FlagPipelineAPITokenShort token for accessing Pipeline API. + FlagPipelineAPITokenShort = "t" + + // FlagPipelineOrganizationID organization id in Pipeline. + FlagPipelineOrganizationID = "pipeline-org-id" + // FlagPipelineClusterID cluster id in Pipeline. + FlagPipelineClusterID = "pipeline-cluster-id" + + // FlagPipelineNodepool name of the nodepool the node belongs to. + FlagPipelineNodepool = "pipeline-nodepool" + + // FlagAPIServerHostPort Kubernetes advertise address API server and Etcd uses this. + FlagAdvertiseAddress = "kubernetes-advertise-address" + // FlagAPIServerHostPort Kubernetes API Server in host port format. + FlagAPIServerHostPort = "kubernetes-api-server" + // FlagKubeadmToken kubeadm token. + FlagKubeadmToken = "kubernetes-node-token" + // FlagCACertHash Kubernetes API Server CA Cert hash. + FlagCACertHash = "kubernetes-api-server-ca-cert-hash" + // FlagAPIServerCertSANs sets extra Subject Alternative Names for the API Server signing cert. + FlagAPIServerCertSANs = "kubernetes-api-server-cert-sans" + // FlagControllerManagerSigningCA Kubernetes Controller Manager needs a single signing cert. + // This is needed when using Intermediate CAs. + FlagControllerManagerSigningCA = "kubernetes-controller-manager-signing-ca" + + // FlagKubernetesVersion Kubernetes version. + FlagKubernetesVersion = "kubernetes-version" + + // FlagNetworkProvider network provider for Kubernetes. + FlagNetworkProvider = "kubernetes-network-provider" + // FlagServiceCIDR range of IP address for service VIPs. + FlagServiceCIDR = "kubernetes-service-cidr" + // FlagPodNetworkCIDR range of IP addresses for the pod network. + FlagPodNetworkCIDR = "kubernetes-pod-network-cidr" + // FlagInfrastructureCIDR range of IP addresses from which the advertise address can be calculated using system's network interfaces. + FlagInfrastructureCIDR = "kubernetes-infrastructure-cidr" + + // FlagCloudProvider cloud provider for kubeadm. + FlagCloudProvider = "kubernetes-cloud-provider" + + // FlagClusterName cluster name + FlagClusterName = "kubernetes-cluster-name" + + // FlagOIDCIssuerURL OIDC issuer URL + FlagOIDCIssuerURL = "kubernetes-oidc-issuer-url" + // FlagOIDCClientID OIDC client ID + FlagOIDCClientID = "kubernetes-oidc-client-id" + + // FlagClusterMode possible values: single, default, ha. + FlagClusterMode = "kubernetes-master-mode" + + // CloudProviderAmazon + CloudProviderAmazon = "aws" + + // FlagImageRepository prefix for image repository. + FlagImageRepository = "image-repository" +) + +var ( + ErrUnsupportedOS = errors.New("unsupported operating system") + ErrInvalidInput = errors.New("invalid input") + ErrValidationFailed = errors.New("validation failed") + ErrUnsupportedNetworkProvider = errors.New("unsupported network provider") + ErrUnsupportedKubernetesVersion = errors.New("unsupported kubernetes version") +) diff --git a/cmd/pke/app/phases/kubeadm/controlplane/controlplane.go b/cmd/pke/app/phases/kubeadm/controlplane/controlplane.go new file mode 100644 index 00000000..8be15de9 --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/controlplane/controlplane.go @@ -0,0 +1,473 @@ +package controlplane + +import ( + "encoding/base64" + "fmt" + "io" + "io/ioutil" + "net" + "net/http" + "net/url" + "os" + "path/filepath" + "text/template" + "time" + + "github.com/Masterminds/semver" + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm" + "github.com/banzaicloud/pke/cmd/pke/app/util/linux" + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" + "github.com/banzaicloud/pke/cmd/pke/app/util/validator" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + use = "kubernetes-controlplane" + short = "Kubernetes Control Plane installation" + + cmdKubeadm = "/bin/kubeadm" + cmdKubectl = "/bin/kubectl" + weaveNetUrl = "https://cloud.weave.works/k8s/net" + kubeConfig = "/etc/kubernetes/admin.conf" + kubeadmConfig = "/etc/kubernetes/kubeadm.conf" + kubeadmAmazonConfig = "/etc/kubernetes/aws.conf" + urlAWSAZ = "http://169.254.169.254/latest/meta-data/placement/availability-zone" + kubernetesCASigningCert = "/etc/kubernetes/pki/cm-signing-ca.crt" +) + +var _ phases.Runnable = (*ControlPlane)(nil) + +type ControlPlane struct { + kubernetesVersion string + networkProvider string + advertiseAddress string + apiServerHostPort string + clusterName string + serviceCIDR string + podNetworkCIDR string + cloudProvider string + nodepool string + controllerManagerSigningCA string + clusterMode string + apiServerCertSANs []string + oidcIssuerURL string + oidcClientID string + imageRepository string +} + +func NewCommand(out io.Writer) *cobra.Command { + return phases.NewCommand(out, &ControlPlane{}) +} + +func (c *ControlPlane) Use() string { + return use +} + +func (c *ControlPlane) Short() string { + return short +} + +func (c *ControlPlane) RegisterFlags(flags *pflag.FlagSet) { + // Kubernetes version + flags.String(constants.FlagKubernetesVersion, "1.13.3", "Kubernetes version") + // Kubernetes network + flags.String(constants.FlagNetworkProvider, "weave", "Kubernetes network provider") + flags.String(constants.FlagAdvertiseAddress, "", "Kubernetes advertise address") + flags.String(constants.FlagAPIServerHostPort, "", "Kubernetes API Server host port") + flags.String(constants.FlagServiceCIDR, "10.10.0.0/16", "range of IP address for service VIPs") + flags.String(constants.FlagPodNetworkCIDR, "10.20.0.0/16", "range of IP addresses for the pod network") + // Kubernetes cluster name + flags.String(constants.FlagClusterName, "pke", "Kubernetes cluster name") + // Kubernetes certificates + flags.StringArray(constants.FlagAPIServerCertSANs, []string{}, "sets extra Subject Alternative Names for the API Server signing cert") + flags.String(constants.FlagControllerManagerSigningCA, "", "Kubernetes Controller Manager signing cert") + // Kubernetes cluster mode + flags.String(constants.FlagClusterMode, "default", "Kubernetes cluster mode") + // Kubernetes cloud provider (optional) + flags.String(constants.FlagCloudProvider, "", "cloud provider. example: aws") + // Pipeline nodepool name (optional) + flags.String(constants.FlagPipelineNodepool, "", "name of the nodepool the node belongs to") + // OIDC authentication parameters (optional) + flags.String(constants.FlagOIDCIssuerURL, "", "URL of the OIDC provider which allows the API server to discover public signing keys") + flags.String(constants.FlagOIDCClientID, "", "A client ID that all OIDC tokens must be issued for") + // Image repository + flags.String(constants.FlagImageRepository, "banzaicloud", "Prefix for image repository") +} + +func (c *ControlPlane) Validate(cmd *cobra.Command) error { + if err := c.masterBootstrapParameters(cmd); err != nil { + return err + } + + if err := validator.NotEmpty(map[string]interface{}{ + constants.FlagKubernetesVersion: c.kubernetesVersion, + constants.FlagNetworkProvider: c.networkProvider, + constants.FlagServiceCIDR: c.serviceCIDR, + constants.FlagPodNetworkCIDR: c.podNetworkCIDR, + constants.FlagClusterName: c.clusterName, + constants.FlagClusterMode: c.clusterMode, + constants.FlagImageRepository: c.imageRepository, + }); err != nil { + return err + } + + if c.networkProvider != "weave" { + return errors.Wrapf(constants.ErrUnsupportedNetworkProvider, "network provider: %s", c.networkProvider) + } + + // Use Controller Manager Signing CA if present (pipeline-certificates step creates it). + if c.controllerManagerSigningCA == "" { + _, err := os.Stat(kubernetesCASigningCert) + if err == nil { + c.controllerManagerSigningCA = kubernetesCASigningCert + } + } + + switch c.clusterMode { + case "single", "default", "ha": + default: + return errors.New("Not supported --" + constants.FlagClusterMode + ". Possible values: single, default or ha.") + } + + return nil +} + +func (c *ControlPlane) Run(out io.Writer) error { + _, _ = fmt.Fprintf(out, "[RUNNING] %s\n", c.Use()) + + if err := installMaster(out, c.kubernetesVersion, c.advertiseAddress, c.apiServerHostPort, c.clusterName, c.serviceCIDR, c.podNetworkCIDR, c.cloudProvider, c.nodepool, c.controllerManagerSigningCA, c.apiServerCertSANs, c.oidcIssuerURL, c.oidcClientID, c.imageRepository); err != nil { + if rErr := kubeadm.Reset(out); rErr != nil { + _, _ = fmt.Fprintf(out, "%v\n", rErr) + } + return err + } + + if err := linux.SystemctlEnableAndStart(out, "kubelet"); err != nil { + return err + } + + if err := installPodNetwork(out, c.podNetworkCIDR, kubeConfig); err != nil { + return err + } + + if err := taintRemoveNoSchedule(out, c.clusterMode, kubeConfig); err != nil { + return err + } + + return nil +} + +func (c *ControlPlane) masterBootstrapParameters(cmd *cobra.Command) (err error) { + c.kubernetesVersion, err = cmd.Flags().GetString(constants.FlagKubernetesVersion) + if err != nil { + return + } + ver, err := semver.NewVersion(c.kubernetesVersion) + if err != nil { + return + } + c.kubernetesVersion = ver.String() + + c.networkProvider, err = cmd.Flags().GetString(constants.FlagNetworkProvider) + if err != nil { + return + } + c.advertiseAddress, err = cmd.Flags().GetString(constants.FlagAdvertiseAddress) + if err != nil { + return + } + c.apiServerHostPort, err = cmd.Flags().GetString(constants.FlagAPIServerHostPort) + if err != nil { + return + } + c.serviceCIDR, err = cmd.Flags().GetString(constants.FlagServiceCIDR) + if err != nil { + return + } + c.podNetworkCIDR, err = cmd.Flags().GetString(constants.FlagPodNetworkCIDR) + if err != nil { + return + } + c.cloudProvider, err = cmd.Flags().GetString(constants.FlagCloudProvider) + if err != nil { + return + } + c.nodepool, err = cmd.Flags().GetString(constants.FlagPipelineNodepool) + if err != nil { + return + } + c.controllerManagerSigningCA, err = cmd.Flags().GetString(constants.FlagControllerManagerSigningCA) + if err != nil { + return + } + c.clusterMode, err = cmd.Flags().GetString(constants.FlagClusterMode) + if err != nil { + return + } + c.apiServerCertSANs, err = cmd.Flags().GetStringArray(constants.FlagAPIServerCertSANs) + if err != nil { + return + } + c.clusterName, err = cmd.Flags().GetString(constants.FlagClusterName) + if err != nil { + return + } + c.oidcIssuerURL, err = cmd.Flags().GetString(constants.FlagOIDCIssuerURL) + if err != nil { + return + } + c.oidcClientID, err = cmd.Flags().GetString(constants.FlagOIDCClientID) + if err != nil { + return + } + c.imageRepository, err = cmd.Flags().GetString(constants.FlagImageRepository) + + return +} + +func installMaster(out io.Writer, kubernetesVersion, advertiseAddress, apiServerHostPort, clusterName, serviceCIDR, podNetworkCIDR, cloudProvider, nodepool, controllerManagerSigningCA string, apiServerCertSANs []string, oidcIssuerURL, oidcClientID, imageRepository string) error { + // write kubeadm config + err := WriteKubeadmConfig(out, kubeadmConfig, advertiseAddress, apiServerHostPort, clusterName, "", kubernetesVersion, serviceCIDR, podNetworkCIDR, cloudProvider, nodepool, controllerManagerSigningCA, apiServerCertSANs, oidcIssuerURL, oidcClientID, imageRepository) + if err != nil { + return err + } + + // write kubeadm aws.conf + err = writeKubeadmAmazonConfig(out, kubeadmAmazonConfig, cloudProvider) + + // kubeadm init --config=/etc/kubernetes/kubeadm.conf + args := []string{ + "init", + "--config=" + kubeadmConfig, + } + err = runner.Cmd(out, cmdKubeadm, args...).CombinedOutputAsync() + if err != nil { + return err + } + + return nil +} + +func installPodNetwork(out io.Writer, podNetworkCIDR, kubeConfig string) error { + // kubectl version + cmd := runner.Cmd(out, cmdKubectl, "version") + cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeConfig) + o, err := cmd.CombinedOutput() + if err != nil { + return err + } + + // base64 + ver := base64.StdEncoding.EncodeToString(o) + + // weave network url + u, err := url.Parse(weaveNetUrl) + if err != nil { + return err + } + q := u.Query() + q.Set("k8s-version", ver) + q.Set("env.IPALLOC_RANGE", podNetworkCIDR) + u.RawQuery = q.Encode() + + // kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')&env.IPALLOC_RANGE=10.200.0.0/16" + cmd = runner.Cmd(out, cmdKubectl, "apply", "-f", u.String()) + cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeConfig) + if err = cmd.CombinedOutputAsync(); err != nil { + return err + } + + return nil +} + +func WriteKubeadmConfig(out io.Writer, filename, advertiseAddress, controlPlaneEndpoint, clusterName, fqdn, kubernetesVersion, serviceCIDR, podCIDR, cloudProvider, nodepool, controllerManagerSigningCA string, apiServerCertSANs []string, oidcIssuerURL, oidcClientID, imageRepository string) error { + dir := filepath.Dir(filename) + + _, _ = fmt.Fprintf(out, "[%s] creating directory: %q\n", use, dir) + err := os.MkdirAll(dir, 0750) + if err != nil { + return err + } + + // API server advertisement + bindPort := "6443" + if advertiseAddress != "" { + host, port, err := splitHostPort(advertiseAddress, "6443") + if err != nil { + return err + } + advertiseAddress = host + bindPort = port + } + + // Control Plane + if controlPlaneEndpoint != "" { + host, port, err := splitHostPort(controlPlaneEndpoint, "6443") + if err != nil { + return err + } + controlPlaneEndpoint = net.JoinHostPort(host, port) + } + + // see https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3 + conf := `apiVersion: kubeadm.k8s.io/v1alpha3 +kind: InitConfiguration +{{ if .APIServerAdvertiseAddress}}apiEndpoint: + advertiseAddress: "{{ .APIServerAdvertiseAddress }}" + bindPort: {{ .APIServerBindPort }}{{end}} +nodeRegistration: + criSocket: "unix:///run/containerd/containerd.sock" + kubeletExtraArgs: + {{if .Nodepool }} + node-labels: "nodepool.banzaicloud.io/name={{ .Nodepool }}"{{end}} + {{if .CloudProvider }} + cloud-provider: {{ .CloudProvider }}{{end}} +--- +apiVersion: kubeadm.k8s.io/v1alpha3 +kind: ClusterConfiguration +clusterName: {{ .ClusterName }} +imageRepository: {{ .ImageRepository }} +unifiedControlPlaneImage: {{ .ImageRepository }}/hyperkube:v{{ .KubernetesVersion }} +networking: + serviceSubnet: "{{ .ServiceCIDR }}" + podSubnet: "{{ .PodCIDR }}" + dnsDomain: "cluster.local" +kubernetesVersion: "v{{ .KubernetesVersion }}" +{{ if .ControlPlaneEndpoint }}controlPlaneEndpoint: "{{ .ControlPlaneEndpoint }}"{{end}} +certificatesDir: "/etc/kubernetes/pki" +{{if .APIServerCertSANs}}apiServerCertSANs: +{{range $k, $san := .APIServerCertSANs}} - "{{ $san }}" +{{end}}{{end}} +apiServerExtraArgs:{{if (and .OIDCIssuerURL .OIDCClientID) }} + oidc-issuer-url: "{{ .OIDCIssuerURL }}" + oidc-client-id: "{{ .OIDCClientID }}" + oidc-username-claim: "email" + oidc-username-prefix: "oidc:" + oidc-groups-claim: "groups"{{end}} +{{if eq .CloudProvider "aws" }} + cloud-provider: aws + cloud-config: /etc/kubernetes/aws.conf +apiServerExtraVolumes: + - name: cloud-config + hostPath: /etc/kubernetes/aws.conf + mountPath: /etc/kubernetes/aws.conf +controllerManagerExtraVolumes: + - name: cloud-config + hostPath: /etc/kubernetes/aws.conf + mountPath: /etc/kubernetes/aws.conf{{end}} +controllerManagerExtraArgs:{{if eq .CloudProvider "aws" }} + cloud-provider: aws + cloud-config: /etc/kubernetes/aws.conf{{end}} + {{ if .ControllerManagerSigningCA }}cluster-signing-cert-file: {{ .ControllerManagerSigningCA }}{{end}} +` + tmpl, err := template.New("kubeadm-config").Parse(conf) + if err != nil { + return err + } + + // create and truncate write only file + w, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + return err + } + defer func() { _ = w.Close() }() + + type data struct { + APIServerAdvertiseAddress string + APIServerBindPort string + ControlPlaneEndpoint string + APIServerCertSANs []string + ClusterName string + FQDN string + KubernetesVersion string + ServiceCIDR string + PodCIDR string + CloudProvider string + Nodepool string + ControllerManagerSigningCA string + OIDCIssuerURL string + OIDCClientID string + ImageRepository string + } + + d := data{ + APIServerAdvertiseAddress: advertiseAddress, + APIServerBindPort: bindPort, + ControlPlaneEndpoint: controlPlaneEndpoint, + APIServerCertSANs: apiServerCertSANs, + ClusterName: clusterName, + FQDN: fqdn, + KubernetesVersion: kubernetesVersion, + ServiceCIDR: serviceCIDR, + PodCIDR: podCIDR, + CloudProvider: cloudProvider, + Nodepool: nodepool, + ControllerManagerSigningCA: controllerManagerSigningCA, + OIDCIssuerURL: oidcIssuerURL, + OIDCClientID: oidcClientID, + ImageRepository: imageRepository, + } + + return tmpl.Execute(w, d) +} + +func writeKubeadmAmazonConfig(out io.Writer, filename, cloudProvider string) error { + if cloudProvider == constants.CloudProviderAmazon { + if http.DefaultClient.Timeout < 10*time.Second { + http.DefaultClient.Timeout = 10 * time.Second + } + + // printf "[GLOBAL]\nZone="$(curl -q -s http://169.254.169.254/latest/meta-data/placement/availability-zone) > /etc/kubernetes/aws.conf + resp, err := http.Get(urlAWSAZ) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + return errors.New(fmt.Sprintf("failed to get aws availability zone. http status code: %d", resp.StatusCode)) + } + defer func() { _ = resp.Body.Close() }() + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return errors.Wrap(err, "failed to read response body") + } + + w, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + return err + } + defer func() { _ = w.Close() }() + + _, err = fmt.Fprintf(w, "[GLOBAL]\nZone=%s\n", b) + return err + } + + return nil +} + +func taintRemoveNoSchedule(out io.Writer, clusterMode, kubeConfig string) error { + if clusterMode != "single" { + _, _ = fmt.Fprintf(out, "skipping NoSchedule taint removal\n") + return nil + } + + // kubectl taint node -l node-role.kubernetes.io/master node-role.kubernetes.io/master:NoSchedule- + cmd := runner.Cmd(out, cmdKubectl, "taint", "node", "-l node-role.kubernetes.io/master", "node-role.kubernetes.io/master:NoSchedule-") + cmd.Env = append(os.Environ(), "KUBECONFIG="+kubeConfig) + return cmd.CombinedOutputAsync() +} + +func splitHostPort(hostport, defaultPort string) (host, port string, err error) { + host, port, err = net.SplitHostPort(hostport) + if aerr, ok := err.(*net.AddrError); ok { + if aerr.Err == "missing port in address" { + hostport = net.JoinHostPort(hostport, defaultPort) + host, port, err = net.SplitHostPort(hostport) + } + } + return +} diff --git a/cmd/pke/app/phases/kubeadm/controlplane/controlplane_test.go b/cmd/pke/app/phases/kubeadm/controlplane/controlplane_test.go new file mode 100644 index 00000000..870c9690 --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/controlplane/controlplane_test.go @@ -0,0 +1,53 @@ +package controlplane + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/stretchr/testify/require" +) + +func TestWriteKubeadmConfig(t *testing.T) { + t.SkipNow() + filename := os.TempDir() + "kubeadm.conf" + t.Log(filename) + err := WriteKubeadmConfig( + os.Stdout, + filename, + "192.168.64.11:6443", + "192.168.64.11:6443", + "my-cluster", + "", + "1.12.2", + "10.32.0.0/24", + "10.200.0.0/16", + constants.CloudProviderAmazon, + "pool1", + "/etc/kubernetes/pki/cm-signing-ca.crt", + []string{"almafa", "vadkorte"}, + "", + "", + "", + ) + require.NoError(t, err) + defer func() { _ = os.Remove(filename) }() + + b, err := ioutil.ReadFile(filename) + require.NoError(t, err) + t.Logf("%s\n", b) +} + +func TestWriteKubeadmAmazonConfig(t *testing.T) { + t.SkipNow() + filename := os.TempDir() + "aws.conf" + t.Log(filename) + err := writeKubeadmAmazonConfig(os.Stdout, filename, constants.CloudProviderAmazon) + require.NoError(t, err) + defer func() { _ = os.Remove(filename) }() + + b, err := ioutil.ReadFile(filename) + require.NoError(t, err) + t.Logf("%s\n", b) +} diff --git a/cmd/pke/app/phases/kubeadm/images/pull.go b/cmd/pke/app/phases/kubeadm/images/pull.go new file mode 100644 index 00000000..4956224f --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/images/pull.go @@ -0,0 +1,99 @@ +package images + +import ( + "fmt" + "io" + + "github.com/Masterminds/semver" + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm/controlplane" + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" + "github.com/banzaicloud/pke/cmd/pke/app/util/validator" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + use = "image-pull" + short = "Pull images used bye PKE tool" + + cmdKubeadm = "/bin/kubeadm" + kubeadmConfig = "/etc/kubernetes/kubeadm.conf" +) + +var _ phases.Runnable = (*Image)(nil) + +type Image struct { + kubernetesVersion string + imageRepository string +} + +func NewCommand(out io.Writer) *cobra.Command { + return phases.NewCommand(out, &Image{}) +} + +func (i *Image) Use() string { + return use +} + +func (i *Image) Short() string { + return short +} + +func (i *Image) RegisterFlags(flags *pflag.FlagSet) { + // Kubernetes version + flags.String(constants.FlagKubernetesVersion, "1.13.3", "Kubernetes version") + // Image repository + flags.String(constants.FlagImageRepository, "banzaicloud", "Prefix for image repository") +} + +func (i *Image) Validate(cmd *cobra.Command) error { + var err error + i.kubernetesVersion, err = cmd.Flags().GetString(constants.FlagKubernetesVersion) + if err != nil { + return err + } + ver, err := semver.NewVersion(i.kubernetesVersion) + if err != nil { + return err + } + i.kubernetesVersion = ver.String() + + i.imageRepository, err = cmd.Flags().GetString(constants.FlagImageRepository) + if err != nil { + return err + } + + if err := validator.NotEmpty(map[string]interface{}{ + constants.FlagKubernetesVersion: i.kubernetesVersion, + constants.FlagImageRepository: i.imageRepository, + }); err != nil { + return err + } + + return nil +} + +func (i *Image) Run(out io.Writer) error { + _, _ = fmt.Fprintf(out, "[RUNNING] %s\n", i.Use()) + + err := controlplane.WriteKubeadmConfig(out, kubeadmConfig, "", "", "", "", i.kubernetesVersion, "", "", "", "", "", []string{}, "", "", i.imageRepository) + if err != nil { + return err + } + // kubeadm config images pull --kubernetes-version 1.13.3 --cri-socket unix:///run/containerd/containerd.sock + err = runner.Cmd( + out, + cmdKubeadm, + "config", + "images", + "pull", + "--config="+kubeadmConfig, + ).CombinedOutputAsync() + if err != nil { + return err + } + + return nil +} diff --git a/cmd/pke/app/phases/kubeadm/node/node.go b/cmd/pke/app/phases/kubeadm/node/node.go new file mode 100644 index 00000000..5907f2c1 --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/node/node.go @@ -0,0 +1,223 @@ +package node + +import ( + "context" + "fmt" + "html/template" + "io" + "os" + "path/filepath" + + "github.com/banzaicloud/pipeline/client" + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/banzaicloud/pke/cmd/pke/app/phases/kubeadm" + "github.com/banzaicloud/pke/cmd/pke/app/util/linux" + "github.com/banzaicloud/pke/cmd/pke/app/util/pipeline" + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" + "github.com/banzaicloud/pke/cmd/pke/app/util/validator" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + use = "kubernetes-node" + short = "Kubernetes worker node installation" + + cmdKubeadm = "/bin/kubeadm" + kubeadmConfig = "/etc/kubernetes/kubeadm.conf" +) + +var _ phases.Runnable = (*Node)(nil) + +type Node struct { + apiServerHostPort string + kubeadmToken string + caCertHash string + cloudProvider string + nodepool string +} + +func NewCommand(out io.Writer) *cobra.Command { + return phases.NewCommand(out, &Node{}) +} + +func (w *Node) Use() string { + return use +} + +func (w *Node) Short() string { + return short +} + +func (w *Node) RegisterFlags(flags *pflag.FlagSet) { + // Pipeline + flags.StringP(constants.FlagPipelineAPIEndpoint, constants.FlagPipelineAPIEndpointShort, "", "Pipeline API server url") + flags.StringP(constants.FlagPipelineAPIToken, constants.FlagPipelineAPITokenShort, "", "Token for accessing Pipeline API") + flags.Int32(constants.FlagPipelineOrganizationID, 0, "Organization ID to use with Pipeline API") + flags.Int32(constants.FlagPipelineClusterID, 0, "Cluster ID to use with Pipeline API") + // Kubernetes cloud provider (optional) + flags.String(constants.FlagCloudProvider, "", "cloud provider. example: aws") + // Kubernetes cluster join parameters + flags.String(constants.FlagAPIServerHostPort, "", "Kubernetes API Server host port") + flags.String(constants.FlagKubeadmToken, "", "PKE join token") + flags.String(constants.FlagCACertHash, "", "CA cert hash") + // Pipeline nodepool name (optional) + flags.String(constants.FlagPipelineNodepool, "", "name of the nodepool the node belongs to") +} + +func (w *Node) Validate(cmd *cobra.Command) error { + if err := w.workerBootstrapParameters(cmd); err != nil { + return err + } + + if err := validator.NotEmpty(map[string]interface{}{ + constants.FlagAPIServerHostPort: w.apiServerHostPort, + constants.FlagKubeadmToken: w.kubeadmToken, + constants.FlagCACertHash: w.caCertHash, + }); err != nil { + return err + } + return nil +} + +func (w *Node) Run(out io.Writer) error { + _, _ = fmt.Fprintf(out, "[RUNNING] %s\n", w.Use()) + + if err := install(out, w.apiServerHostPort, w.kubeadmToken, w.caCertHash, w.cloudProvider, w.nodepool); err != nil { + if rErr := kubeadm.Reset(out); rErr != nil { + _, _ = fmt.Fprintf(out, "%v\n", rErr) + } + return err + } + + return nil +} + +func (w *Node) workerBootstrapParameters(cmd *cobra.Command) (err error) { + // Override values with flags + w.apiServerHostPort, err = cmd.Flags().GetString(constants.FlagAPIServerHostPort) + if err != nil { + return + } + w.kubeadmToken, err = cmd.Flags().GetString(constants.FlagKubeadmToken) + if err != nil { + return + } + w.caCertHash, err = cmd.Flags().GetString(constants.FlagCACertHash) + if err != nil { + return + } + + if w.apiServerHostPort == "" && w.kubeadmToken == "" && w.caCertHash == "" { + w.apiServerHostPort, w.kubeadmToken, w.caCertHash, err = pipelineJoinArgs(cmd) + if err != nil { + return + } + } + + w.cloudProvider, err = cmd.Flags().GetString(constants.FlagCloudProvider) + if err != nil { + return + } + w.nodepool, err = cmd.Flags().GetString(constants.FlagPipelineNodepool) + + return +} + +func pipelineJoinArgs(cmd *cobra.Command) (apiServerHostPort, kubeadmToken, caCertHash string, err error) { + if !pipeline.Enabled(cmd) { + return + } + endpoint, token, orgID, clusterID, err := pipeline.CommandArgs(cmd) + if err != nil { + return + } + + // Pipeline client. + c := pipeline.Client(os.Stdout, endpoint, token) + + var b client.GetClusterBootstrapResponse + b, _, err = c.ClustersApi.GetClusterBootstrap(context.Background(), orgID, clusterID) + if err != nil { + return + } + apiServerHostPort = b.MasterAddress + kubeadmToken = b.Token + caCertHash = b.DiscoveryTokenCaCertHash + return +} + +func install(out io.Writer, apiServerHostPort, token, caCertHash, cloudProvider, nodepool string) error { + // write kubeadm config + if err := writeKubeadmConfig(out, kubeadmConfig, apiServerHostPort, token, caCertHash, cloudProvider, nodepool); err != nil { + return err + } + + // kubeadm join 10.240.0.11:6443 --token 0uk28q.e5i6ewi7xb0g8ye9 --discovery-token-ca-cert-hash sha256:a1a74c00ecccf947b69b49172390018096affbbae25447c4bd0c0906273c1482 --cri-socket=unix:///run/containerd/containerd.sock + if err := runner.Cmd(out, cmdKubeadm, "join", "--config="+kubeadmConfig).CombinedOutputAsync(); err != nil { + return err + } + + if err := linux.SystemctlEnableAndStart(out, "kubelet"); err != nil { + return err + } + + return nil +} + +func writeKubeadmConfig(out io.Writer, filename, apiServerHostPort, token, caCertHash, cloudProvider, nodepool string) error { + dir := filepath.Dir(filename) + + _, _ = fmt.Fprintf(out, "[%s] creating directory: %q\n", use, dir) + err := os.MkdirAll(dir, 0750) + if err != nil { + return err + } + + // see https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3 + conf := `apiVersion: kubeadm.k8s.io/v1alpha3 +kind: JoinConfiguration +nodeRegistration: + criSocket: "unix:///run/containerd/containerd.sock" + kubeletExtraArgs: + {{if .Nodepool }} + node-labels: "nodepool.banzaicloud.io/name={{ .Nodepool }}"{{end}} + {{if .CloudProvider }} + cloud-provider: {{ .CloudProvider }}{{end}} +discoveryTokenAPIServers: + - {{ .APIServerHostPort }} +token: {{ .Token }} +discoveryTokenCACertHashes: + - {{ .CACertHash }} +` + tmpl, err := template.New("kubeadm-config").Parse(conf) + if err != nil { + return err + } + + // create and truncate write only file + w, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) + if err != nil { + return err + } + defer func() { _ = w.Close() }() + + type data struct { + APIServerHostPort string + Token string + CACertHash string + CloudProvider string + Nodepool string + } + + d := data{ + APIServerHostPort: apiServerHostPort, + Token: token, + CACertHash: caCertHash, + CloudProvider: cloudProvider, + Nodepool: nodepool, + } + + return tmpl.Execute(w, d) +} diff --git a/cmd/pke/app/phases/kubeadm/node/node_test.go b/cmd/pke/app/phases/kubeadm/node/node_test.go new file mode 100644 index 00000000..d4af22e1 --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/node/node_test.go @@ -0,0 +1,23 @@ +package node + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/stretchr/testify/require" +) + +func TestWriteKubeadmConfig(t *testing.T) { + t.SkipNow() + filename := os.TempDir() + "kubeadm.conf" + t.Log(filename) + err := writeKubeadmConfig(os.Stdout, filename, "1.2.3.4:1234", "my.token", "sha256:xxx", constants.CloudProviderAmazon, "pool2") + require.NoError(t, err) + defer func() { _ = os.Remove(filename) }() + + b, err := ioutil.ReadFile(filename) + require.NoError(t, err) + t.Logf("%s\n", b) +} diff --git a/cmd/pke/app/phases/kubeadm/reset.go b/cmd/pke/app/phases/kubeadm/reset.go new file mode 100644 index 00000000..64b554b8 --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/reset.go @@ -0,0 +1,22 @@ +package kubeadm + +import ( + "fmt" + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" +) + +const ( + cmdKubeadm = "/bin/kubeadm" +) + +func Reset(out io.Writer) error { + // kubeadm reset --force + _, _ = fmt.Fprintln(out, "Resetting kubeadm...") + err := runner.Cmd(out, cmdKubeadm, "reset", "--force", "--cri-socket=unix:///run/containerd/containerd.sock").CombinedOutputAsync() + if err != nil { + return err + } + return nil +} diff --git a/cmd/pke/app/phases/kubeadm/token/create/create.go b/cmd/pke/app/phases/kubeadm/token/create/create.go new file mode 100644 index 00000000..2e21e739 --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/token/create/create.go @@ -0,0 +1,43 @@ +package create + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + use = "create" + short = "Create Kubernetes bootstrap token" +) + +var _ phases.Runnable = (*Create)(nil) + +type Create struct { + kubernetesVersion string + imageRepository string +} + +func NewCommand(out io.Writer) *cobra.Command { + return phases.NewCommand(out, &Create{}) +} + +func (*Create) Use() string { + return use +} + +func (*Create) Short() string { + return short +} + +func (*Create) RegisterFlags(flags *pflag.FlagSet) {} + +func (*Create) Validate(cmd *cobra.Command) error { + return nil +} + +func (*Create) Run(out io.Writer) error { + return nil +} diff --git a/cmd/pke/app/phases/kubeadm/token/list/list.go b/cmd/pke/app/phases/kubeadm/token/list/list.go new file mode 100644 index 00000000..187ad84d --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/token/list/list.go @@ -0,0 +1,42 @@ +package list + +import ( + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "io" +) + +const ( + use = "list" + short = "List Kubernetes bootstrap token(s)" +) + +var _ phases.Runnable = (*List)(nil) + +type List struct { + kubernetesVersion string + imageRepository string +} + +func NewCommand(out io.Writer) *cobra.Command { + return phases.NewCommand(out, &List{}) +} + +func (*List) Use() string { + return use +} + +func (*List) Short() string { + return short +} + +func (*List) RegisterFlags(flags *pflag.FlagSet) {} + +func (*List) Validate(cmd *cobra.Command) error { + return nil +} + +func (*List) Run(out io.Writer) error { + return nil +} diff --git a/cmd/pke/app/phases/kubeadm/version/version.go b/cmd/pke/app/phases/kubeadm/version/version.go new file mode 100644 index 00000000..7943becb --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/version/version.go @@ -0,0 +1,83 @@ +package version + +import ( + "fmt" + "io" + + "github.com/Masterminds/semver" + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/banzaicloud/pke/cmd/pke/app/util/validator" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + use = "kubernetes-version" + short = "Check Kubernetes version is supported or not" + + constraint = ">= 1.12.0, < 1.12.6 || >= 1.13.0, <= 1.13.4" +) + +var _ phases.Runnable = (*Version)(nil) + +type Version struct { + kubernetesVersion string +} + +func NewCommand(out io.Writer) *cobra.Command { + return phases.NewCommand(out, &Version{}) +} + +func (v *Version) Use() string { + return use +} + +func (v *Version) Short() string { + return short +} + +func (v *Version) RegisterFlags(flags *pflag.FlagSet) { + // Kubernetes version + flags.String(constants.FlagKubernetesVersion, "1.13.3", "Kubernetes version") +} + +func (v *Version) Validate(cmd *cobra.Command) error { + var err error + v.kubernetesVersion, err = cmd.Flags().GetString(constants.FlagKubernetesVersion) + if err != nil { + return err + } + + if err := validator.NotEmpty(map[string]interface{}{ + constants.FlagKubernetesVersion: v.kubernetesVersion, + }); err != nil { + return err + } + + return validVersion(v.kubernetesVersion, constraint) +} + +func (v *Version) Run(out io.Writer) error { + _, _ = fmt.Fprintf(out, "Kubernetes version %q is supported\n", v.kubernetesVersion) + return nil +} + +func validVersion(version, constraint string) error { + c, err := semver.NewConstraint(constraint) + if err != nil { + return err + } + + ver, err := semver.NewVersion(version) + if err != nil { + return err + } + + if !c.Check(ver) { + return errors.Wrapf(constants.ErrUnsupportedKubernetesVersion, "got: %q, expected: %q", version, constraint) + } + + return nil +} diff --git a/cmd/pke/app/phases/kubeadm/version/version_test.go b/cmd/pke/app/phases/kubeadm/version/version_test.go new file mode 100644 index 00000000..ff1ae807 --- /dev/null +++ b/cmd/pke/app/phases/kubeadm/version/version_test.go @@ -0,0 +1,38 @@ +package version + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValidVersion(t *testing.T) { + testCases := []struct { + version string + valid bool + }{ + {"0.0.1", false}, + {"1.12.0", true}, + {"1.12.1", true}, + {"1.12.2", true}, + {"1.12.3", true}, + {"1.12.4", true}, + {"1.12.5", true}, + {"1.12.6", false}, + {"1.13.0", true}, + {"1.13.1", true}, + {"1.13.2", true}, + {"1.13.3", true}, + {"1.13.4", true}, + {"1.13.5", false}, + } + + for _, tc := range testCases { + err := validVersion(tc.version, constraint) + if !tc.valid { + assert.Error(t, err, tc.version) + } else { + assert.NoError(t, err, tc.version) + } + } +} diff --git a/cmd/pke/app/phases/phase.go b/cmd/pke/app/phases/phase.go new file mode 100644 index 00000000..97bed923 --- /dev/null +++ b/cmd/pke/app/phases/phase.go @@ -0,0 +1,78 @@ +package phases + +import ( + "io" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +// Runnable interface for making phased commands. +type Runnable interface { + Use() string + Short() string + RegisterFlags(flags *pflag.FlagSet) + Validate(cmd *cobra.Command) error + Run(out io.Writer) error +} + +// NewCommand create new command. +func NewCommand(out io.Writer, r Runnable) *cobra.Command { + cmd := &cobra.Command{ + Use: r.Use(), + Short: r.Short(), + RunE: func(cmd *cobra.Command, args []string) error { + if err := r.Validate(cmd); err != nil { + return err + } + return r.Run(out) + }, + } + + r.RegisterFlags(cmd.Flags()) + + return cmd +} + +// RunEAllSubcommands runs all sub-commands for a given phase. +func RunEAllSubcommands(cmd *cobra.Command, args []string) error { + for _, c := range cmd.Commands() { + if c.HasParent() { + p := c.Parent() + c.Flags().VisitAll(func(flag *pflag.Flag) { + if f := p.Flag(flag.Name); f != nil { + *flag = *f + } + }) + } + err := c.RunE(c, args) + if err != nil { + return err + } + } + + return nil +} + +// MakeRunnable makes command phase runnable. +func MakeRunnable(cmd *cobra.Command) { + visitedFlags := make(map[string]bool) + for _, c := range cmd.Commands() { + // local flags + c.Flags().VisitAll(func(flag *pflag.Flag) { + if visitedFlags[flag.Name] { + return + } + cmd.Flags().AddFlag(flag) + visitedFlags[flag.Name] = true + }) + // persistent flags + c.PersistentFlags().VisitAll(func(flag *pflag.Flag) { + if visitedFlags[flag.Name] { + return + } + cmd.PersistentFlags().AddFlag(flag) + visitedFlags[flag.Name] = true + }) + } +} diff --git a/cmd/pke/app/phases/pipeline/certificates/certificates.go b/cmd/pke/app/phases/pipeline/certificates/certificates.go new file mode 100644 index 00000000..ca8128fe --- /dev/null +++ b/cmd/pke/app/phases/pipeline/certificates/certificates.go @@ -0,0 +1,160 @@ +package certificates + +import ( + "context" + "fmt" + "io" + "os" + + "github.com/antihax/optional" + "github.com/banzaicloud/pipeline/client" + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/banzaicloud/pke/cmd/pke/app/util/file" + "github.com/banzaicloud/pke/cmd/pke/app/util/pipeline" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + use = "pipeline-certificates" + short = "Pipeline pre-generated certificate download" + + etcdDir = "/etc/kubernetes/pki/etcd" + etcdCACert = "/etc/kubernetes/pki/etcd/ca.crt" + etcdCAKey = "/etc/kubernetes/pki/etcd/ca.key" + kubernetesCASigningCert = "/etc/kubernetes/pki/cm-signing-ca.crt" + kubernetesCACert = "/etc/kubernetes/pki/ca.crt" + kubernetesCAKey = "/etc/kubernetes/pki/ca.key" + frontProxyCACert = "/etc/kubernetes/pki/front-proxy-ca.crt" + frontProxyCAKey = "/etc/kubernetes/pki/front-proxy-ca.key" +) + +var _ phases.Runnable = (*Certificates)(nil) + +type Certificates struct { + pipelineAPIEndpoint string + pipelineAPIToken string + pipelineOrganizationID int32 + pipelineClusterID int32 +} + +func NewCommand(out io.Writer) *cobra.Command { + return phases.NewCommand(out, &Certificates{}) +} + +func (c *Certificates) Use() string { + return use +} + +func (c *Certificates) Short() string { + return short +} + +func (c *Certificates) RegisterFlags(flags *pflag.FlagSet) { + flags.StringP(constants.FlagPipelineAPIEndpoint, constants.FlagPipelineAPIEndpointShort, "", "Pipeline API server url") + flags.StringP(constants.FlagPipelineAPIToken, constants.FlagPipelineAPITokenShort, "", "Token for accessing Pipeline API") + flags.Int32(constants.FlagPipelineOrganizationID, 0, "Organization ID to use with Pipeline API") + flags.Int32(constants.FlagPipelineClusterID, 0, "Cluster ID to use with Pipeline API") +} + +func (c *Certificates) Validate(cmd *cobra.Command) error { + if !pipeline.Enabled(cmd) { + // TODO: Warning + return nil + } + + var err error + c.pipelineAPIEndpoint, c.pipelineAPIToken, c.pipelineOrganizationID, c.pipelineClusterID, err = pipeline.CommandArgs(cmd) + if err != nil { + return err + } + + return pipeline.ValidArgs(c.pipelineAPIEndpoint, c.pipelineAPIToken, c.pipelineOrganizationID, c.pipelineClusterID) +} + +func (c *Certificates) Run(out io.Writer) error { + _, _ = fmt.Fprintf(out, "[RUNNING] %s\n", c.Use()) + + if err := pipeline.ValidArgs(c.pipelineAPIEndpoint, c.pipelineAPIToken, c.pipelineOrganizationID, c.pipelineClusterID); err != nil { + _, _ = fmt.Fprintf(out, "[WARNING] Skipping %s phase due to missing Pipeline API endpoint. err: %v\n", use, err) + return nil + } + + var err error + req := &client.GetSecretsOpts{ + Type_: optional.NewString("pkecert"), + Values: optional.NewBool(true), + Tags: optional.NewInterface([]string{fmt.Sprintf("clusterID:%d", c.pipelineClusterID)}), + } + pc := pipeline.Client(out, c.pipelineAPIEndpoint, c.pipelineAPIToken) + secrets, _, err := pc.SecretsApi.GetSecrets(context.Background(), c.pipelineOrganizationID, req) + if err != nil { + return err + } + if n := len(secrets); n <= 0 || n > 1 { + ids := func(secrets []client.SecretItem) []string { + ids := make([]string, len(secrets)) + for k, s := range secrets { + ids[k] = s.Id + } + return ids + }(secrets) + + return errors.New(fmt.Sprintf("multiple or none PKE certificates are returned for cluster: %q", ids)) + } + + secret := secrets[0] + + _, _ = fmt.Fprintf(out, "[%s] creating directory: %q\n", use, etcdDir) + err = os.MkdirAll(etcdDir, 0750) + if err != nil { + return err + } + // /etc/kubernetes/pki/etcd/ca.crt + if err = write(out, etcdCACert, secret.Values["etcdCaCert"]); err != nil { + return err + } + + // /etc/kubernetes/pki/etcd/ca.key + if err = write(out, etcdCAKey, secret.Values["etcdCaKey"]); err != nil { + return err + } + + // /etc/kubernetes/pki/cm-signing-ca.crt + if err = write(out, kubernetesCASigningCert, secret.Values["kubernetesCaSigningCert"]); err != nil { + return err + } + + // /etc/kubernetes/pki/ca.crt + if err = write(out, kubernetesCACert, secret.Values["kubernetesCaCert"]); err != nil { + return err + } + + // /etc/kubernetes/pki/ca.key + if err = write(out, kubernetesCAKey, secret.Values["kubernetesCaKey"]); err != nil { + return err + } + + // /etc/kubernetes/pki/front-proxy-ca.crt + if err = write(out, frontProxyCACert, secret.Values["frontProxyCaCert"]); err != nil { + return err + } + + // /etc/kubernetes/pki/front-proxy-ca.key + if err = write(out, frontProxyCAKey, secret.Values["frontProxyCaKey"]); err != nil { + return err + } + + return nil +} + +func write(out io.Writer, filename string, value interface{}) error { + _, _ = fmt.Fprintf(out, "[%s] writing file: %s\n", use, filename) + if v, ok := value.(string); ok { + return file.Overwrite(filename, v) + } + + return errors.New(fmt.Sprintf("unexpected interface type. expected string, got: %T", value)) +} diff --git a/cmd/pke/app/phases/pipeline/ready/ready.go b/cmd/pke/app/phases/pipeline/ready/ready.go new file mode 100644 index 00000000..e1ebd8cd --- /dev/null +++ b/cmd/pke/app/phases/pipeline/ready/ready.go @@ -0,0 +1,147 @@ +package ready + +import ( + "context" + "encoding/base64" + "fmt" + "io" + "io/ioutil" + "os" + + "github.com/banzaicloud/pipeline/client" + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/banzaicloud/pke/cmd/pke/app/util/network" + "github.com/banzaicloud/pke/cmd/pke/app/util/pipeline" + "github.com/banzaicloud/pke/cmd/pke/app/util/validator" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + use = "pipeline-ready" + short = "Register node as ready at Pipeline" + + kubeConfig = "/etc/kubernetes/admin.conf" + + RoleMaster Role = "master" + RoleWorker Role = "worker" +) + +type Role string + +var _ phases.Runnable = (*Ready)(nil) + +type Ready struct { + role Role // accepted values: master, worker + cidr string + pipelineAPIEndpoint string + pipelineAPIToken string + pipelineOrganizationID int32 + pipelineClusterID int32 + pipelineNodepool string +} + +func NewCommand(out io.Writer, role Role) *cobra.Command { + return phases.NewCommand(out, &Ready{role: role}) +} + +func (r *Ready) Use() string { + return use +} + +func (r *Ready) Short() string { + return short +} + +func (r *Ready) RegisterFlags(flags *pflag.FlagSet) { + flags.StringP(constants.FlagPipelineAPIEndpoint, constants.FlagPipelineAPIEndpointShort, "", "Pipeline API server url") + flags.StringP(constants.FlagPipelineAPIToken, constants.FlagPipelineAPITokenShort, "", "Token for accessing Pipeline API") + flags.Int32(constants.FlagPipelineOrganizationID, 0, "Organization ID to use with Pipeline API") + flags.Int32(constants.FlagPipelineClusterID, 0, "Cluster ID to use with Pipeline API") + flags.String(constants.FlagPipelineNodepool, "", "name of the nodepool the node belongs to") + flags.String(constants.FlagInfrastructureCIDR, "192.168.64.0/20", "network CIDR for the actual machine") +} + +func (r *Ready) Validate(cmd *cobra.Command) error { + // Run is optional, only validate if Pipeline credentials are present. + if !pipeline.Enabled(cmd) { + return nil + } + + var err error + if r.pipelineAPIEndpoint, r.pipelineAPIToken, r.pipelineOrganizationID, r.pipelineClusterID, err = pipeline.CommandArgs(cmd); err != nil { + return err + } + + if err = pipeline.ValidArgs(r.pipelineAPIEndpoint, r.pipelineAPIToken, r.pipelineOrganizationID, r.pipelineClusterID); err != nil { + return err + } + + if r.pipelineNodepool, err = cmd.Flags().GetString(constants.FlagPipelineNodepool); err != nil { + return err + } + + if err := validator.NotEmpty(map[string]interface{}{ + "Pipeline nodepool": r.pipelineNodepool, + }); err != nil { + return err + } + + r.cidr, err = cmd.Flags().GetString(constants.FlagInfrastructureCIDR) + + return err +} + +// Run Register installed machine at Pipeline. +// Optional step. +// Skipped if no Pipeline credentials are provided. +func (r *Ready) Run(out io.Writer) error { + _, _ = fmt.Fprintf(out, "[RUNNING] %s\n", r.Use()) + + if err := pipeline.ValidArgs(r.pipelineAPIEndpoint, r.pipelineAPIToken, r.pipelineOrganizationID, r.pipelineClusterID); err != nil { + _, _ = fmt.Fprintf(out, "[WARNING][%s] Skipping phase due to missing Pipeline API endpoint credentials. %s\n", use, err) + return nil + } + + // hostname + hostname, err := os.Hostname() + if err != nil { + return err + } + + // ip + ips, err := network.IPv4Addresses() + if err != nil { + return err + } + ip, err := network.ContainsFirst(r.cidr, ips) + if err != nil { + return err + } + + // post node ready + c := pipeline.Client(out, r.pipelineAPIEndpoint, r.pipelineAPIToken) + req := client.PostReadyPkeNodeRequest{ + Name: hostname, + NodePool: r.pipelineNodepool, + Ip: ip.String(), + } + _, _ = fmt.Fprintf(out, "[%s] %v\n", use, req) + + if r.role == RoleMaster { + b, err := ioutil.ReadFile(kubeConfig) + if err != nil { + return errors.Wrapf(err, "unable to read file: %s", kubeConfig) + } + req.Config = base64.StdEncoding.EncodeToString(b) + } + + _, resp, err := c.ClustersApi.PostReadyPKENode(context.Background(), r.pipelineOrganizationID, r.pipelineClusterID, req) + if err != nil { + return errors.Wrapf(err, "post node ready call failed. http status code: %d", resp.StatusCode) + } + + return nil +} diff --git a/cmd/pke/app/phases/runtime/container/container.go b/cmd/pke/app/phases/runtime/container/container.go new file mode 100644 index 00000000..c8618c11 --- /dev/null +++ b/cmd/pke/app/phases/runtime/container/container.go @@ -0,0 +1,43 @@ +package container + +import ( + "fmt" + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/phases" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +const ( + use = "container-runtime" + short = "Container runtime installation" +) + +var _ phases.Runnable = (*Runtime)(nil) + +type Runtime struct{} + +func NewCommand(out io.Writer) *cobra.Command { + return phases.NewCommand(out, &Runtime{}) +} + +func (r *Runtime) Use() string { + return use +} + +func (r *Runtime) Short() string { + return short +} + +func (r *Runtime) RegisterFlags(flags *pflag.FlagSet) {} + +func (r *Runtime) Validate(cmd *cobra.Command) error { + return nil +} + +func (r *Runtime) Run(out io.Writer) error { + _, _ = fmt.Fprintf(out, "[RUNNING] %s\n", r.Use()) + + return installRuntime(out) +} diff --git a/cmd/pke/app/phases/runtime/container/containerd_linux.go b/cmd/pke/app/phases/runtime/container/containerd_linux.go new file mode 100644 index 00000000..0a3e71d5 --- /dev/null +++ b/cmd/pke/app/phases/runtime/container/containerd_linux.go @@ -0,0 +1,152 @@ +package container + +import ( + "fmt" + "io" + "io/ioutil" + "net/url" + "os" + "path/filepath" + + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/util/file" + "github.com/banzaicloud/pke/cmd/pke/app/util/linux" + "github.com/pkg/errors" +) + +const ( + containerDVersion = "1.2.4" + containerDSHA256 = "3391758c62d17a56807ddac98b05487d9e78e5beb614a0602caab747b0eda9e0" + containerDURL = "https://storage.googleapis.com/cri-containerd-release/cri-containerd-%s.linux-amd64.tar.gz" + containerDVersionPath = "/opt/containerd/cluster/version" + + criConfFile = "/etc/sysctl.d/99-kubernetes-cri.conf" + criConf = `net.bridge.bridge-nf-call-iptables = 1 +net.bridge.bridge-nf-call-ip6tables = 1 +net.ipv4.ip_forward = 1 +` + + containerDConfFile = "/etc/systemd/system/kubelet.service.d/0-containerd.conf" + containerDConf = `[Service] +Environment="KUBELET_EXTRA_ARGS=--container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock" +` +) + +func installRuntime(out io.Writer) error { + if ver, err := linux.CentOSVersion(out); err == nil { + if ver == "7" { + return installCentOS7(out) + } + return constants.ErrUnsupportedOS + } + + return constants.ErrUnsupportedOS +} + +func installCentOS7(out io.Writer) error { + // modprobe overlay + if err := linux.ModprobeOverlay(out); err != nil { + return errors.Wrap(err, "missing overlay Linux Kernel module") + } + + // modprobe br_netfilter + if err := linux.ModprobeBFNetFilter(out); err != nil { + return errors.Wrap(err, "missing br_netfilter Linux Kernel module") + } + + // Ensure network settings + // cat > /etc/sysctl.d/99-kubernetes-cri.conf < /etc/systemd/system/kubelet.service.d/0-containerd.conf < /etc/yum.repos.d/kubernetes.repo + // [kubernetes] + // name=Kubernetes + // baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64 + // enabled=1 + // gpgcheck=1 + // repo_gpgcheck=1 + // gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg + // exclude=kube* + // EOF + err = file.Overwrite(k8sRepoFile, k8sRepo) + if err != nil { + return err + } + + // Install kubelet kubeadm and kubectl. + // yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes + if err := linux.YumInstall(out, yumPackages(kubernetesVersion)); err != nil { + return errors.Wrap(err, "unable to install packages") + } + + _ = linux.SystemctlDisableAndStop(out, "kubelet") + + return nil +} + +func yumPackages(kubernetesVersion string) []string { + return []string{ + "kubelet-" + kubernetesVersion + "-0", + "kubeadm-" + kubernetesVersion + "-0", + "kubectl-" + kubernetesVersion + "-0", + "--disableexcludes=kubernetes", + } +} diff --git a/cmd/pke/app/phases/runtime/kubernetes/kubernetes_other.go b/cmd/pke/app/phases/runtime/kubernetes/kubernetes_other.go new file mode 100644 index 00000000..880adbd5 --- /dev/null +++ b/cmd/pke/app/phases/runtime/kubernetes/kubernetes_other.go @@ -0,0 +1,13 @@ +// +build !linux + +package kubernetes + +import ( + "io" + + "github.com/pkg/errors" +) + +func (r *Runtime) installRuntime(w io.Writer, kubernetesVersion string) error { + return errors.Errorf("unsupported operating system") +} diff --git a/cmd/pke/app/pke.go b/cmd/pke/app/pke.go new file mode 100644 index 00000000..7c8db8be --- /dev/null +++ b/cmd/pke/app/pke.go @@ -0,0 +1,18 @@ +package app + +import ( + "flag" + "os" + + "github.com/banzaicloud/pke/cmd/pke/app/cmd" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +func Run(gitVersion, gitCommit, gitTreeState, buildDate string) error { + cobra.EnableCommandSorting = false + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + + c := cmd.NewPKECommand(os.Stdin, os.Stdout, gitVersion, gitCommit, gitTreeState, buildDate) + return c.Execute() +} diff --git a/cmd/pke/app/util/file/download.go b/cmd/pke/app/util/file/download.go new file mode 100644 index 00000000..b90d1e4d --- /dev/null +++ b/cmd/pke/app/util/file/download.go @@ -0,0 +1,62 @@ +package file + +import ( + "crypto/sha256" + "encoding/hex" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + + "github.com/pkg/errors" +) + +func Download(u *url.URL, f string) error { + resp, err := http.Get(u.String()) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + return errors.Errorf("unhandled http status code: %d", resp.StatusCode) + } + defer func() { _ = resp.Body.Close() }() + + out, err := os.Create(f) + if err != nil { + return err + } + defer func() { _ = out.Close() }() + + _, err = io.Copy(out, resp.Body) + if err != nil { + return err + } + + return nil +} + +func SHA256(filepath string) (string, error) { + b, err := ioutil.ReadFile(filepath) + if err != nil { + return "", err + } + h := sha256.New() + if _, err = h.Write(b); err != nil { + return "", err + } + + return hex.EncodeToString(h.Sum(nil)), nil +} + +func SHA256File(f, hash string) error { + hs, err := SHA256(f) + if err != nil { + return err + } + if hs != hash { + return errors.Errorf("hash mismatch. got: %q, expected: %q", hs, hash) + } + + return nil +} diff --git a/cmd/pke/app/util/file/download_test.go b/cmd/pke/app/util/file/download_test.go new file mode 100644 index 00000000..bb280525 --- /dev/null +++ b/cmd/pke/app/util/file/download_test.go @@ -0,0 +1,50 @@ +package file + +import ( + "io/ioutil" + "net/url" + "os" + "testing" +) + +func TestDownloadWithSHA256(t *testing.T) { + //t.SkipNow() + testCases := []struct { + u string + hash string + len int + }{ + { + "https://storage.googleapis.com/cri-containerd-release/cri-containerd-1.2.0.linux-amd64.tar.gz", + "ee076c6260de140f9aa6dee30b0e360abfb80af252d271e697982d1209ca5dee", + 45449776, + }, + } + + for _, tc := range testCases { + u, err := url.Parse(tc.u) + if err != nil { + t.Error(err) + } + f, err := ioutil.TempFile("", "download_test") + if err != nil { + t.Error(err) + } + defer func() { _ = os.Remove(f.Name()) }() + + err = Download(u, f.Name()) + if err != nil { + t.Error(err) + } + + err = SHA256File(f.Name(), tc.hash) + if err != nil { + t.Error(err) + } + + b, err := ioutil.ReadFile(f.Name()) + if len(b) != tc.len { + t.Errorf("unexpected length. got: %d, expected %d", len(b), tc.len) + } + } +} diff --git a/cmd/pke/app/util/file/tar.go b/cmd/pke/app/util/file/tar.go new file mode 100644 index 00000000..1233d682 --- /dev/null +++ b/cmd/pke/app/util/file/tar.go @@ -0,0 +1,74 @@ +package file + +import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" + "os" + "path/filepath" + "syscall" + + "github.com/pkg/errors" +) + +func Untar(out io.Writer, r io.Reader) error { + gz, err := gzip.NewReader(r) + if err != nil { + return errors.Wrap(err, "unable to open gzip") + } + defer func() { _ = gz.Close() }() + + tr := tar.NewReader(gz) + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return errors.Wrap(err, "unable to read next tar item") + } + switch hdr.Typeflag { + case tar.TypeDir: + hdr.Name = Absolutise(string(os.PathSeparator), hdr.Name) + err = os.MkdirAll(hdr.Name, os.FileMode(hdr.Mode)) + _, _ = fmt.Fprintf(out, "mkdir -p %s err: %v\n", hdr.Name, err) + if err != nil { + return errors.Wrapf(err, "unable to create directory: %s, mode: %v", hdr.Name, hdr.FileInfo().Mode()) + } + case tar.TypeReg: + hdr.Name = Absolutise(string(os.PathSeparator), hdr.Name) + _, _ = fmt.Fprintf(out, "write %s ", hdr.Name) + f, err := os.OpenFile(hdr.Name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, hdr.FileInfo().Mode()) + if err != nil { + if e, ok := err.(*os.PathError); ok && e.Err == syscall.EEXIST { + _, _ = fmt.Fprintf(out, "exist, skipping\n") + continue + } + _, _ = fmt.Fprintf(out, "err: %v\n", err) + return errors.Wrapf(err, "unable to create file: %s, mode: %v", hdr.Name, hdr.FileInfo().Mode()) + } + n, err := io.Copy(f, tr) + if err != nil { + _, _ = fmt.Fprintf(out, "err: %v\n", err) + return errors.Wrapf(err, "unable to write file: %s, mode: %v", hdr.Name, hdr.FileInfo().Mode()) + } + if hdr.Size != n { + _, _ = fmt.Fprintf(out, "err: %v\n", err) + return errors.Wrapf(err, "write failure. file: %s, written: %d, expected: %d", hdr.Name, hdr.Size, n) + } + _, _ = fmt.Fprintf(out, "ok\n") + } + } + + return nil +} + +// Absolutise create absolute filepath from relative with given base path. +func Absolutise(base, p string) string { + p = filepath.Clean(p) + if filepath.IsAbs(p) { + return p + } + return filepath.Join(base, filepath.Dir(p), filepath.Base(p)) +} diff --git a/cmd/pke/app/util/file/tar_test.go b/cmd/pke/app/util/file/tar_test.go new file mode 100644 index 00000000..dd6d7168 --- /dev/null +++ b/cmd/pke/app/util/file/tar_test.go @@ -0,0 +1,25 @@ +package file + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAbsolutise(t *testing.T) { + testCases := []struct { + base string + p string + expected string + }{ + {"/", "/usr/local/bin/", "/usr/local/bin"}, + {"/", "./usr/local/bin/", "/usr/local/bin"}, + {"/tmp/", "/usr/local/bin/", "/usr/local/bin"}, + {"/tmp/", "./usr/local/bin/", "/tmp/usr/local/bin"}, + } + + for _, tc := range testCases { + abs := Absolutise(tc.base, tc.p) + assert.Equal(t, tc.expected, abs) + } +} diff --git a/cmd/pke/app/util/file/write.go b/cmd/pke/app/util/file/write.go new file mode 100644 index 00000000..abffcc32 --- /dev/null +++ b/cmd/pke/app/util/file/write.go @@ -0,0 +1,44 @@ +package file + +import ( + "bytes" + "io" + "io/ioutil" + "os" + + "github.com/pkg/errors" +) + +func Overwrite(file, contents string) error { + f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE, 0640) + if err != nil { + return errors.Wrapf(err, "unable to create %q file", file) + } + defer func() { _ = f.Close() }() + + b, err := ioutil.ReadAll(f) + if err != nil { + return errors.Wrapf(err, "unable to read %q file", file) + } + if !bytes.Equal([]byte(contents), b) { + _, err := f.Seek(0, io.SeekStart) + if err != nil { + return errors.Wrapf(err, "unable to seek %q file", file) + } + _, err = f.WriteString(contents) + if err != nil { + return errors.Wrapf(err, "unable to write %q file", file) + } + + n, err := f.Seek(0, io.SeekCurrent) + if err != nil { + return errors.Wrapf(err, "unable to seek %q file", file) + } + err = f.Truncate(n) + if err != nil { + return errors.Wrapf(err, "unable to truncate %q file", file) + } + } + + return nil +} diff --git a/cmd/pke/app/util/file/write_test.go b/cmd/pke/app/util/file/write_test.go new file mode 100644 index 00000000..b1a1185f --- /dev/null +++ b/cmd/pke/app/util/file/write_test.go @@ -0,0 +1,36 @@ +package file + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/require" +) + +const ( + contents = "xxxx" + contentsLonger = "yyyyyy" +) + +func TestOverwrite(t *testing.T) { + f, err := ioutil.TempFile("", "write_test") + require.NoError(t, err) + + err = Overwrite(f.Name(), contents) + require.NoError(t, err) + + b, err := ioutil.ReadFile(f.Name()) + require.Equal(t, contents, string(b)) + + err = Overwrite(f.Name(), contentsLonger) + require.NoError(t, err) + + b, err = ioutil.ReadFile(f.Name()) + require.Equal(t, contentsLonger, string(b)) + + err = Overwrite(f.Name(), contents) + require.NoError(t, err) + + b, err = ioutil.ReadFile(f.Name()) + require.Equal(t, contents, string(b)) +} diff --git a/cmd/pke/app/util/linux/modprobe.go b/cmd/pke/app/util/linux/modprobe.go new file mode 100644 index 00000000..e2b2a1f6 --- /dev/null +++ b/cmd/pke/app/util/linux/modprobe.go @@ -0,0 +1,23 @@ +package linux + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" +) + +const ( + cmdModprobe = "/sbin/modprobe" +) + +func Modprobe(out io.Writer, module string) error { + return runner.Cmd(out, cmdModprobe, module).Run() +} + +func ModprobeOverlay(out io.Writer) error { + return Modprobe(out, "overlay") +} + +func ModprobeBFNetFilter(out io.Writer) error { + return Modprobe(out, "br_netfilter") +} diff --git a/cmd/pke/app/util/linux/os_version_linux.go b/cmd/pke/app/util/linux/os_version_linux.go new file mode 100644 index 00000000..2116dbb7 --- /dev/null +++ b/cmd/pke/app/util/linux/os_version_linux.go @@ -0,0 +1,50 @@ +package linux + +import ( + "bytes" + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" + "github.com/pkg/errors" +) + +var ( + dash = []byte("-") + release = []byte("release") + centos = []byte("centos") + redhat = []byte("redhat") +) + +// CentOSVersion extract CentOS operating system version +func CentOSVersion(w io.Writer) (string, error) { + o, err := runner.Cmd(w, "rpm", "--query", "centos-release").Output() + if err != nil { + return "", err + } + + s := bytes.SplitN(o, dash, 4) + if len(s) >= 3 { + if bytes.Equal(centos, s[0]) && bytes.Equal(release, s[1]) { + return string(s[2]), nil + } + } + + return "", errors.Errorf("unhandled CentOS release output: %s", o) +} + +// RedHatVersion extract RedHat operating system version +func RedHatVersion(w io.Writer) (string, error) { + o, err := runner.Cmd(w, "rpm", "--query", "redhat-release").Output() + if err != nil { + return "", err + } + + s := bytes.SplitN(o, dash, 4) + if len(s) >= 3 { + if bytes.Equal(redhat, s[0]) && bytes.Equal(release, s[1]) { + return string(s[2]), nil + } + } + + return "", errors.Errorf("unhandled RedHat release output: %s", o) +} diff --git a/cmd/pke/app/util/linux/os_version_other.go b/cmd/pke/app/util/linux/os_version_other.go new file mode 100644 index 00000000..1fd2fb02 --- /dev/null +++ b/cmd/pke/app/util/linux/os_version_other.go @@ -0,0 +1,17 @@ +// +build !linux + +package linux + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/constants" +) + +func CentOSVersion(w io.Writer) (string, error) { + return "", constants.ErrUnsupportedOS +} + +func RedHatVersion(w io.Writer) (string, error) { + return "", constants.ErrUnsupportedOS +} diff --git a/cmd/pke/app/util/linux/swap.go b/cmd/pke/app/util/linux/swap.go new file mode 100644 index 00000000..2741d55f --- /dev/null +++ b/cmd/pke/app/util/linux/swap.go @@ -0,0 +1,28 @@ +package linux + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" +) + +const ( + swapoff = "/sbin/swapoff" + sed = "/bin/sed" + fstab = "/etc/fstab" +) + +// SwapOff disables Linux swap. +func SwapOff(out io.Writer) error { + // swapoff -a + if err := runner.Cmd(out, swapoff, "-a").Run(); err != nil { + return err + } + + // sed -i '/swap/s/^/#/' /etc/fstab + if err := runner.Cmd(out, sed, "-i", "/swap/s/^/#/", fstab).Run(); err != nil { + return err + } + + return nil +} diff --git a/cmd/pke/app/util/linux/sysctl.go b/cmd/pke/app/util/linux/sysctl.go new file mode 100644 index 00000000..777364cc --- /dev/null +++ b/cmd/pke/app/util/linux/sysctl.go @@ -0,0 +1,16 @@ +package linux + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" +) + +const ( + cmdSysctl = "/sbin/sysctl" +) + +func SysctlLoadAllFiles(out io.Writer) error { + // sysctl --system + return runner.Cmd(out, cmdSysctl, "--system").Run() +} diff --git a/cmd/pke/app/util/linux/systemctl.go b/cmd/pke/app/util/linux/systemctl.go new file mode 100644 index 00000000..080fcba1 --- /dev/null +++ b/cmd/pke/app/util/linux/systemctl.go @@ -0,0 +1,97 @@ +package linux + +import ( + "io" + "os/exec" + + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" +) + +const ( + cmdSystemctl = "/bin/systemctl" + start = "start" + stop = "stop" + enable = "enable" + disable = "disable" + isEnabled = "is-enabled" + isActive = "is-active" + reload = "daemon-reload" +) + +func Systemctl(out io.Writer, command, service string) error { + if service != "" { + return runner.Cmd(out, cmdSystemctl, command, service).Run() + } + + return runner.Cmd(out, cmdSystemctl, command).Run() +} + +func SystemctlReload(out io.Writer) error { + return Systemctl(out, reload, "") +} + +func SystemctlEnable(out io.Writer, service string) error { + if err := SystemctlReload(out); err != nil { + return err + } + return Systemctl(out, enable, service) +} + +func SystemctlDisable(out io.Writer, service string) error { + if err := SystemctlReload(out); err != nil { + return err + } + return Systemctl(out, disable, service) +} + +func SystemctlEnabled(out io.Writer, service string) (bool, error) { + err := Systemctl(out, isEnabled, service) + if err != nil { + if _, ok := err.(*exec.ExitError); ok { + return false, nil + } + return false, err + } + return true, nil +} + +func SystemctlStart(out io.Writer, service string) error { + if err := SystemctlReload(out); err != nil { + return err + } + return Systemctl(out, start, service) +} + +func SystemctlStop(out io.Writer, service string) error { + if err := SystemctlReload(out); err != nil { + return err + } + return Systemctl(out, stop, service) +} + +func SystemctlActive(out io.Writer, service string) (bool, error) { + err := Systemctl(out, isActive, service) + if err != nil { + if _, ok := err.(*exec.ExitError); ok { + return false, nil + } + return false, err + } + return true, nil +} + +func SystemctlEnableAndStart(out io.Writer, service string) error { + if err := SystemctlEnable(out, service); err != nil { + return err + } + + return SystemctlStart(out, service) +} + +func SystemctlDisableAndStop(out io.Writer, service string) error { + if err := SystemctlDisable(out, service); err != nil { + return err + } + + return SystemctlStop(out, service) +} diff --git a/cmd/pke/app/util/linux/yum.go b/cmd/pke/app/util/linux/yum.go new file mode 100644 index 00000000..8fa5dc6f --- /dev/null +++ b/cmd/pke/app/util/linux/yum.go @@ -0,0 +1,15 @@ +package linux + +import ( + "io" + + "github.com/banzaicloud/pke/cmd/pke/app/util/runner" +) + +const ( + cmdYum = "/bin/yum" +) + +func YumInstall(out io.Writer, packages []string) error { + return runner.Cmd(out, cmdYum, append([]string{"install", "-y"}, packages...)...).CombinedOutputAsync() +} diff --git a/cmd/pke/app/util/network/cidr.go b/cmd/pke/app/util/network/cidr.go new file mode 100644 index 00000000..1ecf253a --- /dev/null +++ b/cmd/pke/app/util/network/cidr.go @@ -0,0 +1,27 @@ +package network + +import ( + "fmt" + "net" + + "github.com/pkg/errors" +) + +func Contains(cidr string, ip net.IP) (bool, error) { + _, c, err := net.ParseCIDR(cidr) + if err != nil { + return false, err + } + + return c.Contains(ip), nil +} + +func ContainsFirst(cidr string, ips []net.IP) (net.IP, error) { + for _, ip := range ips { + if ok, err := Contains(cidr, ip); err == nil && ok { + return ip, nil + } + } + + return nil, errors.New(fmt.Sprintf("cidr %q does not contain ip %q", cidr, ips)) +} diff --git a/cmd/pke/app/util/network/cidr_test.go b/cmd/pke/app/util/network/cidr_test.go new file mode 100644 index 00000000..8cee0dfc --- /dev/null +++ b/cmd/pke/app/util/network/cidr_test.go @@ -0,0 +1,57 @@ +package network + +import ( + "net" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestContains(t *testing.T) { + testCases := []struct { + name string + cidr string + ip net.IP + contains bool + err bool + }{ + {"IP in CIDR", "10.240.0.0/24", net.ParseIP("10.240.0.1"), true, false}, + {"IP not in CIDR", "10.240.0.0/24", net.ParseIP("1.1.1.1"), false, false}, + {"invalid CIDR", "10.240.0.0/100", net.ParseIP("1.1.1.1"), false, true}, + } + for _, tc := range testCases { + contains, err := Contains(tc.cidr, tc.ip) + if tc.err { + require.Error(t, err, tc.name) + continue + } else { + require.NoError(t, err, tc.name) + } + require.Equal(t, tc.contains, contains, tc.name) + } +} + +func TestContainsFirst(t *testing.T) { + testCases := []struct { + name string + cidr string + ips []net.IP + expected net.IP + err bool + }{ + {"IP in CIDR", "10.240.0.0/24", []net.IP{net.ParseIP("10.240.0.1")}, net.ParseIP("10.240.0.1"), false}, + {"IP not in CIDR", "10.240.0.0/24", []net.IP{net.ParseIP("1.1.1.1")}, net.ParseIP("1.1.1.1"), true}, + {"invalid CIDR", "10.240.0.0/100", []net.IP{net.ParseIP("10.240.0.1")}, nil, true}, + {"multiple IPs in CIDR, first match", "10.240.0.0/24", []net.IP{net.ParseIP("1.1.1.1"), net.ParseIP("10.240.10.1"), net.ParseIP("10.240.0.1")}, net.ParseIP("10.240.0.1"), false}, + } + for _, tc := range testCases { + ip, err := ContainsFirst(tc.cidr, tc.ips) + if tc.err { + require.Error(t, err, tc.cidr, tc.ips) + continue + } else { + require.NoError(t, err) + } + require.Equal(t, tc.expected, ip) + } +} diff --git a/cmd/pke/app/util/network/interfaces.go b/cmd/pke/app/util/network/interfaces.go new file mode 100644 index 00000000..77811a95 --- /dev/null +++ b/cmd/pke/app/util/network/interfaces.go @@ -0,0 +1,45 @@ +package network + +import ( + "net" + + "github.com/pkg/errors" +) + +func IPv4Addresses() ([]net.IP, error) { + ips := make([]net.IP, 0) + + interfaces, err := net.Interfaces() + if err != nil { + return nil, err + } + for _, i := range interfaces { + addresses, err := i.Addrs() + if err != nil { + return nil, err + } + for _, addr := range addresses { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + if ip == nil || ip.IsLoopback() { + continue + } + ip = ip.To4() + if ip == nil { + continue // not an ipv4 address + } + ips = append(ips, ip) + } + } + + if len(ips) == 0 { + return nil, errors.New("no IPv4 address found") + } + + return ips, nil +} diff --git a/cmd/pke/app/util/pipeline/client.go b/cmd/pke/app/util/pipeline/client.go new file mode 100644 index 00000000..09716bdc --- /dev/null +++ b/cmd/pke/app/util/pipeline/client.go @@ -0,0 +1,79 @@ +package pipeline + +import ( + "io" + "time" + + "github.com/banzaicloud/pipeline/client" + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/banzaicloud/pke/cmd/pke/app/util/validator" + "github.com/spf13/cobra" + "golang.org/x/oauth2" +) + +// Client initializes Pipeline API client +func Client(out io.Writer, endpoint, token string) *client.APIClient { + config := client.NewConfiguration() + config.BasePath = endpoint + config.UserAgent = "banzai-cli/1.0.0/go" + config.HTTPClient = oauth2.NewClient(nil, oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: token}, + )) + config.HTTPClient.Timeout = 30 * time.Second + config.HTTPClient.Transport = &transportLogger{ + roundTripper: config.HTTPClient.Transport, + output: out, + } + + return client.NewAPIClient(config) +} + +// CommandArgs extracts args needed for Pipeline API client. +func CommandArgs(cmd *cobra.Command) (endpoint, token string, orgID, clusterID int32, err error) { + endpoint, err = cmd.Flags().GetString(constants.FlagPipelineAPIEndpoint) + if err != nil { + return + } + + token, err = cmd.Flags().GetString(constants.FlagPipelineAPIToken) + if err != nil { + return + } + + orgID, err = cmd.Flags().GetInt32(constants.FlagPipelineOrganizationID) + if err != nil { + return + } + + clusterID, err = cmd.Flags().GetInt32(constants.FlagPipelineClusterID) + if err != nil { + return + } + + return +} + +func Enabled(cmd *cobra.Command) bool { + endpoint, token, orgID, clusterID, err := CommandArgs(cmd) + if err != nil { + // TODO: remove this silent error. + return false + } + + return validator.Empty(map[string]interface{}{ + constants.FlagPipelineAPIEndpoint: endpoint, + constants.FlagPipelineAPIToken: token, + constants.FlagPipelineOrganizationID: orgID, + constants.FlagPipelineClusterID: clusterID, + }) != nil +} + +// ValidArgs ensures all Pipeline API args are present. +func ValidArgs(endpoint, token string, orgID, clusterID int32) error { + return validator.NotEmpty(map[string]interface{}{ + constants.FlagPipelineAPIEndpoint: endpoint, + constants.FlagPipelineAPIToken: token, + constants.FlagPipelineOrganizationID: orgID, + constants.FlagPipelineClusterID: clusterID, + }) +} diff --git a/cmd/pke/app/util/pipeline/transport.go b/cmd/pke/app/util/pipeline/transport.go new file mode 100644 index 00000000..788383e8 --- /dev/null +++ b/cmd/pke/app/util/pipeline/transport.go @@ -0,0 +1,50 @@ +package pipeline + +import ( + "context" + "fmt" + "io" + "net/http" + "net/http/httputil" + "time" +) + +type transportLogger struct { + roundTripper http.RoundTripper + output io.Writer +} + +func (t *transportLogger) RoundTrip(req *http.Request) (*http.Response, error) { + ctx := context.WithValue(req.Context(), "requestTS", time.Now()) + req = req.WithContext(ctx) + + _, _ = fmt.Fprintf(t.output, "%s --> %s %q\n", req.Proto, req.Method, req.URL) + + resp, err := t.transport().RoundTrip(req) + if err != nil { + return resp, err + } + + ctx = resp.Request.Context() + if ts, ok := ctx.Value("requestTS").(time.Time); ok { + _, _ = fmt.Fprintf(t.output, "%s <-- %d %q %s\n", resp.Proto, resp.StatusCode, resp.Request.URL, time.Now().Sub(ts)) + } else { + _, _ = fmt.Fprintf(t.output, "%s <-- %d %q\n", resp.Proto, resp.StatusCode, resp.Request.URL) + if resp.StatusCode/100 != 2 { + if b, err := httputil.DumpResponse(resp, true); err != nil { + _, _ = fmt.Fprintf(t.output, "%s\n", b) + } + + } + } + + return resp, err + +} +func (t *transportLogger) transport() http.RoundTripper { + if t.roundTripper != nil { + return t.roundTripper + } + + return http.DefaultTransport +} diff --git a/cmd/pke/app/util/runner/command.go b/cmd/pke/app/util/runner/command.go new file mode 100644 index 00000000..e9f00a24 --- /dev/null +++ b/cmd/pke/app/util/runner/command.go @@ -0,0 +1,94 @@ +package runner + +import ( + "bufio" + "fmt" + "io" + "os/exec" + "time" +) + +type Command struct { + name string + arg []string + w io.Writer + ts time.Time + *exec.Cmd +} + +func Cmd(w io.Writer, name string, arg ...string) *Command { + return &Command{ + name: name, + arg: arg, + w: w, + Cmd: exec.Command(name, arg...), + } +} + +func (c *Command) CombinedOutput() ([]byte, error) { + c.ts = time.Now() + out, err := c.Cmd.CombinedOutput() + _, _ = fmt.Fprintf(c.w, "%s %s err: %v %s\n", c.name, c.arg, err, time.Now().Sub(c.ts)) + if len(out) > 0 { + _, _ = fmt.Fprintln(c.w, string(out)) + } + return out, err +} + +func (c *Command) CombinedOutputAsync() error { + c.ts = time.Now() + stdout, err := c.Cmd.StdoutPipe() + if err != nil { + return err + } + stderr, err := c.Cmd.StderrPipe() + if err != nil { + return err + } + go func() { + combined := io.MultiReader(stdout, stderr) + scanner := bufio.NewScanner(combined) + for scanner.Scan() { + m := scanner.Text() + _, _ = fmt.Fprintln(c.w, m) + } + }() + + err = c.Start() + if err != nil { + return err + } + + err = c.Wait() + + return err +} + +func (c *Command) Output() ([]byte, error) { + c.ts = time.Now() + out, err := c.Cmd.Output() + _, _ = fmt.Fprintf(c.w, "%s %s err: %v %s\n", c.name, c.arg, err, time.Now().Sub(c.ts)) + if len(out) > 0 { + _, _ = fmt.Fprintln(c.w, string(out)) + } + return out, err +} + +func (c *Command) Run() error { + c.ts = time.Now() + err := c.Cmd.Run() + _, _ = fmt.Fprintf(c.w, "%s %s err: %v %s\n", c.name, c.arg, err, time.Now().Sub(c.ts)) + return err +} + +func (c *Command) Start() error { + c.ts = time.Now() + _, _ = fmt.Fprintf(c.w, "%s %s\n", c.name, c.arg) + return c.Cmd.Start() +} + +func (c *Command) Wait() error { + err := c.Cmd.Wait() + _, _ = fmt.Fprintf(c.w, "%s %s err: %v %s\n", c.name, c.arg, err, time.Now().Sub(c.ts)) + return err +} diff --git a/cmd/pke/app/util/runner/command_test.go b/cmd/pke/app/util/runner/command_test.go new file mode 100644 index 00000000..f2314418 --- /dev/null +++ b/cmd/pke/app/util/runner/command_test.go @@ -0,0 +1,37 @@ +package runner + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestRun(t *testing.T) { + c := Cmd(ioutil.Discard, "echo", "ok") + err := c.Run() + require.NoError(t, err) +} + +func TestOutput(t *testing.T) { + c := Cmd(ioutil.Discard, "echo", "ok") + out, err := c.Output() + require.NoError(t, err) + require.Equal(t, []byte("ok\n"), out) +} + +func TestPipeOut(t *testing.T) { + c := Cmd(ioutil.Discard, "echo", "ok") + o, err := c.StdoutPipe() + require.NoError(t, err) + + err = c.Start() + require.NoError(t, err) + + out, err := ioutil.ReadAll(o) + require.NoError(t, err) + require.Equal(t, []byte("ok\n"), out) + + err = c.Wait() + require.NoError(t, err) +} diff --git a/cmd/pke/app/util/validator/parameters.go b/cmd/pke/app/util/validator/parameters.go new file mode 100644 index 00000000..74ded91f --- /dev/null +++ b/cmd/pke/app/util/validator/parameters.go @@ -0,0 +1,40 @@ +package validator + +import ( + "github.com/banzaicloud/pke/cmd/pke/app/constants" + "github.com/pkg/errors" +) + +// NotEmpty gives error, if any of the given args is empty. Map key is returned in the error message. +func NotEmpty(args map[string]interface{}) error { + for k, v := range args { + switch arg := v.(type) { + case string: + if arg == "" { + return errors.Wrapf(constants.ErrValidationFailed, "missing %s", k) + } + case int32: + if arg <= 0 { + return errors.Wrapf(constants.ErrValidationFailed, "missing %s", k) + } + } + } + return nil +} + +// Empty gives error, if any of the given args is not empty. Map key is returned in the error message. +func Empty(args map[string]interface{}) error { + for k, v := range args { + switch arg := v.(type) { + case string: + if arg != "" { + return errors.Wrapf(constants.ErrValidationFailed, "missing %s", k) + } + case int32: + if arg > 0 { + return errors.Wrapf(constants.ErrValidationFailed, "missing %s", k) + } + } + } + return nil +} diff --git a/cmd/pke/docs/generate.go b/cmd/pke/docs/generate.go new file mode 100644 index 00000000..7d8b0341 --- /dev/null +++ b/cmd/pke/docs/generate.go @@ -0,0 +1,18 @@ +package main + +import ( + "io/ioutil" + "log" + "os" + + "github.com/banzaicloud/pke/cmd/pke/app/cmd" + "github.com/spf13/cobra/doc" +) + +func main() { + c := cmd.NewPKECommand(os.Stdin, ioutil.Discard, "", "", "", "") + err := doc.GenMarkdownTree(c, ".") + if err != nil { + log.Fatal(err) + } +} diff --git a/cmd/pke/docs/pke.md b/cmd/pke/docs/pke.md new file mode 100644 index 00000000..fd215718 --- /dev/null +++ b/cmd/pke/docs/pke.md @@ -0,0 +1,21 @@ +## pke + +Bootstrap a secure Kubernetes cluster with Banzai Cloud Pipeline Kubernetes Engine (PKE) + +### Synopsis + +Bootstrap a secure Kubernetes cluster with Banzai Cloud Pipeline Kubernetes Engine (PKE) + +### Options + +``` + -h, --help help for pke +``` + +### SEE ALSO + +* [pke install](pke_install.md) - Install a single Banzai Cloud Pipeline Kubernetes Engine (PKE) machine +* [pke machine-image](pke_machine-image.md) - Machine image build helper for Banzai Cloud Pipeline Kubernetes Engine (PKE) +* [pke token](pke_token.md) - Manage Kubernetes bootstrap tokens +* [pke version](pke_version.md) - Print tool version + diff --git a/cmd/pke/docs/pke_install.md b/cmd/pke/docs/pke_install.md new file mode 100644 index 00000000..4ac22bca --- /dev/null +++ b/cmd/pke/docs/pke_install.md @@ -0,0 +1,21 @@ +## pke install + +Install a single Banzai Cloud Pipeline Kubernetes Engine (PKE) machine + +### Synopsis + +Install a single Banzai Cloud Pipeline Kubernetes Engine (PKE) machine + +### Options + +``` + -h, --help help for install +``` + +### SEE ALSO + +* [pke](pke.md) - Bootstrap a secure Kubernetes cluster with Banzai Cloud Pipeline Kubernetes Engine (PKE) +* [pke install master](pke_install_master.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node +* [pke install single](pke_install_single.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine +* [pke install worker](pke_install_worker.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node + diff --git a/cmd/pke/docs/pke_install_master.md b/cmd/pke/docs/pke_install_master.md new file mode 100644 index 00000000..ffaf0577 --- /dev/null +++ b/cmd/pke/docs/pke_install_master.md @@ -0,0 +1,48 @@ +## pke install master + +Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node + +### Synopsis + +Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node + +``` +pke install master [flags] +``` + +### Options + +``` + -h, --help help for master + --image-repository string Prefix for image repository (default "banzaicloud") + --kubernetes-advertise-address string Kubernetes advertise address + --kubernetes-api-server string Kubernetes API Server host port + --kubernetes-api-server-cert-sans stringArray sets extra Subject Alternative Names for the API Server signing cert + --kubernetes-cloud-provider string cloud provider. example: aws + --kubernetes-cluster-name string Kubernetes cluster name (default "pke") + --kubernetes-controller-manager-signing-ca string Kubernetes Controller Manager signing cert + --kubernetes-infrastructure-cidr string network CIDR for the actual machine (default "192.168.64.0/20") + --kubernetes-master-mode string Kubernetes cluster mode (default "default") + --kubernetes-network-provider string Kubernetes network provider (default "weave") + --kubernetes-oidc-client-id string A client ID that all OIDC tokens must be issued for + --kubernetes-oidc-issuer-url string URL of the OIDC provider which allows the API server to discover public signing keys + --kubernetes-pod-network-cidr string range of IP addresses for the pod network (default "10.20.0.0/16") + --kubernetes-service-cidr string range of IP address for service VIPs (default "10.10.0.0/16") + --kubernetes-version string Kubernetes version (default "1.13.3") + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-nodepool string name of the nodepool the node belongs to + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install](pke_install.md) - Install a single Banzai Cloud Pipeline Kubernetes Engine (PKE) machine +* [pke install master container-runtime](pke_install_master_container-runtime.md) - Container runtime installation +* [pke install master kubernetes-controlplane](pke_install_master_kubernetes-controlplane.md) - Kubernetes Control Plane installation +* [pke install master kubernetes-runtime](pke_install_master_kubernetes-runtime.md) - Kubernetes runtime installation +* [pke install master kubernetes-version](pke_install_master_kubernetes-version.md) - Check Kubernetes version is supported or not +* [pke install master pipeline-certificates](pke_install_master_pipeline-certificates.md) - Pipeline pre-generated certificate download +* [pke install master pipeline-ready](pke_install_master_pipeline-ready.md) - Register node as ready at Pipeline + diff --git a/cmd/pke/docs/pke_install_master_container-runtime.md b/cmd/pke/docs/pke_install_master_container-runtime.md new file mode 100644 index 00000000..476bec75 --- /dev/null +++ b/cmd/pke/docs/pke_install_master_container-runtime.md @@ -0,0 +1,22 @@ +## pke install master container-runtime + +Container runtime installation + +### Synopsis + +Container runtime installation + +``` +pke install master container-runtime [flags] +``` + +### Options + +``` + -h, --help help for container-runtime +``` + +### SEE ALSO + +* [pke install master](pke_install_master.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node + diff --git a/cmd/pke/docs/pke_install_master_kubernetes-controlplane.md b/cmd/pke/docs/pke_install_master_kubernetes-controlplane.md new file mode 100644 index 00000000..5963a565 --- /dev/null +++ b/cmd/pke/docs/pke_install_master_kubernetes-controlplane.md @@ -0,0 +1,37 @@ +## pke install master kubernetes-controlplane + +Kubernetes Control Plane installation + +### Synopsis + +Kubernetes Control Plane installation + +``` +pke install master kubernetes-controlplane [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-controlplane + --image-repository string Prefix for image repository (default "banzaicloud") + --kubernetes-advertise-address string Kubernetes advertise address + --kubernetes-api-server string Kubernetes API Server host port + --kubernetes-api-server-cert-sans stringArray sets extra Subject Alternative Names for the API Server signing cert + --kubernetes-cloud-provider string cloud provider. example: aws + --kubernetes-cluster-name string Kubernetes cluster name (default "pke") + --kubernetes-controller-manager-signing-ca string Kubernetes Controller Manager signing cert + --kubernetes-master-mode string Kubernetes cluster mode (default "default") + --kubernetes-network-provider string Kubernetes network provider (default "weave") + --kubernetes-oidc-client-id string A client ID that all OIDC tokens must be issued for + --kubernetes-oidc-issuer-url string URL of the OIDC provider which allows the API server to discover public signing keys + --kubernetes-pod-network-cidr string range of IP addresses for the pod network (default "10.20.0.0/16") + --kubernetes-service-cidr string range of IP address for service VIPs (default "10.10.0.0/16") + --kubernetes-version string Kubernetes version (default "1.13.3") + --pipeline-nodepool string name of the nodepool the node belongs to +``` + +### SEE ALSO + +* [pke install master](pke_install_master.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node + diff --git a/cmd/pke/docs/pke_install_master_kubernetes-runtime.md b/cmd/pke/docs/pke_install_master_kubernetes-runtime.md new file mode 100644 index 00000000..509b3281 --- /dev/null +++ b/cmd/pke/docs/pke_install_master_kubernetes-runtime.md @@ -0,0 +1,23 @@ +## pke install master kubernetes-runtime + +Kubernetes runtime installation + +### Synopsis + +Kubernetes runtime installation + +``` +pke install master kubernetes-runtime [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-runtime + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke install master](pke_install_master.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node + diff --git a/cmd/pke/docs/pke_install_master_kubernetes-version.md b/cmd/pke/docs/pke_install_master_kubernetes-version.md new file mode 100644 index 00000000..b9c09ade --- /dev/null +++ b/cmd/pke/docs/pke_install_master_kubernetes-version.md @@ -0,0 +1,23 @@ +## pke install master kubernetes-version + +Check Kubernetes version is supported or not + +### Synopsis + +Check Kubernetes version is supported or not + +``` +pke install master kubernetes-version [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-version + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke install master](pke_install_master.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node + diff --git a/cmd/pke/docs/pke_install_master_pipeline-certificates.md b/cmd/pke/docs/pke_install_master_pipeline-certificates.md new file mode 100644 index 00000000..f579ca80 --- /dev/null +++ b/cmd/pke/docs/pke_install_master_pipeline-certificates.md @@ -0,0 +1,26 @@ +## pke install master pipeline-certificates + +Pipeline pre-generated certificate download + +### Synopsis + +Pipeline pre-generated certificate download + +``` +pke install master pipeline-certificates [flags] +``` + +### Options + +``` + -h, --help help for pipeline-certificates + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install master](pke_install_master.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node + diff --git a/cmd/pke/docs/pke_install_master_pipeline-ready.md b/cmd/pke/docs/pke_install_master_pipeline-ready.md new file mode 100644 index 00000000..1d975648 --- /dev/null +++ b/cmd/pke/docs/pke_install_master_pipeline-ready.md @@ -0,0 +1,28 @@ +## pke install master pipeline-ready + +Register node as ready at Pipeline + +### Synopsis + +Register node as ready at Pipeline + +``` +pke install master pipeline-ready [flags] +``` + +### Options + +``` + -h, --help help for pipeline-ready + --kubernetes-infrastructure-cidr string network CIDR for the actual machine (default "192.168.64.0/20") + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-nodepool string name of the nodepool the node belongs to + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install master](pke_install_master.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Master node + diff --git a/cmd/pke/docs/pke_install_single.md b/cmd/pke/docs/pke_install_single.md new file mode 100644 index 00000000..d6b19a5b --- /dev/null +++ b/cmd/pke/docs/pke_install_single.md @@ -0,0 +1,48 @@ +## pke install single + +Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine + +### Synopsis + +Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine + +``` +pke install single [flags] +``` + +### Options + +``` + -h, --help help for single + --image-repository string Prefix for image repository (default "banzaicloud") + --kubernetes-advertise-address string Kubernetes advertise address + --kubernetes-api-server string Kubernetes API Server host port + --kubernetes-api-server-cert-sans stringArray sets extra Subject Alternative Names for the API Server signing cert + --kubernetes-cloud-provider string cloud provider. example: aws + --kubernetes-cluster-name string Kubernetes cluster name (default "pke") + --kubernetes-controller-manager-signing-ca string Kubernetes Controller Manager signing cert + --kubernetes-infrastructure-cidr string network CIDR for the actual machine (default "192.168.64.0/20") + --kubernetes-master-mode string Kubernetes cluster mode (default "default") + --kubernetes-network-provider string Kubernetes network provider (default "weave") + --kubernetes-oidc-client-id string A client ID that all OIDC tokens must be issued for + --kubernetes-oidc-issuer-url string URL of the OIDC provider which allows the API server to discover public signing keys + --kubernetes-pod-network-cidr string range of IP addresses for the pod network (default "10.20.0.0/16") + --kubernetes-service-cidr string range of IP address for service VIPs (default "10.10.0.0/16") + --kubernetes-version string Kubernetes version (default "1.13.3") + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-nodepool string name of the nodepool the node belongs to + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install](pke_install.md) - Install a single Banzai Cloud Pipeline Kubernetes Engine (PKE) machine +* [pke install single container-runtime](pke_install_single_container-runtime.md) - Container runtime installation +* [pke install single kubernetes-controlplane](pke_install_single_kubernetes-controlplane.md) - Kubernetes Control Plane installation +* [pke install single kubernetes-runtime](pke_install_single_kubernetes-runtime.md) - Kubernetes runtime installation +* [pke install single kubernetes-version](pke_install_single_kubernetes-version.md) - Check Kubernetes version is supported or not +* [pke install single pipeline-certificates](pke_install_single_pipeline-certificates.md) - Pipeline pre-generated certificate download +* [pke install single pipeline-ready](pke_install_single_pipeline-ready.md) - Register node as ready at Pipeline + diff --git a/cmd/pke/docs/pke_install_single_container-runtime.md b/cmd/pke/docs/pke_install_single_container-runtime.md new file mode 100644 index 00000000..1995263a --- /dev/null +++ b/cmd/pke/docs/pke_install_single_container-runtime.md @@ -0,0 +1,22 @@ +## pke install single container-runtime + +Container runtime installation + +### Synopsis + +Container runtime installation + +``` +pke install single container-runtime [flags] +``` + +### Options + +``` + -h, --help help for container-runtime +``` + +### SEE ALSO + +* [pke install single](pke_install_single.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine + diff --git a/cmd/pke/docs/pke_install_single_kubernetes-controlplane.md b/cmd/pke/docs/pke_install_single_kubernetes-controlplane.md new file mode 100644 index 00000000..271f7fff --- /dev/null +++ b/cmd/pke/docs/pke_install_single_kubernetes-controlplane.md @@ -0,0 +1,37 @@ +## pke install single kubernetes-controlplane + +Kubernetes Control Plane installation + +### Synopsis + +Kubernetes Control Plane installation + +``` +pke install single kubernetes-controlplane [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-controlplane + --image-repository string Prefix for image repository (default "banzaicloud") + --kubernetes-advertise-address string Kubernetes advertise address + --kubernetes-api-server string Kubernetes API Server host port + --kubernetes-api-server-cert-sans stringArray sets extra Subject Alternative Names for the API Server signing cert + --kubernetes-cloud-provider string cloud provider. example: aws + --kubernetes-cluster-name string Kubernetes cluster name (default "pke") + --kubernetes-controller-manager-signing-ca string Kubernetes Controller Manager signing cert + --kubernetes-master-mode string Kubernetes cluster mode (default "default") + --kubernetes-network-provider string Kubernetes network provider (default "weave") + --kubernetes-oidc-client-id string A client ID that all OIDC tokens must be issued for + --kubernetes-oidc-issuer-url string URL of the OIDC provider which allows the API server to discover public signing keys + --kubernetes-pod-network-cidr string range of IP addresses for the pod network (default "10.20.0.0/16") + --kubernetes-service-cidr string range of IP address for service VIPs (default "10.10.0.0/16") + --kubernetes-version string Kubernetes version (default "1.13.3") + --pipeline-nodepool string name of the nodepool the node belongs to +``` + +### SEE ALSO + +* [pke install single](pke_install_single.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine + diff --git a/cmd/pke/docs/pke_install_single_kubernetes-runtime.md b/cmd/pke/docs/pke_install_single_kubernetes-runtime.md new file mode 100644 index 00000000..7ddb6bf0 --- /dev/null +++ b/cmd/pke/docs/pke_install_single_kubernetes-runtime.md @@ -0,0 +1,23 @@ +## pke install single kubernetes-runtime + +Kubernetes runtime installation + +### Synopsis + +Kubernetes runtime installation + +``` +pke install single kubernetes-runtime [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-runtime + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke install single](pke_install_single.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine + diff --git a/cmd/pke/docs/pke_install_single_kubernetes-version.md b/cmd/pke/docs/pke_install_single_kubernetes-version.md new file mode 100644 index 00000000..4294572b --- /dev/null +++ b/cmd/pke/docs/pke_install_single_kubernetes-version.md @@ -0,0 +1,23 @@ +## pke install single kubernetes-version + +Check Kubernetes version is supported or not + +### Synopsis + +Check Kubernetes version is supported or not + +``` +pke install single kubernetes-version [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-version + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke install single](pke_install_single.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine + diff --git a/cmd/pke/docs/pke_install_single_pipeline-certificates.md b/cmd/pke/docs/pke_install_single_pipeline-certificates.md new file mode 100644 index 00000000..43bf5446 --- /dev/null +++ b/cmd/pke/docs/pke_install_single_pipeline-certificates.md @@ -0,0 +1,26 @@ +## pke install single pipeline-certificates + +Pipeline pre-generated certificate download + +### Synopsis + +Pipeline pre-generated certificate download + +``` +pke install single pipeline-certificates [flags] +``` + +### Options + +``` + -h, --help help for pipeline-certificates + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install single](pke_install_single.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine + diff --git a/cmd/pke/docs/pke_install_single_pipeline-ready.md b/cmd/pke/docs/pke_install_single_pipeline-ready.md new file mode 100644 index 00000000..7dd93511 --- /dev/null +++ b/cmd/pke/docs/pke_install_single_pipeline-ready.md @@ -0,0 +1,28 @@ +## pke install single pipeline-ready + +Register node as ready at Pipeline + +### Synopsis + +Register node as ready at Pipeline + +``` +pke install single pipeline-ready [flags] +``` + +### Options + +``` + -h, --help help for pipeline-ready + --kubernetes-infrastructure-cidr string network CIDR for the actual machine (default "192.168.64.0/20") + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-nodepool string name of the nodepool the node belongs to + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install single](pke_install_single.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) on a single machine + diff --git a/cmd/pke/docs/pke_install_worker.md b/cmd/pke/docs/pke_install_worker.md new file mode 100644 index 00000000..135e3e9c --- /dev/null +++ b/cmd/pke/docs/pke_install_worker.md @@ -0,0 +1,38 @@ +## pke install worker + +Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node + +### Synopsis + +Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node + +``` +pke install worker [flags] +``` + +### Options + +``` + -h, --help help for worker + --kubernetes-api-server string Kubernetes API Server host port + --kubernetes-api-server-ca-cert-hash string CA cert hash + --kubernetes-cloud-provider string cloud provider. example: aws + --kubernetes-infrastructure-cidr string network CIDR for the actual machine (default "192.168.64.0/20") + --kubernetes-node-token string PKE join token + --kubernetes-version string Kubernetes version (default "1.13.3") + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-nodepool string name of the nodepool the node belongs to + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install](pke_install.md) - Install a single Banzai Cloud Pipeline Kubernetes Engine (PKE) machine +* [pke install worker container-runtime](pke_install_worker_container-runtime.md) - Container runtime installation +* [pke install worker kubernetes-node](pke_install_worker_kubernetes-node.md) - Kubernetes worker node installation +* [pke install worker kubernetes-runtime](pke_install_worker_kubernetes-runtime.md) - Kubernetes runtime installation +* [pke install worker kubernetes-version](pke_install_worker_kubernetes-version.md) - Check Kubernetes version is supported or not +* [pke install worker pipeline-ready](pke_install_worker_pipeline-ready.md) - Register node as ready at Pipeline + diff --git a/cmd/pke/docs/pke_install_worker_container-runtime.md b/cmd/pke/docs/pke_install_worker_container-runtime.md new file mode 100644 index 00000000..3d38d938 --- /dev/null +++ b/cmd/pke/docs/pke_install_worker_container-runtime.md @@ -0,0 +1,22 @@ +## pke install worker container-runtime + +Container runtime installation + +### Synopsis + +Container runtime installation + +``` +pke install worker container-runtime [flags] +``` + +### Options + +``` + -h, --help help for container-runtime +``` + +### SEE ALSO + +* [pke install worker](pke_install_worker.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node + diff --git a/cmd/pke/docs/pke_install_worker_kubernetes-node.md b/cmd/pke/docs/pke_install_worker_kubernetes-node.md new file mode 100644 index 00000000..b419ca42 --- /dev/null +++ b/cmd/pke/docs/pke_install_worker_kubernetes-node.md @@ -0,0 +1,31 @@ +## pke install worker kubernetes-node + +Kubernetes worker node installation + +### Synopsis + +Kubernetes worker node installation + +``` +pke install worker kubernetes-node [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-node + --kubernetes-api-server string Kubernetes API Server host port + --kubernetes-api-server-ca-cert-hash string CA cert hash + --kubernetes-cloud-provider string cloud provider. example: aws + --kubernetes-node-token string PKE join token + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-nodepool string name of the nodepool the node belongs to + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install worker](pke_install_worker.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node + diff --git a/cmd/pke/docs/pke_install_worker_kubernetes-runtime.md b/cmd/pke/docs/pke_install_worker_kubernetes-runtime.md new file mode 100644 index 00000000..c931c978 --- /dev/null +++ b/cmd/pke/docs/pke_install_worker_kubernetes-runtime.md @@ -0,0 +1,23 @@ +## pke install worker kubernetes-runtime + +Kubernetes runtime installation + +### Synopsis + +Kubernetes runtime installation + +``` +pke install worker kubernetes-runtime [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-runtime + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke install worker](pke_install_worker.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node + diff --git a/cmd/pke/docs/pke_install_worker_kubernetes-version.md b/cmd/pke/docs/pke_install_worker_kubernetes-version.md new file mode 100644 index 00000000..4d79093e --- /dev/null +++ b/cmd/pke/docs/pke_install_worker_kubernetes-version.md @@ -0,0 +1,23 @@ +## pke install worker kubernetes-version + +Check Kubernetes version is supported or not + +### Synopsis + +Check Kubernetes version is supported or not + +``` +pke install worker kubernetes-version [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-version + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke install worker](pke_install_worker.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node + diff --git a/cmd/pke/docs/pke_install_worker_pipeline-ready.md b/cmd/pke/docs/pke_install_worker_pipeline-ready.md new file mode 100644 index 00000000..6ff19d41 --- /dev/null +++ b/cmd/pke/docs/pke_install_worker_pipeline-ready.md @@ -0,0 +1,28 @@ +## pke install worker pipeline-ready + +Register node as ready at Pipeline + +### Synopsis + +Register node as ready at Pipeline + +``` +pke install worker pipeline-ready [flags] +``` + +### Options + +``` + -h, --help help for pipeline-ready + --kubernetes-infrastructure-cidr string network CIDR for the actual machine (default "192.168.64.0/20") + --pipeline-cluster-id int32 Cluster ID to use with Pipeline API + --pipeline-nodepool string name of the nodepool the node belongs to + --pipeline-org-id int32 Organization ID to use with Pipeline API + -t, --pipeline-token string Token for accessing Pipeline API + -u, --pipeline-url string Pipeline API server url +``` + +### SEE ALSO + +* [pke install worker](pke_install_worker.md) - Installs Banzai Cloud Pipeline Kubernetes Engine (PKE) Worker node + diff --git a/cmd/pke/docs/pke_machine-image.md b/cmd/pke/docs/pke_machine-image.md new file mode 100644 index 00000000..2d9f4179 --- /dev/null +++ b/cmd/pke/docs/pke_machine-image.md @@ -0,0 +1,28 @@ +## pke machine-image + +Machine image build helper for Banzai Cloud Pipeline Kubernetes Engine (PKE) + +### Synopsis + +Machine image build helper for Banzai Cloud Pipeline Kubernetes Engine (PKE) + +``` +pke machine-image [flags] +``` + +### Options + +``` + -h, --help help for machine-image + --image-repository string Prefix for image repository (default "banzaicloud") + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke](pke.md) - Bootstrap a secure Kubernetes cluster with Banzai Cloud Pipeline Kubernetes Engine (PKE) +* [pke machine-image container-runtime](pke_machine-image_container-runtime.md) - Container runtime installation +* [pke machine-image image-pull](pke_machine-image_image-pull.md) - Pull images used bye PKE tool +* [pke machine-image kubernetes-runtime](pke_machine-image_kubernetes-runtime.md) - Kubernetes runtime installation +* [pke machine-image kubernetes-version](pke_machine-image_kubernetes-version.md) - Check Kubernetes version is supported or not + diff --git a/cmd/pke/docs/pke_machine-image_container-runtime.md b/cmd/pke/docs/pke_machine-image_container-runtime.md new file mode 100644 index 00000000..adf76f40 --- /dev/null +++ b/cmd/pke/docs/pke_machine-image_container-runtime.md @@ -0,0 +1,22 @@ +## pke machine-image container-runtime + +Container runtime installation + +### Synopsis + +Container runtime installation + +``` +pke machine-image container-runtime [flags] +``` + +### Options + +``` + -h, --help help for container-runtime +``` + +### SEE ALSO + +* [pke machine-image](pke_machine-image.md) - Machine image build helper for Banzai Cloud Pipeline Kubernetes Engine (PKE) + diff --git a/cmd/pke/docs/pke_machine-image_image-pull.md b/cmd/pke/docs/pke_machine-image_image-pull.md new file mode 100644 index 00000000..ebf7ea2b --- /dev/null +++ b/cmd/pke/docs/pke_machine-image_image-pull.md @@ -0,0 +1,24 @@ +## pke machine-image image-pull + +Pull images used bye PKE tool + +### Synopsis + +Pull images used bye PKE tool + +``` +pke machine-image image-pull [flags] +``` + +### Options + +``` + -h, --help help for image-pull + --image-repository string Prefix for image repository (default "banzaicloud") + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke machine-image](pke_machine-image.md) - Machine image build helper for Banzai Cloud Pipeline Kubernetes Engine (PKE) + diff --git a/cmd/pke/docs/pke_machine-image_kubernetes-runtime.md b/cmd/pke/docs/pke_machine-image_kubernetes-runtime.md new file mode 100644 index 00000000..5ee4f5f1 --- /dev/null +++ b/cmd/pke/docs/pke_machine-image_kubernetes-runtime.md @@ -0,0 +1,23 @@ +## pke machine-image kubernetes-runtime + +Kubernetes runtime installation + +### Synopsis + +Kubernetes runtime installation + +``` +pke machine-image kubernetes-runtime [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-runtime + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke machine-image](pke_machine-image.md) - Machine image build helper for Banzai Cloud Pipeline Kubernetes Engine (PKE) + diff --git a/cmd/pke/docs/pke_machine-image_kubernetes-version.md b/cmd/pke/docs/pke_machine-image_kubernetes-version.md new file mode 100644 index 00000000..43f59ec0 --- /dev/null +++ b/cmd/pke/docs/pke_machine-image_kubernetes-version.md @@ -0,0 +1,23 @@ +## pke machine-image kubernetes-version + +Check Kubernetes version is supported or not + +### Synopsis + +Check Kubernetes version is supported or not + +``` +pke machine-image kubernetes-version [flags] +``` + +### Options + +``` + -h, --help help for kubernetes-version + --kubernetes-version string Kubernetes version (default "1.13.3") +``` + +### SEE ALSO + +* [pke machine-image](pke_machine-image.md) - Machine image build helper for Banzai Cloud Pipeline Kubernetes Engine (PKE) + diff --git a/cmd/pke/docs/pke_token.md b/cmd/pke/docs/pke_token.md new file mode 100644 index 00000000..1b84e43f --- /dev/null +++ b/cmd/pke/docs/pke_token.md @@ -0,0 +1,20 @@ +## pke token + +Manage Kubernetes bootstrap tokens + +### Synopsis + +Manage Kubernetes bootstrap tokens + +### Options + +``` + -h, --help help for token +``` + +### SEE ALSO + +* [pke](pke.md) - Bootstrap a secure Kubernetes cluster with Banzai Cloud Pipeline Kubernetes Engine (PKE) +* [pke token create](pke_token_create.md) - Create Kubernetes bootstrap token +* [pke token list](pke_token_list.md) - List Kubernetes bootstrap token(s) + diff --git a/cmd/pke/docs/pke_token_create.md b/cmd/pke/docs/pke_token_create.md new file mode 100644 index 00000000..a9529c2d --- /dev/null +++ b/cmd/pke/docs/pke_token_create.md @@ -0,0 +1,22 @@ +## pke token create + +Create Kubernetes bootstrap token + +### Synopsis + +Create Kubernetes bootstrap token + +``` +pke token create [flags] +``` + +### Options + +``` + -h, --help help for create +``` + +### SEE ALSO + +* [pke token](pke_token.md) - Manage Kubernetes bootstrap tokens + diff --git a/cmd/pke/docs/pke_token_list.md b/cmd/pke/docs/pke_token_list.md new file mode 100644 index 00000000..ef65876b --- /dev/null +++ b/cmd/pke/docs/pke_token_list.md @@ -0,0 +1,22 @@ +## pke token list + +List Kubernetes bootstrap token(s) + +### Synopsis + +List Kubernetes bootstrap token(s) + +``` +pke token list [flags] +``` + +### Options + +``` + -h, --help help for list +``` + +### SEE ALSO + +* [pke token](pke_token.md) - Manage Kubernetes bootstrap tokens + diff --git a/cmd/pke/docs/pke_version.md b/cmd/pke/docs/pke_version.md new file mode 100644 index 00000000..8cda1617 --- /dev/null +++ b/cmd/pke/docs/pke_version.md @@ -0,0 +1,23 @@ +## pke version + +Print tool version + +### Synopsis + +Print tool version + +``` +pke version [flags] +``` + +### Options + +``` + -h, --help help for version + -o, --output string Output format; available options are 'yaml', 'json' and 'short' +``` + +### SEE ALSO + +* [pke](pke.md) - Bootstrap a secure Kubernetes cluster with Banzai Cloud Pipeline Kubernetes Engine (PKE) + diff --git a/cmd/pke/pke.go b/cmd/pke/pke.go new file mode 100644 index 00000000..5ba16abb --- /dev/null +++ b/cmd/pke/pke.go @@ -0,0 +1,21 @@ +package main + +import ( + "os" + + "github.com/banzaicloud/pke/cmd/pke/app" +) + +var ( + Version string + CommitHash string + GitTreeState string + BuildDate string +) + +func main() { + if err := app.Run(Version, CommitHash, GitTreeState, BuildDate); err != nil { + os.Exit(1) + } + os.Exit(0) +} diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..8693ed78 --- /dev/null +++ b/go.mod @@ -0,0 +1,16 @@ +module github.com/banzaicloud/pke + +go 1.12 + +require ( + github.com/Masterminds/semver v1.4.2 + github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6 + github.com/banzaicloud/pipeline v0.0.0-20190311122237-7db66a712b1b + github.com/cpuguy83/go-md2man v1.0.8 // indirect + github.com/ghodss/yaml v1.0.0 + github.com/pkg/errors v0.8.1 + github.com/spf13/cobra v0.0.3 + github.com/spf13/pflag v1.0.3 + github.com/stretchr/testify v1.3.0 + golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..eb9f1079 --- /dev/null +++ b/go.sum @@ -0,0 +1,502 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +contrib.go.opencensus.io/exporter/ocagent v0.2.0/go.mod h1:0fnkYHF+ORKj7HWzOExKkUHeFX79gXSKUQbpnAM+wzo= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-sdk-for-go v22.2.2+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-storage-blob-go v0.0.0-20181022225951-5152f14ace1c/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/InVisionApp/go-logger v1.0.1/go.mod h1:+cGTDSn+P8105aZkeOfIhdd7vFO5X1afUHcjvanY0L8= +github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= +github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/Masterminds/semver v1.4.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.14.1+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/SAP/go-hdb v0.13.2/go.mod h1:etBT+FAi1t5k3K3tf5vQTnosgYmhDkRi8jEnQqCnxF0= +github.com/SermoDigital/jose v0.9.1/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= +github.com/ThreeDotsLabs/watermill v0.1.2/go.mod h1:c0DOrvvuqbB8uhZlgY/fukFFfv1WZ6HinSktALd9b38= +github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20180822052843-1c5a1c93a9c1/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA= +github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20180615125516-36bf7aa2f916/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6 h1:uZuxRZCz65cG1o6K/xUqImNcYKtmk9ylqaH0itMSvzA= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/apache/thrift v0.0.0-20151001171628-53dd39833a08/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61/go.mod h1:ikc1XA58M+Rx7SEbf0bLJCfBkwayZ8T5jBo5FXK8Uz8= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/EventBus v0.0.0-20180315140547-d46933a94f05/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.16.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= +github.com/banzaicloud/anchore-image-validator v0.0.0-20181204185657-bf9806201a4e/go.mod h1:VJiVAbcVK7jA47SF+VvQe5NK93vSMiumk7Cr8HK6cv4= +github.com/banzaicloud/bank-vaults v0.0.0-20181228154154-8f1348d7821a/go.mod h1:DCXyt+jITEQ5JUfxOWiYUKUE6ILZ5P4IU0MKgGcnmuc= +github.com/banzaicloud/cicd-go v0.0.0-20190214150755-832df3e92677/go.mod h1:ND5gChfnQKdrvWBqMdN0sUkYLpR5P9AccDam/hDdbmA= +github.com/banzaicloud/go-gin-prometheus v0.0.0-20181204122313-8145dbf52419/go.mod h1:1eXhK1Ld1vRFbNpqi8Eu1ktCCk5LARA1Tbdl8EsAfgE= +github.com/banzaicloud/logrus-runtime-formatter v0.0.0-20180617171254-12df4a18567f/go.mod h1:2GxaTh0YYmhQEMQ4wJ8Izr7sBecWZtnXlDzybR1hSO8= +github.com/banzaicloud/nodepool-labels-operator v0.0.0-20190219103855-a13c1b05f240/go.mod h1:EL7DTCfTrnvz79aX/MMq5Asw8ZAl7rJFzCKgAzesEFA= +github.com/banzaicloud/pipeline v0.0.0-20190311122237-7db66a712b1b h1:Em/3WinnwFiF3YkygvuTq/ehtl8YYMCeI5LR0dqlB50= +github.com/banzaicloud/pipeline v0.0.0-20190311122237-7db66a712b1b/go.mod h1:mN0ZRI2+/+5L8dcV6FR25IdvSEq8aftlMRvL0Qj0AS8= +github.com/banzaicloud/prometheus-config v0.0.0-20181214142820-fc6ae4756a29/go.mod h1:yqyOUqqONEQQzgmilQldTuKgJyS9Ahs97wG1K0Onfvo= +github.com/beevik/etree v0.0.0-20161216042344-4cd0dd976db8/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= +github.com/beorn7/perks v0.0.0-20160229213445-3ac7bf7a47d1/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/briankassouf/jose v0.9.1/go.mod h1:HQhVmdUf7dBNwIIdBTivnCDxcf6IZY3/zrb+uKSJz6Y= +github.com/bugsnag/bugsnag-go v1.4.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/cactus/go-statsd-client v3.1.1+incompatible/go.mod h1:cMRcwZDklk7hXp+Law83urTHUiHMzCev/r4JMYr/zU0= +github.com/cenkalti/backoff v2.0.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.0.2-0.20180913191712-f303ae3f8d6a/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.1.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/centrify/cloud-golang-sdk v0.0.0-20190214225812-119110094d0f/go.mod h1:C0rtzmGXgN78pYR0tGJFhtHgkbAs0lIbHwkB81VxDQE= +github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/chrismalek/oktasdk-go v0.0.0-20181212195951-3430665dfaa0/go.mod h1:5d8DqS60xkj9k3aXfL3+mXBH0DPYO0FQjcKosxl+b/Q= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cockroachdb/cmux v0.0.0-20170110192607-30d10be49292/go.mod h1:qRiX68mZX1lGBkTWyp3CLcenw9I94W2dLeRvMzcn9N4= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/confluentinc/confluent-kafka-go v0.11.6/go.mod h1:u2zNLny2xq+5rWeTQjFHbDzzNuba4P1vo31r9r4uAdg= +github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.2.9+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v0.0.0-20170307191026-be73733bb8cc/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-oidc v2.0.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190212144455-93d5ec2c7f76/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.8 h1:DwoNytLphI8hzS2Af4D0dfaEaiSq2bN05mEm4R6vf8M= +github.com/cpuguy83/go-md2man v1.0.8/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY= +github.com/crossdock/crossdock-go v0.0.0-20160816171116-049aabb0122b/go.mod h1:v9FBN7gdVTpiD/+LZ7Po0UKvROyT87uLVxTHVky/dlQ= +github.com/dancannon/gorethink v4.0.0+incompatible/go.mod h1:BLvkat9KmZc1efyYwhz3WnybhRZtgF1K929FD8z1avU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20190204142019-df6d76eb9289/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/dexidp/dex v0.0.0-20190205125449-7bd4071b4c8c/go.mod h1:rEGuBYSugwnIPKxDMKMj/5WISluZG6baZqVX0xXny0o= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/didip/tollbooth v4.0.0+incompatible/go.mod h1:A9b0665CE6l1KmzpDws2++elm/CsuWBMa5Jv4WY0PEY= +github.com/dimchansky/utfbom v1.0.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/docker/distribution v0.0.0-20180327202408-83389a148052/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.0.0-20170731201938-4f3616fb1c11/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.3.2/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libcompose v0.4.0/go.mod h1:EyqDS+Iyca0hS44T7qIMTeO1EOYWWWNOGpufHu9R8cs= +github.com/docker/spdystream v0.0.0-20170912183627-bc6354cbbc29/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/duosecurity/duo_api_golang v0.0.0-20190107154727-539434bf0d45/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo= +github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= +github.com/elazarl/goproxy v0.0.0-20181111060418-2ce16c963a8a/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/evanphx/json-patch v3.0.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fatih/structtag v1.0.0/go.mod h1:IKitwq45uXL/yqi5mYghiD3w9H6eTOvI9vnk8tXMphA= +github.com/felixge/httpsnoop v1.0.0/go.mod h1:3+D9sFq0ahK/JeJPhCBUV1xlf4/eIYrUQaxulT0VzX8= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fullsailor/pkcs7 v0.0.0-20180613152042-8306686428a5/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/gammazero/deque v0.0.0-20190130191400-2afb3858e9c7/go.mod h1:GeIq9qoE43YdGnDXURnmKTnGg15pQz4mYkXSTChbneI= +github.com/gammazero/workerpool v0.0.0-20181230203049-86a96b5d5d92/go.mod h1:w9RqFVO2BM3xwWEcAB8Fwp0OviTBBEiRmSBDfbXnd3w= +github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v0.0.0-20161020005002-bea76d6a4713/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/cors v0.0.0-20170318125340-cf4846e6a636/go.mod h1:cw+u9IsAkC16e42NtYYVCLsHYXE98nB3M7Dr9mLSeH4= +github.com/gin-contrib/sse v0.0.0-20190124093953-61b50c2ef482/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-gonic/gin v1.3.1-0.20190204012700-5acf6601170b/go.mod h1:1LxhNsJuqDSRHN+tYaDKqQ8vYKN30DhOqscovOEg5i8= +github.com/go-chi/chi v3.3.3+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-ldap/ldap v3.0.1+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-openapi/jsonpointer v0.0.0-20180322222829-3a0015ad55fa/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonreference v0.0.0-20180322222742-3fb327e6747d/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/spec v0.0.0-20180326232708-9acd88844bc1/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/swag v0.0.0-20180302192843-ceb469cb0fdf/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stomp/stomp v2.0.2+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c= +github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gocql/gocql v0.0.0-20190219221429-ec4793573d14/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= +github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v0.0.0-20171113180720-1e59b77b52bf/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-github v15.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/goph/emperror v0.16.0/go.mod h1:vakOpsf2BTE0/C0snxzXm5/l8pv6qjBhIqm/qlgDYC8= +github.com/goph/logur v0.9.0/go.mod h1:PfIUaGrVwMKoEWyHjPF4820Qcitq0xJNmje9Eh7eRJA= +github.com/goph/logur v0.11.0/go.mod h1:SUhs+0vskrKgPHfpceKH+bB9K6ceen8x3zAOqEWJWpA= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= +github.com/gorilla/context v0.0.0-20160525203319-aed02d124ae4/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v0.0.0-20161206055144-3a5767ca75ec/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v0.0.0-20160605233521-9fa818a44c2b/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v0.0.0-20181208214519-12bd4761fc66/go.mod h1:Ieo8HYsV0qN9WIJeic1HRzDxX9UY5BkplHncRmmZPwU= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gosimple/slug v1.1.1/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/gregjones/httpcache v0.0.0-20190203031600-7a902570cb17/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170826090648-0dafe0d496ea/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/gtank/cryptopasta v0.0.0-20160720052843-e7e23673cac3/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/consul v1.4.2/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.0.0-20171218145408-d5fe4b57a186/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-gcp-common v0.0.0-20180425173946-763e39302965/go.mod h1:LNbios2fdMAuLA1dsYUvUcoCYIfywcCEK8/ooaWjoOA= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.0.0-20181001195459-61d530d6c27f/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-memdb v0.0.0-20181108192425-032f93b25bec/go.mod h1:kbfItVoBJwCfKXDXN4YoAXjxcFVZ7MRrJzyTX6H4giE= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-retryablehttp v0.0.0-20180531211321-3b087ef2d313/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM= +github.com/hashicorp/go-rootcerts v0.0.0-20160503143440-6bb64b370b90/go.mod h1:o4zcYY1e0GEZI6eSEr+43QDYmuGglw1qSO6qdHUHCgg= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/nomad v0.8.7/go.mod h1:WRaKjdO1G2iqi86TvTjIYtKTyxg4pl7NLr9InxtWaI0= +github.com/hashicorp/raft v1.0.0/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/vault v1.0.1/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= +github.com/hashicorp/vault-plugin-auth-alicloud v0.0.0-20181109180636-f278a59ca3e8/go.mod h1:o3i5QQWgV5+SYouIn++L9D0kbhLYB3FjxNRHNf6KS+Q= +github.com/hashicorp/vault-plugin-auth-azure v0.0.0-20190201222632-0af1d040b5b3/go.mod h1:f+VmjSQIxxO+YTeO3FbPWRPCPbd3f3lwpP6jaO/YduQ= +github.com/hashicorp/vault-plugin-auth-centrify v0.0.0-20180816201131-66b0a34a58bf/go.mod h1:IIz+CMBKBEFyjeBeFUlpoUuMOyFb7mybOUNP6GX1xuk= +github.com/hashicorp/vault-plugin-auth-gcp v0.0.0-20190201215414-7d4c2101e7d0/go.mod h1:E/E+5CuQCjOn/YGCmZ/tA7GwLey/lN1PwwJOOa9Iqy0= +github.com/hashicorp/vault-plugin-auth-jwt v0.0.0-20190214185457-a61556be6730/go.mod h1:j6Xmkj3dzuC63mivquwVVTlxjwDndwNxi4cJUku40J8= +github.com/hashicorp/vault-plugin-auth-kubernetes v0.0.0-20190201222209-db96aa4ab438/go.mod h1:PqRUU5TaQ6FwVTsHPLrJs1F+T5IjbSzlfTy9cTyGeHM= +github.com/hashicorp/vault-plugin-secrets-ad v0.0.0-20190131222416-4796d9980125/go.mod h1:4vRQzvp3JI+g4oUqzcklIEj2UKyhQnpIo+BDbh2uzYM= +github.com/hashicorp/vault-plugin-secrets-alicloud v0.0.0-20190131211812-b0abe36195cb/go.mod h1:rl8WzY7++fZMLXd6Z/k/o9wUmMbOqpTLhbtKs1loMU0= +github.com/hashicorp/vault-plugin-secrets-azure v0.0.0-20181207232500-0087bdef705a/go.mod h1:/DhLpYuRP2o00gkj6S0Gy7NvKk5AaAtP6p3f+OmxDUI= +github.com/hashicorp/vault-plugin-secrets-gcp v0.0.0-20180921173200-d6445459e80c/go.mod h1:IV2OZZZ9FCtSYeKDLsnO5JipMdjwachVISz9pNuQjhs= +github.com/hashicorp/vault-plugin-secrets-gcpkms v0.0.0-20190116164938-d6b25b0b4a39/go.mod h1:2n62quNV4DvfMY5Lxx82NJmx+9pYtv4RltLIFKxEO4E= +github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20190227052836-76a82948fe5b/go.mod h1:VJHHT2SC1tAPrfENQeBhLlb5FbZoKZM+oC/ROmEftz0= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/heptio/ark v0.9.3/go.mod h1:rAijmSLOn6qs7oJI4Ck6M7/GSBqQ9RDYou4CgykNyQc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jeffchao/backoff v0.0.0-20140404060208-9d7fd7aa17f2/go.mod h1:xkfESuHriIekR+4RoV+fu91j/CfnYM29Zi2tMFw5iD4= +github.com/jefferai/jsonx v1.0.0/go.mod h1:OGmqmi2tTeI/PS+qQfBDToLHHJIy/RMp24fPo8vFvoQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jinzhu/gorm v1.9.1/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= +github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v0.0.0-20180314132004-b7dfa9a24504/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.0.0-20160907122059-bcac9884e750/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/keybase/go-crypto v0.0.0-20181127160227-255a5089e85a/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/lestrrat-go/backoff v0.0.0-20190107202757-0bc2a4274cd0/go.mod h1:CNQaGVRTtvkLlWshyDozYy79pBflEOWskqCMSxLTfQ0= +github.com/lib/pq v0.0.0-20181016162627-9eb73efc1fcc/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180323154445-8b799c424f57/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b/go.mod h1:5MWrJXKRQyhQdUCF+vu6U5c4nQpg70vW3eHaU0/AYbU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-sqlite3 v0.0.0-20160907162043-3fb7a0e792ed/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v0.0.0-20150406173934-fc2b8d3a73c4/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/michaelklishin/rabbit-hole v1.5.0/go.mod h1:vvI1uOitYZi0O5HEGXhaWC1XT80Gy+HvFheJ+5Krlhk= +github.com/microcosm-cc/bluemonday v0.0.0-20180327211928-995366fdf961/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/pointerstructure v0.0.0-20170205204203-f2329fcfa9e2/go.mod h1:KMNPMpc0BU/kZEgyDhBplsDn/mjnJMhyMjq4MWboN20= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/oracle/oci-go-sdk v2.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/ory-am/common v0.4.0/go.mod h1:oCYGuwwM8FyYMKqh9vrhBaeUoyz/edx0bgJN6uS6/+k= +github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v0.0.0-20181005164709-635575b42742/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20160421231612-c97913dcbd76/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/otp v1.1.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= +github.com/prashantv/protectmem v0.0.0-20171002184600-e20412882b3a/go.mod h1:lzZQ3Noex5pfAy7mkAeCjcBDteYU85uWWnJ/y6gKU8k= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.0-pre1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_model v0.0.0-20150212101744-fa8ad6fec335/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20170220103846-49fee292b27b/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20170216223256-a1dba9ce8bae/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/qor/assetfs v0.0.0-20170713023933-ff57fdc13a14/go.mod h1:GZSCP3jIneuPsav3pXmpmJwz9ES+Fuq4ZPOUC3wwckQ= +github.com/qor/auth v0.0.0-20190103025640-46aae9fa92fa/go.mod h1:W1ePrrC11DHVhm3nNdIhvD5X23supw1uqTv+EtTUTHs= +github.com/qor/mailer v0.0.0-20170814094430-1e6ac7106955/go.mod h1:83J4znr9Zj5OF4XPQzh+HFGPwUfXrYPCixwSc+QXTYM= +github.com/qor/middlewares v0.0.0-20170822143614-781378b69454/go.mod h1:PejEyg3hS+Toh5m0AKRv2jK5br8qIoHLqmHrpg0WJYg= +github.com/qor/qor v0.0.0-20180313040854-1fb0672178f1/go.mod h1:oG+LgDEnsI9avcFFdczoZnBe3rw42s4cG433w6XpEig= +github.com/qor/redirect_back v0.0.0-20170907030740-b4161ed6f848/go.mod h1:AVSTi6lUuohiM2HbnXuN07YucBDRSGHaKz8jAI2DYOU= +github.com/qor/render v0.0.0-20171201033449-63566e46f01b/go.mod h1:0cGVpTjSVSjjyrhLiLTMgbMeblLQba7vcKkZHMLlYJw= +github.com/qor/responder v0.0.0-20160314063933-ecae0be66c1a/go.mod h1:0TL2G+qGDYhHJ6XIJ6UcqkZVN+jp8AGqGU2wDnv2qas= +github.com/qor/session v0.0.0-20170907035918-8206b0adab70/go.mod h1:ldgcaca0ZGx6tFtd/w0ELq5jHD/KLJ1Lbdn8qhr/pQ0= +github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/rollbar/rollbar-go v1.0.2/go.mod h1:AcFs5f0I+c71bpHlXNNDbOWJiKwjFDtISeXco0L5PKQ= +github.com/rs/zerolog v1.11.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/russellhaering/goxmldsig v0.0.0-20170324122954-eaac44c63fe0/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM= +github.com/russross/blackfriday v1.5.1 h1:B8ZN6pD4PVofmlDCDUdELeYrbsVIDM/bpjW3v3zgcRc= +github.com/russross/blackfriday v1.5.1/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v0.0.0-20160226084822-572520ed46db/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/samuel/go-thrift v0.0.0-20160419172024-e9042807f4f5/go.mod h1:Vrkh1pnjV9Bl8c3P9zH0/D4NlOHWP5d4/hF4YTULaec= +github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sirupsen/logrus v0.0.0-20170713114250-a3f95b5c4235/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.0-20160615143614-bc81c21bd0d8/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20160610190902-367864438f1b/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/streadway/amqp v0.0.0-20190225234609-30f8ed68076e/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/technosophos/moniker v0.0.0-20180509230615-a5dbd03a2245/go.mod h1:O1c8HleITsZqzNZDjSNzirUGsMT0oGu9LhHKoJrqO+A= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/uber-common/bark v1.2.1/go.mod h1:g0ZuPcD7XiExKHynr93Q742G/sbrdVQkghrqLGOoFuY= +github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= +github.com/uber-go/mapdecode v1.0.0/go.mod h1:b5nP15FwXTgpjTjeA9A2uTHXV5UJCl4arwKpP0FP1Hw= +github.com/uber-go/tally v3.3.7+incompatible/go.mod h1:YDTIBxdXyOU/sCWilKB4bgyufu1cEi0jdVnRdxvjnmU= +github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.0.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/uber/tchannel-go v1.12.0/go.mod h1:Rrgz1eL8kMjW/nEzZos0t+Heq0O4LhnUJVA32OvWKHo= +github.com/ugorji/go/codec v0.0.0-20181127175209-856da096dbdf/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/cadence v0.8.0/go.mod h1:CQivfHCJ44B1kKL4LLtOhcepUwNoRodZceo/wU5Nthw= +go.uber.org/dig v1.7.0/go.mod h1:z+dSd2TP9Usi48jL8M3v63iSBVkiwtVyMKxMZYYauPg= +go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= +go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/net/metrics v1.0.1/go.mod h1:cQvI3JawIRCZEgrpuF3rrV2OrQGLchMqJPyPAH7GUdo= +go.uber.org/thriftrw v1.16.1/go.mod h1:a0+HZMaS9tmHDCPyrrx1GjYWFRK02xzxnrK1Nl9LiLU= +go.uber.org/tools v0.0.0-20170523140223-ce2550dad714/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/yarpc v1.36.1/go.mod h1:5wt+WtAfoQh3yGyup7479I35hUobLqCfb0oewxC58jE= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20160711182412-2c99acdd1e9b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20170413175226-5602c733f70a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190119204137-ed066c81e75e h1:MDa3fSUp6MdYHouVmCCNz/zaH2a6CRcxY3VhT/K3C5Q= +golang.org/x/net v0.0.0-20190119204137-ed066c81e75e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20160718223228-08c8d727d239/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20151211033651-833a04a10549/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180828065106-d99a578cf41b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.0.0-20170401064109-f4b4367115ec/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181201035826-d0ca3933b724/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190211224914-44bee7e801e4/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20190111181425-455dee39f703/go.mod h1:HyxHN0BdhQ9jLjP1ppRm1JHMruzksPklmzI2+T+z1jM= +google.golang.org/appengine v0.0.0-20160621060416-267c27e74922/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20170404132009-411e09b969b1/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/grpc v0.0.0-20170413033559-0e8b58d22f34/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= +gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/gomail.v2 v2.0.0-20150902115704-41f357289737/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/gorethink/gorethink.v4 v4.1.0/go.mod h1:M7JgwrUAmshJ3iUbEK0Pt049MPyPK+CYDGGaEjdZb/c= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/ory-am/dockertest.v2 v2.2.3/go.mod h1:kDHEsan1UcKFYH1c28sDmqnmeqIpB4Nj682gSNhYDYM= +gopkg.in/square/go-jose.v2 v2.1.8/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20160301204022-a83829b6f129/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.0.0-20180628040859-072894a440bd/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/api v0.0.0-20180712090710-2d6f90ab1293/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apiextensions-apiserver v0.0.0-20180328075702-9beab23b2663/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= +k8s.io/apimachinery v0.0.0-20180621070125-103fd098999d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apiserver v0.0.0-20180327065226-f4a9d3132586/go.mod h1:6bqaTSOSJavUIXUtfaR9Os9JtTCm8ZqH2SUl2S60C4w= +k8s.io/client-go v8.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/helm v2.11.0+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= +k8s.io/kube-openapi v0.0.0-20190208205540-d7c86cdc46e3/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +k8s.io/kubernetes v1.11.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/kubernetes v1.11.5/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20180208044234-258e2a2fa645/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +layeh.com/radius v0.0.0-20190118135028-0f678f039617/go.mod h1:fywZKyu//X7iRzaxLgPWsvc0L26IUpVvE/aeIL2JtIQ= +vbom.ml/util v0.0.0-20170409195630-256737ac55c4/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI=