Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upi/vsphere: multiple terraform updates #1518

Merged
merged 4 commits into from
Apr 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 18 additions & 26 deletions upi/vsphere/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,31 @@ sshKey: YOUR_SSH_KEY
2. Run `openshift-install create ignition-configs`.

3. Fill out a terraform.tfvars file with the ignition configs generated.
There is an example terraform.tfvars file in this directory named terraform.tfvars.example. The example file is set up for use with the dev cluster running at vcsa.vmware.devcluster.openshift.com. At a minimum, you need to set values for `cluster_id`, `cluster_domain`, `vsphere_user`, `vsphere_password`, `bootstrap_ignition_url`, `control_plane_ignition`, and `compute_ignition`.
There is an example terraform.tfvars file in this directory named terraform.tfvars.example. The example file is set up for use with the dev cluster running at vcsa.vmware.devcluster.openshift.com. At a minimum, you need to set values for the following variables.
* cluster_id
* cluster_domain
* vsphere_user
* vsphere_password
* ipam_token
* bootstrap_ignition_url
* control_plane_ignition
* compute_ignition
The bootstrap ignition config must be placed in a location that will be accessible by the bootstrap machine. For example, you could store the bootstrap ignition config in a gist.
Initially, the `bootstrap_complete` variable must be false, the `bootstrap_ip` variable must be an empty string, and the `control_plane_ips variable must be an empty list.

4. Run `terraform init`.

5. Run `terraform apply -auto-approve`.
5. Ensure that you have you AWS profile set and a region specified. The installation will use create AWS route53 resources for routing to the OpenShift cluster.

6. Find the IP address of the bootstrap machine.
If you provided an extra user, you can use that user to log into the bootstrap machine via the vSphere web console.
Alternatively, you could iterate through the IP addresses in the 139.178.89.192/26 block looking for one that has the expected hostname, which is bootstrap-0.{cluster_domain}. For example, `ssh -i ~/.ssh/libra.pem -o StrictHostNameChecking=no -q core@139.178.89.199 hostname`
6. Run `terraform apply -auto-approve`.
This will create the OpenShift cluster

7. Update the terraform.tfvars file with the IP address of the bootstrap machine.
7. Run `openshift-install upi bootstrap-complete`. Wait for the bootstrapping to complete.

8. Run `terraform apply -auto-approve`.
From this point forward, route53 resources will be managed by terraform. You will need to have your AWS profile set and a region specified.
8. Run `terraform apply -auto-approve -var 'bootstrap_complete=true'`.
This will destroy the bootstrap VM.

9. Find the IP addresses of the control plane machines. See step 6 for examples of how to do this. The expected hostnames are control-plane-{0,1,2}.{cluster_domain}. The control plane machines will change their IP addresses once. You need the final IP addresses. If you happen to use the first set of IP addresses, you can later update the IP addresses in the terraform.tfvars file and re-run terraform.
9. Run `openshift-install upi finish`. Wait for the cluster install to finish.

10. Update the terraform.tfvars file with the IP addresses of the control plane machines.
10. Enjoy your new OpenShift cluster.

11. Run `terraform apply -auto-approve`.

12. Run `openshift-install user-provided-infrastructure`. Wait for the bootstrapping to complete.
You *may* need to log into each of the control plane machines. It would seem that, for some reason, the etcd-member pod does not start until the machine is logged into.

13. Update the terraform.tfvars file to set the `bootstrap_complete` variable to "true".

14. Run `terraform apply -auto-approve`.

15. Run `openshift-install user-provided-infrastructure finish`. Wait for the cluster install to finish.
Currently, the cluster install does not finish. There is an outstanding issue with the openshift-console operator not installing successfully. The cluster should still be usable save for the console, however.

16. Enjoy your new OpenShift cluster.

17. Run `terraform destroy -auto-approve`.
11. Run `terraform destroy -auto-approve`.
59 changes: 59 additions & 0 deletions upi/vsphere/machine/cidr_to_ip.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash
# cidr_to_ip -
# https://www.terraform.io/docs/providers/external/data_source.html
# Based on info from here: https://gist.github.com/irvingpop/968464132ded25a206ced835d50afa6b
# This script takes requests an IP address from an IPAM server
# echo '{"cidr": "139.178.89.192/26", "hostname": "control-plane-0.dphillip.devcluster.openshift.com", "ipam": "ipam_address", "ipam_token", "api_token" }' | ./cidr_to_ip.sh
function error_exit() {
echo "$1" 1>&2
exit 1
}

function check_deps() {
test -f "$(command -v jq)" || error_exit "jq command not detected in path, please install it"
test -f "$(command -v ipcalc)" || error_exit "ipcalc command not detected in path, please install it"

}

function parse_input() {
# jq reads from stdin so we don't have to set up any inputs, but let's validate the outputs
eval "$(jq -r '@sh "export CIDR=\(.cidr) hostname=\(.hostname) ipam=\(.ipam) ipam_token=\(.ipam_token)"')"
if [[ -z "${CIDR}" ]]; then export CIDR=none; fi
if [[ -z "${hostname}" ]]; then export hostname=none; fi
if [[ -z "${ipam}" ]]; then export ipam=none; fi
if [[ -z "${ipam_token}" ]]; then export ipam_token=none; fi
}

function produce_output() {
cidr=$CIDR

# Build the curl and run it
lo=$(ipcalc -n $cidr | cut -f2 -d=)

# Request an IP address. Verify that the IP address reserved matches the IP
# address returned. Loop until the reservation matches the address returned.
# The verification and looping is a crude way of overcoming the lack of
# currency safety in the IPAM server.
while true
do
ip_address=$(curl -s "http://$ipam/api/getFreeIP.php?apiapp=address&apitoken=$ipam_token&subnet=$lo&host=${hostname}")

if ! [[ $ip_address =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then error_exit "could not reserve an IP address: ${ip_address}"; fi

reserved_ip=$(curl -s "http://$ipam/api/getIPs.php?apiapp=address&apitoken=$ipam_token&domain=${hostname}" | \
jq -r ".\"${hostname}\"")

if [[ "$ip_address" == "$reserved_ip" ]]
then
jq -n \
--arg ip_address "$ip_address" \
'{"ip_address":$ip_address}'
exit 0
fi
done
}

# main()
check_deps
parse_input
produce_output
73 changes: 69 additions & 4 deletions upi/vsphere/machine/main.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
locals {
mask = "${element(split("/", var.machine_cidr), 1)}"
gw = "${cidrhost(var.machine_cidr,1)}"

ignition_encoded = "data:text/plain;charset=utf-8;base64,${base64encode(var.ignition)}"
}

Expand All @@ -17,6 +20,19 @@ data "vsphere_virtual_machine" "template" {
datacenter_id = "${var.datacenter_id}"
}

data "external" "ip_address" {
count = "${var.instance_count}"

program = ["bash", "${path.module}/cidr_to_ip.sh"]

query = {
cidr = "${var.machine_cidr}"
hostname = "${var.name}-${count.index}.${var.cluster_domain}"
ipam = "${var.ipam}"
ipam_token = "${var.ipam_token}"
}
}

data "ignition_file" "hostname" {
count = "${var.instance_count}"

Expand All @@ -29,6 +45,44 @@ data "ignition_file" "hostname" {
}
}

data "ignition_file" "static_ip" {
count = "${var.instance_count}"

filesystem = "root"
path = "/etc/sysconfig/network-scripts/ifcfg-eth0"
mode = "420"

content {
content = <<EOF
TYPE=Ethernet
BOOTPROTO=none
NAME=eth0
DEVICE=eth0
ONBOOT=yes
IPADDR=${data.external.ip_address.*.result.ip_address[count.index]}
PREFIX=${local.mask}
GATEWAY=${local.gw}
DNS1=8.8.8.8
EOF
}
}

data "ignition_systemd_unit" "restart" {
count = "${var.instance_count}"

name = "restart.service"

content = <<EOF
[Unit]
ConditionFirstBoot=yes
[Service]
Type=idle
ExecStart=/sbin/reboot
[Install]
WantedBy=multi-user.target
EOF
}

data "ignition_user" "extra_users" {
count = "${length(var.extra_user_names)}"

Expand All @@ -43,8 +97,13 @@ data "ignition_config" "ign" {
source = "${var.ignition_url != "" ? var.ignition_url : local.ignition_encoded}"
}

systemd = [
"${data.ignition_systemd_unit.restart.*.id[count.index]}",
]

files = [
"${data.ignition_file.hostname.*.id[count.index]}",
"${data.ignition_file.static_ip.*.id[count.index]}",
]

users = ["${data.ignition_user.extra_users.*.id}"]
Expand All @@ -62,9 +121,6 @@ resource "vsphere_virtual_machine" "vm" {
folder = "${var.folder}"
enable_disk_uuid = "true"

wait_for_guest_net_timeout = 0
wait_for_guest_net_routable = false

network_interface {
network_id = "${data.vsphere_network.network.id}"
}
Expand All @@ -81,7 +137,16 @@ resource "vsphere_virtual_machine" "vm" {

vapp {
properties {
"guestinfo.coreos.config.data" = "${data.ignition_config.ign.*.rendered[count.index]}"
"guestinfo.ignition.config.data" = "${base64encode(data.ignition_config.ign.*.rendered[count.index])}"
"guestinfo.ignition.config.data.encoding" = "base64"
}
}

provisioner "local-exec" {
when = "destroy"

command = <<EOF
curl "http://${var.ipam}/api/removeHost.php?apiapp=address&apitoken=${var.ipam_token}&host=${var.name}-${count.index}.${var.cluster_domain}"
EOF
}
}
3 changes: 3 additions & 0 deletions upi/vsphere/machine/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "ip_addresses" {
value = "${data.external.ip_address.*.result.ip_address}"
}
12 changes: 12 additions & 0 deletions upi/vsphere/machine/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,15 @@ variable "datacenter_id" {
variable "template" {
type = "string"
}

variable "ipam" {
type = "string"
}

variable "ipam_token" {
type = "string"
}

variable "machine_cidr" {
type = "string"
}
32 changes: 21 additions & 11 deletions upi/vsphere/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ data "vsphere_datacenter" "dc" {
name = "${var.vsphere_datacenter}"
}

module "folder" {
source = "./folder"

path = "${var.cluster_id}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

module "resource_pool" {
source = "./resource_pool"

Expand All @@ -17,13 +24,6 @@ module "resource_pool" {
vsphere_cluster = "${var.vsphere_cluster}"
}

module "folder" {
source = "./folder"

path = "${var.cluster_id}"
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}

module "bootstrap" {
source = "./machine"

Expand All @@ -37,6 +37,9 @@ module "bootstrap" {
datacenter_id = "${data.vsphere_datacenter.dc.id}"
template = "${var.vm_template}"
cluster_domain = "${var.cluster_domain}"
ipam = "${var.ipam}"
ipam_token = "${var.ipam_token}"
machine_cidr = "${var.machine_cidr}"

extra_user_names = ["${var.extra_user_names}"]
extra_user_password_hashes = ["${var.extra_user_password_hashes}"]
Expand All @@ -46,7 +49,7 @@ module "control_plane" {
source = "./machine"

name = "control-plane"
instance_count = "${var.control_plane_instance_count}"
instance_count = "${var.control_plane_count}"
ignition = "${var.control_plane_ignition}"
resource_pool_id = "${module.resource_pool.pool_id}"
folder = "${module.folder.path}"
Expand All @@ -55,6 +58,9 @@ module "control_plane" {
datacenter_id = "${data.vsphere_datacenter.dc.id}"
template = "${var.vm_template}"
cluster_domain = "${var.cluster_domain}"
ipam = "${var.ipam}"
ipam_token = "${var.ipam_token}"
machine_cidr = "${var.machine_cidr}"

extra_user_names = ["${var.extra_user_names}"]
extra_user_password_hashes = ["${var.extra_user_password_hashes}"]
Expand All @@ -64,7 +70,7 @@ module "compute" {
source = "./machine"

name = "compute"
instance_count = "${var.compute_instance_count}"
instance_count = "${var.compute_count}"
ignition = "${var.compute_ignition}"
resource_pool_id = "${module.resource_pool.pool_id}"
folder = "${module.folder.path}"
Expand All @@ -73,6 +79,9 @@ module "compute" {
datacenter_id = "${data.vsphere_datacenter.dc.id}"
template = "${var.vm_template}"
cluster_domain = "${var.cluster_domain}"
ipam = "${var.ipam}"
ipam_token = "${var.ipam_token}"
machine_cidr = "${var.machine_cidr}"

extra_user_names = ["${var.extra_user_names}"]
extra_user_password_hashes = ["${var.extra_user_password_hashes}"]
Expand All @@ -83,6 +92,7 @@ module "dns" {

base_domain = "${var.base_domain}"
cluster_domain = "${var.cluster_domain}"
bootstrap_ip = "${var.bootstrap_complete ? "" : var.bootstrap_ip}"
control_plane_ips = "${var.control_plane_ips}"
bootstrap_ips = ["${module.bootstrap.ip_addresses}"]
control_plane_ips = ["${module.control_plane.ip_addresses}"]
compute_ips = ["${module.compute.ip_addresses}"]
}
Loading