diff --git a/Dockerfile b/Dockerfile index 96739cb..fae5351 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,12 +9,14 @@ LABEL org.opencontainers.image.description "An image containing all the Spectro ADD terraform/ /terraform ADD packs/ /packs +ADD edge/ /edge ADD static/defaults/htpasswd-basic /auth/htpasswd-basic ADD static/defaults/ngrok.yml /auth/ngrok.yml ADD static/defaults/registry-config.yml etc/spectro/config.yml ARG PALETTE_CLI_VERSION ARG PALETTE_EDGE_VERSION +ARG PACKER_VERSION=1.8.7 ENV REGISTRY_LOG_LEVEL=info ENV REGISTRY_AUTH=htpasswd @@ -22,6 +24,7 @@ ENV REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" ENV REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd-basic COPY --from=server /registry /usr/local/bin/ +COPY --from=server /etc/spectro/config.yml /etc/spectro/config.yml RUN adduser -H -u 1002 -D appuser appuser && \ apk update && \ @@ -49,7 +52,10 @@ RUN wget https://software.spectrocloud.com/spectro-registry/v$PALETTE_CLI_VERSI git clone https://github.com/spectrocloud/CanvOS.git && \ rm -rf /var/cache/apk/* - +ADD https://releases.hashicorp.com/packer/${PACKER_VERSION}/packer_${PACKER_VERSION}_linux_amd64.zip /usr/local/sbin/ +RUN unzip /usr/local/sbin/packer_${PACKER_VERSION}_linux_amd64.zip -d /usr/local/sbin && \ + rm -rf /usr/local/sbin/packer_${PACKER_VERSION}_linux_amd64.zip +RUN apk add xorriso govc EXPOSE 5000 CMD ["/bin/bash"] \ No newline at end of file diff --git a/Makefile b/Makefile index b3dd56a..5a629df 100644 --- a/Makefile +++ b/Makefile @@ -3,4 +3,4 @@ init: build-docker: @echo "Building docker image" - docker build --build-arg PALETTE_VERSION=$(VERSION) --build-arg PALETTE_CLI_VERSION=$(VERSION) --build-arg PALETTE_EDGE_VERSION=$(EDGE) -t tutorials . \ No newline at end of file + docker build --build-arg PALETTE_VERSION=$(VERSION) --build-arg PALETTE_CLI_VERSION=$(VERSION) --build-arg PALETTE_EDGE_VERSION=$(EDGE) --build-arg PACKER_VERSION=1.8.7 -t tutorials . \ No newline at end of file diff --git a/docs/docker.md b/docs/docker.md index deab2e3..5a266be 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -38,6 +38,8 @@ The Docker image includes the following tools. | `ca-certificates` | Common set of CA certificates | | `canvos` | A utility for creating Edge artifacts | | `nano` | A text editior for Unix-like computing systems or operating environments using a command line interface| +| `packer` | Hashicorp Image Builder for building Edge Native images | +| `GOVC` | Tool for interracting with VMware Vsphere via API | ### Spectro Cloud Pack Registry Server @@ -67,6 +69,6 @@ make build-docker VERSION=3.4.0 EDGE=3.4.3 OR ```shell -docker build --build-arg PALETTE_VERSION=3.3.0 --build-arg PALETTE_CLI_VERSION=3.4.0 --build-arg PALETTE_EDGE_VERSION=3.4.3 -t tutorials . +docker build --build-arg PALETTE_VERSION=3.3.0 --build-arg PALETTE_CLI_VERSION=3.4.0 --build-arg PALETTE_EDGE_VERSION=3.4.3 --build-arg PACKER_VERSION=1.8.7 -t tutorials . ``` diff --git a/edge/vmware/README.md b/edge/vmware/README.md new file mode 100644 index 0000000..8236f42 --- /dev/null +++ b/edge/vmware/README.md @@ -0,0 +1,77 @@ +# Overview +This directory contains the files referenced in the [Deploy an Edge Cluster on VMware](https://docs.spectrocloud.com/clusters/edge/deploy-cluster) tutorial. Use the files in this directory with the tutorial. The following code block shows the list of files. + + +```bash +. +└── vmware + ├── README.md + ├── clone_vm_template + │   ├── delete-edge-host.sh # Deletes the VMs + │   ├── deploy-edge-host.sh # Provisions the VMs + │   └── setenv.sh # Defines the GOVC environment variables + └── packer + ├── build.pkr.hcl # Packer build script + ├── meta-data # Sample template + ├── user-data # Sample template + └── vsphere.hcl # Contains the VM template name, VM configuration, and ISO file name +``` + + +The **vmware/packer/** folder contains the Packer code responsible for creating a VM template in VMWare vCenter from the Edge installer ISO image. Here is a brief description of files present in this folder: + +- **build.pkr.hcl** is the Packer build script. + +- **vsphere.hcl** defines the VM template name, VM configuration, and ISO file name to use. The VM configuration conforms to the [minimum device requirements](https://docs.spectrocloud.com/clusters/edge/architecture/#minimumdevicerequirements). + +- **meta-data** and **user-data** are sample template files. These file are optional for the build process. + + +The **vmware/clone_vm_template** folder contains the shell scripts containing GOVC command line instructions. Here is a brief description of the files present in this folder: + +- **delete-edge-host.sh** provisions the VMs + +- **deploy-edge-host.sh** deletes the VMs. + +- **setenv.sh** defines the GOVC environment variables, the number of VMs, a prefix string for the VM name, and the VM template name. + +# Dependencies +Your environment must have Packer and GOVC installed. The tutorials container comes with these dependencies pre-installed. If you are not using the tutorials container, you must install these dependencies on your machine. Here are the instructions to install these on a Linux machine. + +To install Packer, refer to these official [instructions](https://developer.hashicorp.com/packer/tutorials/docker-get-started/get-started-install-cli). + +To install GOVC, you must first install Go using the following instructions: +```bash +wget https://go.dev/dl/go1.20.5.linux-amd64.tar.gz +sudo tar -C /usr/local -xzf go1.20.5.linux-amd64.tar.gz +export PATH=$PATH:/usr/local/go/bin +go version +``` +After installing Go, you can install [GOVC CLI utility](https://github.com/vmware/govmomi/tree/main/govc) and `xorriso` dependency as: +```bash +curl -L -o - "https://github.com/vmware/govmomi/releases/latest/download/govc_$(uname -s)_$(uname -m).tar.gz" | tar -C /usr/local/bin -xvzf - govc +sudo apt-get install -y xorriso +``` + + +# Prerequisites +To use the Packer and GOVC files, you need the following VMWare permissions: + +```bash +Datastore.AllocateSpace +Host.Config.AdvancedConfig +Host.Config.NetService +Host.Config.Network +Network.Assign +System.Anonymous +System.Read +System.View +VApp.Import +VirtualMachine.Config.AddNewDisk +VirtualMachine.Config.AdvancedConfig +``` + +You will need the VMWare vCenter server URL, login credentials, and names of the data center, destination datastore, resource pool, destination folder (not on Datastore, on the vSphere logical view), cluster, and DHCP enabled network to be assigned to the VM template. + + +Refer to the [Deploy an Edge Cluster on VMware](https://docs.spectrocloud.com/clusters/edge/deploy-cluster) tutorial to learn how to use Packer and GOVC files present in this folder. \ No newline at end of file diff --git a/edge/vmware/clone_vm_template/delete-edge-host.sh b/edge/vmware/clone_vm_template/delete-edge-host.sh new file mode 100755 index 0000000..675da14 --- /dev/null +++ b/edge/vmware/clone_vm_template/delete-edge-host.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +source ./setenv.sh + +set -o errexit +set -o nounset +set -o pipefail + +vm_array=( $(seq 1 $NO_OF_VMS ) ) + + +echo "Cleaning Previous VMs on vSphere" + +for VM in ${vm_array[@]}; + do + echo "Getting UUID $VM_PREFIX-$VM" + UUID=$(govc vm.info $VM_PREFIX-$VM | grep UUID: | sed "s/.* //" | sed "s/-//g") + if govc vm.destroy $VM_PREFIX-$VM #> /dev/null 2>&1 + then + echo "Deleted $VM_PREFIX-$VM" + fi +done \ No newline at end of file diff --git a/edge/vmware/clone_vm_template/deploy-edge-host.sh b/edge/vmware/clone_vm_template/deploy-edge-host.sh new file mode 100755 index 0000000..0d76fa1 --- /dev/null +++ b/edge/vmware/clone_vm_template/deploy-edge-host.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +source ./setenv.sh + +set -o errexit +set -o nounset +set -o pipefail + +vm_array=( $(seq 1 $NO_OF_VMS ) ) + + +for VM in ${vm_array[@]}; + do + if govc vm.clone -link=true -m 8000 -on=false -vm $GOVC_FOLDER/$INSTALLER_TEMPLATE $VM_PREFIX-$VM + then + echo "Cloned VM $VM_PREFIX-$VM" + else + echo "Failed to clone VM $VM_PREFIX-$VM" + fi + + echo "Powering on VM $VM_PREFIX-$VM" + if ! govc vm.power -on=true -wait=false $VM_PREFIX-$VM + then + echo "Failed to power on VM $VM_PREFIX-$VM" + fi + + echo "Getting UUID $VM_PREFIX-$VM" + # govc vm.info got uuid with middle ending, need to convert the first 3 components + u=$(govc vm.info $VM_PREFIX-$VM | grep UUID: | sed "s/.* //" | sed "s/-//g") + UUID=${u:6:2}${u:4:2}${u:2:2}${u:0:2}${u:10:2}${u:8:2}${u:14:2}${u:12:2}${u:16} + echo "Edge Host ID VM $VM_PREFIX-$VM : edge-$UUID" +done + diff --git a/edge/vmware/clone_vm_template/setenv.sh b/edge/vmware/clone_vm_template/setenv.sh new file mode 100644 index 0000000..4899293 --- /dev/null +++ b/edge/vmware/clone_vm_template/setenv.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Number of VMs to provision +export NO_OF_VMS=3 +export VM_PREFIX="demo" +export INSTALLER_TEMPLATE="palette-edge-template" + +################################################## +#### DO NOT MODIFY BELOW HERE #################### +################################################## + +# GOVC Properties +# vCenter Endpoint +export GOVC_URL="https://${vcenter_server}" # Use HTTPS. For example, https://vcenter.company.com +export GOVC_USERNAME="${vcenter_username}" +export GOVC_PASSWORD="${vcenter_password}" +export GOVC_INSECURE=1 #1 if insecure +export GOVC_DATACENTER="${vcenter_datacenter}" +export GOVC_DATASTORE="${vcenter_datastore}" +export GOVC_NETWORK="${vcenter_network}" +export GOVC_RESOURCE_POOL="${vcenter_resource_pool}" +export GOVC_FOLDER="${vcenter_folder}" diff --git a/edge/vmware/packer/.env b/edge/vmware/packer/.env new file mode 100755 index 0000000..2f3b41c --- /dev/null +++ b/edge/vmware/packer/.env @@ -0,0 +1,21 @@ +#!/bin/bash +export vcenter_server="Enter a value" # Example: vcenter.spectrocloud.dev +export vcenter_username="Enter a value" +export vcenter_password="Enter a value" +export vcenter_datacenter="Enter a value" +export vcenter_datastore="Enter a value" +export vcenter_resource_pool="Enter a value" +export vcenter_folder="Enter a value" +export vcenter_cluster="Enter a value" +export vcenter_network="Enter a value" + + +export PKR_VAR_vcenter_server=${vcenter_server} +export PKR_VAR_vcenter_username=${vcenter_username} +export PKR_VAR_vcenter_password=${vcenter_password} +export PKR_VAR_vcenter_datacenter=${vcenter_datacenter} +export PKR_VAR_vcenter_datastore=${vcenter_datastore} +export PKR_VAR_vcenter_resource_pool=${vcenter_resource_pool} +export PKR_VAR_vcenter_folder=${vcenter_folder} +export PKR_VAR_vcenter_cluster=${vcenter_cluster} +export PKR_VAR_vcenter_network=${vcenter_network} \ No newline at end of file diff --git a/edge/vmware/packer/build.pkr.hcl b/edge/vmware/packer/build.pkr.hcl new file mode 100644 index 0000000..09c91bc --- /dev/null +++ b/edge/vmware/packer/build.pkr.hcl @@ -0,0 +1,227 @@ +variable "vcenter_username" { + type = string + description = "The username for authenticating to vCenter." + default = "" + sensitive = true +} +variable "vcenter_password" { + type = string + description = "The password for authenticating to vCenter." + default = "" + sensitive = true +} +# vSphere Objects + +variable "vcenter_insecure_connection" { + type = bool + description = "If true, does not validate the vCenter server's TLS certificate." + default = true +} + +variable "vcenter_server" { + type = string + description = "The fully qualified domain name or IP address of the vCenter Server instance." + default = "" +} + +variable "vcenter_datacenter" { + type = string + description = "Required if there is more than one datacenter in vCenter." + default = "" +} + +variable "vcenter_host" { + type = string + description = "The ESXi host where target VM is created." + default = "" +} + +variable "vcenter_cluster" { + type = string + description = "The cluster where target VM is created." + default = "" +} + +variable "vcenter_datastore" { + type = string + description = "Required for clusters, or if the target host has multiple datastores." + default = "" +} +variable "vcenter_resource_pool" { + type = string + description = "Resource Pool to be assigned." + default = "" +} +variable "vcenter_network" { + type = string + description = "The network segment or port group name to which the primary virtual network adapter will be connected." + default = "" +} + +variable "vcenter_folder" { + type = string + description = "The VM folder in which the VM template will be created." + default = "" +} + +# ISO Objects +variable "iso" { + type = string + description = "Filename of the local ISO file" +} + +variable "iso_checksum" { + type = string + description = "Filename of the local ISO Checksum File" +} + +# Virtual Machine Settings + +variable "vm_name" { + type = string + description = "The template vm name" + default = "" +} + +variable "vm_guest_os_type" { + type = string + description = "The guest operating system type, also know as guestid." + default = "" +} + +variable "vm_version" { + type = number + description = "The VM virtual hardware version." + # https://kb.vmware.com/s/article/1003746 +} + +variable "vm_firmware" { + type = string + description = "The virtual machine firmware. (e.g. 'bios' or 'efi')" + default = "" +} + +variable "vm_cdrom_type" { + type = string + description = "The virtual machine CD-ROM type." + default = "" +} + +variable "vm_cpu_sockets" { + type = number + description = "The number of virtual CPUs sockets." +} + +variable "vm_cpu_cores" { + type = number + description = "The number of virtual CPUs cores per socket." +} + +variable "vm_mem_size" { + type = number + description = "The size for the virtual memory in MB." +} + +variable "vm_disk_size" { + type = number + description = "The size for the virtual disk in MB." +} + +variable "thin_provision" { + type = bool + description = "Thin or Thick provisioning of the disk" +} + +variable "disk_eagerly_scrub" { + type = bool + description = "eagrly scrub zeros" + default = false +} + +variable "vm_disk_controller_type" { + type = list(string) + description = "The virtual disk controller types in sequence." +} + +variable "vm_network_card" { + type = string + description = "The virtual network card type." + default = "" +} + +variable "vm_boot_wait" { + type = string + description = "The time to wait before boot. " + default = "" +} + +variable "shell_scripts" { + type = list(string) + description = "A list of scripts." + default = [] +} +################################################################################## +# SOURCE +################################################################################## + +source "vsphere-iso" "edge-template" { + vcenter_server = var.vcenter_server + username = var.vcenter_username + password = var.vcenter_password + datacenter = var.vcenter_datacenter + datastore = var.vcenter_datastore + resource_pool = var.vcenter_resource_pool + host = var.vcenter_host + cluster = var.vcenter_cluster + folder = var.vcenter_folder + insecure_connection = var.vcenter_insecure_connection + remove_cdrom = true + convert_to_template = true + guest_os_type = var.vm_guest_os_type + vm_version = var.vm_version + vm_name = var.vm_name + firmware = var.vm_firmware + CPUs = var.vm_cpu_sockets + cpu_cores = var.vm_cpu_cores + CPU_hot_plug = false + RAM = var.vm_mem_size + RAM_hot_plug = false + cdrom_type = var.vm_cdrom_type + disk_controller_type = var.vm_disk_controller_type + + storage { + disk_size = var.vm_disk_size + disk_controller_index = 0 + disk_thin_provisioned = var.thin_provision + disk_eagerly_scrub = var.disk_eagerly_scrub + } + network_adapters { + network = var.vcenter_network + network_card = var.vm_network_card + } + disable_shutdown = true + shutdown_timeout = "10m" + communicator = "none" + iso_url = "${path.cwd}/${var.iso}" + iso_checksum = "file:file://${path.cwd}/${var.iso_checksum}" + boot_order = "disk,cdrom" + # ssh_username = "kairos" + # ssh_password = "kairos" + # ssh_timeout = "5m" + cd_files = ["${path.cwd}/meta-data", "${path.cwd}/user-data"] + cd_label = "cidata" +} + +################################################################################## +# BUILD +################################################################################## + +build { + sources = [ + "source.vsphere-iso.edge-template"] + # provisioner "shell" { + # scripts = ["scripts/wait.sh"] + # expect_disconnect = true + # skip_clean = true + # } +} diff --git a/edge/vmware/packer/meta-data b/edge/vmware/packer/meta-data new file mode 100644 index 0000000..e69de29 diff --git a/edge/vmware/packer/user-data b/edge/vmware/packer/user-data new file mode 100644 index 0000000..061a2e7 --- /dev/null +++ b/edge/vmware/packer/user-data @@ -0,0 +1,4 @@ +#cloud-config +# stylus: +# site: +# edgeHostToken: aUAxxxxxxxxx0ChYCrO \ No newline at end of file diff --git a/edge/vmware/packer/vsphere.hcl b/edge/vmware/packer/vsphere.hcl new file mode 100644 index 0000000..c2622b2 --- /dev/null +++ b/edge/vmware/packer/vsphere.hcl @@ -0,0 +1,25 @@ +# Virtual Machine Settings +########### DO NOT EDIT ################# +# VM Template Name +vm_name = "palette-edge-template" + +# VM Settings +vm_guest_os_type = "ubuntu64Guest" +vm_version = 14 +vm_firmware = "bios" +vm_cdrom_type = "sata" +vm_cpu_sockets = 4 +vm_cpu_cores = 1 +vm_mem_size = 8192 +vm_disk_size = 51200 +thin_provision = true +disk_eagerly_scrub = false +vm_disk_controller_type = ["pvscsi"] +vm_network_card = "vmxnet3" +vm_boot_wait = "5s" + + +# ISO Objects + +iso = "build/palette-edge-installer.iso" +iso_checksum = "build/palette-edge-installer.iso.sha256"