Bootstrap container code for GCP
This commit provides the Go code and scripts for the Bootstrap container for GCP. The Bootstrap container (bootstrap_capg) for Google Cloud is designed to accept three commands: create, delete and help. - create - will create an Ephemeral GKE cluster in Google Cloud - delete - will delete the Ephemeral GKE cluster from the Google Cloud - help - Stdout the help text for using this container. Please, refer to the bootstrap_capg/README.md for further details. Change-Id: Ifad7c7a7fede0230029716c9e093449f5886e859
This commit is contained in:
parent
f45d429c3c
commit
aa624ce27c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
||||
*build/
|
||||
bootstrap_capg/.vscode/launch.json
|
||||
bootstrap_capg/go.mod
|
||||
|
56
bootstrap_capg/Dockerfile
Normal file
56
bootstrap_capg/Dockerfile
Normal file
@ -0,0 +1,56 @@
|
||||
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ARG GCP_SDK=gcr.io/google.com/cloudsdktool/cloud-sdk:308.0.0
|
||||
ARG GOLANG=golang:1.14.4
|
||||
|
||||
############################################
|
||||
# Build GCP Bootstrap Container application
|
||||
############################################
|
||||
FROM ${GOLANG} as builder
|
||||
WORKDIR /home/build
|
||||
# copy the capg bootstrap container app code
|
||||
COPY main.go .
|
||||
COPY config/ config/
|
||||
# Build capg bootstrap container application
|
||||
RUN go mod init opendev.org/airship/images/bootstrap_capg && \
|
||||
go get -d -v ./... && \
|
||||
go install . && \
|
||||
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o capg-ephemeral .
|
||||
|
||||
############################################
|
||||
# Run GCP Bootstrap Container
|
||||
############################################
|
||||
FROM ${GCP_SDK}
|
||||
LABEL org.opencontainers.image.authors='airship-discuss@lists.airshipit.org, irc://#airshipit@freenode' \
|
||||
org.opencontainers.image.url='https://airshipit.org' \
|
||||
org.opencontainers.image.documentation='https://opendev.org/airship/images/src/branch/master/bootstrap_capg/README.md' \
|
||||
org.opencontainers.image.source='https://opendev.org/airship/images' \
|
||||
org.opencontainers.image.vendor='The Airship Authors' \
|
||||
org.opencontainers.image.licenses='Apache-2.0'
|
||||
|
||||
RUN adduser --disabled-password bootstrap
|
||||
USER bootstrap
|
||||
|
||||
WORKDIR /home/bootstrap
|
||||
ENV HOME=/home/bootstrap
|
||||
ENV PATH="${PATH}:${HOME}"
|
||||
|
||||
# Copy the Google Cloud Bootstrap Container command
|
||||
COPY --from=builder /home/build/capg-ephemeral .
|
||||
# Copy help file
|
||||
COPY assets/help.txt .
|
||||
|
||||
# # Executes the script to create the GKE cluster
|
||||
CMD ["capg-ephemeral"]
|
56
bootstrap_capg/Makefile
Normal file
56
bootstrap_capg/Makefile
Normal file
@ -0,0 +1,56 @@
|
||||
SHELL := /bin/bash
|
||||
PUSH_IMAGE ?= false
|
||||
GIT_VERSION ?= v0.1.0
|
||||
GIT_MODULE ?= opendev.org/airship/airshipctl/pkg/version
|
||||
|
||||
GO_FLAGS := -ldflags '-extldflags "-static"' -tags=netgo
|
||||
GO_FLAGS += -ldflags "-X ${GIT_MODULE}.gitVersion=${GIT_VERSION}"
|
||||
|
||||
DOCKER_MAKE_TARGET := build
|
||||
|
||||
# docker image options
|
||||
DOCKER_REGISTRY ?= quay.io
|
||||
DOCKER_FORCE_CLEAN ?= true
|
||||
DOCKER_IMAGE_NAME ?= capg-bootstrap
|
||||
DOCKER_IMAGE_PREFIX ?= airshipit
|
||||
DOCKER_IMAGE_TAG ?= latest
|
||||
DOCKER_IMAGE ?= $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_PREFIX)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)
|
||||
DOCKER_TARGET_STAGE ?= release
|
||||
|
||||
PATH += :/usr/local/go/bin
|
||||
HELP_FILE ?= /tmp/help.txt
|
||||
ORIGINAL_HELP_FILE = ./assets/help.txt
|
||||
|
||||
.PHONY: all
|
||||
all: images
|
||||
|
||||
.PHONY: images
|
||||
images: Dockerfile \
|
||||
main.go \
|
||||
config/gke_cluster.go \
|
||||
config/gcp_cluster.go \
|
||||
config/gcp_config.go \
|
||||
assets/help.txt
|
||||
@docker build . --network=host \
|
||||
--build-arg MAKE_TARGET=$(DOCKER_MAKE_TARGET) \
|
||||
--tag $(DOCKER_IMAGE) \
|
||||
--force-rm=$(DOCKER_FORCE_CLEAN)
|
||||
ifeq ($(PUSH_IMAGE), true)
|
||||
docker push $(IMAGE)
|
||||
endif
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@docker image rm $(DOCKER_IMAGE)
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@echo TODO
|
||||
|
||||
# style checks
|
||||
.PHONY: tests
|
||||
tests: images
|
||||
if [ -f $(HELP_FILE) ]; then sudo rm $(HELP_FILE); fi
|
||||
cp gcp-config.yaml /tmp
|
||||
docker run -v /tmp:/kube --env-file bootstrap-env.list --name capg-test $(DOCKER_IMAGE)
|
||||
cmp $(HELP_FILE) $(ORIGINAL_HELP_FILE)
|
32
bootstrap_capg/README.md
Normal file
32
bootstrap_capg/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# GCP Bootstrap Container
|
||||
|
||||
This project contains the Go application and configuration files for
|
||||
implementing the GCP Bootstrap container.
|
||||
|
||||
The GCP Bootstrap container is responsible to create or delete a Kubernetes
|
||||
(K8S) cluster on GCP Cloud platform using the GKE (Google Kubernetes Engine).
|
||||
|
||||
## Go Application
|
||||
|
||||
The Go application is the bootstrap container orchestrator that is responsible
|
||||
for translating commands into actions: create, delete, help.
|
||||
|
||||
This Go application uses the Ephemeral cluster configuration file
|
||||
(e.g., gcp-config.yaml) to determine the Google Cloud credentials and
|
||||
data to use to create or delete the ephemeral cluster.
|
||||
|
||||
## Dockerfile
|
||||
|
||||
The **Dockerfile** uses a multi-stage builds to first build the Go application
|
||||
then create the GCP bootstrap container image.
|
||||
|
||||
## Build
|
||||
|
||||
To build the bootstrap container image, execute the following command:
|
||||
|
||||
```bash
|
||||
make images
|
||||
```
|
||||
|
||||
This command will build the Go application and then create the bootstrap
|
||||
container image.
|
66
bootstrap_capg/assets/help.txt
Normal file
66
bootstrap_capg/assets/help.txt
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
Google Cloud Ephemeral Configuration File Definition
|
||||
-----------------------------------------------------
|
||||
The GCP Bootstrap container creates an Ephemeral K8S cluster on the Google Cloud platform.
|
||||
The container requires authentication credentials and other information about the cluster to deploy.
|
||||
It requires a YAML configuration file with the format provided below.
|
||||
|
||||
<YAML>
|
||||
apiVersion: v1
|
||||
kind: GoogleCloudConfig
|
||||
metadata:
|
||||
name: <Ephemeral K8S cluster name>
|
||||
credentials:
|
||||
project: <Google Cloud Project ID>
|
||||
account: <Google Cloud Account ID>
|
||||
credential: <credentials.json filename>
|
||||
spec:
|
||||
region: <Google Cloud Region, e.g., us-central1>
|
||||
Zone: <Google Cloud Zone, e.g., us-central1-c>
|
||||
cluster:
|
||||
k8sVersion: <Kubernetes version, e.g., 1.16.9-gke.6>
|
||||
machineSize: <Google Cloud Compute VM Type, e.g., e2-medium>
|
||||
diskSize: <Google Cloud compute disk size>
|
||||
replicas: <Node Replica Number for the cluster>
|
||||
kubeconfig: <Kubeconfig filename, Default is 'kubeconfig'>
|
||||
</YMAL>
|
||||
|
||||
The JSON format is also a valid configuration file for this bootstrap container.
|
||||
|
||||
<JSON>
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "GoogleCloudConfig",
|
||||
"metadata": {
|
||||
"name": "<Ephemeral K8S cluster name>"
|
||||
},
|
||||
"credentials": {
|
||||
"project": "<Google Cloud Project ID>",
|
||||
"account": "<Google Cloud Account ID>",
|
||||
"credential": "<credentials.json filename>"
|
||||
},
|
||||
"spec": {
|
||||
"region": "<Google Cloud Region, e.g., us-central1>",
|
||||
"zone": "<Google Cloud Compute VM Type, e.g., e2-medium>",
|
||||
"cluster": {
|
||||
"k8sVersion": "<Kubernetes version, e.g., 1.16.9-gke.6>",
|
||||
"machineSize": "<Google Cloud Compute VM Type, e.g., e2-medium>",
|
||||
"diskSize": <Google Cloud compute disk size>,
|
||||
"replicas": <Node Replica Number for the cluster>,
|
||||
"kubeconfig": "<Kubeconfig filename, Default is 'kubeconfig'>"
|
||||
}
|
||||
}
|
||||
}
|
||||
</JSON>
|
||||
|
||||
The expected location for the GCP bootstrap configuration file is dictated by the "volume" mount
|
||||
specified in the Airship config file (bootstrapInfo.ephemeral.container.volume).
|
||||
For example, /home/esidshi/.airship folder as shown in the snippet below:
|
||||
|
||||
<Snippet>
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
ephemeral:
|
||||
container:
|
||||
volume: /home/esidshi/.airship:/kube
|
||||
</Snippet>
|
3
bootstrap_capg/bootstrap-env.list
Normal file
3
bootstrap_capg/bootstrap-env.list
Normal file
@ -0,0 +1,3 @@
|
||||
BOOTSTRAP_COMMAND=help
|
||||
BOOTSTRAP_CONFIG=gcp-config.yaml
|
||||
BOOTSTRAP_VOLUME=/tmp:/kube
|
101
bootstrap_capg/config/gcp_cluster.go
Normal file
101
bootstrap_capg/config/gcp_cluster.go
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
bootstrapHelpFile = "help.txt"
|
||||
|
||||
// BootstrapCommand environment variable
|
||||
bootstrapHome = "HOME"
|
||||
bootstrapCommand = "BOOTSTRAP_COMMAND"
|
||||
bootstrapConfig = "BOOTSTRAP_CONFIG"
|
||||
bootstrapVolume = "BOOTSTRAP_VOLUME"
|
||||
bootstrapVolumeSep = ":"
|
||||
)
|
||||
|
||||
// GetVolumeMountPoints extracts the source and destination of a volume mount
|
||||
func GetVolumeMountPoints(volumeMount string) (string, string) {
|
||||
sepPos := strings.Index(volumeMount, bootstrapVolumeSep)
|
||||
|
||||
srcMountPoint := volumeMount[:sepPos]
|
||||
dstMountPoint := volumeMount[sepPos+1:]
|
||||
|
||||
return srcMountPoint, dstMountPoint
|
||||
}
|
||||
|
||||
// execute - is used to invoke gcloud CLI commands
|
||||
func execute(command string, arg ...string) error {
|
||||
cmd := exec.Command(command, arg...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Printf("Error executing script %s\n", command)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.Printf("Error waiting for command execution: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateGKECluster creates the GKE cluster
|
||||
func CreateGKECluster(gcpConfig *GcpConfig) error {
|
||||
return prepareGCPCluster(gcpConfig, true)
|
||||
}
|
||||
|
||||
// DeleteGKECluster deletes the GKE cluster
|
||||
func DeleteGKECluster(gcpConfig *GcpConfig) error {
|
||||
return prepareGCPCluster(gcpConfig, false)
|
||||
}
|
||||
|
||||
// HelpGKECluster returns the help.txt for the GKE cluster
|
||||
func HelpGKECluster() error {
|
||||
homeDir := os.Getenv(bootstrapHome)
|
||||
src := homeDir + "/" + bootstrapHelpFile
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
log.Printf("Could not open %s file\n", src)
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
_, dstMountPoint := GetVolumeMountPoints(os.Getenv(bootstrapVolume))
|
||||
dst := dstMountPoint + "/" + bootstrapHelpFile
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
log.Printf("Could not create %s file\n", dst)
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
if err != nil {
|
||||
log.Printf("Failed to copy %s file to %s\n", src, dst)
|
||||
return err
|
||||
}
|
||||
return out.Close()
|
||||
}
|
117
bootstrap_capg/config/gcp_config.go
Normal file
117
bootstrap_capg/config/gcp_config.go
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// GcpConfig holds configurations for bootstrap steps
|
||||
type GcpConfig struct {
|
||||
// +optional
|
||||
Kind string `yaml:"kind" validate:"required"`
|
||||
|
||||
// +optional
|
||||
APIVersion string `yaml:"apiVersion" validate:"required"`
|
||||
|
||||
// Configuration parameters for metadata
|
||||
Metadata *Metadata `yaml:"metadata" validate:"required"`
|
||||
|
||||
// Configuration parameters for metadata
|
||||
Credentials *Credentials `yaml:"credentials" validate:"required"`
|
||||
|
||||
// Configuration parameters for spec
|
||||
Spec *Spec `yaml:"spec"`
|
||||
}
|
||||
|
||||
// Metadata structure provides the cluster name to assign and labels to the k8s cluster
|
||||
type Metadata struct {
|
||||
Name string `yaml:"name" validate:"required"`
|
||||
Labels []string `yaml:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// Credentials structu provides the credentials to authenticate with Azure Cloud
|
||||
type Credentials struct {
|
||||
Project string `yaml:"project" validate:"required"`
|
||||
Account string `yaml:"account" validate:"required"`
|
||||
Credential string `yaml:"credential" validate:"required"`
|
||||
}
|
||||
|
||||
// Spec structure contains the info for the ck8s luster to deploy
|
||||
type Spec struct {
|
||||
Region string `yaml:"region,omitempty"`
|
||||
Zone string `yaml:"zone,omitempty"`
|
||||
Cluster Cluster `yaml:"cluster"`
|
||||
}
|
||||
|
||||
// Cluster struct provides data for the k8s cluster to deploy
|
||||
type Cluster struct {
|
||||
// Kubernetes version to deploy
|
||||
K8SVersion string `yaml:"k8sVersion,omitempty"`
|
||||
|
||||
// Google Cloud Compote VM size to use for the cluster
|
||||
MachineSize string `yaml:"machineSize,omitempty"`
|
||||
|
||||
// Google Cloud Compote disk size to use for the cluster
|
||||
DiskSize uint8 `yaml:"diskSize,omitempty" validate:"gte=1"`
|
||||
|
||||
// Number of nodes to deploy for the cluster
|
||||
Replicas uint8 `yaml:"replicas,omitempty" validate:"gte=1,lte=100"`
|
||||
|
||||
// Kubeconfig filename to save
|
||||
Kubeconfig string `yaml:"kubeconfig,omitempty"`
|
||||
}
|
||||
|
||||
// ReadYAMLFile reads YAML-formatted configuration file and
|
||||
// de-serializes it to a given object
|
||||
func ReadYAMLFile(filePath string, cfg *GcpConfig) error {
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
log.Printf("Failed to read GCP Ephemeral configuration file: err #%v ", err)
|
||||
return err
|
||||
}
|
||||
return yaml.Unmarshal(data, cfg)
|
||||
}
|
||||
|
||||
// ValidateConfigFile validates GCP configuration file for the Ephemeral Cluster
|
||||
func ValidateConfigFile(config *GcpConfig) error {
|
||||
validate := validator.New()
|
||||
err := validate.Struct(config)
|
||||
if err != nil {
|
||||
var invalidError *validator.InvalidValidationError
|
||||
if errors.As(err, &invalidError) {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Ephemeral cluster configuration file validation failed")
|
||||
for _, err := range err.(validator.ValidationErrors) {
|
||||
log.Printf(" Namespace = %s\n", err.Namespace())
|
||||
log.Printf(" Tag = %s\n", err.Tag())
|
||||
log.Printf(" Type = %s\n", err.Type())
|
||||
log.Printf(" Value = %s\n", err.Value())
|
||||
log.Printf(" Param = %s\n\n", err.Param())
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
159
bootstrap_capg/config/gke_cluster.go
Normal file
159
bootstrap_capg/config/gke_cluster.go
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
gcloud = "gcloud"
|
||||
auth = "auth"
|
||||
activateServiceAccount = "activate-service-account"
|
||||
config = "config"
|
||||
set = "set"
|
||||
project = "project"
|
||||
container = "container"
|
||||
clusters = "clusters"
|
||||
create = "create"
|
||||
delete = "delete"
|
||||
getCredentials = "get-credentials"
|
||||
|
||||
zoneP = "--zone"
|
||||
nodeLocations = "--node-locations"
|
||||
keyFileP = "--key-file"
|
||||
clusterVersionP = "--cluster-version"
|
||||
machineTypeP = "--machine-type"
|
||||
numNodesP = "--num-nodes"
|
||||
enableIPAlias = "--enable-ip-alias"
|
||||
imageTypeP = "--image-type"
|
||||
diskTypeP = "--disk-type"
|
||||
diskSizeP = "--disk-size"
|
||||
metadataP = "--metadata"
|
||||
scopesP = "--scopes"
|
||||
enableStackDriverKubernetesP = "--enable-stackdriver-kubernetes"
|
||||
enableAutoUpgradeP = "--enable-autoupgrade"
|
||||
enableAutoRepairP = "--enable-autorepair"
|
||||
quietP = "--quiet"
|
||||
|
||||
defaultClusterName = "capi-gcp"
|
||||
defaultRegion = "us-central1"
|
||||
defaultZone = "us-central1-c"
|
||||
defaultMachineSize = "e2-medium"
|
||||
defaultK8SVersion = "1.16.13-gke.401"
|
||||
defaultKubeconfig = "kubeconfig"
|
||||
|
||||
kubeconfigVar = "KUBECONFIG"
|
||||
)
|
||||
|
||||
// defaultGCPConfig verify if any optional config data is missing.
|
||||
func defaultGCPConfig(gcpConfig *GcpConfig) error {
|
||||
if gcpConfig.Spec.Region == "" {
|
||||
gcpConfig.Spec.Region = defaultRegion
|
||||
}
|
||||
if gcpConfig.Spec.Zone == "" {
|
||||
gcpConfig.Spec.Zone = defaultZone
|
||||
}
|
||||
if gcpConfig.Metadata.Name == "" {
|
||||
gcpConfig.Metadata.Name = defaultClusterName
|
||||
}
|
||||
if gcpConfig.Spec.Cluster.MachineSize == "" {
|
||||
gcpConfig.Spec.Cluster.MachineSize = defaultMachineSize
|
||||
}
|
||||
if gcpConfig.Spec.Cluster.K8SVersion == "" {
|
||||
gcpConfig.Spec.Cluster.K8SVersion = defaultK8SVersion
|
||||
}
|
||||
if gcpConfig.Spec.Cluster.Kubeconfig == "" {
|
||||
gcpConfig.Spec.Cluster.Kubeconfig = defaultKubeconfig
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepareGCPCluster logs in, create resource group, etc
|
||||
func prepareGCPCluster(gcpConfig *GcpConfig, isCreate bool) error {
|
||||
// Verify if Google Cloud config file provides all information needed for creating a cluster
|
||||
err := defaultGCPConfig(gcpConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get Kubeconfig filename
|
||||
volMount := os.Getenv("BOOTSTRAP_VOLUME")
|
||||
_, dstMount := GetVolumeMountPoints(volMount)
|
||||
|
||||
gcpProject := gcpConfig.Credentials.Project
|
||||
gcpAccount := gcpConfig.Credentials.Account
|
||||
gcpCredential := dstMount + "/" + gcpConfig.Credentials.Credential
|
||||
|
||||
clusterName := gcpConfig.Metadata.Name
|
||||
region := gcpConfig.Spec.Region
|
||||
zone := gcpConfig.Spec.Zone
|
||||
|
||||
machineSize := gcpConfig.Spec.Cluster.MachineSize
|
||||
nodeCount := strconv.FormatInt(int64(gcpConfig.Spec.Cluster.Replicas), 10)
|
||||
k8sVersion := gcpConfig.Spec.Cluster.K8SVersion
|
||||
kubeconfigFile := gcpConfig.Spec.Cluster.Kubeconfig
|
||||
|
||||
// login to GCP account using Service Principal
|
||||
err = execute(gcloud, auth, activateServiceAccount, gcpAccount, keyFileP, gcpCredential)
|
||||
if err != nil {
|
||||
log.Printf("Failed to login into GCP using Service Account\n")
|
||||
return err
|
||||
}
|
||||
|
||||
// Set project to use to the configuration
|
||||
err = execute(gcloud, config, set, project, gcpProject)
|
||||
if err != nil {
|
||||
log.Printf("Failed to set GCP project to the configuration\n")
|
||||
return err
|
||||
}
|
||||
|
||||
if isCreate {
|
||||
// Creating Google GKE cluster
|
||||
err = execute(gcloud, container, clusters, create, clusterName,
|
||||
zoneP, zone, nodeLocations, zone,
|
||||
numNodesP, nodeCount, machineTypeP, machineSize,
|
||||
enableIPAlias, enableAutoUpgradeP, enableAutoRepairP,
|
||||
clusterVersionP, k8sVersion)
|
||||
if err != nil {
|
||||
log.Printf("Failed to create GKE cluster %s in %s region.\n", clusterName, region)
|
||||
return err
|
||||
}
|
||||
|
||||
// Retrieving the Kubeconfig file for the cluster
|
||||
dstKubeconfig := dstMount + "/" + kubeconfigFile
|
||||
os.Setenv(kubeconfigVar, dstKubeconfig)
|
||||
err = execute(gcloud, container, clusters, getCredentials, clusterName, zoneP, zone)
|
||||
if err != nil {
|
||||
log.Printf("Failed to retrieve kubeconfig file for GCP cluster %s in %s region.\n", clusterName, region)
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(dstKubeconfig); err != nil {
|
||||
log.Printf("Failed to retrieve kubeconfig file for GCP cluster %s in %s region.\n", clusterName, region)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Delete GCP GKE cluster
|
||||
err = execute(gcloud, container, clusters, delete, clusterName, zoneP, zone, quietP)
|
||||
if err != nil {
|
||||
log.Printf("Failed to delete GKE cluster %s in %s region.\n", clusterName, region)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
23
bootstrap_capg/gcp-config.json
Normal file
23
bootstrap_capg/gcp-config.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "GoogleCloudConfig",
|
||||
"metadata": {
|
||||
"name": "capi-google-zuul"
|
||||
},
|
||||
"credentials": {
|
||||
"project": "peak-vista-274815",
|
||||
"account": "airship-kubernetes-account@peak-vista-274815.iam.gserviceaccount.com",
|
||||
"credential": "gcp-credentials.json"
|
||||
},
|
||||
"spec": {
|
||||
"region": "us-central1",
|
||||
"zone": "us-central1-c",
|
||||
"cluster": {
|
||||
"k8sVersion": "1.16.13-gke.1",
|
||||
"machineSize": "e2-medium",
|
||||
"diskSize": 100,
|
||||
"replicas": 1,
|
||||
"kubeconfig": "capg.kubeconfig"
|
||||
}
|
||||
}
|
||||
}
|
29
bootstrap_capg/gcp-config.yaml
Normal file
29
bootstrap_capg/gcp-config.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
apiVersion: v1
|
||||
kind: GoogleCloudConfig
|
||||
metadata:
|
||||
name: capi-google-zuul
|
||||
credentials:
|
||||
project: <GCP Project ID>
|
||||
account: <GCP Account ID>
|
||||
credential: gcp-credentials.json
|
||||
spec:
|
||||
region: us-central1
|
||||
zone: us-central1-c
|
||||
cluster:
|
||||
k8sVersion: 1.16.13-gke.401
|
||||
machineSize: e2-medium
|
||||
diskSize: 100
|
||||
replicas: 1
|
||||
kubeconfig: capg.kubeconfig
|
12
bootstrap_capg/gcp-credentials.json
Normal file
12
bootstrap_capg/gcp-credentials.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "<your project ID>. NOTE: This file was generated by Google Cloud",
|
||||
"private_key_id": "<your project key ID>",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----<enter your private key here>-----END PRIVATE KEY-----\n",
|
||||
"client_email": "<your account email>",
|
||||
"client_id": "<your client id>",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/airship-kubernetes-account%40peak-vista-274815.iam.gserviceaccount.com"
|
||||
}
|
78
bootstrap_capg/main.go
Normal file
78
bootstrap_capg/main.go
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"opendev.org/airship/images/bootstrap_capg/config"
|
||||
)
|
||||
|
||||
const (
|
||||
createCmd = "create"
|
||||
deleteCmd = "delete"
|
||||
helpCmd = "help"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var configPath string
|
||||
|
||||
flag.StringVar(&configPath, "c", "", "Path for the Google Cloud bootstrap configuration (yaml) file")
|
||||
flag.Parse()
|
||||
|
||||
if configPath == "" {
|
||||
volMount := os.Getenv("BOOTSTRAP_VOLUME")
|
||||
_, dstMount := config.GetVolumeMountPoints(volMount)
|
||||
gcpConfigPath := dstMount + "/" + os.Getenv("BOOTSTRAP_CONFIG")
|
||||
configPath = gcpConfigPath
|
||||
}
|
||||
|
||||
configYAML := &config.GcpConfig{}
|
||||
err := config.ReadYAMLFile(configPath, configYAML)
|
||||
if err != nil {
|
||||
log.Printf("Failed to load Google Cloud Bootstrap config file")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = config.ValidateConfigFile(configYAML)
|
||||
if err != nil {
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
command := os.Getenv("BOOTSTRAP_COMMAND")
|
||||
switch {
|
||||
case command == createCmd:
|
||||
err = config.CreateGKECluster(configYAML)
|
||||
if err != nil {
|
||||
os.Exit(5)
|
||||
}
|
||||
case command == deleteCmd:
|
||||
err = config.DeleteGKECluster(configYAML)
|
||||
if err != nil {
|
||||
os.Exit(6)
|
||||
}
|
||||
case command == helpCmd:
|
||||
err = config.HelpGKECluster()
|
||||
if err != nil {
|
||||
os.Exit(7)
|
||||
}
|
||||
default:
|
||||
log.Printf("The --command parameter value shall be 'create', 'delete' or 'help'")
|
||||
os.Exit(8)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
Loading…
Reference in New Issue
Block a user