|
1 | 1 | # Deploy a VM with vAppConfig
|
2 | 2 |
|
3 |
| -// TODO ([github.com/vmware-tanzu/vm-operator#123](https://github.com/vmware-tanzu/vm-operator/issues/123)) |
| 3 | +This page reviews the bootstrap method vAppConfig. |
| 4 | + |
| 5 | +## Description |
| 6 | +The vAppConfig bootstrap method is useful for legacy VM images that rely on bespoke, boot-time processes that leverage vAppConfig properties for customizing a guest. |
| 7 | + |
| 8 | +## Purpose |
| 9 | +As a DevOps user, you can assign Golang-based template strings to vAppConfig values to send information into the guest that is not known ahead of time, such as the IPAM data settings used to configure the VM's network stack. |
| 10 | + |
| 11 | +## Example |
| 12 | +=== "VirtualMachine" |
| 13 | + |
| 14 | + ```yaml |
| 15 | + apiVersion: vmoperator.vmware.com/v1alpha1 |
| 16 | + kind: VirtualMachine |
| 17 | + metadata: |
| 18 | + name: legacy-vm |
| 19 | + namespace: test-ns |
| 20 | + spec: |
| 21 | + className: best-effort-small |
| 22 | + imageName: haproxy-v0.2.0 |
| 23 | + powerState: poweredOn |
| 24 | + storageClass: wcpglobal-storage-profile |
| 25 | + vmMetadata: |
| 26 | + secretName: my-secret |
| 27 | + transport: vAppConfig |
| 28 | + ``` |
| 29 | + |
| 30 | +=== "vAppConfig" |
| 31 | + |
| 32 | + ```yaml |
| 33 | + apiVersion: v1 |
| 34 | + kind: Secret |
| 35 | + metadata: |
| 36 | + name: my-secret |
| 37 | + namespace: test-ns |
| 38 | + stringData: |
| 39 | + nameservers: "{{ (index .V1alpha1.Net.Nameservers 0) }}" |
| 40 | + management_ip: "{{ (index (index .V1alpha1.Net.Devices 0).IPAddresses 0) }}" |
| 41 | + hostname: "{{ .V1alpha1.VM.Name }} " |
| 42 | + management_gateway: "{{ (index .V1alpha1.Net.Devices 0).Gateway4 }}" |
| 43 | + ``` |
| 44 | + |
| 45 | +=== "vAppConfig with supporting template" |
| 46 | + |
| 47 | + ```yaml |
| 48 | + apiVersion: v1 |
| 49 | + kind: Secret |
| 50 | + metadata: |
| 51 | + name: my-secret |
| 52 | + namespace: test-ns |
| 53 | + stringData: |
| 54 | + # see more details on below Supporting Template Queries section |
| 55 | + nameservers: "{{ V1alpha1_FormatNameservers 2 \",\" }}" |
| 56 | + management_ip: "{{ V1alpha1_FormatIP \"192.168.1.10\" \"255.255.255.0\" }}" |
| 57 | + hostname: "{{ .V1alpha1.VM.Name }} " |
| 58 | + management_gateway: "{{ (index .V1alpha1.Net.Devices 0).Gateway4 }}" |
| 59 | + ``` |
| 60 | + |
| 61 | +:wave: The Golang based template string is a representation of [vm-operator virtualmachinetempl_types v1alpha1 api](https://github.com/vmware-tanzu/vm-operator/blob/25fb865e615d377192a870583ab32973e9fbd32a/api/v1alpha1/virtualmachinetempl_types.go#L4) |
| 62 | + |
| 63 | +:wave: The fields `nameservers`, `hostname`, `management_ip` and `management_gateway` are derived from image `haproxy-v0.2.0` OVF properties. |
| 64 | +```xml |
| 65 | +<Property ovf:key="nameservers" ovf:type="string" ovf:userConfigurable="true" ovf:value="1.1.1.1, 1.0.0.1"> |
| 66 | + <Label>2.2. DNS</Label> |
| 67 | + <Description>A comma-separated list of IP addresses for up to three DNS servers</Description> |
| 68 | +</Property> |
| 69 | +<Property ovf:key="hostname" ovf:type="string" ovf:userConfigurable="true" ovf:value="ubuntuguest"> |
| 70 | + <Description>Specifies the hostname for the appliance</Description> |
| 71 | +</Property> |
| 72 | +<Property ovf:key="management_ip" ovf:type="string" ovf:userConfigurable="true"> |
| 73 | + <Label>2.3. Management IP</Label> |
| 74 | + <Description>The static IP address for the appliance on the Management Port Group in CIDR format (.For eg. ip/subnet mask bits). This cannot be DHCP.</Description> |
| 75 | +</Property> |
| 76 | +``` |
| 77 | + |
| 78 | +## Supporting Template Queries |
| 79 | +To spare users the effort to construct a correct template string, there are some supporting template queries vm-operator provides. |
| 80 | + |
| 81 | +| Query name | Signature | Description | |
| 82 | +| -------- | -------- | -------- | |
| 83 | +| V1alpha1_FirstIP | `func () string` | Get the first non-loopback IP with CIDR from first NIC. | |
| 84 | +| V1alpha1_FirstIPFromNIC | `func (index int) string` | Get non-loopback IP address with CIDR from the ith NIC. if index out of bound, template string won't be parsed. | |
| 85 | +| V1alpha1_FormatIP | `func (IP string, netmask string) string` | see below for detailed use case.| |
| 86 | +| V1alpha1_FirstNicMacAddr | `func() (string, error)` | Get the first NIC's MAC address. | |
| 87 | +| V1alpha1_FormatNameservers| `func (count int, delimiter string) string` | Format the first occurred count of nameservers with specific delimiter (A n.For egative number for count would mean all nameservers). | |
| 88 | +| V1alpha1_IP | `func(IP string) string` | Format a static IP address with default netmask CIDR. If IP is not valid, template string won't be parsed. | |
| 89 | +| V1alpha1_IPsFromNIC | `func (index int) []string` | List all IPs with CIDR from the ith NIC. if index out of bound, template string won't be parsed. | |
| 90 | +| V1alpha1_SubnetMask | `func(cidr string) (string, error)` | Get subnet mask from a CIDR notation IP address and prefix length. | |
| 91 | + |
| 92 | +### `V1alpha1_FormatIP` |
| 93 | +1. Format an IP address with network length. A netmask can be either the length, ex. /24, or the decimal notation, ex. 255.255.255.0. Return IP sans CIDR when input is valid. |
| 94 | + |
| 95 | +2. Format an IP address with CIDR: |
| 96 | + - if input netmask is different with CIDR, replace and return IP with new CIDR. |
| 97 | + - if input netmask is empty string, return IP sans CIDR. |
| 98 | + - if input netmask is not valid, return empty string. |
| 99 | + |
| 100 | +**Note** when OVF only takes in IP sans CIDR, use `V1alpha1_FormatIP` and pass empty string as input netmask: |
| 101 | +```yaml |
| 102 | +management_ip: '{{ V1alpha1_FormatIP V1alpha1_FirstIP "" }}' # return first non-loopback IP from first NIC without CIDR. For eg, "192.168.1.10". |
| 103 | +``` |
| 104 | +
|
| 105 | +### Examples |
| 106 | +```yaml |
| 107 | + management_ip: "{{ V1alpha1_FirstIP }}" # return first non-loopback IP with CIDR from first NIC. |
| 108 | + management_ip: "{{ V1alpha1_FirstIPFromNIC 1 }}" # return first non-loopback IP with CIDR from second NIC. |
| 109 | + management_ip: "{{ V1alpha1_FormatIP \"192.168.1.10\" \"255.255.255.0\" }}" # return IP with CIDR. For eg,"192.168.1.10/24". |
| 110 | + management_ip: "{{ V1alpha1_IP \"192.168.1.37\" }}" # return IP with default netmask CIDR. |
| 111 | + nameservers: "{{ V1alpha1_FormatNameservers 2 \",\" }}" # return 2 nameservers with "," as delimiter. For eg,"10.20.145.1, 10.20.145.2". |
| 112 | + subnet_mask: "{{ V1alpha1_SubnetMask V1alpha1_FirstIP }}" # return the subnet mask of the first non-loopback IP with CIDR from first NIC. For eg, "255.255.255.0". |
| 113 | + mac_address: "{{ v1alpha1_FirstNicMacAddr }}" # return the first NIC's MAC Address. |
| 114 | +``` |
| 115 | +
|
0 commit comments