Bootstrap container for openstack provider (capo)
This patchset provides the Go code and scripts for the Bootstrap container for Openstack. The Bootstrap container for Openstack provider accepts three commands: create, delete and help. - create - creates an Ephemeral K8S cluster in Openstack - delete - deletes the Ephemeral K8S cluster in Openstack - help - Stdout the help text for usage of the bootstrap container. Documentation is available at bootstrap_capo/README.md Change-Id: Idd444834070b84170f18561626c487e23a3ca951
This commit is contained in:
parent
32374c3293
commit
3b351b1aa1
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ bootstrap_capg/go.mod
|
||||
bootstrap_capz/.vscode/launch.json
|
||||
bootstrap_capz/go.mod
|
||||
bootstrap_capz/go.sum
|
||||
bootstrap_capo/capo-ephemeral
|
||||
|
66
bootstrap_capo/Dockerfile
Normal file
66
bootstrap_capo/Dockerfile
Normal file
@ -0,0 +1,66 @@
|
||||
# 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 GO_IMAGE=golang:1.14.4
|
||||
|
||||
ARG PYTHON_IMAGE=python:3.8
|
||||
|
||||
FROM ${GO_IMAGE} as builder
|
||||
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0 \
|
||||
GOOS=linux \
|
||||
GOARCH=amd64
|
||||
|
||||
WORKDIR /home/build
|
||||
|
||||
COPY main.go go.mod go.sum ./
|
||||
COPY config/ config/
|
||||
COPY resource/ resource/
|
||||
|
||||
RUN go install /home/build
|
||||
RUN go build -o capo-ephemeral /home/build
|
||||
|
||||
FROM ${PYTHON_IMAGE}
|
||||
|
||||
LABEL org.opencontainers.image.authors='airship-discuss@lists.airshipit.org, irc://#airshipit@freenode' \
|
||||
org.opencontainers.image.url='https://airshipit.org' \
|
||||
org.opencontainers.image.source='https://opendev.org/airship/images' \
|
||||
org.opencontainers.image.vendor='The Airship Authors' \
|
||||
org.opencontainers.image.licenses='Apache-2.0'
|
||||
|
||||
RUN set -ex && \
|
||||
pip install python-openstackclient
|
||||
|
||||
RUN set -ex && \
|
||||
apt-get update
|
||||
|
||||
RUN useradd -m bootstrap
|
||||
|
||||
USER bootstrap
|
||||
|
||||
WORKDIR /home/bootstrap
|
||||
|
||||
ENV HOME=/home/bootstrap
|
||||
|
||||
ENV PATH="${PATH}:${HOME}"
|
||||
|
||||
# Copy the binary from builder
|
||||
COPY --from=builder /home/build/capo-ephemeral .
|
||||
|
||||
# Copy resources including scripts and help.txt file
|
||||
COPY resource/* $HOME/
|
||||
|
||||
# Executes the go application capo-ephemeral
|
||||
CMD ["capo-ephemeral"]
|
55
bootstrap_capo/Makefile
Normal file
55
bootstrap_capo/Makefile
Normal file
@ -0,0 +1,55 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
PUSH_IMAGE ?= false
|
||||
|
||||
DOCKER_MAKE_TARGET := build
|
||||
|
||||
# docker image options
|
||||
DOCKER_REGISTRY ?= quay.io
|
||||
DOCKER_FORCE_CLEAN ?= true
|
||||
DOCKER_IMAGE_NAME ?= capo-ephemeral
|
||||
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
|
||||
CONTAINER_TEMP = capo-ephemeral-temp
|
||||
|
||||
.PHONY: all
|
||||
all: build docker
|
||||
|
||||
.PHONY: images
|
||||
images: build docker
|
||||
|
||||
.PHONY: build
|
||||
build: main.go go.mod go.sum config/openstack_cluster.go config/openstack_config.go Dockerfile
|
||||
@docker build --target builder --network=host \
|
||||
--build-arg MAKE_TARGET=$(DOCKER_MAKE_TARGET) \
|
||||
--tag $(DOCKER_IMAGE) .
|
||||
docker run --name $(CONTAINER_TEMP) $(DOCKER_IMAGE) /bin/true
|
||||
docker cp $(CONTAINER_TEMP):/home/build/capo-ephemeral .
|
||||
|
||||
.PHONY: docker
|
||||
docker: capo-ephemeral resource/create-k8s-cluster.sh resource/delete-k8s-cluster.sh resource/user-data.sh resource/help.txt Dockerfile
|
||||
@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 $(DOCKER_IMAGE)
|
||||
endif
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm capo-ephemeral
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@echo TODO
|
||||
|
||||
# style checks
|
||||
.PHONY: tests
|
||||
tests: images
|
||||
sudo rm -f $(HELP_FILE)
|
||||
cp openstack-config.yaml /tmp
|
||||
docker run -v /tmp:/kube --env-file bootstrap-env.list --name capo-bootstrap-test $(DOCKER_IMAGE)
|
102
bootstrap_capo/README.md
Normal file
102
bootstrap_capo/README.md
Normal file
@ -0,0 +1,102 @@
|
||||
# Openstack Bootstrap Container
|
||||
|
||||
This project contains the Go application as well as the shell scripts and configuration files for
|
||||
implementing the Openstack Bootstrap container.
|
||||
|
||||
The Openstack Bootstrap container is responsible to create or delete a Kubernetes (K8S) cluster on
|
||||
Openstack. The K8S cluster is created using `kubeadm`.
|
||||
|
||||
## Go Application
|
||||
|
||||
The Go application is the container orchestrator that is responsible for translating commands
|
||||
into actions: create, delete, help.
|
||||
|
||||
The Go application reads the Ephemeral cluster configuration file (e.g., openstack-config.yaml) and
|
||||
converts the attributes into environment variables. These environment variables are used by the
|
||||
shell scripts to create or delete the K8S cluster.
|
||||
|
||||
To build this Go application, execute the following commands:
|
||||
|
||||
```bash
|
||||
go install .
|
||||
go build -o capo-ephemeral
|
||||
```
|
||||
|
||||
## Shell Scripts
|
||||
|
||||
The shell scripts make use of openstack cli commands to create and delete K8S cluster.
|
||||
The other alternative that was considered was to use magnum container orchestration APIs.
|
||||
In order to keep things generic, openstack cli command was chosen to create and delete the K8S
|
||||
cluster.
|
||||
|
||||
### Create K8S Cluster script
|
||||
|
||||
The **create-k8s-cluster.sh** script creates a K8S cluster using the information provided in
|
||||
the Ephemeral cluster configuration file. It passes `user-data.sh` script in the
|
||||
`openstack server create` command to execute series of steps to initiate creation of the K8S
|
||||
cluster at boot time. Once the cluster is created, its **kubeconfig** file is copied to the
|
||||
container's volume mount, "sharing" it with the host.
|
||||
|
||||
### Delete K8S Cluster script
|
||||
|
||||
The **delete-k8s-cluster.sh** script deletes the underlying VM and the K8S cluster using the
|
||||
information provided in the Ephemeral cluster configuration file.
|
||||
|
||||
## Dockerfile
|
||||
|
||||
The **Dockerfile** is used to build the Openstack Bootstrap container image.
|
||||
Execute the following command to build the Bootstrap container image:
|
||||
|
||||
```bash
|
||||
make docker
|
||||
```
|
||||
|
||||
## Pre-requisite
|
||||
|
||||
- [Devstack](https://docs.openstack.org/devstack/latest/guides/devstack-with-lbaas-v2.html)
|
||||
is installed.
|
||||
- The most recent version of the *64-bit amd64-arch QCOW2* image for *Ubuntu 18.04* is used for
|
||||
creating the ephemeral cluster.
|
||||
The image is available
|
||||
[here](https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img) for
|
||||
download and should be available in the devstack environment.
|
||||
|
||||
- `~/.airship/` directory on host machine contains `clouds.yaml` and `openstack-config.yaml` files.
|
||||
- airship configuration file is updated with `ephemeral` cluster configuration information.
|
||||
|
||||
## Appendix
|
||||
|
||||
### Required Configuration
|
||||
|
||||
#### Ephemeral Cluster Configuration
|
||||
|
||||
```bash
|
||||
$ cat openstack-config.yaml
|
||||
apiVersion: v1
|
||||
kind: OpenstackCloudConfig
|
||||
metadata:
|
||||
name: capi-openstack
|
||||
credentials:
|
||||
credential: clouds.yaml
|
||||
cloudName: devstack
|
||||
spec:
|
||||
cluster:
|
||||
machineSize: ds4G
|
||||
kubeconfig: capo.kubeconfig
|
||||
securityGroup: bootstrap-sec-grp
|
||||
```
|
||||
|
||||
#### Airship Configuration
|
||||
|
||||
```bash
|
||||
$ cat ~/.airship/config
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
ephemeral:
|
||||
container:
|
||||
image: quay.io/airshipit/capo-bootstrap:latest
|
||||
name: capo-bootstrap
|
||||
volume: /home/stack/.airship:/kube
|
||||
ephemeralCluster:
|
||||
config: openstack-config.yaml
|
||||
```
|
3
bootstrap_capo/bootstrap-env.list
Normal file
3
bootstrap_capo/bootstrap-env.list
Normal file
@ -0,0 +1,3 @@
|
||||
BOOTSTRAP_COMMAND=help
|
||||
BOOTSTRAP_CONFIG=openstack-config.yaml
|
||||
BOOTSTRAP_VOLUME=/tmp:/kube
|
13
bootstrap_capo/clouds.yaml
Normal file
13
bootstrap_capo/clouds.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
clouds:
|
||||
devstack:
|
||||
auth:
|
||||
auth_url: "http://10.0.1.4/identity"
|
||||
password: pass
|
||||
project_domain_id: default
|
||||
project_name: demo
|
||||
user_domain_id: default
|
||||
username: demo
|
||||
identity_api_version: "3"
|
||||
region_name: RegionOne
|
||||
volume_api_version: "3"
|
||||
|
104
bootstrap_capo/config/openstack_cluster.go
Normal file
104
bootstrap_capo/config/openstack_cluster.go
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Bootstrap container environment variables
|
||||
openstackCredential = "OS_CREDENTIAL_FILE"
|
||||
openstackSecurityGroup = "OS_SECURITY_GROUP"
|
||||
openstackCloudName = "OS_CLOUD"
|
||||
openstackMachineSize = "OS_MACHINE_FLAVOR"
|
||||
openstackKubeconfigFile = "OS_KUBECONFIG_FILE"
|
||||
|
||||
bootstrapHelpFile = "help.txt"
|
||||
|
||||
// BootstrapCommand environment variable
|
||||
bootstrapHome = "SRC_DIR"
|
||||
bootstrapVolumeSep = ":"
|
||||
)
|
||||
|
||||
// SetOpenstackCloudEnvVars sets the environment variables used by the script
|
||||
func SetOpenstackCloudEnvVars(config *OpenstackConfig) error {
|
||||
err := os.Setenv(openstackCredential, config.Credentials.Credential)
|
||||
err = os.Setenv(openstackCloudName, config.Credentials.CloudName)
|
||||
err = os.Setenv(openstackSecurityGroup, config.Spec.Cluster.SecurityGroup)
|
||||
err = os.Setenv(openstackMachineSize, config.Spec.Cluster.MachineSize)
|
||||
err = os.Setenv(openstackKubeconfigFile, config.Spec.Cluster.Kubeconfig)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetVolumeMountPoints extracts the source and destination of a volume mount
|
||||
func GetVolumeMountPoints(volumeMount string) (string, string, error) {
|
||||
if len(volumeMount) == 0 {
|
||||
return "", "", errors.New("volume mount is mandatory, please provide volume mount")
|
||||
}
|
||||
sepPos := strings.Index(volumeMount, bootstrapVolumeSep)
|
||||
srcMountPoint := volumeMount[:sepPos]
|
||||
dstMountPoint := volumeMount[sepPos+1:]
|
||||
|
||||
return srcMountPoint, dstMountPoint, nil
|
||||
}
|
||||
|
||||
// CreateOSCluster creates the ephemeral K8S cluster in Openstack
|
||||
func CreateOSCluster() error {
|
||||
srcDir := os.Getenv(bootstrapHome)
|
||||
shellScriptFile := "./create-k8s-cluster.sh"
|
||||
shellScript := filepath.Join(srcDir, shellScriptFile)
|
||||
return execute(shellScript)
|
||||
}
|
||||
|
||||
// DeleteOSCluster deletes the ephemeral K8S cluster in Openstack
|
||||
func DeleteOSCluster() error {
|
||||
srcDir := os.Getenv(bootstrapHome)
|
||||
shellScriptFile := "./delete-k8s-cluster.sh"
|
||||
shellScript := filepath.Join(srcDir, shellScriptFile)
|
||||
return execute(shellScript)
|
||||
}
|
||||
|
||||
func execute(shellScript string) error {
|
||||
cmd := exec.Command(shellScript)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
log.Printf("Executing script %s\n", shellScript)
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
return cmd.Wait()
|
||||
}
|
||||
|
||||
// HelpOSCluster prints the help information to supplement the creation of K8S ephemeral cluster
|
||||
func HelpOSCluster() error {
|
||||
srcDir := os.Getenv(bootstrapHome)
|
||||
src := filepath.Join(srcDir, bootstrapHelpFile)
|
||||
b, err := ioutil.ReadFile(src)
|
||||
fmt.Fprintln(os.Stdout, string(b))
|
||||
return err
|
||||
}
|
82
bootstrap_capo/config/openstack_config.go
Normal file
82
bootstrap_capo/config/openstack_config.go
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
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 (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// OpenstackConfig holds configurations for bootstrap steps
|
||||
type OpenstackConfig struct {
|
||||
// +optional
|
||||
Kind string `yaml:"kind,omitempty"`
|
||||
|
||||
// +optional
|
||||
APIVersion string `yaml:"apiVersion,omitempty"`
|
||||
|
||||
// Configuration parameters for metadata
|
||||
Metadata *Metadata `yaml:"metadata"`
|
||||
|
||||
// Configuration parameters for metadata
|
||||
Credentials *Credentials `yaml:"credentials"`
|
||||
|
||||
// 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"`
|
||||
Labels []string `yaml:"labels,omitempty"`
|
||||
}
|
||||
|
||||
// Credentials structu provides the credentials to authenticate with Azure Cloud
|
||||
type Credentials struct {
|
||||
Credential string `yaml:"credential"`
|
||||
CloudName string `yaml:"cloudName"`
|
||||
}
|
||||
|
||||
// Spec structure contains the info for the ck8s luster to deploy
|
||||
type Spec struct {
|
||||
Cluster Cluster `yaml:"cluster"`
|
||||
}
|
||||
|
||||
// Cluster struct provides data for the k8s cluster to deploy
|
||||
type Cluster struct {
|
||||
// flavor of VM
|
||||
MachineSize string `yaml:"machineSize,omitempty"`
|
||||
|
||||
// Kubeconfig filename to save
|
||||
Kubeconfig string `yaml:"kubeconfig,omitempty"`
|
||||
|
||||
// security group
|
||||
SecurityGroup string `yaml:"securityGroup,omitempty"`
|
||||
}
|
||||
|
||||
// ReadYAMLFile reads YAML-formatted configuration file and
|
||||
// de-serializes it to a given object
|
||||
func ReadYAMLFile(filePath string, cfg *OpenstackConfig) error {
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
log.Printf("Attempting to read Openstack bootstrap cluster configuration file at '%s'", filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return yaml.Unmarshal(data, cfg)
|
||||
}
|
8
bootstrap_capo/go.mod
Normal file
8
bootstrap_capo/go.mod
Normal file
@ -0,0 +1,8 @@
|
||||
module capo
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
sigs.k8s.io/yaml v1.2.0
|
||||
)
|
8
bootstrap_capo/go.sum
Normal file
8
bootstrap_capo/go.sum
Normal file
@ -0,0 +1,8 @@
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
85
bootstrap_capo/main.go
Normal file
85
bootstrap_capo/main.go
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
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 (
|
||||
"capo/config"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"flag"
|
||||
)
|
||||
|
||||
const (
|
||||
createCmd = "create"
|
||||
deleteCmd = "delete"
|
||||
helpCmd = "help"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var configPath string
|
||||
|
||||
flag.StringVar(&configPath, "c", "", "Path for the Openstack Cloud bootstrap configuration (yaml) file")
|
||||
flag.Parse()
|
||||
|
||||
volMount := os.Getenv("BOOTSTRAP_VOLUME")
|
||||
|
||||
_, dstMount, err := config.GetVolumeMountPoints(volMount)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to get volume mount, please provide volume mount")
|
||||
os.Exit(1)
|
||||
}
|
||||
openstackConfigPath := dstMount + "/" + os.Getenv("BOOTSTRAP_CONFIG")
|
||||
if len(configPath) == 0 {
|
||||
configPath = openstackConfigPath
|
||||
}
|
||||
|
||||
configYAML := config.OpenstackConfig{}
|
||||
err = config.ReadYAMLFile(configPath, &configYAML)
|
||||
if err != nil {
|
||||
log.Printf("Failed to load Openstack Cloud Bootstrap config file")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
err = config.SetOpenstackCloudEnvVars(&configYAML)
|
||||
if err != nil {
|
||||
log.Printf("Failed to set Openstack Cloud environment variables")
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
command := os.Getenv("BOOTSTRAP_COMMAND")
|
||||
switch {
|
||||
case command == createCmd:
|
||||
err = config.CreateOSCluster()
|
||||
if err != nil {
|
||||
os.Exit(4)
|
||||
}
|
||||
case command == deleteCmd:
|
||||
err = config.DeleteOSCluster()
|
||||
if err != nil {
|
||||
os.Exit(5)
|
||||
}
|
||||
case command == helpCmd:
|
||||
err = config.HelpOSCluster()
|
||||
if err != nil {
|
||||
os.Exit(6)
|
||||
}
|
||||
default:
|
||||
log.Printf("The --command parameter value shall be 'create', 'delete' or 'help'")
|
||||
os.Exit(7)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
12
bootstrap_capo/openstack-config.yaml
Normal file
12
bootstrap_capo/openstack-config.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: OpenstackCloudConfig
|
||||
metadata:
|
||||
name: capi-openstack
|
||||
credentials:
|
||||
credential: clouds.yaml
|
||||
cloudName: devstack
|
||||
spec:
|
||||
cluster:
|
||||
machineSize: ds4G
|
||||
kubeconfig: capo.kubeconfig
|
||||
securityGroup: bootstrap-sec-grp
|
144
bootstrap_capo/resource/create-k8s-cluster.sh
Executable file
144
bootstrap_capo/resource/create-k8s-cluster.sh
Executable file
@ -0,0 +1,144 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
# Bootstrap Environment Variables MUST be provided when running the Container
|
||||
echo "Checking that Openstack Cloud Name has been provided ..."
|
||||
if [[ -z "$OS_CLOUD" ]]; then
|
||||
echo "Openstack cloud name MUST be provided."
|
||||
exit 1
|
||||
else
|
||||
echo "OS_CLOUD = $OS_CLOUD"
|
||||
fi
|
||||
|
||||
echo "Checking that Openstack Cloud Configuration has been provided ..."
|
||||
if [[ -z "$OS_CREDENTIAL_FILE" ]]; then
|
||||
echo "Openstack Cloud Configuration MUST be provided."
|
||||
exit 1
|
||||
else
|
||||
echo "OS_CREDENTIAL_FILE = $OS_CREDENTIAL_FILE"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Checking Environment Variables used by the Bootstrap Container ..."
|
||||
|
||||
if [[ -z "$OS_MACHINE_FLAVOR" ]]; then
|
||||
echo "Assigning default value for OS_MACHINE_FLAVOR"
|
||||
export OS_MACHINE_FLAVOR="ds2G"
|
||||
fi
|
||||
|
||||
if [[ -z "$OS_KUBECONFIG_FILE" ]]; then
|
||||
echo "Assigning default value for OS_KUBECONFIG_FILE"
|
||||
export OS_KUBECONFIG_FILE="kubeconfig"
|
||||
fi
|
||||
if [[ -z "$OS_SECURITY_GROUP" ]]; then
|
||||
echo "Assigning default value for OS_SECURITY_GROUP"
|
||||
export OS_SECURITY_GROUP="bootstrap-mgmt-sec-grp"
|
||||
fi
|
||||
|
||||
cp /kube/"$OS_CREDENTIAL_FILE" ~
|
||||
|
||||
echo "OS_CLOUD = $OS_CLOUD"
|
||||
echo "OS_CREDENTIAL_FILE = $OS_CREDENTIAL_FILE"
|
||||
echo "OS_MACHINE_FLAVOR = $OS_MACHINE_FLAVOR"
|
||||
echo "OS_KUBECONFIG_FILE = $OS_KUBECONFIG_FILE"
|
||||
echo "OS_SECURITY_GROUP = $OS_SECURITY_GROUP"
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
|
||||
echo "creating envs"
|
||||
|
||||
export SECURITY_GROUP=$OS_SECURITY_GROUP
|
||||
export CAPI_VM="bootstrap-k8s"
|
||||
|
||||
export OS_USERNAME=admin
|
||||
|
||||
echo "listing all active images"
|
||||
openstack image list
|
||||
|
||||
echo "SECURITY_GROUP = $SECURITY_GROUP"
|
||||
echo "VM NAME = $CAPI_VM"
|
||||
|
||||
#echo "creating security group"
|
||||
openstack security group create --project demo --project-domain Default $SECURITY_GROUP
|
||||
|
||||
#echo "adding rules to the security group"
|
||||
openstack security group rule create $SECURITY_GROUP --protocol tcp --remote-ip 0.0.0.0/0
|
||||
|
||||
openstack security group rule create $SECURITY_GROUP --protocol tcp --dst-port 10248:10252 --remote-ip 0.0.0.0/0
|
||||
|
||||
export PRIVATE_NETWORK_ID=$(openstack network show private | grep "\<id\>" | awk '{print $4}' )
|
||||
export K8S_IMAGE_ID=$(openstack image list | grep "ubuntu-k8s" | awk '{print $2}' )
|
||||
|
||||
echo "PRIVATE_NW_ID = $PRIVATE_NETWORK_ID"
|
||||
echo "K8S_IMAGE = $K8S_IMAGE_ID"
|
||||
|
||||
#Generate ssh key pair without being prompted for pass phrase
|
||||
ssh-keygen -f ~/.ssh/id_rsa -t rsa -N ''
|
||||
|
||||
echo "printing public key"
|
||||
echo $(cat ~/.ssh/id_rsa.pub)
|
||||
export SSH_KEY_PUB=$(cat ~/.ssh/id_rsa.pub)
|
||||
echo $SSH_KEY_PUB > stack.pub
|
||||
|
||||
openstack keypair delete stack
|
||||
|
||||
echo "creating openstack key pair"
|
||||
openstack keypair create --public-key stack.pub stack
|
||||
|
||||
echo "************** listing key pairs ***************"
|
||||
openstack keypair list
|
||||
|
||||
export FLOATING_IP_ADDRESS=${FLOATING_IP_ADDRESS:-172.24.4.199}
|
||||
|
||||
echo "Add floating IP to public network"
|
||||
openstack floating ip create public --floating-ip-address $FLOATING_IP_ADDRESS
|
||||
|
||||
echo "creating vm for spinning up ephemeral kubernetes cluster"
|
||||
openstack server create --image $K8S_IMAGE_ID --flavor $OS_MACHINE_FLAVOR --security-group $SECURITY_GROUP --nic net-id=$PRIVATE_NETWORK_ID \
|
||||
--key-name stack --user-data user-data.sh $CAPI_VM --wait
|
||||
|
||||
echo "associating floating ip with vm"
|
||||
openstack server add floating ip $CAPI_VM $FLOATING_IP_ADDRESS
|
||||
|
||||
echo "waiting for kubernets cluster to be up"
|
||||
|
||||
#echo "check if kube config is ready on remote vm"
|
||||
|
||||
N=0
|
||||
MAX_RETRY=30
|
||||
DELAY=60
|
||||
|
||||
until [ "$N" -ge ${MAX_RETRY} ]
|
||||
do
|
||||
if ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa ubuntu@$FLOATING_IP_ADDRESS '[ -d /home/ubuntu/.kube/ ]'; then
|
||||
printf "kube config is available\n"
|
||||
break
|
||||
else
|
||||
printf "Kube config does not exist, or still being created\n"
|
||||
N=$((N+1))
|
||||
echo "$N: Retry to check if kubeconfig exists"
|
||||
sleep ${DELAY}
|
||||
fi
|
||||
done
|
||||
|
||||
echo "copying the kubeconfig of ephemeral cluster to container host"
|
||||
scp -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa ubuntu@$FLOATING_IP_ADDRESS:/home/ubuntu/.kube/config /kube/$OS_KUBECONFIG_FILE
|
||||
|
||||
chmod +rw /kube/$OS_KUBECONFIG_FILE
|
||||
|
||||
echo "done copying kubeconfig file"
|
||||
|
||||
echo "*************** done ***************"
|
80
bootstrap_capo/resource/delete-k8s-cluster.sh
Executable file
80
bootstrap_capo/resource/delete-k8s-cluster.sh
Executable file
@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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.
|
||||
|
||||
# Bootstrap Environment Variables MUST be provided when running the Container
|
||||
echo "Checking that Openstack Cloud Name has been provided ..."
|
||||
if [[ -z "$OS_CLOUD" ]]; then
|
||||
echo "Openstack cloud name MUST be provided."
|
||||
exit 1
|
||||
else
|
||||
echo "OS_CLOUD = $OS_CLOUD"
|
||||
fi
|
||||
|
||||
echo "Checking that Openstack Cloud Configuration has been provided ..."
|
||||
if [[ -z "$OS_CREDENTIAL_FILE" ]]; then
|
||||
echo "Openstack Cloud Configuration MUST be provided."
|
||||
exit 1
|
||||
else
|
||||
echo "OS_CREDENTIAL_FILE = $OS_CREDENTIAL_FILE"
|
||||
fi
|
||||
|
||||
cp /kube/$OS_CREDENTIAL_FILE ~
|
||||
|
||||
echo "deleting the k8s ephemeral cluster"
|
||||
|
||||
if [[ -z "$OS_KUBECONFIG_FILE" ]]; then
|
||||
echo "Assigning default value for OS_KUBECONFIG_FILE"
|
||||
export OS_KUBECONFIG_FILE="kubeconfig"
|
||||
fi
|
||||
if [[ -z "$OS_SECURITY_GROUP" ]]; then
|
||||
echo "Assigning default value for OS_SECURITY_GROUP"
|
||||
export OS_SECURITY_GROUP="bootstrap-mgmt-sec-grp"
|
||||
fi
|
||||
|
||||
export SECURITY_GROUP=$OS_SECURITY_GROUP
|
||||
export CAPI_VM="bootstrap-k8s"
|
||||
export FLOATING_IP_ADDRESS=${FLOATING_IP_ADDRESS:-172.24.4.199}
|
||||
echo "OS_CLOUD = $OS_CLOUD"
|
||||
echo "OS_CREDENTIAL_FILE = $OS_CREDENTIAL_FILE"
|
||||
echo "OS_MACHINE_FLAVOR = $OS_MACHINE_FLAVOR"
|
||||
echo "OS_KUBECONFIG_FILE = $OS_KUBECONFIG_FILE"
|
||||
echo "OS_SECURITY_GROUP = $OS_SECURITY_GROUP"
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
openstack server delete $CAPI_VM --wait
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "*** Failed to delete cluster in VM $CAPI_VM "
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "K8s cluster deleted successfully in VM $CAPI_VM"
|
||||
|
||||
openstack security group delete $SECURITY_GROUP
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "*** Failed to delete security group $SECURITY_GROUP."
|
||||
exit 1
|
||||
fi
|
||||
echo "Security Group $SECURITY_GROUP is deleted successfully."
|
||||
|
||||
openstack floating ip delete $FLOATING_IP_ADDRESS
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "*** Failed to delete floating ip $FLOATING_IP_ADDRESS."
|
||||
exit 1
|
||||
fi
|
||||
echo "Floating IP $FLOATING_IP is released successfully."
|
||||
|
||||
echo "Kubernetes ephemeral cluster on vm $CAPI_VM is deleted successfully."
|
32
bootstrap_capo/resource/help.txt
Normal file
32
bootstrap_capo/resource/help.txt
Normal file
@ -0,0 +1,32 @@
|
||||
Openstack Ephemeral Configuration File Definition
|
||||
-----------------------------------------------------
|
||||
The Openstack Bootstrap container creates an Ephemeral K8S cluster on the Openstack.
|
||||
The container requires clouds.yaml credentials and other information about the cluster to deploy.
|
||||
It requires a YAML configuration file with the format provided below.
|
||||
|
||||
<Openstack Config Definition>
|
||||
apiVersion: v1
|
||||
kind: OpenstackConfig
|
||||
metadata:
|
||||
name: <metadata-name>
|
||||
credentials:
|
||||
credential: <Clouds.yaml file of devstack>
|
||||
cloudName: <openstack cloud name i.e. devstack>
|
||||
spec:
|
||||
cluster:
|
||||
machineSize: <Openstack VM flavor, e.g. ds2G>
|
||||
kubeconfig: <Kubeconfig filename, Default is 'kubeconfig'>
|
||||
securityGroup:<Security Group that'll be attached to the VM>
|
||||
</Openstack Config Definition>
|
||||
|
||||
The expected location for the Openstack bootstrap configuration file is dictated by the "volume" mount
|
||||
specified in the Airship config file (bootstrapInfo.ephemeral.container.volume).
|
||||
For example, $HOME/.airship folder and shown in the snippet below:
|
||||
|
||||
<Snippet>
|
||||
apiVersion: airshipit.org/v1alpha1
|
||||
bootstrapInfo:
|
||||
ephemeral:
|
||||
container:
|
||||
volume: /home/stack/.airship:/kube
|
||||
</Snippet>
|
55
bootstrap_capo/resource/user-data.sh
Executable file
55
bootstrap_capo/resource/user-data.sh
Executable file
@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
|
||||
DEBIAN_FRONTEND=noninteractive apt-get remove -y resolvconf
|
||||
sed -i 's/domain-name-servers, domain-search, //' /etc/dhcp/dhclient.conf
|
||||
service networking restart
|
||||
sed -i '/nameserver/d' /etc/resolv.conf
|
||||
export NAMESERVER=${NAMESERVER:-8.8.8.8}
|
||||
export NAMESERVER_OTHER=${NAMESERVER_OTHER:-8.8.4.4}
|
||||
echo 'nameserver '"$NAMESERVER" >> /etc/resolv.conf
|
||||
echo 'nameserver '"$NAMESERVER_OTHER" >> /etc/resolv.conf
|
||||
echo "nameserver is set"
|
||||
|
||||
apt-get update
|
||||
apt-get upgrade -y
|
||||
apt-get install -y apt-transport-https ca-certificates curl \
|
||||
software-properties-common
|
||||
|
||||
apt-get install -y docker.io
|
||||
|
||||
bash -c 'cat << EOF > /etc/docker/daemon.json
|
||||
{
|
||||
"exec-opts": ["native.cgroupdriver=systemd"]
|
||||
}
|
||||
EOF'
|
||||
|
||||
export APT_KEY_GPG_URL=${APT_KEY_GPG_URL:-https://packages.cloud.google.com/apt/doc/apt-key.gpg}
|
||||
export K8S_IO_DEB_URL=${K8S_IO_DEB_URL:-http://apt.kubernetes.io/}
|
||||
|
||||
curl -s "$APT_KEY_GPG_URL" | sudo apt-key add -
|
||||
|
||||
bash -c 'cat << EOF > /etc/apt/sources.list.d/kubernetes.list
|
||||
deb $K8S_IO_DEB_URL kubernetes-xenial main
|
||||
EOF'
|
||||
|
||||
export K8S_VERSION=${K8S_VERSION:-1.19.0-00}
|
||||
|
||||
apt update
|
||||
|
||||
apt install -y kubelet="$K8S_VERSION" kubeadm="$K8S_VERSION" kubectl="$K8S_VERSION"
|
||||
|
||||
export CONTROL_PLANE_IP=${CONTROL_PLANE_IP:-172.24.4.199}
|
||||
|
||||
kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-cert-extra-sans="$CONTROL_PLANE_IP" \
|
||||
--control-plane-endpoint="$CONTROL_PLANE_IP"
|
||||
|
||||
mkdir -p /home/ubuntu/.kube
|
||||
|
||||
cp -i /etc/kubernetes/admin.conf /home/ubuntu/.kube/config
|
||||
|
||||
chown ubuntu:ubuntu /home/ubuntu/.kube/config
|
||||
|
||||
export CALICO_URL=${CALICO_URL:-https://docs.projectcalico.org/v3.15/manifests/calico.yaml}
|
||||
|
||||
export KUBECONFIG=/etc/kubernetes/admin.conf && \
|
||||
kubectl apply -f "$CALICO_URL"
|
28
playbooks/airship-images-go-install.yaml
Normal file
28
playbooks/airship-images-go-install.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
# 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.
|
||||
|
||||
- hosts: primary
|
||||
vars_files:
|
||||
- vars/version.yaml
|
||||
tasks:
|
||||
- name: install go language
|
||||
shell: |
|
||||
sudo -E curl -sO "{{url}}"/go/"{{golang_version}}".tar.gz
|
||||
sudo tar -C /usr/local -xzf "{{golang_version}}".tar.gz
|
||||
rm "{{golang_version}}".tar.gz
|
||||
cat >> ~/.profile << EOF
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
EOF
|
||||
become: yes
|
||||
when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
|
3
playbooks/vars/version.yaml
Normal file
3
playbooks/vars/version.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
---
|
||||
golang_version: go1.14.1.linux-amd64
|
||||
url: https://dl.google.com
|
Loading…
Reference in New Issue
Block a user