Skip to content

Commit

Permalink
Feature/Initialize the solution (#1)
Browse files Browse the repository at this point in the history
* Add LICENCE, editorconfig, CODEOWNERS

* Add first scripts

* Reworked the scripts

* Add sample (to be improved)

* Add download script

* Improve comments

* Update sample

* Rename download.sh to setup.sh

* Update scripts

* Update index.sh

* Update source scripts

* Continue rancher installation sample script

* Update functions

* Rename back to download.sh

* Update scripts

* Add Rancher cluster functions

* Add log

* Add CI pipeline (GitHub action)

* Add makdownlint configuration file

* Update CI to run on PR targetting develop branch

* Update README

* Fix minor typo in README

* Split README with scripts README

* Cosmetic changes

* Try to use shellcheck in CI pipeline

* Add TODO for personal Helm chart repo usage

* Add missing sudo in CI pipeline new install

* Add check on jq

* Fix shell code

* Fix typo in previous commit

* Moving script as bash files

* Manage Rancher 2.9 installation

* Trying to fix last code error

* Try to fix issue with waiting for clusterissuers

* Amend last try
  • Loading branch information
devpro committed Sep 3, 2024
1 parent e2fc39b commit 8b8cc38
Show file tree
Hide file tree
Showing 17 changed files with 1,400 additions and 1 deletion.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# sets global approvers
* @devpro @hierynomus
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- develop
schedule:
- cron: "0 2 * * 1-5"
workflow_dispatch: {}

jobs:
code-check:
runs-on: ubuntu-latest
steps:
- name: Checks-out the repository
uses: actions/checkout@v4
- name: Lints Markdown files
uses: DavidAnson/markdownlint-cli2-action@v16
with:
globs: '**/*.md'
# checking shell code with ShellCheck (https://github.com/koalaman/shellcheck)
- name: Installs packages
run: sudo apt install shellcheck
- name: Checks shell file code
run:
shellcheck -e SC2086 -e SC2034 scripts/**/*.sh
4 changes: 4 additions & 0 deletions .markdownlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# ref. https://github.com/DavidAnson/markdownlint
default: true
MD013: # Line length
line_length: 240
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,31 @@
# lab-setup
# Lab Setup

[![CI](https://github.com/SUSE/lab-setup/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/SUSE/lab-setup/actions/workflows/ci.yml)

Welcome! You'll find in this repository some IT material to help setup your lab environments.

It is used internally at SUSE (the goal being to capitalize and factorize), but is open to everyone. Feel free to contribute and share feedback!

## Getting started

### Bash scripting

* Download and source the files (here targetting `develop` branch but you can chose the revision you want):

```bash
SETUP_FOLDER=lab-setup
curl -sfL https://raw.githubusercontent.com/SUSE/lab-setup/feature/init-solution/scripts/download.sh \
| GIT_REVISION=refs/heads/develop sh -s -- -o $SETUP_FOLDER
. $SETUP_FOLDER/scripts/index.sh
```

* Try some functions:

```bash
# create a Kubernetes cluster (K3s distribution)
k3s_create_cluster v1.23
```

* Look at concrete examples: [Rancher installation with downstream cluster](samples/scripting/rancher_installation.sh)

* Browse the [catalog of functions](scripts/README.md#shell-functions)
47 changes: 47 additions & 0 deletions samples/scripting/rancher_installation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash

# downloads and sources shared scripts
SETUP_FOLDER=temp
curl -sfL https://raw.githubusercontent.com/SUSE/lab-setup/feature/init-solution/scripts/download.sh \
| GIT_REVISION=refs/heads/feature/init-solution sh -s -- -o $SETUP_FOLDER
. $SETUP_FOLDER/scripts/index.sh

# defines variables
K3S_VERSION='v1.23'
CERTMANAGER_VERSION='v1.11.0'
LETSENCRYPT_EMAIL_ADDRESS='john.wick@thecontinental.hotel'
RANCHER_REPOSITORY='latest'
RANCHER_VERSION='2.8.2'
RANCHER_DOMAIN="rancher.awesome.com"
RANCHER_REPLICAS='1'
ADMIN_PASSWORD='Sus3R@ncherR0x'
INGRESS_CLASSNAME='traefik'
DOWNSTREAM_CLUSTER_NAME='demo'
RKE2_K8S_VERSION='v1.27.16+rke2r1'

# create management cluster
k3s_create_cluster $K3S_VERSION
k3s_copy_kubeconfig
k8s_wait_fornodesandpods
kubectl get nodes
kubectl get pods -A
k8s_install_certmanager $CERTMANAGER_VERSION
k8s_create_letsencryptclusterissuer $INGRESS_CLASSNAME $LETSENCRYPT_EMAIL_ADDRESS
kubectl get clusterissuers

# install and initialize Rancher
rancher_install_withcertmanagerclusterissuer $RANCHER_REPOSITORY $RANCHER_VERSION $RANCHER_REPLICAS $RANCHER_DOMAIN letsencrypt-prod
RANCHER_URL="https://${RANCHER_DOMAIN}"
rancher_first_login $RANCHER_URL $ADMIN_PASSWORD
rancher_create_apikey $RANCHER_URL $LOGIN_TOKEN 'Automation API Key'
echo "DEBUG API_TOKEN=${API_TOKEN}"
rancher_list_clusters $RANCHER_URL $API_TOKEN
rancher_wait_capiready

# creates downstream cluster
rancher_create_customcluster $RANCHER_URL $API_TOKEN $DOWNSTREAM_CLUSTER_NAME $RKE2_K8S_VERSION
rancher_get_clusterregistrationcommand $RANCHER_URL $API_TOKEN $CLUSTER_ID

# executes the registration from downstream server
echo 'Registering downstream cluster (RKE2)...'
ssh -o StrictHostKeyChecking=accept-new downstream1 "${REGISTRATION_COMMAND} --etcd --controlplane --worker"
22 changes: 22 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Scripting

## Bash functions

Name | Source
-----------------------------------------------|---------------------------------------------------------------------------------------------
`k3s_copy_kubeconfig` | [scripts/k3s/cluster-lifecycle.sh](scripts/k3s/cluster-lifecycle.sh)
`k3s_create_cluster` | [scripts/k3s/cluster-lifecycle.sh](scripts/k3s/cluster-lifecycle.sh)
`k8s_create_letsencryptclusterissuer` | [scripts/kubernetes/certificate-management.sh](scripts/kubernetes/certificate-management.sh)
`k8s_install_certmanager` | [scripts/kubernetes/certificate-management.sh](scripts/kubernetes/certificate-management.sh)
`k8s_wait_fornodesandpods` | [scripts/kubernetes/cluster-status.sh](scripts/kubernetes/cluster-status.sh)
`rancher_create_apikey` | [scripts/rancher/user-actions.sh](scripts/rancher/user-actions.sh)
`rancher_create_customcluster` | [scripts/rancher/cluster-actions.sh](scripts/rancher/cluster-actions.sh)
`rancher_first_login` | [scripts/rancher/manager-lifecycle.sh](scripts/rancher/manager-lifecycle.sh)
`rancher_get_clusterid` | [scripts/rancher/cluster-actions.sh](scripts/rancher/cluster-actions.sh)
`rancher_get_clusterregistrationcommand` | [scripts/rancher/cluster-actions.sh](scripts/rancher/cluster-actions.sh)
`rancher_install_withcertmanagerclusterissuer` | [scripts/rancher/manager-lifecycle.sh](scripts/rancher/manager-lifecycle.sh)
`rancher_list_clusters` | [scripts/rancher/cluster-actions.sh](scripts/rancher/cluster-actions.sh)
`rancher_login_withpassword` | [scripts/rancher/user-actions.sh](scripts/rancher/user-actions.sh)
`rancher_update_password` | [scripts/rancher/user-actions.sh](scripts/rancher/user-actions.sh)
`rancher_update_serverurl` | [scripts/rancher/manager-settings.sh](scripts/rancher/manager-settings.sh)
`rancher_wait_capiready` | [scripts/rancher/manager-lifecycle.sh](scripts/rancher/manager-lifecycle.sh)
88 changes: 88 additions & 0 deletions scripts/download.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/bin/sh
# Script to download a specific version of the scripts from GitHub

# Usage:
# curl ... | ENV_VAR=... sh -
# or
# ENV_VAR=... ./setup.sh
#
# Examples:
# Downloading scripts from a "develop" branch in a temp local folder "temp":
# curl -sfL https://raw.githubusercontent.com/SUSE/lab-setup/feature/init-solution/scripts/setup.sh | GIT_REVISION=refs/heads/develop sh -s -- -o temp
# Downloading scripts from a specific revision "d8b7564fbf91473074e86b598ae06c7e4e522b9f" in the default local folder:
# curl -sfL https://raw.githubusercontent.com/SUSE/lab-setup/feature/init-solution/scripts/setup.sh | GIT_REVISION=d8b7564fbf91473074e86b598ae06c7e4e522b9f sh -
# Testing locally the setup script:
# GIT_REVISION=refs/heads/feature/init-solution ./lab-setup/scripts/setup.sh -o temp
#
# Environment variables:
# - GIT_REVISION
# Git revision (refs/heads/<branch-name>, refs/tags/vX.Y.Z for a tag, xxxxxxxxxxxxxxxx for a commit hashcode)
# - OUTPUT_FOLDER
# Output folder, where the scripts folder will be created with script directory tree inside, overriden if -o is used

info() {
echo '[INFO] ' "$@"
}

warn() {
echo '[WARN] ' "$@" >&2
}

fatal() {
echo '[ERROR] ' "$@" >&2
exit 1
}

verify_system() {
info 'Verify system requirements'
if [ -x /usr/bin/git ] || type git > /dev/null 2>&1; then
return
fi
fatal 'Git is not installed in the machine'
if ! command -v jq &> /dev/null; then
fatal 'jq is not installed in the machine'
fi
}

setup_env() {
info 'Setup variables'
case "$1" in
("-o")
OUTPUT_FOLDER=$2
shift
shift
;;
(*)
OUTPUT_FOLDER=${OUTPUT_FOLDER:-'lab-setup'}
;;
esac

GIT_REVISION=${GIT_REVISION:-'refs/heads/develop'}
GIT_REPO_NAME='lab-setup'
GIT_FOLDER=$(echo "$GIT_REVISION" | sed 's/\//-/g' | sed 's/refs-//' | sed 's/heads-//')
}

download() {
info 'Download scripts'
wget https://github.com/SUSE/${GIT_REPO_NAME}/archive/${GIT_REVISION}.zip -O ${GIT_REPO_NAME}.zip
unzip -o ${GIT_REPO_NAME}.zip
mkdir -p ${OUTPUT_FOLDER}
if [ -d ${OUTPUT_FOLDER}/scripts ]; then
info "Delete ${OUTPUT_FOLDER}/scripts"
rm -rf ${OUTPUT_FOLDER}/scripts
fi
mv ${GIT_REPO_NAME}-${GIT_FOLDER}/scripts ${OUTPUT_FOLDER}
}

cleanup() {
info 'Clean-up'
rm -f ${GIT_REPO_NAME}.zip
rm -rf ${GIT_REPO_NAME}-${GIT_FOLDER}
}

{
verify_system
setup_env "$@"
download
cleanup
}
10 changes: 10 additions & 0 deletions scripts/index.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
# File to be sourced to have all shell functions available in the bash terminal

SCRIPT_FOLDER=$(dirname "${BASH_SOURCE[0]}")
for file in ${SCRIPT_FOLDER}/*/*.sh
do {
echo "Sourcing ${file}"
. $file
}
done
29 changes: 29 additions & 0 deletions scripts/k3s/cluster-lifecycle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash
# Collection of functions to manage K3s cluster lifecycle

#######################################
# Create a K3s cluster
# Arguments:
# K3s version
# Examples:
# k3s_create_cluster "v1.23"
#######################################
k3s_create_cluster() {
local version=$1

echo "Create management cluster (K3s)..."
curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL="${version}" K3S_KUBECONFIG_MODE="644" sh -
}

#######################################
# Copy K3s kubeconfig file to local user file
# Arguments:
# None
# Examples:
# k3s_copy_kubeconfig
#######################################
k3s_copy_kubeconfig() {
mkdir -p ~/.kube
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
chmod 600 ~/.kube/config
}
49 changes: 49 additions & 0 deletions scripts/kubernetes/certificate-management.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash
# Collection of functions to add components to manage certificates in a Kubernetes cluster

#######################################
# Install cert-manager and wait for the the application to be running
# Arguments:
# cert-manager version
# Examples:
# k8s_install_certmanager "v1.11.0"
#######################################
k8s_install_certmanager() {
local version=$1

echo "Installing cert-manager..."
helm repo add jetstack https://charts.jetstack.io
helm repo update
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/${version}/cert-manager.crds.yaml
helm upgrade --install cert-manager jetstack/cert-manager \
--namespace cert-manager --create-namespace \
--version ${version} \
2>/dev/null
kubectl wait pods -n cert-manager -l app.kubernetes.io/instance=cert-manager --for condition=Ready 2>/dev/null
}

#######################################
# Create certificate cluster issuers using Let's Encrypt
# Arguments:
# Ingress class name (traefik, nginx, etc.)
# administrator email address (to receive notifications for Let's Encrypt)
# Examples:
# k8s_create_letsencryptclusterissuer traefik john.wick@google.com
#######################################
k8s_create_letsencryptclusterissuer() {
local ingressClassname=$1
local emailAddress=$2

echo "Creating certificate issuers using Let's Encrypt..."
# TODO move charts to this repository
helm repo add devpro https://devpro.github.io/helm-charts
helm repo update
helm upgrade --install letsencrypt devpro/letsencrypt --namespace cert-manager \
--set ingress.className=${ingressClassname} \
--set registration.emailAddress=${emailAddress} \
2>/dev/null
sleep 5
while kubectl get clusterissuers -o json | jq -e '.items[] | select(.status.conditions[] | select(.type == "Ready" and .status != "True"))' > /dev/null; do
sleep 1
done
}
41 changes: 41 additions & 0 deletions scripts/kubernetes/cluster-status.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash
# Collection of functions to add query status on a Kubernetes cluster

#######################################
# Wait for the Kubernetes cluster to be available (checking nodes and pods)
# Arguments:
# None
# Examples:
# k8s_wait_fornodesandpods
#######################################
k8s_wait_fornodesandpods() {
# checks nodes are ready
while ! kubectl get nodes --no-headers 2>/dev/null | grep -q .; do
echo "Waiting for nodes to be available..."
sleep 5
done
while true; do
NOT_READY_NODES=$(kubectl get nodes --no-headers 2>/dev/null | grep -c " Ready")
if [ "$NOT_READY_NODES" -eq 0 ]; then
echo "All nodes are ready."
break
else
sleep 5
fi
done

# checks pods are completed or running
while ! kubectl get pods --all-namespaces --no-headers 2>/dev/null | grep -q .; do
echo "Waiting for pods to be available..."
sleep 5
done
while true; do
NOT_READY_PODS=$(kubectl get pods --all-namespaces --field-selector=status.phase!=Running,status.phase!=Succeeded --no-headers 2>/dev/null | wc -l)
if [ "$NOT_READY_PODS" -eq 0 ]; then
echo "All pods are in Running or Completed status."
break
else
sleep 5
fi
done
}
Loading

0 comments on commit 8b8cc38

Please sign in to comment.