Red Hat’s provided SaaS portal to deploy an OCP cluster either on baremetal or virtual machines.
In this article however I want to demonstrate a Single Node OpenShift deployment without using the UI web interface and instead rely on the underlying REST API that drives the Assisted Installer. This can be useful for automating the deployment of clusters without user intervention.
The first step to achieve this will be to obtain an OpenShift Cluster Manager API Token. This token provides the ability to authenticate against your Red Hat OpenShift Cluster Manager account without the need of a username or password.
Place this token into a file called ocm-token:
$ echo "Token String From OCM API Token Link Above" > ~/ocm-token
export OFFLINE_ACCESS_TOKEN=$(cat ~/ocm-token) # Loading my token into a variable export ASSISTED_SERVICE_API="api.openshift.com" # Setting the Assisted Installer API endpoint export CLUSTER_VERSION="4.8" # OpenShift version export CLUSTER_IMAGE="quay.io/openshift-release-dev/ocp-release:4.8.2-x86_64" # OpenShift Quay image version export CLUSTER_NAME="kni1" # OpenShift cluster name export CLUSTER_DOMAIN="schmaustech.com" # Domain name where my cluster will be deployed export CLUSTER_NET_TYPE="OVNKubernetes" # Network type to deploy with OpenShift export MACHINE_CIDR_NET="192.168.0.0/24" # Machine CIDR network export SNO_STATICIP_NODE_NAME="master-0" # Node name of my SNO node export PULL_SECRET=$(cat ~/pull-secret.json | jq -R .) # Loading my pull-secret into variable export CLUSTER_SSHKEY=$(cat ~/.ssh/id_rsa.pub) # Loading the public key into variable
cat << EOF > ~/deployment.json
{
"kind": "Cluster",
"name": "$CLUSTER_NAME",
"openshift_version": "$CLUSTER_VERSION",
"ocp_release_image": "$CLUSTER_IMAGE",
"base_dns_domain": "$CLUSTER_DOMAIN",
"hyperthreading": "all",
"user_managed_networking": true,
"vip_dhcp_allocation": false,
"high_availability_mode": "None",
"hosts": [],
"ssh_public_key": "$CLUSTER_SSHKEY",
"pull_secret": $PULL_SECRET,
"network_type": "OVNKubernetes"
}
EOF
$ export TOKEN=$(curl \
--silent \
--data-urlencode "grant_type=refresh_token" \
--data-urlencode "client_id=cloud-services" \
--data-urlencode "refresh_token=${OFFLINE_ACCESS_TOKEN}" \
https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token | \
jq -r .access_token)
$ export CLUSTER_ID=$( curl -s -X POST "https://$ASSISTED_SERVICE_API/api/assisted-install/v1/clusters" \ -d @./deployment.json \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ | jq '.id' ) $ export CLUSTER_ID=$( sed -e 's/^"//' -e 's/"$//' <<<"$CLUSTER_ID")
$ echo $CLUSTER_ID e85fc7d5-f274-4359-acc5-48044fc67132
$ DATA=$(mktemp)
$ jq -n --arg SSH_KEY "$CLUSTER_SSHKEY" --arg NMSTATE_YAML1 "$(cat ~/sno-server.yaml)" \
'{
"ssh_public_key": $SSH_KEY,
"image_type": "full-iso",
"static_network_config": [
{
"network_yaml": $NMSTATE_YAML1,
"mac_interface_map": [{"mac_address": "52:54:00:82:23:e2", "logical_nic_name": "ens9"}]
}
]
}' >> $DATA
$ cat ~/sno-server.yaml
dns-resolver:
config:
server:
- 192.168.0.10
interfaces:
- ipv4:
address:
- ip: 192.168.0.204
prefix-length: 24
dhcp: false
enabled: true
name: ens9
state: up
type: ethernet
routes:
config:
- destination: 0.0.0.0/0
next-hop-address: 192.168.0.1
next-hop-interface: ens9
table-id: 254
$ echo $DATA
/tmp/tmp.3Jqw7lU6Qf
$ cat /tmp/tmp.3Jqw7lU6Qf
{
"ssh_public_key": "SSHKEY REDACTED",
"image_type": "full-iso",
"static_network_config": [
{
"network_yaml": "dns-resolver:\n config:\n server:\n - 192.168.0.10\ninterfaces:\n- ipv4:\n address:\n - ip: 192.168.0.204\n prefix-length: 24\n dhcp: false\n enabled: true\n name: ens9\n state: up\n type: ethernet\nroutes:\n config:\n - destination: 0.0.0.0/0\n next-hop-address: 192.168.0.1\n next-hop-interface: ens9\n table-id: 254",
"mac_interface_map": [
{
"mac_address": "52:54:00:82:23:e2",
"logical_nic_name": "ens9"
}
]
}
]
}
$ curl -X POST \ "https://$ASSISTED_SERVICE_API/api/assisted-install/v1/clusters/$CLUSTER_ID/downloads/image" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d @$DATA
(...) "static_network_config":"dns-resolver:\n config:\n server:\n - 192.168.0.10\ninterfaces:\n- ipv4:\n address:\n - ip: 192.168.0.204\n prefix-length: 24\n dhcp: false\n enabled: true\n name: ens9\n state: up\n type: ethernet\nroutes:\n config:\n - destination: 0.0.0.0/0\n next-hop-address: 192.168.0.1\n next-hop-interface: ens9\n table-id: 254HHHHH52:54:00:82:23:e2=ens9","type":"full-iso"} (...)
$ curl -L \
"http://$ASSISTED_SERVICE_API/api/assisted-install/v1/clusters/$CLUSTER_ID/downloads/image" \
-o ~/discovery-image-$CLUSTER_NAME.iso \
-H "Authorization: Bearer $TOKEN"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 984M 100 984M 0 0 10.4M 0 0:01:34 0:01:34 --:--:-- 10.5M
$ scp ~/discovery-image-kni1.iso root@192.168.0.5:/slowdata/images/ $ /usr/bin/ipmitool -I lanplus -H192.168.0.10 -p6252 -Uadmin -Ppassword chassis power off $ ssh root@192.168.0.5 "virsh change-media rhacm-master-0 hda /slowdata/images/discovery-image-kni1.iso" $ ssh root@192.168.0.5 "virt-format --format=raw --partition=none -a /fastdata2/images/master-0.img" $ /usr/bin/ipmitool -I lanplus -H192.168.0.10 -p6252 -Uadmin -Ppassword chassis power on $ sleep 300
$ curl -X PATCH \
"https://$ASSISTED_SERVICE_API/api/assisted-install/v1/clusters/$CLUSTER_ID" \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{ \"requested_hostname\": \"$SNO_STATICIP_NODE_NAME.$CLUSTER_NAME.$CLUSTER_DOMAIN\"}" | jq
(...) "requested_hostname": "master-0.kni1.schmaustech.com", (...)
$ curl -X PATCH \
"https://$ASSISTED_SERVICE_API/api/assisted-install/v1/clusters/$CLUSTER_ID" \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{ \"machine_network_cidr\": \"$MACHINE_CIDR_NET\"}" | jq
(...) "machine_network_cidr": "192.168.0.0/24", (...)
$ curl -X POST \ "https://$ASSISTED_SERVICE_API/api/assisted-install/v1/clusters/$CLUSTER_ID/actions/install" \ -H "accept: application/json" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" | jq
(...) "status": "preparing-for-installation", "status_info": "Preparing cluster for installation", "status_updated_at": "2021-08-06T20:56:17.565Z", (...)
$ export TOKEN=$(curl \
--silent \
--data-urlencode "grant_type=refresh_token" \
--data-urlencode "client_id=cloud-services" \
--data-urlencode "refresh_token=${OFFLINE_ACCESS_TOKEN}" \
https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token | \
jq -r .access_token)
$ curl -s -X GET \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ "https://$ASSISTED_SERVICE_API/api/assisted-install/v1/clusters/$CLUSTER_ID" | jq . (...) "status": "installed", "status_info": "Cluster is installed", "status_updated_at": "2021-08-06T21:45:04.375Z", (...)
$ curl -s -X GET \ "https://$ASSISTED_SERVICE_API/api/assisted-install/v1/clusters/$CLUSTER_ID/downloads/kubeconfig" > kubeconfig-kni1 \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN"
$ export KUBECONFIG=~/kubeconfig-kni1 $ oc get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME master-0.kni1.schmaustech.com Ready master,worker 156m v1.21.1+051ac4f 192.168.0.204 none Red Hat Enterprise Linux CoreOS 48.84.202107202156-0 (Ootpa) 4.18.0-305.10.2.el8_4.x86_64 cri-o://1.21.2-5.rhaos4.8.gitb27d974.el8 $ oc get co NAME VERSION AVAILABLE PROGRESSING DEGRADED SINCE authentication 4.8.2 True False False 134m baremetal 4.8.2 True False False 144m cloud-credential 4.8.2 True False False 147m cluster-autoscaler 4.8.2 True False False 146m config-operator 4.8.2 True False False 151m console 4.8.2 True False False 135m csi-snapshot-controller 4.8.2 True False False 147m dns 4.8.2 True False False 144m etcd 4.8.2 True False False 146m image-registry 4.8.2 True False False 141m ingress 4.8.2 True False False 141m insights 4.8.2 True False False 135m kube-apiserver 4.8.2 True False False 143m kube-controller-manager 4.8.2 True False False 143m kube-scheduler 4.8.2 True False False 143m kube-storage-version-migrator 4.8.2 True False False 151m machine-api 4.8.2 True False False 146m machine-approver 4.8.2 True False False 147m machine-config 4.8.2 True False False 143m marketplace 4.8.2 True False False 144m monitoring 4.8.2 True False False 138m network 4.8.2 True False False 152m node-tuning 4.8.2 True False False 146m openshift-apiserver 4.8.2 True False False 143m openshift-controller-manager 4.8.2 True False False 146m openshift-samples 4.8.2 True False False 142m operator-lifecycle-manager 4.8.2 True False False 144m operator-lifecycle-manager-catalog 4.8.2 True False False 147m operator-lifecycle-manager-packageserver 4.8.2 True False False 144m service-ca 4.8.2 True False False 151m storage 4.8.2 True False False 146m



