Skip to content

Commit

Permalink
Added an example to deploy all Edge3.0 components using EIB
Browse files Browse the repository at this point in the history
  • Loading branch information
e-minguez committed Apr 11, 2024
1 parent 8f9c290 commit 4ee350f
Show file tree
Hide file tree
Showing 22 changed files with 584 additions and 0 deletions.
34 changes: 34 additions & 0 deletions examples/edge-stack-iso/custom/files/basic-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash
# Pre-requisites. Cluster already running
export KUBECTL="/var/lib/rancher/rke2/bin/kubectl"
export KUBECONFIG="/etc/rancher/rke2/rke2.yaml"

##################
# METAL3 DETAILS #
##################
export METAL3_CHART_TARGETNAMESPACE="metal3-system"
export METAL3_CLUSTERCTLVERSION="1.6.2"
export METAL3_CAPICOREVERSION="1.6.0"
export METAL3_CAPIMETAL3VERSION="1.6.0"
export METAL3_CAPIRKE2VERSION="0.2.6"
export METAL3_CAPIPROVIDER="rke2"
export METAL3_CAPISYSTEMNAMESPACE="capi-system"
export METAL3_RKE2BOOTSTRAPNAMESPACE="rke2-bootstrap-system"
export METAL3_CAPM3NAMESPACE="capm3-system"
export METAL3_RKE2CONTROLPLANENAMESPACE="rke2-control-plane-system"

###########
# METALLB #
###########
export METALLBNAMESPACE="metallb-system"

###########
# RANCHER #
###########
export RANCHER_CHART_TARGETNAMESPACE="cattle-system"
export RANCHER_FINALPASSWORD="adminadminadmin"

die(){
echo ${1} 1>&2
exit ${2}
}
30 changes: 30 additions & 0 deletions examples/edge-stack-iso/custom/files/edge-stack-setup.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[Unit]
Description=Setup Edge stack components
Wants=network-online.target
# It requires rke2 or k3s running, but it won't fail if those services are not present
After=network.target network-online.target rke2-server.service k3s.service
# At least, the basic-setup.sh one needs to be present
ConditionPathExists=/opt/edge/bin/basic-setup.sh

[Service]
User=root
Type=forking
# Metal3 can take A LOT to download the IPA image
TimeoutStartSec=1800

ExecStartPre=/bin/sh -c "echo 'Setting up Edge components...'"
# Scripts are executed in StartPre because Start can only run a single on
ExecStartPre=/opt/edge/bin/rancher.sh
ExecStartPre=/opt/edge/bin/metal3.sh
ExecStart=/bin/sh -c "echo 'Finished setting up Edge components'"
RemainAfterExit=yes
KillMode=process
# Disable & delete everything
ExecStartPost=rm -f /opt/edge/bin/rancher.sh
ExecStartPost=rm -f /opt/edge/bin/metal3.sh
ExecStartPost=rm -f /opt/edge/bin/basic-setup.sh
ExecStartPost=/bin/sh -c "systemctl disable edge-stack-setup.service"
ExecStartPost=rm -f /etc/systemd/system/edge-stack-setup.service

[Install]
WantedBy=multi-user.target
126 changes: 126 additions & 0 deletions examples/edge-stack-iso/custom/files/metal3.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/bin/bash
set -euo pipefail

BASEDIR="$(dirname "$0")"
source ${BASEDIR}/basic-setup.sh

METAL3LOCKNAMESPACE="default"
METAL3LOCKCMNAME="metal3-lock"

# Get or create the lock to run all those steps just in a single node
# As the first node is created WAY before the others, this should be enough
# TODO: Investigate if leases is better
if [ $(${KUBECTL} get cm -n ${METAL3LOCKNAMESPACE} ${METAL3LOCKCMNAME} -o name | wc -l) -lt 1 ]; then
${KUBECTL} create configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE} --from-literal foo=bar
else
exit 0
fi

# Wait for metal3
while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CHART_TARGETNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CHART_TARGETNAMESPACE} -l app.kubernetes.io/name=metal3-ironic -o name) --timeout=10s; do sleep 2 ; done

# Get the ironic IP
IRONICIP=$(${KUBECTL} get cm -n ${METAL3_CHART_TARGETNAMESPACE} ironic-bmo -o jsonpath='{.data.IRONIC_IP}')

# Wait for metallb
while ! ${KUBECTL} wait --for condition=ready -n ${METALLBNAMESPACE} $(${KUBECTL} get pods -n ${METALLBNAMESPACE} -l app.kubernetes.io/component=controller -o name) --timeout=10s; do sleep 2 ; done

# Don't create the ippool if already created
${KUBECTL} get ipaddresspool -n ${METALLBNAMESPACE} ironic-ip-pool -o name || cat <<-EOF | ${KUBECTL} apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: ironic-ip-pool
namespace: ${METALLBNAMESPACE}
spec:
addresses:
- ${IRONICIP}/32
serviceAllocation:
priority: 100
serviceSelectors:
- matchExpressions:
- {key: app.kubernetes.io/name, operator: In, values: [metal3-ironic]}
EOF

# Same for L2 Advs
${KUBECTL} get L2Advertisement -n ${METALLBNAMESPACE} ironic-ip-pool-l2-adv -o name || cat <<-EOF | ${KUBECTL} apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: ironic-ip-pool-l2-adv
namespace: ${METALLBNAMESPACE}
spec:
ipAddressPools:
- ironic-ip-pool
EOF

# If clusterctl is not installed, install it
if ! command -v clusterctl > /dev/null 2>&1; then
LINUXARCH=$(uname -m)
case $(uname -m) in
"x86_64")
export GOARCH="amd64" ;;
"aarch64")
export GOARCH="arm64" ;;
"*")
echo "Arch not found, assuming amd64"
export GOARCH="amd64" ;;
esac

# Clusterctl bin
# Maybe just use the binary from hauler if available
curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v${METAL3_CLUSTERCTLVERSION}/clusterctl-linux-${GOARCH} -o /usr/local/bin/clusterctl
chmod +x /usr/local/bin/clusterctl
fi

# If rancher is deployed
if [ $(${KUBECTL} get pods -n ${RANCHER_CHART_TARGETNAMESPACE} -l app=rancher -o name | wc -l) -ge 1 ]; then
cat <<-EOF | ${KUBECTL} apply -f -
apiVersion: management.cattle.io/v3
kind: Feature
metadata:
name: embedded-cluster-api
spec:
value: false
EOF

# Disable Rancher webhooks for CAPI
${KUBECTL} delete mutatingwebhookconfiguration.admissionregistration.k8s.io mutating-webhook-configuration
${KUBECTL} delete validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration
${KUBECTL} wait --for=delete namespace/cattle-provisioning-capi-system --timeout=300s
fi

# Deploy CAPI
if [ $(${KUBECTL} get pods -n ${METAL3_CAPISYSTEMNAMESPACE} -o name | wc -l) -lt 1 ]; then

# https://github.com/rancher-sandbox/cluster-api-provider-rke2#setting-up-clusterctl
mkdir -p ~/.cluster-api
cat <<-EOF > ~/.cluster-api/clusterctl.yaml
images:
all:
repository: registry.opensuse.org/isv/suse/edge/clusterapi/containerfile/suse
EOF

clusterctl init \
--core "cluster-api:v${METAL3_CAPICOREVERSION}"\
--infrastructure "metal3:v${METAL3_CAPIMETAL3VERSION}"\
--bootstrap "${METAL3_CAPIPROVIDER}:v${METAL3_CAPIRKE2VERSION}"\
--control-plane "${METAL3_CAPIPROVIDER}:v${METAL3_CAPIRKE2VERSION}"

# Wait for capi-controller-manager
while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CAPISYSTEMNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CAPISYSTEMNAMESPACE} -l cluster.x-k8s.io/provider=cluster-api -o name) --timeout=10s; do sleep 2 ; done

# Wait for capm3-controller-manager, there are two pods, the ipam and the capm3 one, just wait for the first one
while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_CAPM3NAMESPACE} $(${KUBECTL} get pods -n ${METAL3_CAPM3NAMESPACE} -l cluster.x-k8s.io/provider=infrastructure-metal3 -o name | head -n1 ) --timeout=10s; do sleep 2 ; done

# Wait for rke2-bootstrap-controller-manager
while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_RKE2BOOTSTRAPNAMESPACE} $(${KUBECTL} get pods -n ${METAL3_RKE2BOOTSTRAPNAMESPACE} -l cluster.x-k8s.io/provider=bootstrap-rke2 -o name) --timeout=10s; do sleep 2 ; done

# Wait for rke2-control-plane-controller-manager
while ! ${KUBECTL} wait --for condition=ready -n ${METAL3_RKE2CONTROLPLANENAMESPACE} $(${KUBECTL} get pods -n ${METAL3_RKE2CONTROLPLANENAMESPACE} -l cluster.x-k8s.io/provider=control-plane-rke2 -o name) --timeout=10s; do sleep 2 ; done

fi

# Clean up the lock cm

${KUBECTL} delete configmap ${METAL3LOCKCMNAME} -n ${METAL3LOCKNAMESPACE}
53 changes: 53 additions & 0 deletions examples/edge-stack-iso/custom/files/rancher.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/bash
set -euo pipefail

BASEDIR="$(dirname "$0")"
source ${BASEDIR}/basic-setup.sh

RANCHERLOCKNAMESPACE="default"
RANCHERLOCKCMNAME="rancher-lock"

if [ -z "${RANCHER_FINALPASSWORD}" ]; then
# If there is no final password, then finish the setup right away
exit 0
fi

# Get or create the lock to run all those steps just in a single node
# As the first node is created WAY before the others, this should be enough
# TODO: Investigate if leases is better
if [ $(${KUBECTL} get cm -n ${RANCHERLOCKNAMESPACE} ${RANCHERLOCKCMNAME} -o name | wc -l) -lt 1 ]; then
${KUBECTL} create configmap ${RANCHERLOCKCMNAME} -n ${RANCHERLOCKNAMESPACE} --from-literal foo=bar
else
exit 0
fi

# Wait for rancher to be deployed
while ! ${KUBECTL} wait --for condition=ready -n ${RANCHER_CHART_TARGETNAMESPACE} $(${KUBECTL} get pods -n ${RANCHER_CHART_TARGETNAMESPACE} -l app=rancher -o name) --timeout=10s; do sleep 2 ; done
until ${KUBECTL} get ingress -n ${RANCHER_CHART_TARGETNAMESPACE} rancher > /dev/null 2>&1; do sleep 10; done

RANCHERBOOTSTRAPPASSWORD=$(${KUBECTL} get secret -n ${RANCHER_CHART_TARGETNAMESPACE} bootstrap-secret -o jsonpath='{.data.bootstrapPassword}' | base64 -d)
RANCHERHOSTNAME=$(${KUBECTL} get ingress -n ${RANCHER_CHART_TARGETNAMESPACE} rancher -o jsonpath='{.spec.rules[0].host}')

# Skip the whole process if things have been set already
if [ -z $(${KUBECTL} get settings.management.cattle.io first-login -ojsonpath='{.value}') ]; then
# Add the protocol
RANCHERHOSTNAME="https://${RANCHERHOSTNAME}"
TOKEN=""
while [ -z "${TOKEN}" ]; do
# Get token
sleep 2
TOKEN=$(curl -sk -X POST ${RANCHERHOSTNAME}/v3-public/localProviders/local?action=login -H 'content-type: application/json' -d "{\"username\":\"admin\",\"password\":\"${RANCHERBOOTSTRAPPASSWORD}\"}" | jq -r .token)
done

# Set password
curl -sk ${RANCHERHOSTNAME}/v3/users?action=changepassword -H 'content-type: application/json' -H "Authorization: Bearer $TOKEN" -d "{\"currentPassword\":\"${RANCHERBOOTSTRAPPASSWORD}\",\"newPassword\":\"${RANCHER_FINALPASSWORD}\"}"

# Create a temporary API token (ttl=60 minutes)
APITOKEN=$(curl -sk ${RANCHERHOSTNAME}/v3/token -H 'content-type: application/json' -H "Authorization: Bearer ${TOKEN}" -d '{"type":"token","description":"automation","ttl":3600000}' | jq -r .token)

curl -sk ${RANCHERHOSTNAME}/v3/settings/server-url -H 'content-type: application/json' -H "Authorization: Bearer ${APITOKEN}" -X PUT -d "{\"name\":\"server-url\",\"value\":\"${RANCHERHOSTNAME}\"}"
curl -sk ${RANCHERHOSTNAME}/v3/settings/telemetry-opt -X PUT -H 'content-type: application/json' -H 'accept: application/json' -H "Authorization: Bearer ${APITOKEN}" -d '{"value":"out"}'
fi

# Clean up the lock cm
${KUBECTL} delete configmap ${RANCHERLOCKCMNAME} -n ${RANCHERLOCKNAMESPACE}
4 changes: 4 additions & 0 deletions examples/edge-stack-iso/custom/scripts/99-alias.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
echo "alias k=kubectl" >> /etc/profile.local
echo "alias kubectl=/var/lib/rancher/rke2/bin/kubectl" >> /etc/profile.local
echo "export KUBECONFIG=/etc/rancher/rke2/rke2.yaml" >> /etc/profile.local
11 changes: 11 additions & 0 deletions examples/edge-stack-iso/custom/scripts/99-edge-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

# Copy the scripts from combustion to the final location
mkdir -p /opt/edge/bin/
for script in basic-setup.sh rancher.sh metal3.sh; do
cp ${script} /opt/edge/bin/
done

# Copy the systemd unit file and enable it at boot
cp edge-stack-setup.service /etc/systemd/system/edge-stack-setup.service
systemctl enable edge-stack-setup.service
8 changes: 8 additions & 0 deletions examples/edge-stack-iso/custom/scripts/99-register.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
set -euo pipefail

# Registration https://www.suse.com/support/kb/doc/?id=000018564
if ! which SUSEConnect > /dev/null 2>&1; then
zypper --non-interactive install suseconnect-ng
fi
SUSEConnect --email "<EMAIL>" --url "https://scc.suse.com" --regcode "<REGCODE>"
Loading

0 comments on commit 4ee350f

Please sign in to comment.