diff --git a/cmd/hauler/app/bundle.go b/cmd/hauler/app/bundle.go deleted file mode 100644 index 139a5da..0000000 --- a/cmd/hauler/app/bundle.go +++ /dev/null @@ -1,36 +0,0 @@ -package app - -import ( - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -type bundleOpts struct { - bundleDir string -} - -// NewBundleCommand creates a new sub command under -// haulterctl for bundling images and artifacts -func NewBundleCommand() *cobra.Command { - opts := &bundleOpts{} - - cmd := &cobra.Command{ - Use: "bundle", - Short: "bundle images or artifact for relocation", - Long: "", - Aliases: []string{"b"}, - RunE: func(cmd *cobra.Command, args []string) error { - return cmd.Help() - }, - } - - f := cmd.PersistentFlags() - f.StringVarP(&opts.bundleDir, "bundledir", "b", "./bundle", - "directory locating a bundle, if one exists we will append (./bundle)") - - cmd.AddCommand(NewBundleArtifactsCommand(opts)) - - viper.AutomaticEnv() - - return cmd -} diff --git a/cmd/hauler/app/bundle_artifacts.go b/cmd/hauler/app/bundle_artifacts.go deleted file mode 100644 index 7e67cd2..0000000 --- a/cmd/hauler/app/bundle_artifacts.go +++ /dev/null @@ -1,51 +0,0 @@ -package app - -import ( - "context" - "fmt" - - "github.com/spf13/cobra" -) - -type bundleArtifactsOpts struct { - bundle *bundleOpts -} - -// NewBundleArtifactsCommand creates a new sub command of bundle for artifacts -func NewBundleArtifactsCommand(bundle *bundleOpts) *cobra.Command { - - opts := &bundleArtifactsOpts{bundle: bundle} - - cmd := &cobra.Command{ - Use: "artifacts", - Short: "Choose a folder on disk, new artifact containing all of folder's contents", - RunE: func(cmd *cobra.Command, args []string) error { - return opts.Run() - }, - } - - return cmd -} - -func (o *bundleArtifactsOpts) Run() error { - - //TODO - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - //b := bundle.NewLayoutStore(o.bundleDir) - // - //images := []string{"alpine:latest", "registry:2.7.1"} - // - //for _, i := range images { - // if err := b.Add(ctx, i); err != nil { - // return err - // } - //} - _ = ctx - - fmt.Println("bundle artifacts") - fmt.Println(o.bundle.bundleDir) - - return nil -} diff --git a/cmd/hauler/app/copy.go b/cmd/hauler/app/copy.go index feb6310..763f6ba 100644 --- a/cmd/hauler/app/copy.go +++ b/cmd/hauler/app/copy.go @@ -11,8 +11,9 @@ var ( copyLong = `hauler copies artifacts stored on a registry to local disk` copyExample = ` - # Run Hauler - hauler copy locahost:5000/artifacts:latest` +# Run Hauler +hauler copy locahost:5000/artifacts:latest +` ) type copyOpts struct { @@ -34,7 +35,7 @@ func NewCopyCommand() *cobra.Command { Long: copyLong, Example: copyExample, Aliases: []string{"c", "cp"}, - //Args: cobra.MinimumNArgs(1), + Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { opts.sourceRef = args[0] return opts.Run(opts.sourceRef) diff --git a/cmd/hauler/app/relocate_artifacts.go b/cmd/hauler/app/relocate_artifacts.go index 4845cf1..85c25c4 100644 --- a/cmd/hauler/app/relocate_artifacts.go +++ b/cmd/hauler/app/relocate_artifacts.go @@ -13,12 +13,12 @@ type relocateArtifactsOpts struct { } var ( - relocateArtifactsLong = `hauler relocate artifacts process an archive with files - to be pushed to a registry` + relocateArtifactsLong = `hauler relocate artifacts process an archive with files to be pushed to a registry` relocateArtifactsExample = ` - # Run Hauler - hauler relocate artifacts artifacts.tar.zst locahost:5000/artifacts:latest` +# Run Hauler +hauler relocate artifacts artifacts.tar.zst locahost:5000/artifacts:latest +` ) // NewRelocateArtifactsCommand creates a new sub command of relocate for artifacts @@ -32,6 +32,8 @@ func NewRelocateArtifactsCommand(relocate *relocateOpts) *cobra.Command { Short: "Use artifact from bundle artifacts to populate a target file server with the artifact's contents", Long: relocateArtifactsLong, Example: relocateArtifactsExample, + Args: cobra.MinimumNArgs(2), + Aliases: []string{"a", "art", "af"}, RunE: func(cmd *cobra.Command, args []string) error { opts.inputFile = args[0] opts.destRef = args[1] @@ -43,7 +45,6 @@ func NewRelocateArtifactsCommand(relocate *relocateOpts) *cobra.Command { } func (o *relocateArtifactsOpts) Run(dst string, input string) error { - ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() diff --git a/cmd/hauler/app/relocate_images.go b/cmd/hauler/app/relocate_images.go index 8c9fbe5..bca390b 100644 --- a/cmd/hauler/app/relocate_images.go +++ b/cmd/hauler/app/relocate_images.go @@ -14,12 +14,13 @@ import ( ) var ( - relocateImagesLong = `hauler relocate images processes a bundle provides by hauler - package build and copies all of the collected images to a registry` + relocateImagesLong = `hauler relocate images processes a bundle provides by hauler package build and copies all of +the collected images to a registry` relocateImagesExample = ` - # Run Hauler - hauler relocate images pkg.tar.zst locahost:5000` +# Run Hauler +hauler relocate images pkg.tar.zst locahost:5000 +` ) type relocateImagesOpts struct { @@ -38,6 +39,8 @@ func NewRelocateImagesCommand(relocate *relocateOpts) *cobra.Command { Short: "Use artifact from bundle images to populate a target registry with the artifact's images", Long: relocateImagesLong, Example: relocateImagesExample, + Args: cobra.MinimumNArgs(2), + Aliases: []string{"i", "img", "imgs"}, RunE: func(cmd *cobra.Command, args []string) error { opts.inputFile = args[0] opts.destRef = args[1] diff --git a/cmd/hauler/app/root.go b/cmd/hauler/app/root.go index e9abcf1..b4991dc 100644 --- a/cmd/hauler/app/root.go +++ b/cmd/hauler/app/root.go @@ -1,7 +1,6 @@ package app import ( - "fmt" "io" "os" "time" @@ -9,31 +8,27 @@ import ( "github.com/rancherfederal/hauler/pkg/log" "github.com/spf13/cobra" - - homedir "github.com/mitchellh/go-homedir" - "github.com/spf13/viper" ) var ( - cfgFile string loglevel string timeout time.Duration getLong = `hauler provides CLI-based air-gap migration assistance using k3s. - Choose your functionality and new a package when internet access is available, - then deploy the package into your air-gapped environment. - ` +Choose your functionality and new a package when internet access is available, +then deploy the package into your air-gapped environment. +` getExample = ` - # Run Hauler - hauler pkg build - hauler pkg run pkg.tar.zst - hauler bundle images - hauler bundle artifacts - hauler relocate artifacts artifacts.tar.zst - hauler relocate images pkg.tar.zst locahost:5000 - hauler copy local:5000/artifacts:latest` +hauler pkg build +hauler pkg run pkg.tar.zst + +hauler relocate artifacts artifacts.tar.zst +hauler relocate images pkg.tar.zst locahost:5000 + +hauler copy localhost:5000/artifacts:latest +` ) type rootOpts struct { @@ -64,48 +59,21 @@ func NewRootCommand() *cobra.Command { }, } - cobra.OnInitialize(initConfig) + cobra.OnInitialize() cmd.AddCommand(NewRelocateCommand()) - cmd.AddCommand(NewBundleCommand()) cmd.AddCommand(NewCopyCommand()) - cmd.AddCommand(NewPkgCommand()) f := cmd.PersistentFlags() f.StringVarP(&loglevel, "loglevel", "l", "debug", "Log level (debug, info, warn, error, fatal, panic)") - f.StringVarP(&cfgFile, "config", "c", "./hauler.yaml", - "config file (./hauler.yaml)") f.DurationVar(&timeout, "timeout", 1*time.Minute, - "timeout for operations") + "TODO: timeout for operations") return cmd } -// initConfig reads in config file and ENV variables if set. -func initConfig() { - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := homedir.Dir() - cobra.CheckErr(err) - - // Search config in home directory with name ".hauler" (without extension). - viper.AddConfigPath(home) - viper.SetConfigName(".hauler") - } - - viper.AutomaticEnv() // read in environment variables that match - - // If a config file is found, read it in. - if err := viper.ReadInConfig(); err == nil { - fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) - } -} - func setupCliLogger(out io.Writer, level string) (log.Logger, error) { l := log.NewLogger(out) diff --git a/k3ama.sh b/k3ama.sh deleted file mode 100755 index ecee310..0000000 --- a/k3ama.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash - -# , , _______________________________ -# ,-----------|'------'| | | -# /. '-' |-' |_____________________________| -# |/| | | -# | .________.'----' _______________________________ -# | || | || | | -# \__|' \__|' |_____________________________| -# -# |‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾| -# |________________________________________________________| -# | -# |‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾| -# |________________________________________________________| -# -# k3ama - airgap migration assistant - -LOCAL_IMAGES_FILEPATH=/var/lib/rancher/k3s/agent/images -ADDL_IMAGES=./artifacts/images - -copy_images(){ - cp -rvf ${ADDL_IMAGES}/* ${LOCAL_IMAGES_FILEPATH} -} - -install_k3s(){ - AIRGAP_IMAGES_TAR="$1" - - ## Note: currently requires root - mkdir -p ${LOCAL_IMAGES_FILEPATH} - echo "copying ${AIRGAP_IMAGES_TAR} -> ${LOCAL_IMAGES_FILEPATH}" - cp artifacts/k3s-airgap-images-amd64.tar /var/lib/rancher/k3s/agent/images - # copy over the k3s binary - cp ./artifacts/k3s /usr/local/bin/k3s - chmod +x /usr/local/bin/k3s - - INSTALL_K3S_SKIP_DOWNLOAD=true ./scripts/k3s-install.sh -} - -uninstall_k3s(){ - if [ -f "/usr/local/bin/k3s-uninstall.sh" ]; then - /usr/local/bin/k3s-uninstall.sh - else - echo "k3s is not installed" - fi -} - -check_deps(){ - #TODO - echo "TODO: check to ensure that the dependencies are in place." - #rpm -qa | grep k3s-selinux -} - -#gather_selinux_rpms(){ -# if ! yum list installed yum-utils >/dev/null 2>&1; then -# yum install -y yum-utils -# fi - #wget -O ./https://rpm.rancher.io/k3s-selinux-0.1.1-rc1.el7.noarch.rpm - #yumdownloader --destdir=. --resolve container-selinux selinux-policy-base -#} - -usage () { - echo "USAGE: $0 [--image-list rancher-images.txt] [--images rancher-images.tar.gz]" - echo " [-l|--image-list path] text file with list of images; one image per line." - echo " [-i|--images path] tar.gz generated by docker save." - echo " [-h|--help] Usage message" -} - -check_firewalld(){ - if pgrep -x "firewalld" >/dev/null - then - echo "[FATAL] disable firewalld first" - fi -} - -check_selinux(){ - # yes i know we want selinux, but it's a pain in the ass right now and i will come back to it - SELINUXSTATUS=$(getenforce) - if [ "$SELINUXSTATUS" == "Permissive" ]; then - echo "[FATAL] disable selinux" - exit 1 - else - echo "SELINUX disabled. continuing" - fi -} - -copy_yaml_manifests(){ - cp -r ./yaml/* /var/lib/rancher/k3s/server/manifests -} - -copy_local_bins(){ - if [ -f "./artifacts/k9s" ]; then - cp -v ./artifacts/k9s /usr/local/bin/ - fi -} - -copy_local_kubectl(){ - echo "TODO" -} - -iptable_block_docker_io() { - # iptables -A OUTPUT -p tcp -m string --string "docker.io" --algo kmp -j REJECT - echo "iptable_block_docker_io() disabled" -} -## TODO: Make this interactive with case statements - -uninstall_k3s -copy_local_bins -iptable_block_docker_io -check_deps -check_firewalld -#check_selinux -install_k3s ./artifacts/k3s-airgap-images-amd64.tar -copy_images -copy_yaml_manifests - - - - -/usr/local/bin/k3s kubectl get pods -A -w - - -####### -# Notes: -# - workaround: busybox is not included in the main images.txt list and therefor the pvcs cannot create. -# - VAGRANT FAIL: INFO[0000] Preparing data dir /var/lib/rancher/k3s/data ... for some reason local-path provisioner cannot create vols in vagrant -# - bug: RunContainerError results you try to reinstall k3s on top of an old instance WHEN RUNNING SELINUX -####### \ No newline at end of file diff --git a/pkg/bootstrap/booter.go b/pkg/bootstrap/booter.go index 90a0777..4924fd6 100644 --- a/pkg/bootstrap/booter.go +++ b/pkg/bootstrap/booter.go @@ -113,7 +113,7 @@ func (b booter) PostBoot(ctx context.Context, d driver.Driver) error { } b.logger.Infof("Installing fleet crds") - fleetCrdRelease, fleetCrdErr := installChart(cf, fleetCrdChart, "fleet-crd", nil, b.logger) + fleetCrdRelease, fleetCrdErr := installChart(cf, fleetCrdChart, "fleet-crd", nil, b.logger) if fleetCrdErr != nil { return fleetCrdErr } diff --git a/pkg/bootstrap/config.go b/pkg/bootstrap/config.go index a2c2e10..1b209fe 100644 --- a/pkg/bootstrap/config.go +++ b/pkg/bootstrap/config.go @@ -5,20 +5,20 @@ import ( ) type BootSettings struct { - config *genericclioptions.ConfigFlags - Namespace string + config *genericclioptions.ConfigFlags + Namespace string KubeConfig string } func NewBootConfig(ns, kubepath string) *BootSettings { env := &BootSettings{ - Namespace: ns, - KubeConfig: kubepath, + Namespace: ns, + KubeConfig: kubepath, } env.config = &genericclioptions.ConfigFlags{ - Namespace: &env.Namespace, - KubeConfig: &env.KubeConfig, + Namespace: &env.Namespace, + KubeConfig: &env.KubeConfig, } return env } @@ -26,4 +26,4 @@ func NewBootConfig(ns, kubepath string) *BootSettings { // RESTClientGetter gets the kubeconfig from BootSettings func (s *BootSettings) RESTClientGetter() genericclioptions.RESTClientGetter { return s.config -} \ No newline at end of file +} diff --git a/scripts/k3s-install.sh b/scripts/k3s-install.sh deleted file mode 100755 index 1e4180e..0000000 --- a/scripts/k3s-install.sh +++ /dev/null @@ -1,801 +0,0 @@ -#!/bin/sh -set -e - -# Usage: -# curl ... | ENV_VAR=... sh - -# or -# ENV_VAR=... ./install.sh -# -# Example: -# Installing a server without traefik: -# curl ... | INSTALL_K3S_EXEC="--disable=traefik" sh - -# Installing an agent to point at a server: -# curl ... | K3S_TOKEN=xxx K3S_URL=https://server-url:6443 sh - -# -# Environment variables: -# - K3S_* -# Environment variables which begin with K3S_ will be preserved for the -# systemd service to use. Setting K3S_URL without explicitly setting -# a systemd exec command will default the command to "agent", and we -# enforce that K3S_TOKEN or K3S_CLUSTER_SECRET is also set. -# -# - INSTALL_K3S_SKIP_DOWNLOAD -# If set to true will not download k3s hash or binary. -# -# - INSTALL_K3S_SYMLINK -# If set to 'skip' will not create symlinks, 'force' will overwrite, -# default will symlink if command does not exist in path. -# -# - INSTALL_K3S_SKIP_ENABLE -# If set to true will not enable or start k3s service. -# -# - INSTALL_K3S_SKIP_START -# If set to true will not start k3s service. -# -# - INSTALL_K3S_VERSION -# Version of k3s to download from github. Will attempt to download from the -# stable channel if not specified. -# -# - INSTALL_K3S_COMMIT -# Commit of k3s to download from temporary cloud storage. -# * (for developer & QA use) -# -# - INSTALL_K3S_BIN_DIR -# Directory to install k3s binary, links, and uninstall script to, or use -# /usr/local/bin as the default -# -# - INSTALL_K3S_BIN_DIR_READ_ONLY -# If set to true will not write files to INSTALL_K3S_BIN_DIR, forces -# setting INSTALL_K3S_SKIP_DOWNLOAD=true -# -# - INSTALL_K3S_SYSTEMD_DIR -# Directory to install systemd service and environment files to, or use -# /etc/systemd/system as the default -# -# - INSTALL_K3S_EXEC or script arguments -# Command with flags to use for launching k3s in the systemd service, if -# the command is not specified will default to "agent" if K3S_URL is set -# or "server" if not. The final systemd command resolves to a combination -# of EXEC and script args ($@). -# -# The following commands result in the same behavior: -# curl ... | INSTALL_K3S_EXEC="--disable=traefik" sh -s - -# curl ... | INSTALL_K3S_EXEC="server --disable=traefik" sh -s - -# curl ... | INSTALL_K3S_EXEC="server" sh -s - --disable=traefik -# curl ... | sh -s - server --disable=traefik -# curl ... | sh -s - --disable=traefik -# -# - INSTALL_K3S_NAME -# Name of systemd service to create, will default from the k3s exec command -# if not specified. If specified the name will be prefixed with 'k3s-'. -# -# - INSTALL_K3S_TYPE -# Type of systemd service to create, will default from the k3s exec command -# if not specified. -# -# - INSTALL_K3S_SELINUX_WARN -# If set to true will continue if k3s-selinux policy is not found. -# -# - INSTALL_K3S_CHANNEL_URL -# Channel URL for fetching k3s download URL. -# Defaults to 'https://update.k3s.io/v1-release/channels'. -# -# - INSTALL_K3S_CHANNEL -# Channel to use for fetching k3s download URL. -# Defaults to 'stable'. - -GITHUB_URL=https://github.com/rancher/k3s/releases -STORAGE_URL=https://storage.googleapis.com/k3s-ci-builds -DOWNLOADER= - -# --- helper functions for logs --- -info() -{ - echo '[INFO] ' "$@" -} -warn() -{ - echo '[WARN] ' "$@" >&2 -} -fatal() -{ - echo '[ERROR] ' "$@" >&2 - exit 1 -} - -# --- fatal if no systemd or openrc --- -verify_system() { - if [ -x /sbin/openrc-run ]; then - HAS_OPENRC=true - return - fi - if [ -d /run/systemd ]; then - HAS_SYSTEMD=true - return - fi - fatal 'Can not find systemd or openrc to use as a process supervisor for k3s' -} - -# --- add quotes to command arguments --- -quote() { - for arg in "$@"; do - printf '%s\n' "$arg" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/" - done -} - -# --- add indentation and trailing slash to quoted args --- -quote_indent() { - printf ' \\\n' - for arg in "$@"; do - printf '\t%s \\\n' "$(quote "$arg")" - done -} - -# --- escape most punctuation characters, except quotes, forward slash, and space --- -escape() { - printf '%s' "$@" | sed -e 's/\([][!#$%&()*;<=>?\_`{|}]\)/\\\1/g;' -} - -# --- escape double quotes --- -escape_dq() { - printf '%s' "$@" | sed -e 's/"/\\"/g' -} - -# --- ensures $K3S_URL is empty or begins with https://, exiting fatally otherwise --- -verify_k3s_url() { - case "${K3S_URL}" in - "") - ;; - https://*) - ;; - *) - fatal "Only https:// URLs are supported for K3S_URL (have ${K3S_URL})" - ;; - esac -} - -# --- define needed environment variables --- -setup_env() { - # --- use command args if passed or create default --- - case "$1" in - # --- if we only have flags discover if command should be server or agent --- - (-*|"") - if [ -z "${K3S_URL}" ]; then - CMD_K3S=server - else - if [ -z "${K3S_TOKEN}" ] && [ -z "${K3S_CLUSTER_SECRET}" ]; then - fatal "Defaulted k3s exec command to 'agent' because K3S_URL is defined, but K3S_TOKEN or K3S_CLUSTER_SECRET is not defined." - fi - CMD_K3S=agent - fi - ;; - # --- command is provided --- - (*) - CMD_K3S=$1 - shift - ;; - esac - - verify_k3s_url - - CMD_K3S_EXEC="${CMD_K3S}$(quote_indent "$@")" - - # --- use systemd name if defined or create default --- - if [ -n "${INSTALL_K3S_NAME}" ]; then - SYSTEM_NAME=k3s-${INSTALL_K3S_NAME} - else - if [ "${CMD_K3S}" = server ]; then - SYSTEM_NAME=k3s - else - SYSTEM_NAME=k3s-${CMD_K3S} - fi - fi - - # --- check for invalid characters in system name --- - valid_chars=$(printf '%s' "${SYSTEM_NAME}" | sed -e 's/[][!#$%&()*;<=>?\_`{|}/[:space:]]/^/g;' ) - if [ "${SYSTEM_NAME}" != "${valid_chars}" ]; then - invalid_chars=$(printf '%s' "${valid_chars}" | sed -e 's/[^^]/ /g') - fatal "Invalid characters for system name: - ${SYSTEM_NAME} - ${invalid_chars}" - fi - - # --- use sudo if we are not already root --- - SUDO=sudo - if [ $(id -u) -eq 0 ]; then - SUDO= - fi - - # --- use systemd type if defined or create default --- - if [ -n "${INSTALL_K3S_TYPE}" ]; then - SYSTEMD_TYPE=${INSTALL_K3S_TYPE} - else - if [ "${CMD_K3S}" = server ]; then - SYSTEMD_TYPE=notify - else - SYSTEMD_TYPE=exec - fi - fi - - # --- use binary install directory if defined or create default --- - if [ -n "${INSTALL_K3S_BIN_DIR}" ]; then - BIN_DIR=${INSTALL_K3S_BIN_DIR} - else - BIN_DIR=/usr/local/bin - fi - - # --- use systemd directory if defined or create default --- - if [ -n "${INSTALL_K3S_SYSTEMD_DIR}" ]; then - SYSTEMD_DIR="${INSTALL_K3S_SYSTEMD_DIR}" - else - SYSTEMD_DIR=/etc/systemd/system - fi - - # --- set related files from system name --- - SERVICE_K3S=${SYSTEM_NAME}.service - UNINSTALL_K3S_SH=${UNINSTALL_K3S_SH:-${BIN_DIR}/${SYSTEM_NAME}-uninstall.sh} - KILLALL_K3S_SH=${KILLALL_K3S_SH:-${BIN_DIR}/k3s-killall.sh} - - # --- use service or environment location depending on systemd/openrc --- - if [ "${HAS_SYSTEMD}" = true ]; then - FILE_K3S_SERVICE=${SYSTEMD_DIR}/${SERVICE_K3S} - FILE_K3S_ENV=${SYSTEMD_DIR}/${SERVICE_K3S}.env - elif [ "${HAS_OPENRC}" = true ]; then - $SUDO mkdir -p /etc/rancher/k3s - FILE_K3S_SERVICE=/etc/init.d/${SYSTEM_NAME} - FILE_K3S_ENV=/etc/rancher/k3s/${SYSTEM_NAME}.env - fi - - # --- get hash of config & exec for currently installed k3s --- - PRE_INSTALL_HASHES=$(get_installed_hashes) - - # --- if bin directory is read only skip download --- - if [ "${INSTALL_K3S_BIN_DIR_READ_ONLY}" = true ]; then - INSTALL_K3S_SKIP_DOWNLOAD=true - fi - - # --- setup channel values - INSTALL_K3S_CHANNEL_URL=${INSTALL_K3S_CHANNEL_URL:-'https://update.k3s.io/v1-release/channels'} - INSTALL_K3S_CHANNEL=${INSTALL_K3S_CHANNEL:-'stable'} -} - -# --- check if skip download environment variable set --- -can_skip_download() { - if [ "${INSTALL_K3S_SKIP_DOWNLOAD}" != true ]; then - return 1 - fi -} - -# --- verify an executabe k3s binary is installed --- -verify_k3s_is_executable() { - if [ ! -x ${BIN_DIR}/k3s ]; then - fatal "Executable k3s binary not found at ${BIN_DIR}/k3s" - fi -} - -# --- set arch and suffix, fatal if architecture not supported --- -setup_verify_arch() { - if [ -z "$ARCH" ]; then - ARCH=$(uname -m) - fi - case $ARCH in - amd64) - ARCH=amd64 - SUFFIX= - ;; - x86_64) - ARCH=amd64 - SUFFIX= - ;; - arm64) - ARCH=arm64 - SUFFIX=-${ARCH} - ;; - aarch64) - ARCH=arm64 - SUFFIX=-${ARCH} - ;; - arm*) - ARCH=arm - SUFFIX=-${ARCH}hf - ;; - *) - fatal "Unsupported architecture $ARCH" - esac -} - -# --- verify existence of network downloader executable --- -verify_downloader() { - # Return failure if it doesn't exist or is no executable - [ -x "$(which $1)" ] || return 1 - - # Set verified executable as our downloader program and return success - DOWNLOADER=$1 - return 0 -} - -# --- create tempory directory and cleanup when done --- -setup_tmp() { - TMP_DIR=$(mktemp -d -t k3s-install.XXXXXXXXXX) - TMP_HASH=${TMP_DIR}/k3s.hash - TMP_BIN=${TMP_DIR}/k3s.bin - cleanup() { - code=$? - set +e - trap - EXIT - rm -rf ${TMP_DIR} - exit $code - } - trap cleanup INT EXIT -} - -# --- use desired k3s version if defined or find version from channel --- -get_release_version() { - if [ -n "${INSTALL_K3S_COMMIT}" ]; then - VERSION_K3S="commit ${INSTALL_K3S_COMMIT}" - elif [ -n "${INSTALL_K3S_VERSION}" ]; then - VERSION_K3S=${INSTALL_K3S_VERSION} - else - info "Finding release for channel ${INSTALL_K3S_CHANNEL}" - version_url="${INSTALL_K3S_CHANNEL_URL}/${INSTALL_K3S_CHANNEL}" - case $DOWNLOADER in - curl) - VERSION_K3S=$(curl -w '%{url_effective}' -L -s -S ${version_url} -o /dev/null | sed -e 's|.*/||') - ;; - wget) - VERSION_K3S=$(wget -SqO /dev/null ${version_url} 2>&1 | grep -i Location | sed -e 's|.*/||') - ;; - *) - fatal "Incorrect downloader executable '$DOWNLOADER'" - ;; - esac - fi - info "Using ${VERSION_K3S} as release" -} - -# --- download from github url --- -download() { - [ $# -eq 2 ] || fatal 'download needs exactly 2 arguments' - - case $DOWNLOADER in - curl) - curl -o $1 -sfL $2 - ;; - wget) - wget -qO $1 $2 - ;; - *) - fatal "Incorrect executable '$DOWNLOADER'" - ;; - esac - - # Abort if download command failed - [ $? -eq 0 ] || fatal 'Download failed' -} - -# --- download hash from github url --- -download_hash() { - if [ -n "${INSTALL_K3S_COMMIT}" ]; then - HASH_URL=${STORAGE_URL}/k3s${SUFFIX}-${INSTALL_K3S_COMMIT}.sha256sum - else - HASH_URL=${GITHUB_URL}/download/${VERSION_K3S}/sha256sum-${ARCH}.txt - fi - info "Downloading hash ${HASH_URL}" - download ${TMP_HASH} ${HASH_URL} - HASH_EXPECTED=$(grep " k3s${SUFFIX}$" ${TMP_HASH}) - HASH_EXPECTED=${HASH_EXPECTED%%[[:blank:]]*} -} - -# --- check hash against installed version --- -installed_hash_matches() { - if [ -x ${BIN_DIR}/k3s ]; then - HASH_INSTALLED=$(sha256sum ${BIN_DIR}/k3s) - HASH_INSTALLED=${HASH_INSTALLED%%[[:blank:]]*} - if [ "${HASH_EXPECTED}" = "${HASH_INSTALLED}" ]; then - return - fi - fi - return 1 -} - -# --- download binary from github url --- -download_binary() { - if [ -n "${INSTALL_K3S_COMMIT}" ]; then - BIN_URL=${STORAGE_URL}/k3s${SUFFIX}-${INSTALL_K3S_COMMIT} - else - BIN_URL=${GITHUB_URL}/download/${VERSION_K3S}/k3s${SUFFIX} - fi - info "Downloading binary ${BIN_URL}" - download ${TMP_BIN} ${BIN_URL} -} - -# --- verify downloaded binary hash --- -verify_binary() { - info "Verifying binary download" - HASH_BIN=$(sha256sum ${TMP_BIN}) - HASH_BIN=${HASH_BIN%%[[:blank:]]*} - if [ "${HASH_EXPECTED}" != "${HASH_BIN}" ]; then - fatal "Download sha256 does not match ${HASH_EXPECTED}, got ${HASH_BIN}" - fi -} - -# --- setup permissions and move binary to system directory --- -setup_binary() { - chmod 755 ${TMP_BIN} - info "Installing k3s to ${BIN_DIR}/k3s" - $SUDO chown root:root ${TMP_BIN} - $SUDO mv -f ${TMP_BIN} ${BIN_DIR}/k3s -} - -# --- setup selinux policy --- -setup_selinux() { - policy_hint="please install: - yum install -y container-selinux selinux-policy-base - rpm -i https://rpm.rancher.io/k3s-selinux-0.1.1-rc1.el7.noarch.rpm -" - policy_error=fatal - if [ "$INSTALL_K3S_SELINUX_WARN" = true ]; then - policy_error=warn - fi - - if ! $SUDO chcon -u system_u -r object_r -t container_runtime_exec_t ${BIN_DIR}/k3s >/dev/null 2>&1; then - if $SUDO grep '^\s*SELINUX=enforcing' /etc/selinux/config >/dev/null 2>&1; then - $policy_error "Failed to apply container_runtime_exec_t to ${BIN_DIR}/k3s, ${policy_hint}" - fi - else - if [ ! -f /usr/share/selinux/packages/k3s.pp ]; then - $policy_error "Failed to find the k3s-selinux policy, ${policy_hint}" - fi - fi -} - -# --- download and verify k3s --- -download_and_verify() { - if can_skip_download; then - info 'Skipping k3s download and verify' - verify_k3s_is_executable - return - fi - - setup_verify_arch - verify_downloader curl || verify_downloader wget || fatal 'Can not find curl or wget for downloading files' - setup_tmp - get_release_version - download_hash - - if installed_hash_matches; then - info 'Skipping binary downloaded, installed k3s matches hash' - return - fi - - download_binary - verify_binary - setup_binary -} - -# --- add additional utility links --- -create_symlinks() { - [ "${INSTALL_K3S_BIN_DIR_READ_ONLY}" = true ] && return - [ "${INSTALL_K3S_SYMLINK}" = skip ] && return - - for cmd in kubectl crictl ctr; do - if [ ! -e ${BIN_DIR}/${cmd} ] || [ "${INSTALL_K3S_SYMLINK}" = force ]; then - which_cmd=$(which ${cmd} 2>/dev/null || true) - if [ -z "${which_cmd}" ] || [ "${INSTALL_K3S_SYMLINK}" = force ]; then - info "Creating ${BIN_DIR}/${cmd} symlink to k3s" - $SUDO ln -sf k3s ${BIN_DIR}/${cmd} - else - info "Skipping ${BIN_DIR}/${cmd} symlink to k3s, command exists in PATH at ${which_cmd}" - fi - else - info "Skipping ${BIN_DIR}/${cmd} symlink to k3s, already exists" - fi - done -} - -# --- create killall script --- -create_killall() { - [ "${INSTALL_K3S_BIN_DIR_READ_ONLY}" = true ] && return - info "Creating killall script ${KILLALL_K3S_SH}" - $SUDO tee ${KILLALL_K3S_SH} >/dev/null << \EOF -#!/bin/sh -[ $(id -u) -eq 0 ] || exec sudo $0 $@ - -for bin in /var/lib/rancher/k3s/data/**/bin/; do - [ -d $bin ] && export PATH=$PATH:$bin:$bin/aux -done - -set -x - -for service in /etc/systemd/system/k3s*.service; do - [ -s $service ] && systemctl stop $(basename $service) -done - -for service in /etc/init.d/k3s*; do - [ -x $service ] && $service stop -done - -pschildren() { - ps -e -o ppid= -o pid= | \ - sed -e 's/^\s*//g; s/\s\s*/\t/g;' | \ - grep -w "^$1" | \ - cut -f2 -} - -pstree() { - for pid in $@; do - echo $pid - for child in $(pschildren $pid); do - pstree $child - done - done -} - -killtree() { - kill -9 $( - { set +x; } 2>/dev/null; - pstree $@; - set -x; - ) 2>/dev/null -} - -getshims() { - ps -e -o pid= -o args= | sed -e 's/^ *//; s/\s\s*/\t/;' | grep -w 'k3s/data/[^/]*/bin/containerd-shim' | cut -f1 -} - -killtree $({ set +x; } 2>/dev/null; getshims; set -x) - -do_unmount() { - { set +x; } 2>/dev/null - MOUNTS= - while read ignore mount ignore; do - MOUNTS="$mount\n$MOUNTS" - done /dev/null | grep 'master cni0' | while read ignore iface ignore; do - iface=${iface%%@*} - [ -z "$iface" ] || ip link delete $iface -done -ip link delete cni0 -ip link delete flannel.1 -rm -rf /var/lib/cni/ -iptables-save | grep -v KUBE- | grep -v CNI- | iptables-restore -EOF - $SUDO chmod 755 ${KILLALL_K3S_SH} - $SUDO chown root:root ${KILLALL_K3S_SH} -} - -# --- create uninstall script --- -create_uninstall() { - [ "${INSTALL_K3S_BIN_DIR_READ_ONLY}" = true ] && return - info "Creating uninstall script ${UNINSTALL_K3S_SH}" - $SUDO tee ${UNINSTALL_K3S_SH} >/dev/null << EOF -#!/bin/sh -set -x -[ \$(id -u) -eq 0 ] || exec sudo \$0 \$@ - -${KILLALL_K3S_SH} - -if which systemctl; then - systemctl disable ${SYSTEM_NAME} - systemctl reset-failed ${SYSTEM_NAME} - systemctl daemon-reload -fi -if which rc-update; then - rc-update delete ${SYSTEM_NAME} default -fi - -rm -f ${FILE_K3S_SERVICE} -rm -f ${FILE_K3S_ENV} - -remove_uninstall() { - rm -f ${UNINSTALL_K3S_SH} -} -trap remove_uninstall EXIT - -if (ls ${SYSTEMD_DIR}/k3s*.service || ls /etc/init.d/k3s*) >/dev/null 2>&1; then - set +x; echo 'Additional k3s services installed, skipping uninstall of k3s'; set -x - exit -fi - -for cmd in kubectl crictl ctr; do - if [ -L ${BIN_DIR}/\$cmd ]; then - rm -f ${BIN_DIR}/\$cmd - fi -done - -rm -rf /etc/rancher/k3s -rm -rf /run/k3s -rm -rf /run/flannel -rm -rf /var/lib/rancher/k3s -rm -rf /var/lib/kubelet -rm -f ${BIN_DIR}/k3s -rm -f ${KILLALL_K3S_SH} -EOF - $SUDO chmod 755 ${UNINSTALL_K3S_SH} - $SUDO chown root:root ${UNINSTALL_K3S_SH} -} - -# --- disable current service if loaded -- -systemd_disable() { - $SUDO rm -f /etc/systemd/system/${SERVICE_K3S} || true - $SUDO rm -f /etc/systemd/system/${SERVICE_K3S}.env || true - $SUDO systemctl disable ${SYSTEM_NAME} >/dev/null 2>&1 || true -} - -# --- capture current env and create file containing k3s_ variables --- -create_env_file() { - info "env: Creating environment file ${FILE_K3S_ENV}" - UMASK=$(umask) - umask 0377 - env | grep '^K3S_' | $SUDO tee ${FILE_K3S_ENV} >/dev/null - env | egrep -i '^(NO|HTTP|HTTPS)_PROXY' | $SUDO tee -a ${FILE_K3S_ENV} >/dev/null - umask $UMASK -} - -# --- write systemd service file --- -create_systemd_service_file() { - info "systemd: Creating service file ${FILE_K3S_SERVICE}" - $SUDO tee ${FILE_K3S_SERVICE} >/dev/null << EOF -[Unit] -Description=Lightweight Kubernetes -Documentation=https://k3s.io -Wants=network-online.target - -[Install] -WantedBy=multi-user.target - -[Service] -Type=${SYSTEMD_TYPE} -EnvironmentFile=${FILE_K3S_ENV} -KillMode=process -Delegate=yes -# Having non-zero Limit*s causes performance problems due to accounting overhead -# in the kernel. We recommend using cgroups to do container-local accounting. -LimitNOFILE=1048576 -LimitNPROC=infinity -LimitCORE=infinity -TasksMax=infinity -TimeoutStartSec=0 -Restart=always -RestartSec=5s -ExecStartPre=-/sbin/modprobe br_netfilter -ExecStartPre=-/sbin/modprobe overlay -ExecStart=${BIN_DIR}/k3s \\ - ${CMD_K3S_EXEC} - -EOF -} - -# --- write openrc service file --- -create_openrc_service_file() { - LOG_FILE=/var/log/${SYSTEM_NAME}.log - - info "openrc: Creating service file ${FILE_K3S_SERVICE}" - $SUDO tee ${FILE_K3S_SERVICE} >/dev/null << EOF -#!/sbin/openrc-run - -depend() { - after network-online - want cgroups -} - -start_pre() { - rm -f /tmp/k3s.* -} - -supervisor=supervise-daemon -name=${SYSTEM_NAME} -command="${BIN_DIR}/k3s" -command_args="$(escape_dq "${CMD_K3S_EXEC}") - >>${LOG_FILE} 2>&1" - -output_log=${LOG_FILE} -error_log=${LOG_FILE} - -pidfile="/var/run/${SYSTEM_NAME}.pid" -respawn_delay=5 -respawn_max=0 - -set -o allexport -if [ -f /etc/environment ]; then source /etc/environment; fi -if [ -f ${FILE_K3S_ENV} ]; then source ${FILE_K3S_ENV}; fi -set +o allexport -EOF - $SUDO chmod 0755 ${FILE_K3S_SERVICE} - - $SUDO tee /etc/logrotate.d/${SYSTEM_NAME} >/dev/null << EOF -${LOG_FILE} { - missingok - notifempty - copytruncate -} -EOF -} - -# --- write systemd or openrc service file --- -create_service_file() { - [ "${HAS_SYSTEMD}" = true ] && create_systemd_service_file - [ "${HAS_OPENRC}" = true ] && create_openrc_service_file - return 0 -} - -# --- get hashes of the current k3s bin and service files -get_installed_hashes() { - $SUDO sha256sum ${BIN_DIR}/k3s ${FILE_K3S_SERVICE} ${FILE_K3S_ENV} 2>&1 || true -} - -# --- enable and start systemd service --- -systemd_enable() { - info "systemd: Enabling ${SYSTEM_NAME} unit" - $SUDO systemctl enable ${FILE_K3S_SERVICE} >/dev/null - $SUDO systemctl daemon-reload >/dev/null -} - -systemd_start() { - info "systemd: Starting ${SYSTEM_NAME}" - $SUDO systemctl restart ${SYSTEM_NAME} -} - -# --- enable and start openrc service --- -openrc_enable() { - info "openrc: Enabling ${SYSTEM_NAME} service for default runlevel" - $SUDO rc-update add ${SYSTEM_NAME} default >/dev/null -} - -openrc_start() { - info "openrc: Starting ${SYSTEM_NAME}" - $SUDO ${FILE_K3S_SERVICE} restart -} - -# --- startup systemd or openrc service --- -service_enable_and_start() { - [ "${INSTALL_K3S_SKIP_ENABLE}" = true ] && return - - [ "${HAS_SYSTEMD}" = true ] && systemd_enable - [ "${HAS_OPENRC}" = true ] && openrc_enable - - [ "${INSTALL_K3S_SKIP_START}" = true ] && return - - POST_INSTALL_HASHES=$(get_installed_hashes) - if [ "${PRE_INSTALL_HASHES}" = "${POST_INSTALL_HASHES}" ]; then - info 'No change detected so skipping service start' - return - fi - - [ "${HAS_SYSTEMD}" = true ] && systemd_start - [ "${HAS_OPENRC}" = true ] && openrc_start - return 0 -} - -# --- re-evaluate args to include env command --- -eval set -- $(escape "${INSTALL_K3S_EXEC}") $(quote "$@") - -# --- run the install process -- -{ - verify_system - setup_env "$@" - download_and_verify - setup_selinux - create_symlinks - create_killall - create_uninstall - systemd_disable - create_env_file - create_service_file - service_enable_and_start -}