diff --git a/.gitignore b/.gitignore
index 12c2a1f..936d613 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
*build/
bootstrap_capg/.vscode/launch.json
bootstrap_capg/go.mod
+bootstrap_capz/.vscode/launch.json
+bootstrap_capz/go.mod
+bootstrap_capz/go.sum
diff --git a/bootstrap_capz/Dockerfile b/bootstrap_capz/Dockerfile
new file mode 100644
index 0000000..e5ca084
--- /dev/null
+++ b/bootstrap_capz/Dockerfile
@@ -0,0 +1,57 @@
+# 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 AZ_SDK=mcr.microsoft.com/azure-cli:2.8.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_capz && \
+ go get -d -v ./... && \
+ go install . && \
+ CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o capz-ephemeral .
+
+############################################
+# Run Azure Bootstrap Container
+############################################
+FROM ${AZ_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 --gecos "" bootstrap
+USER bootstrap
+
+WORKDIR /home/bootstrap
+ENV HOME=/home/bootstrap
+ENV PATH="${PATH}:${HOME}"
+
+# Copy the Azure Bootstrap Container command
+COPY --from=builder /home/build/capz-ephemeral .
+# Copy help file
+COPY assets/help.txt .
+
+# Executes the Azure Bootstrap command
+CMD ["capz-ephemeral"]
diff --git a/bootstrap_capz/Makefile b/bootstrap_capz/Makefile
new file mode 100644
index 0000000..5e5548e
--- /dev/null
+++ b/bootstrap_capz/Makefile
@@ -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 ?= capz-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/azure_cluster.go \
+ config/aks_cluster.go \
+ config/azure_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 $(DOCKER_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 azure-config.yaml /tmp
+ docker run -v /tmp:/kube --env-file bootstrap-env.list --name capz-test $(DOCKER_IMAGE)
+ cmp $(HELP_FILE) $(ORIGINAL_HELP_FILE)
diff --git a/bootstrap_capz/README.md b/bootstrap_capz/README.md
new file mode 100644
index 0000000..7e740ef
--- /dev/null
+++ b/bootstrap_capz/README.md
@@ -0,0 +1,32 @@
+# Azure Bootstrap Container
+
+This project contains the Go application and configuration files for
+implementing the Azure Bootstrap container.
+
+The Azure Bootstrap container is responsible to create or delete a Kubernetes
+(K8S) cluster on Azure Cloud platform using the AKS (Azure Kubernetes Service).
+
+## 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., azure-config.yaml) to determine the Azure 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 Azure 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.
diff --git a/bootstrap_capz/assets/help.txt b/bootstrap_capz/assets/help.txt
new file mode 100644
index 0000000..dac01ff
--- /dev/null
+++ b/bootstrap_capz/assets/help.txt
@@ -0,0 +1,64 @@
+
+Azure Ephemeral Configuration File Definition
+---------------------------------------------
+The Azure Bootstrap container creates an Ephemeral K8S cluster on the Azure 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.
+
+
+apiVersion: v1
+kind: AzureConfig
+metadata:
+ name:
+credentials:
+ tenant:
+ client:
+ secret:
+spec:
+ resourceGroup:
+ region:
+ cluster:
+ k8sVersion:
+ vmSize:
+ replicas:
+ kubeconfig:
+
+
+It also accepts the JSON file format.
+
+
+{
+ "apiVersion":"v1",
+ "kind":"AzureConfig",
+ "metadata":{
+ "name":""
+ },
+ "credentials":{
+ "tenant":"",
+ "client":"",
+ "secret":""
+ },
+ "spec":{
+ "resourceGroup":"",
+ "region":"",
+ "cluster":{
+ "k8sVersion":"",
+ "vmSize":"",
+ "replicas":,
+ "kubeconfig":""
+ }
+ }
+}
+
+
+The expected location for the Azure 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 and shown in the snippet below:
+
+
+apiVersion: airshipit.org/v1alpha1
+bootstrapInfo:
+ ephemeral:
+ container:
+ volume: /home/esidshi/.airship:/kube
+
diff --git a/bootstrap_capz/azure-config.json b/bootstrap_capz/azure-config.json
new file mode 100644
index 0000000..6afa44c
--- /dev/null
+++ b/bootstrap_capz/azure-config.json
@@ -0,0 +1,22 @@
+{
+ "apiVersion":"v1",
+ "credentials":{
+ "tenant":"",
+ "client":"",
+ "secret":""
+ },
+ "kind":"AzureConfig",
+ "metadata":{
+ "name":"capi-azure-zuul"
+ },
+ "region":"centralus",
+ "resourceGroup":"airship2-zuul-rg",
+ "spec":{
+ "cluster":{
+ "k8sVersion":"1.18.6",
+ "kubeconfig":"capz.kubeconfig",
+ "replicas":1,
+ "vmSize":"Standard_B2s"
+ }
+ }
+}
\ No newline at end of file
diff --git a/bootstrap_capz/azure-config.yaml b/bootstrap_capz/azure-config.yaml
new file mode 100644
index 0000000..e4f7275
--- /dev/null
+++ b/bootstrap_capz/azure-config.yaml
@@ -0,0 +1,28 @@
+# 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: AzureConfig
+metadata:
+ name: capi-azure-zuul
+credentials:
+ tenant:
+ client:
+ secret:
+spec:
+ resourceGroup: airship2-zuul-rg
+ region: centralus
+ cluster:
+ k8sVersion: 1.18.6
+ vmSize: Standard_B2s
+ replicas: 1
+ kubeconfig: capz.kubeconfig
diff --git a/bootstrap_capz/bootstrap-env.list b/bootstrap_capz/bootstrap-env.list
new file mode 100644
index 0000000..dc57c41
--- /dev/null
+++ b/bootstrap_capz/bootstrap-env.list
@@ -0,0 +1,3 @@
+BOOTSTRAP_COMMAND=help
+BOOTSTRAP_CONFIG=azure-config.yaml
+BOOTSTRAP_VOLUME=/tmp:/kube
\ No newline at end of file
diff --git a/bootstrap_capz/config/aks_cluster.go b/bootstrap_capz/config/aks_cluster.go
new file mode 100644
index 0000000..663316f
--- /dev/null
+++ b/bootstrap_capz/config/aks_cluster.go
@@ -0,0 +1,165 @@
+/*
+ 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 (
+ az = "az"
+ aks = "aks"
+ login = "login"
+ group = "group"
+ create = "create"
+ delete = "delete"
+ getCredentials = "get-credentials"
+ servicePrincipalP = "--service-principal"
+ usernameP = "--username"
+ passwordP = "--password"
+ tenantP = "--tenant"
+ clientSecretP = "--client-secret"
+ resourceGroupP = "--resource-group"
+ locationP = "--location"
+ nameP = "--name"
+ nodeVMSizeP = "--node-vm-size"
+ nodeCountP = "--node-count"
+ k8sVersionP = "--kubernetes-version"
+ generateSSHKeysP = "--generate-ssh-keys"
+ fileP = "--file"
+ yesP = "--yes"
+
+ defaultRegion = "centralus"
+ defaultResourceGroup = "airship2-aks-rg"
+ defaultClusterName = "capi-azure"
+ defaultVMSize = "Standard_B2s"
+ defaultK8SVersion = "1.18.6"
+ defaultKubeconfig = "kubeconfig"
+)
+
+// defaulAzureConfig verify if any optional config data is missing.
+func defaulAzureConfig(azConfig *AzureConfig) error {
+ if azConfig.Spec.Region == "" {
+ azConfig.Spec.Region = defaultRegion
+ }
+ if azConfig.Spec.ResourceGroup == "" {
+ azConfig.Spec.ResourceGroup = defaultResourceGroup
+ }
+ if azConfig.Metadata.Name == "" {
+ azConfig.Metadata.Name = defaultClusterName
+ }
+ if azConfig.Spec.Cluster.VMSize == "" {
+ azConfig.Spec.Cluster.VMSize = defaultVMSize
+ }
+ if azConfig.Spec.Cluster.K8SVersion == "" {
+ azConfig.Spec.Cluster.K8SVersion = defaultK8SVersion
+ }
+ if azConfig.Spec.Cluster.Kubeconfig == "" {
+ azConfig.Spec.Cluster.Kubeconfig = defaultKubeconfig
+ }
+ return nil
+}
+
+// prepareAKSCluster logs in, create resource group, etc
+func prepareAKSCluster(azConfig *AzureConfig, isCreate bool) error {
+ // Verify if azure config file provides all information needed for creating a cluster
+ err := defaulAzureConfig(azConfig)
+ if err != nil {
+ return err
+ }
+
+ tenantID := azConfig.Credentials.Tenant
+ clientID := azConfig.Credentials.Client
+ clientSecret := azConfig.Credentials.Secret
+ region := azConfig.Spec.Region
+ resourceGroup := azConfig.Spec.ResourceGroup
+ clusterName := azConfig.Metadata.Name
+ vmSize := azConfig.Spec.Cluster.VMSize
+ nodeCount := strconv.FormatInt(int64(azConfig.Spec.Cluster.Replicas), 10)
+ k8sVersion := azConfig.Spec.Cluster.K8SVersion
+ kubeconfigFile := azConfig.Spec.Cluster.Kubeconfig
+
+ // login to Azure account using Service Principal
+ err = execute(az, login, servicePrincipalP,
+ usernameP, clientID,
+ passwordP, clientSecret,
+ tenantP, tenantID)
+ if err != nil {
+ log.Printf("Failed to login into Azure using Service Principal\n")
+ return err
+ }
+
+ if isCreate {
+ // Create resource group for the AKS cluster
+ err = execute(az, group, create,
+ resourceGroupP, resourceGroup,
+ locationP, region)
+ if err != nil {
+ log.Printf("Failed to create resource group %s in %s region.\n", resourceGroup, region)
+ return err
+ }
+
+ // Creating Azure AKS cluster
+ err = execute(az, aks, create,
+ resourceGroupP, resourceGroup,
+ nameP, clusterName,
+ servicePrincipalP, clientID,
+ clientSecretP, clientSecret,
+ locationP, region,
+ nodeVMSizeP, vmSize,
+ nodeCountP, nodeCount,
+ k8sVersionP, k8sVersion,
+ generateSSHKeysP)
+ if err != nil {
+ log.Printf("Failed to create AKS cluster %s in %s region.\n", clusterName, region)
+ return err
+ }
+
+ // Get Kubeconfig filename
+ volMount := os.Getenv("BOOTSTRAP_VOLUME")
+ _, dstMount := GetVolumeMountPoints(volMount)
+
+ kubeconfig := dstMount + "/" + kubeconfigFile
+
+ // Delete existing Kubeconfig file, if any
+ err = os.Remove(kubeconfig)
+ if err != nil {
+ log.Printf("Failed to remove existing kubeconfig file %s.\n", kubeconfig)
+ return err
+ }
+
+ // Retrieving the Kubeconfig file for the cluster
+ err = execute(az, aks, getCredentials,
+ resourceGroupP, resourceGroup,
+ nameP, clusterName,
+ fileP, kubeconfig)
+ if err != nil {
+ log.Printf("Failed to retrieve kubeconfig file for AKS cluster %s in %s region.\n", clusterName, region)
+ return err
+ }
+ } else {
+ // Delete Azure AKS cluster
+ err = execute(az, aks, delete,
+ resourceGroupP, resourceGroup,
+ nameP, clusterName, yesP)
+ if err != nil {
+ log.Printf("Failed to delete AKS cluster %s in %s region.\n", clusterName, region)
+ return err
+ }
+ }
+ return nil
+}
diff --git a/bootstrap_capz/config/azure_cluster.go b/bootstrap_capz/config/azure_cluster.go
new file mode 100644
index 0000000..dc26c62
--- /dev/null
+++ b/bootstrap_capz/config/azure_cluster.go
@@ -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 bash command
+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
+}
+
+// CreateAKSCluster creates the AKS cluster
+func CreateAKSCluster(config *AzureConfig) error {
+ return prepareAKSCluster(config, true)
+}
+
+// DeleteAKSCluster deletes the AKS cluster
+func DeleteAKSCluster(config *AzureConfig) error {
+ return prepareAKSCluster(config, false)
+}
+
+// HelpAKSCluster returns the help.txt for the AKS cluster
+func HelpAKSCluster() 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()
+}
diff --git a/bootstrap_capz/config/azure_config.go b/bootstrap_capz/config/azure_config.go
new file mode 100644
index 0000000..d5dee0d
--- /dev/null
+++ b/bootstrap_capz/config/azure_config.go
@@ -0,0 +1,137 @@
+/*
+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"
+)
+
+// AzureConfig holds configurations for bootstrap steps
+type AzureConfig struct {
+ // +optional
+ Kind string `json:"kind" validate:"required"`
+
+ // +optional
+ APIVersion string `json:"apiVersion" validate:"required"`
+
+ // Configuration parameters for metadata
+ Metadata *Metadata `json:"metadata"`
+
+ // Configuration parameters for metadata
+ Credentials *Credentials `json:"credentials" validate:"required"`
+
+ // Configuration parameters for spec
+ Spec *Spec `json:"spec"`
+}
+
+// Metadata structure provides the cluster name to assign and labels to the k8s cluster
+type Metadata struct {
+ Name string `json:"name" validate:"required"`
+ Labels []string `json:"labels,omitempty"`
+}
+
+// Credentials structu provides the credentials to authenticate with Azure Cloud
+type Credentials struct {
+ Tenant string `json:"tenant" validate:"required"`
+ Client string `json:"client" validate:"required"`
+ Secret string `json:"secret" validate:"required"`
+}
+
+// Spec structure contains the info for the ck8s luster to deploy
+type Spec struct {
+ Region string `json:"region,omitempty"`
+ ResourceGroup string `json:"resourceGroup,omitempty"`
+ Cluster Cluster `json:"cluster"`
+}
+
+// Cluster struct provides data for the k8s cluster to deploy
+type Cluster struct {
+ // Kubernetes version to deploy
+ K8SVersion string `json:"k8sVersion,omitempty"`
+
+ // Azure VM size to use for the cluster
+ VMSize string `json:"vmSize,omitempty"`
+
+ // Number of nodes to deploy for the cluster
+ Replicas uint8 `json:"replicas,omitempty" validate:"gte=1,lte=100"`
+
+ // Kubeconfig filename to save
+ Kubeconfig string `json:"kubeconfig,omitempty"`
+}
+
+// ReadYAMLFile reads YAML-formatted configuration file and
+// de-serializes it to a given object
+func ReadYAMLFile(filePath string, cfg *AzureConfig) error {
+ data, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ log.Printf("yamlFile.Get err #%v ", err)
+ return err
+ }
+ return yaml.Unmarshal(data, cfg)
+}
+
+// ReadYAMLtoJSON reads YAML-formatted configuration file and
+// de-serializes it to a given object
+func ReadYAMLtoJSON(filePath string) (string, error) {
+ data, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ log.Printf("Failed to read Azure Ephemeral configuration file: err #%v ", err)
+
+ return "", err
+ }
+ jsonByte, err := yaml.YAMLToJSON(data)
+ if err != nil {
+ log.Printf("YAMLtoJSON err #%v ", err)
+ return "", err
+ }
+ jsonStr := string(jsonByte)
+ return jsonStr, nil
+}
+
+// ValidateConfigFile validates Azure configuration file for the Ephemeral Cluster
+func ValidateConfigFile(config *AzureConfig) error {
+ var validate *validator.Validate
+
+ validate = validator.New()
+ err := validate.Struct(config)
+ if err != nil {
+ // this check is only needed when your code could produce
+ // an invalid value for validation such as interface with nil value.
+ 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", err.Param())
+ log.Println()
+ }
+ return err
+ }
+ return nil
+}
diff --git a/bootstrap_capz/main.go b/bootstrap_capz/main.go
new file mode 100644
index 0000000..84c884e
--- /dev/null
+++ b/bootstrap_capz/main.go
@@ -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_capz/config"
+)
+
+const (
+ createCmd = "create"
+ deleteCmd = "delete"
+ helpCmd = "help"
+)
+
+func main() {
+ var configPath string
+
+ flag.StringVar(&configPath, "c", "", "Path for the Azure bootstrap configuration (yaml) file")
+ flag.Parse()
+
+ if configPath == "" {
+ volMount := os.Getenv("BOOTSTRAP_VOLUME")
+ _, dstMount := config.GetVolumeMountPoints(volMount)
+ azureConfigPath := dstMount + "/" + os.Getenv("BOOTSTRAP_CONFIG")
+ configPath = azureConfigPath
+ }
+
+ configYAML := &config.AzureConfig{}
+ err := config.ReadYAMLFile(configPath, configYAML)
+ if err != nil {
+ log.Printf("Failed to load Azure 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.CreateAKSCluster(configYAML)
+ if err != nil {
+ os.Exit(5)
+ }
+ case command == deleteCmd:
+ err = config.DeleteAKSCluster(configYAML)
+ if err != nil {
+ os.Exit(6)
+ }
+ case command == helpCmd:
+ err = config.HelpAKSCluster()
+ 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)
+}