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

chore: installer script #118

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
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
Empty file modified .github/wb-logo.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion .gitignore
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@ cert-issuer.yaml
*.tfvars
node_modules
staging/*
js/
js/

/install.sh
assets
logs
packages/
*.gz
6 changes: 2 additions & 4 deletions .prettierrc
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"parser": "typescript",
"trailingComma": "es5",
"trailingComma": "all",
"singleQuote": true,
"bracketSpacing": false,
"jsxBracketSameLine": true,
"tabWidth": 2
"semi": false
}
Empty file modified .vscode/settings.json
100644 → 100755
Empty file.
Empty file modified CHANGELOG.md
100644 → 100755
Empty file.
Empty file modified LICENSE
100644 → 100755
Empty file.
Empty file modified README.md
100644 → 100755
Empty file.
Empty file modified SECURITY.md
100644 → 100755
Empty file.
79 changes: 79 additions & 0 deletions installer/build.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import * as fs from 'fs'
// import * as readline from 'readline'
import { spawnSync } from 'child_process'

const INSTALLER_SCRIPT = `${__dirname}/install.sh`
const INSTALLER_SCRIPT_VARIABLE_DIR = 'DIR'

const generateAirgapScript = Boolean(process.env.AIRGAP)

function readBashVariables(filePath: string) {
const content = fs.readFileSync(filePath, { encoding: 'utf-8' })
const lines = content.split('\n')
const result: Record<string, string | undefined> = {}
for (const line of lines) {
const l = line.startsWith('export ') ? line.slice(7) : line
const match = l.match(/^\s*([\w-]+)\s*=\s*(.*)\s*/)
if (match) {
const variable = match[1]
const value = match[2].replace(/^"|^'|"$/g, '')
const output = spawnSync('bash', ['-c', `echo ${value}`])

result[variable] = output.stdout.toString().trim()
}
}
return result
}

function getImportLines(filePath: string) {
const content = fs.readFileSync(filePath, { encoding: 'utf-8' })
const lines = content.split('\n')
const imports: string[] = []
let withinTags = false
for (const line of lines) {
if (line.startsWith('# </ImportInline>')) withinTags = false
if (withinTags && !line.startsWith('#')) imports.push(line)
if (line.includes('# <ImportInline>')) withinTags = true
}
return imports
}

function main() {
const scriptVariables = readBashVariables(INSTALLER_SCRIPT)
const dir = scriptVariables[INSTALLER_SCRIPT_VARIABLE_DIR]

if (dir == null) {
console.error(
`Could not find '${INSTALLER_SCRIPT_VARIABLE_DIR}' variable in bash script`,
)
return
}

let content = fs
.readFileSync(INSTALLER_SCRIPT, { encoding: 'utf-8' })
.split('\n')

if (generateAirgapScript)
content = content.map((d) =>
d.startsWith('export AIRGAP=') ? 'export AIRGAP=1' : d,
)

for (const importLine of getImportLines(INSTALLER_SCRIPT)) {
const importScriptPath = importLine.replace(
`. $${INSTALLER_SCRIPT_VARIABLE_DIR}`,
dir,
)
console.log(`Importing: ${importScriptPath} (${importLine})`)
const importScript = fs.readFileSync(importScriptPath, {
encoding: 'utf-8',
})

const i = content.findIndex((l) => l === importLine)
if (i === -1) continue
content[i] = `${importScript}\n`
}

fs.writeFileSync('./install.sh', content.join('\n'))
}

main()
33 changes: 33 additions & 0 deletions installer/bundle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash

set -e

DIR=.

# <ImportInline>
. $DIR/installer/configs/1.27.2.sh
. $DIR/installer/configs/base.sh
. $DIR/installer/common/kubernetes.sh
. $DIR/installer/common/addons.sh
. $DIR/installer/common/kubeadm.sh
. $DIR/installer/common/logging.sh
. $DIR/installer/common/discover.sh
. $DIR/installer/common/packages.sh
. $DIR/installer/common/semver.sh
. $DIR/installer/common/utils.sh
. $DIR/installer/common/dependencies.sh
. $DIR/installer/common/images.sh
# </ImportInline>

log_step "Generating installer"
pnpm build:installer:airgap

kubernetes_packages_download
dependencies_download
images_download
addons_download

log_step "Creating tar"
tar -czvf installer-$ARCH-$KUBERNETES_VERSION.tar.gz $DIR/install.sh $DIR/packages

printf "\n"
18 changes: 18 additions & 0 deletions installer/common/addons.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
function addons_download() {
mkdir -p $MANIFEST
if [ -z "$AIRGAP" ] || [ "$AIRGAP" != "1" ]; then
log_step "Downloading addons"

local manifest_path=$MANIFEST/contour.yaml
# TODO: figure out a way to lock the script down
local manifest_url="https://projectcontour.io/quickstart/contour.yaml"
package_download_url_with_retry "$manifest_url" "$manifest_path"
fi
}

function addons_install() {
mkdir -p $MANIFEST

local contour=$MANIFEST/contour.yaml
kubectl apply -f $contour
}
13 changes: 13 additions & 0 deletions installer/common/dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function install_dependencies() {
dependencies_download
}

function dependencies_download() {
mkdir -p $DEPENDENCIES
if [ -z "$AIRGAP" ] || [ "$AIRGAP" != "1" ]; then
log_step "Downloading host dependencies"
pushd $DEPENDENCIES > /dev/null 2>&1
package_download "openssl.tar.gz" "https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz"
popd > /dev/null 2>&1
fi
}
36 changes: 36 additions & 0 deletions installer/common/discover.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
LSB_DIST=
DIST_VERSION=
PRIVATE_IP=

function discover() {
discover_lsb
discover_private_ip

printf "\n--- System Info ---\n"
printf "Linux: $LSB_DIST\n"
printf "Version: $DIST_VERSION\n"
printf "Private IP: $PRIVATE_IP\n"
printf "\n"
}

function discover_private_ip() {
if [ -n "$PRIVATE_ADDRESS" ]; then
return 0
fi

if command_exists "ifconfig"; then
PRIVATE_IP=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1')
elif command_exists "ip"; then
PRIVATE_IP=$(ip -4 addr | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1')
fi
}


function discover_lsb() {
if [ -f /etc/os-release ] && [ -r /etc/os-release ]; then
LSB_DIST="$(. /etc/os-release && echo "$ID")"
DIST_VERSION="$(. /etc/os-release && echo "$VERSION_ID")"
else
bail "Error: Unknown operating system."
fi
}
46 changes: 46 additions & 0 deletions installer/common/images.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
function image_download() {
local name=$1
local url=$2

printf "Downloading $name\n"

if [ -f "$name" ]; then
printf "$name already downloaded\n"
return
fi

if command_exists docker; then
docker pull $url > /dev/null 2>&1
docker save $url | gzip > $name.tar.gz
elif command_exists ctr; then
ctr images pull --plain-http $url > /dev/null 2>&1
ctr --namespace=default images export - $url | gzip > $name.tar.gz
else
log_warning "No support client installed for pulling images"
fi
}

function images_download() {
log_step "Downloading images"

mkdir -p $IMAGES
if [ -z "$AIRGAP" ] || [ "$AIRGAP" != "1" ]; then
pushd $IMAGES > /dev/null 2>&1
image_download "coredns" $IMAGE_COREDNS
image_download "etcd" $IMAGE_ETCD
image_download "kube-apiserver" $IMAGE_KUBE_API
image_download "kube-controller-manager" $IMAGE_KUBE_CONTROLLER
image_download "kube-scheduler" $IMAGE_KUBE_SCHEDULER
image_download "kube-proxy" $IMAGE_KUBE_PROXY
image_download "pause" $IMAGE_PAUSE

# ingress
image_download "contour" $IMAGE_CONTOUR
image_download "envoy" $IMAGE_ENVOY
popd > /dev/null 2>&1
fi
}

function images_load() {
find "$1" -type f | xargs -I {} bash -c "cat {} | gunzip | ctr -a $(kubeadm_get_containerd_sock) -n=k8s.io images import -"
}
8 changes: 8 additions & 0 deletions installer/common/kubeadm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function kubeadm_api_is_healthy() {
addr=$PRIVATE_IP:6443
curl --globoff --noproxy "*" --fail --silent --insecure "https://$addr/healthz" >/dev/null
}

function kubeadm_get_containerd_sock() {
echo "/run/containerd/containerd.sock"
}
Loading