feat: verify master nodes exist and not an even number
Signed-off-by: Devin Buhl <devin@buhl.casa>
This commit is contained in:
1 file changed
+77
-108
@@ -22,12 +22,10 @@ EOF
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
local verify=
|
local verify=
|
||||||
|
|
||||||
parse_command_line "$@"
|
parse_command_line "$@"
|
||||||
|
|
||||||
verify_binaries
|
verify_binaries
|
||||||
|
|
||||||
if [[ "${verify}" == 1 ]]; then
|
if [[ "${verify}" == 1 ]]; then
|
||||||
|
verify_master_count
|
||||||
verify_ansible_hosts
|
verify_ansible_hosts
|
||||||
verify_metallb
|
verify_metallb
|
||||||
verify_kubevip
|
verify_kubevip
|
||||||
@@ -40,39 +38,30 @@ main() {
|
|||||||
# generate sops configuration file
|
# generate sops configuration file
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/.sops.yaml"
|
> "${PROJECT_DIR}/.sops.yaml"
|
||||||
|
|
||||||
# generate cluster settings
|
# generate cluster settings
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/flux/cluster-settings.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/flux/cluster-settings.yaml" \
|
||||||
> "${PROJECT_DIR}/kubernetes/flux/vars/cluster-settings.yaml"
|
> "${PROJECT_DIR}/kubernetes/flux/vars/cluster-settings.yaml"
|
||||||
|
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/flux/cluster.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/flux/cluster.yaml" \
|
||||||
> "${PROJECT_DIR}/kubernetes/flux/config/cluster.yaml"
|
> "${PROJECT_DIR}/kubernetes/flux/config/cluster.yaml"
|
||||||
|
|
||||||
# generate secrets
|
# generate secrets
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cluster-secrets.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cluster-secrets.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/kubernetes/flux/vars/cluster-secrets.sops.yaml"
|
> "${PROJECT_DIR}/kubernetes/flux/vars/cluster-secrets.sops.yaml"
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/flux/vars/cluster-secrets.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/flux/vars/cluster-secrets.sops.yaml"
|
||||||
|
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cert-manager-secret.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cert-manager-secret.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/kubernetes/apps/cert-manager/cert-manager/issuers/secret.sops.yaml"
|
> "${PROJECT_DIR}/kubernetes/apps/cert-manager/cert-manager/issuers/secret.sops.yaml"
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/cert-manager/cert-manager/issuers/secret.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/cert-manager/cert-manager/issuers/secret.sops.yaml"
|
||||||
|
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cloudflare-ddns-secret.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/cloudflare-ddns-secret.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/kubernetes/apps/networking/cloudflare-ddns/app/secret.sops.yaml"
|
> "${PROJECT_DIR}/kubernetes/apps/networking/cloudflare-ddns/app/secret.sops.yaml"
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/networking/cloudflare-ddns/app/secret.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/networking/cloudflare-ddns/app/secret.sops.yaml"
|
||||||
|
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/external-dns-secret.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/external-dns-secret.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/kubernetes/apps/networking/external-dns/app/secret.sops.yaml"
|
> "${PROJECT_DIR}/kubernetes/apps/networking/external-dns/app/secret.sops.yaml"
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/networking/external-dns/app/secret.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/networking/external-dns/app/secret.sops.yaml"
|
||||||
|
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/terraform/secret.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/terraform/secret.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/terraform/cloudflare/secret.sops.yaml"
|
> "${PROJECT_DIR}/terraform/cloudflare/secret.sops.yaml"
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/terraform/cloudflare/secret.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/terraform/cloudflare/secret.sops.yaml"
|
||||||
|
|
||||||
# generate ansible settings
|
# generate ansible settings
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/ansible/kube-vip.yml" \
|
envsubst < "${PROJECT_DIR}/tmpl/ansible/kube-vip.yml" \
|
||||||
> "${PROJECT_DIR}/ansible/inventory/group_vars/kubernetes/kube-vip.yml"
|
> "${PROJECT_DIR}/ansible/inventory/group_vars/kubernetes/kube-vip.yml"
|
||||||
|
|
||||||
# generate ansible hosts file and secrets
|
# generate ansible hosts file and secrets
|
||||||
generate_ansible_hosts
|
generate_ansible_hosts
|
||||||
generate_ansible_host_secrets
|
generate_ansible_host_secrets
|
||||||
@@ -99,7 +88,6 @@ parse_command_line() {
|
|||||||
|
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -z "$verify" ]]; then
|
if [[ -z "$verify" ]]; then
|
||||||
verify=0
|
verify=0
|
||||||
fi
|
fi
|
||||||
@@ -107,7 +95,7 @@ parse_command_line() {
|
|||||||
|
|
||||||
_has_binary() {
|
_has_binary() {
|
||||||
command -v "${1}" >/dev/null 2>&1 || {
|
command -v "${1}" >/dev/null 2>&1 || {
|
||||||
_log "ERROR" "${1} is not installed or not found in \$PATH"
|
_log "ERROR(${FUNCNAME[0]})" "${1} is not installed or not found in \$PATH"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,7 +106,7 @@ _has_optional_envar() {
|
|||||||
[[ "${!option}" == "" ]] && {
|
[[ "${!option}" == "" ]] && {
|
||||||
_log "WARN" "Unset optional variable ${option}"
|
_log "WARN" "Unset optional variable ${option}"
|
||||||
} || {
|
} || {
|
||||||
_log "INFO" "Found variable '${option}' with value '${!option}'"
|
_log "INFO(${FUNCNAME[0]})" "Found variable '${option}' with value '${!option}'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,22 +114,21 @@ _has_envar() {
|
|||||||
local option="${1}"
|
local option="${1}"
|
||||||
# shellcheck disable=SC2015
|
# shellcheck disable=SC2015
|
||||||
[[ "${!option}" == "" ]] && {
|
[[ "${!option}" == "" ]] && {
|
||||||
_log "ERROR" "Unset variable ${option}"
|
_log "ERROR(${FUNCNAME[0]})" "Unset variable ${option}"
|
||||||
exit 1
|
exit 1
|
||||||
} || {
|
} || {
|
||||||
_log "INFO" "Found variable '${option}' with value '${!option}'"
|
_log "INFO(${FUNCNAME[0]})" "Found variable '${option}' with value '${!option}'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_has_valid_ip() {
|
_has_valid_ip() {
|
||||||
local ip="${1}"
|
local ip="${1}"
|
||||||
local variable_name="${2}"
|
local variable_name="${2}"
|
||||||
|
|
||||||
if ! ipcalc "${ip}" | awk 'BEGIN{FS=":"; is_invalid=0} /^INVALID/ {is_invalid=1; print $1} END{exit is_invalid}' >/dev/null 2>&1; then
|
if ! ipcalc "${ip}" | awk 'BEGIN{FS=":"; is_invalid=0} /^INVALID/ {is_invalid=1; print $1} END{exit is_invalid}' >/dev/null 2>&1; then
|
||||||
_log "INFO" "Variable '${variable_name}' has an invalid IP address '${ip}'"
|
_log "INFO(${FUNCNAME[0]})" "Variable '${variable_name}' has an invalid IP address '${ip}'"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
_log "INFO" "Variable '${variable_name}' has a valid IP address '${ip}'"
|
_log "INFO(${FUNCNAME[0]})" "Variable '${variable_name}' has a valid IP address '${ip}'"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,31 +136,27 @@ verify_addressing() {
|
|||||||
local found_kube_vip="false"
|
local found_kube_vip="false"
|
||||||
local found_k8s_gateway="false"
|
local found_k8s_gateway="false"
|
||||||
local found_ingress="false"
|
local found_ingress="false"
|
||||||
|
|
||||||
# Verify the metallb min and metallb ceiling are in the same network
|
# Verify the metallb min and metallb ceiling are in the same network
|
||||||
metallb_subnet_min=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f1 | cut -d. -f1,2,3)
|
metallb_subnet_min=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f1 | cut -d. -f1,2,3)
|
||||||
metallb_subnet_ceil=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f2 | cut -d. -f1,2,3)
|
metallb_subnet_ceil=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f2 | cut -d. -f1,2,3)
|
||||||
if [[ "${metallb_subnet_min}" != "${metallb_subnet_ceil}" ]]; then
|
if [[ "${metallb_subnet_min}" != "${metallb_subnet_ceil}" ]]; then
|
||||||
_log "ERROR" "The provided MetalLB IP range '${BOOTSTRAP_METALLB_LB_RANGE}' is not in the same subnet"
|
_log "ERROR(${FUNCNAME[0]})" "The provided MetalLB IP range '${BOOTSTRAP_METALLB_LB_RANGE}' is not in the same subnet"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Verify the node IP addresses are on the same network as the metallb range
|
# Verify the node IP addresses are on the same network as the metallb range
|
||||||
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
|
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
|
||||||
node_subnet=$(echo "${!var}" | cut -d. -f1,2,3)
|
node_subnet=$(echo "${!var}" | cut -d. -f1,2,3)
|
||||||
if [[ "${node_subnet}" != "${metallb_subnet_min}" ]]; then
|
if [[ "${node_subnet}" != "${metallb_subnet_min}" ]]; then
|
||||||
_log "ERROR" "The subnet for node '${!var}' is not in the same subnet as the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
_log "ERROR(${FUNCNAME[0]})" "The subnet for node '${!var}' is not in the same subnet as the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Verify the kube-vip IP is in the same network as the metallb range
|
# Verify the kube-vip IP is in the same network as the metallb range
|
||||||
kubevip_subnet=$(echo "${BOOTSTRAP_KUBE_VIP_ADDR}" | cut -d. -f1,2,3)
|
kubevip_subnet=$(echo "${BOOTSTRAP_KUBE_VIP_ADDR}" | cut -d. -f1,2,3)
|
||||||
if [[ "${kubevip_subnet}" != "${metallb_subnet_min}" ]]; then
|
if [[ "${kubevip_subnet}" != "${metallb_subnet_min}" ]]; then
|
||||||
_log "ERROR" "The subnet for kupe-vip '${BOOTSTRAP_KUBE_VIP_ADDR}' is not the same subnet as the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
_log "ERROR(${FUNCNAME[0]})" "The subnet for kupe-vip '${BOOTSTRAP_KUBE_VIP_ADDR}' is not the same subnet as the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Depending on the IP address, verify if it should be in the metallb range or not
|
# Depending on the IP address, verify if it should be in the metallb range or not
|
||||||
metallb_octet_min=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f1 | cut -d. -f4)
|
metallb_octet_min=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f1 | cut -d. -f4)
|
||||||
metallb_octet_ceil=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f2 | cut -d. -f4)
|
metallb_octet_ceil=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f2 | cut -d. -f4)
|
||||||
@@ -188,27 +171,23 @@ verify_addressing() {
|
|||||||
if [[ "${addr}" == "${BOOTSTRAP_METALLB_INGRESS_ADDR}" ]]; then
|
if [[ "${addr}" == "${BOOTSTRAP_METALLB_INGRESS_ADDR}" ]]; then
|
||||||
found_ingress="true"
|
found_ingress="true"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
|
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
|
||||||
if [[ "${!var}" == "${addr}" ]]; then
|
if [[ "${!var}" == "${addr}" ]]; then
|
||||||
_log "ERROR" "The IP for node '${!var}' should NOT be in the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
_log "ERROR(${FUNCNAME[0]})" "The IP for node '${!var}' should NOT be in the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "${found_kube_vip}" == "true" ]]; then
|
if [[ "${found_kube_vip}" == "true" ]]; then
|
||||||
_log "ERROR" "The IP for kube-vip '${BOOTSTRAP_KUBE_VIP_ADDR}' should NOT be in the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
_log "ERROR(${FUNCNAME[0]})" "The IP for kube-vip '${BOOTSTRAP_KUBE_VIP_ADDR}' should NOT be in the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${found_k8s_gateway}" == "false" ]]; then
|
if [[ "${found_k8s_gateway}" == "false" ]]; then
|
||||||
_log "ERROR" "The IP for k8s_gateway '${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}' should be in the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
_log "ERROR(${FUNCNAME[0]})" "The IP for k8s_gateway '${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}' should be in the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${found_ingress}" == "false" ]]; then
|
if [[ "${found_ingress}" == "false" ]]; then
|
||||||
_log "ERROR" "The IP for ingress '${BOOTSTRAP_METALLB_INGRESS_ADDR}' should be in the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
_log "ERROR(${FUNCNAME[0]})" "The IP for ingress '${BOOTSTRAP_METALLB_INGRESS_ADDR}' should be in the provided metallb range '${BOOTSTRAP_METALLB_LB_RANGE}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -216,19 +195,17 @@ verify_addressing() {
|
|||||||
verify_age() {
|
verify_age() {
|
||||||
_has_envar "BOOTSTRAP_AGE_PUBLIC_KEY"
|
_has_envar "BOOTSTRAP_AGE_PUBLIC_KEY"
|
||||||
_has_envar "SOPS_AGE_KEY_FILE"
|
_has_envar "SOPS_AGE_KEY_FILE"
|
||||||
|
|
||||||
if [[ ! "$BOOTSTRAP_AGE_PUBLIC_KEY" =~ ^age.* ]]; then
|
if [[ ! "$BOOTSTRAP_AGE_PUBLIC_KEY" =~ ^age.* ]]; then
|
||||||
_log "ERROR" "BOOTSTRAP_AGE_PUBLIC_KEY does not start with age"
|
_log "ERROR(${FUNCNAME[0]})" "BOOTSTRAP_AGE_PUBLIC_KEY does not start with age"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
_log "INFO" "Age public key is in the correct format"
|
_log "INFO(${FUNCNAME[0]})" "Age public key is in the correct format"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f ~/.config/sops/age/keys.txt ]]; then
|
if [[ ! -f ~/.config/sops/age/keys.txt ]]; then
|
||||||
_log "ERROR" "Unable to find Age file keys.txt in ~/.config/sops/age"
|
_log "ERROR(${FUNCNAME[0]})" "Unable to find Age file keys.txt in ~/.config/sops/age"
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
_log "INFO" "Found Age public key '${BOOTSTRAP_AGE_PUBLIC_KEY}'"
|
_log "INFO(${FUNCNAME[0]})" "Found Age public key '${BOOTSTRAP_AGE_PUBLIC_KEY}'"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,14 +225,12 @@ verify_binaries() {
|
|||||||
_has_binary "task"
|
_has_binary "task"
|
||||||
_has_binary "terraform"
|
_has_binary "terraform"
|
||||||
_has_binary "tflint"
|
_has_binary "tflint"
|
||||||
|
|
||||||
if ! [[ "$(sops --version)" =~ 3\.[0-9]+\.[0-9]+ ]]; then
|
if ! [[ "$(sops --version)" =~ 3\.[0-9]+\.[0-9]+ ]]; then
|
||||||
_log "ERROR" "Incompatible sops version, make sure you are using the latest release of github.com/mozilla/sops"
|
_log "ERROR(${FUNCNAME[0]})" "Incompatible sops version, make sure you are using the latest release of github.com/mozilla/sops"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [[ "$(yq --version)" =~ 4\.[0-9]+\.[0-9]+ ]]; then
|
if ! [[ "$(yq --version)" =~ 4\.[0-9]+\.[0-9]+ ]]; then
|
||||||
_log "ERROR" "Incompatible yq version, make sure you are using the latest release of github.com/mikefarah/yq"
|
_log "ERROR(${FUNCNAME[0]})" "Incompatible yq version, make sure you are using the latest release of github.com/mikefarah/yq"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -266,91 +241,62 @@ verify_kubevip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
verify_metallb() {
|
verify_metallb() {
|
||||||
local ip_floor=
|
|
||||||
local ip_ceil=
|
|
||||||
_has_envar "BOOTSTRAP_METALLB_LB_RANGE"
|
_has_envar "BOOTSTRAP_METALLB_LB_RANGE"
|
||||||
_has_envar "BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR"
|
_has_envar "BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR"
|
||||||
_has_envar "BOOTSTRAP_METALLB_INGRESS_ADDR"
|
_has_envar "BOOTSTRAP_METALLB_INGRESS_ADDR"
|
||||||
|
_has_valid_ip "$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f1)" "BOOTSTRAP_METALLB_LB_RANGE"
|
||||||
ip_floor=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f1)
|
_has_valid_ip "$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f2)" "BOOTSTRAP_METALLB_LB_RANGE"
|
||||||
ip_ceil=$(echo "${BOOTSTRAP_METALLB_LB_RANGE}" | cut -d- -f2)
|
|
||||||
|
|
||||||
_has_valid_ip "${ip_floor}" "BOOTSTRAP_METALLB_LB_RANGE"
|
|
||||||
_has_valid_ip "${ip_ceil}" "BOOTSTRAP_METALLB_LB_RANGE"
|
|
||||||
_has_valid_ip "${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}" "BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR"
|
_has_valid_ip "${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}" "BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR"
|
||||||
_has_valid_ip "${BOOTSTRAP_METALLB_INGRESS_ADDR}" "BOOTSTRAP_METALLB_INGRESS_ADDR"
|
_has_valid_ip "${BOOTSTRAP_METALLB_INGRESS_ADDR}" "BOOTSTRAP_METALLB_INGRESS_ADDR"
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_git_repository() {
|
verify_git_repository() {
|
||||||
_has_envar "BOOTSTRAP_GIT_REPOSITORY"
|
_has_envar "BOOTSTRAP_GIT_REPOSITORY"
|
||||||
|
|
||||||
export GIT_TERMINAL_PROMPT=0
|
export GIT_TERMINAL_PROMPT=0
|
||||||
pushd "$(mktemp -d)" >/dev/null 2>&1
|
pushd "$(mktemp -d)" >/dev/null 2>&1
|
||||||
[ "$(git ls-remote "${BOOTSTRAP_GIT_REPOSITORY}" 2> /dev/null)" ] || {
|
[ "$(git ls-remote "${BOOTSTRAP_GIT_REPOSITORY}" 2> /dev/null)" ] || {
|
||||||
_log "ERROR" "Unable to find the remote Git repository '${BOOTSTRAP_GIT_REPOSITORY}'"
|
_log "ERROR(${FUNCNAME[0]})" "Unable to find the remote Git repository '${BOOTSTRAP_GIT_REPOSITORY}'"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
popd >/dev/null 2>&1
|
popd >/dev/null 2>&1
|
||||||
export GIT_TERMINAL_PROMPT=1
|
export GIT_TERMINAL_PROMPT=1
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_github_webhook() {
|
verify_master_count() {
|
||||||
_has_envar "BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET"
|
local master_node_count=
|
||||||
|
master_node_count=0
|
||||||
WEBHOOK_SECRET="${BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET}"
|
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
|
||||||
|
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
|
||||||
if [[ "${WEBHOOK_SECRET}" == "generated" ]]; then
|
node_control="BOOTSTRAP_ANSIBLE_CONTROL_NODE_${node_id}"
|
||||||
WEBHOOK_SECRET="$(openssl rand -base64 30)"
|
if [[ "${!node_control}" == "true" ]]; then
|
||||||
|
master_node_count=$((master_node_count+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Check for existance of master nodes and that their count is not an even number
|
||||||
|
if [[ ${master_node_count} -eq 0 || $((master_node_count%2)) -eq 0 ]]; then
|
||||||
|
_log "ERROR(${FUNCNAME[0]})" "You must have 1, 3 or an odd number of master nodes >=3 inorder for etcd to have quorum"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
_log "INFO(${FUNCNAME[0]})" "Verified control plane node count"
|
||||||
export BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET="${WEBHOOK_SECRET}"
|
|
||||||
_log "INFO" "Using GitHub Token '${WEBHOOK_SECRET}' for Flux"
|
|
||||||
|
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/github-webhook-token-secret.sops.yaml" \
|
|
||||||
> "${PROJECT_DIR}/kubernetes/apps/flux-system/addons/webhooks/github/secret.sops.yaml"
|
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/flux-system/addons/webhooks/github/secret.sops.yaml"
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_weave_gitops() {
|
|
||||||
_has_envar "BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD"
|
|
||||||
|
|
||||||
WEAVE_GITOPS_ADMIN_PASSWORD="${BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD}"
|
|
||||||
|
|
||||||
if [[ "${WEAVE_GITOPS_ADMIN_PASSWORD}" == "generated" ]]; then
|
|
||||||
WEAVE_GITOPS_ADMIN_PASSWORD="$(openssl rand -base64 30)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
export BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD="${WEAVE_GITOPS_ADMIN_PASSWORD}"
|
|
||||||
_log "INFO" "Using admin password '${WEAVE_GITOPS_ADMIN_PASSWORD}' for Weave Gitops"
|
|
||||||
|
|
||||||
# Convert password to bcrypt hash
|
|
||||||
export BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD="$(echo -n "${BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD}" | gitops get bcrypt-hash)"
|
|
||||||
|
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/weave-gitops-secret.sops.yaml" \
|
|
||||||
> "${PROJECT_DIR}/kubernetes/apps/flux-system/weave-gitops/app/secret.sops.yaml"
|
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/flux-system/weave-gitops/app/secret.sops.yaml"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_cloudflare() {
|
verify_cloudflare() {
|
||||||
local account_zone=
|
local account_zone=
|
||||||
local errors=
|
local errors=
|
||||||
|
|
||||||
_has_envar "BOOTSTRAP_CLOUDFLARE_APIKEY"
|
_has_envar "BOOTSTRAP_CLOUDFLARE_APIKEY"
|
||||||
_has_envar "BOOTSTRAP_CLOUDFLARE_DOMAIN"
|
_has_envar "BOOTSTRAP_CLOUDFLARE_DOMAIN"
|
||||||
_has_envar "BOOTSTRAP_CLOUDFLARE_EMAIL"
|
_has_envar "BOOTSTRAP_CLOUDFLARE_EMAIL"
|
||||||
|
|
||||||
# Try to retrieve zone information from Cloudflare's API
|
# Try to retrieve zone information from Cloudflare's API
|
||||||
account_zone=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${BOOTSTRAP_CLOUDFLARE_DOMAIN}&status=active" \
|
account_zone=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${BOOTSTRAP_CLOUDFLARE_DOMAIN}&status=active" \
|
||||||
-H "X-Auth-Email: ${BOOTSTRAP_CLOUDFLARE_EMAIL}" \
|
-H "X-Auth-Email: ${BOOTSTRAP_CLOUDFLARE_EMAIL}" \
|
||||||
-H "X-Auth-Key: ${BOOTSTRAP_CLOUDFLARE_APIKEY}" \
|
-H "X-Auth-Key: ${BOOTSTRAP_CLOUDFLARE_APIKEY}" \
|
||||||
-H "Content-Type: application/json"
|
-H "Content-Type: application/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
if [[ "$(echo "${account_zone}" | jq ".success")" == "true" ]]; then
|
if [[ "$(echo "${account_zone}" | jq ".success")" == "true" ]]; then
|
||||||
_log "INFO" "Verified Cloudflare Account and Zone information"
|
_log "INFO(${FUNCNAME[0]})" "Verified Cloudflare Account and Zone information"
|
||||||
else
|
else
|
||||||
errors=$(echo "${account_zone}" | jq -c ".errors")
|
errors=$(echo "${account_zone}" | jq -c ".errors")
|
||||||
_log "ERROR" "Unable to get Cloudflare Account and Zone information ${errors}"
|
_log "ERROR(${FUNCNAME[0]})" "Unable to get Cloudflare Account and Zone information ${errors}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -364,12 +310,10 @@ verify_ansible_hosts() {
|
|||||||
local node_hostname=
|
local node_hostname=
|
||||||
local default_control_node_prefix=
|
local default_control_node_prefix=
|
||||||
local default_worker_node_prefix=
|
local default_worker_node_prefix=
|
||||||
|
|
||||||
default_control_node_prefix="BOOTSTRAP_ANSIBLE_DEFAULT_CONTROL_NODE_HOSTNAME_PREFIX"
|
default_control_node_prefix="BOOTSTRAP_ANSIBLE_DEFAULT_CONTROL_NODE_HOSTNAME_PREFIX"
|
||||||
default_worker_node_prefix="BOOTSTRAP_ANSIBLE_DEFAULT_NODE_HOSTNAME_PREFIX"
|
default_worker_node_prefix="BOOTSTRAP_ANSIBLE_DEFAULT_NODE_HOSTNAME_PREFIX"
|
||||||
_has_optional_envar "${default_control_node_prefix}"
|
_has_optional_envar "${default_control_node_prefix}"
|
||||||
_has_optional_envar "${default_worker_node_prefix}"
|
_has_optional_envar "${default_worker_node_prefix}"
|
||||||
|
|
||||||
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
|
for var in "${!BOOTSTRAP_ANSIBLE_HOST_ADDR_@}"; do
|
||||||
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
|
node_id=$(echo "${var}" | awk -F"_" '{print $5}')
|
||||||
node_addr="BOOTSTRAP_ANSIBLE_HOST_ADDR_${node_id}"
|
node_addr="BOOTSTRAP_ANSIBLE_HOST_ADDR_${node_id}"
|
||||||
@@ -382,34 +326,30 @@ verify_ansible_hosts() {
|
|||||||
_has_envar "${node_password}"
|
_has_envar "${node_password}"
|
||||||
_has_envar "${node_control}"
|
_has_envar "${node_control}"
|
||||||
_has_optional_envar "${node_hostname}"
|
_has_optional_envar "${node_hostname}"
|
||||||
|
|
||||||
if [[ "${!node_addr}" == "${BOOTSTRAP_KUBE_VIP_ADDR}" && "${BOOTSTRAP_KUBE_VIP_ENABLED}" == "true" ]]; then
|
if [[ "${!node_addr}" == "${BOOTSTRAP_KUBE_VIP_ADDR}" && "${BOOTSTRAP_KUBE_VIP_ENABLED}" == "true" ]]; then
|
||||||
_log "ERROR" "The kube-vip IP '${BOOTSTRAP_KUBE_VIP_ADDR}' should not be the same as the IP for node '${!node_addr}'"
|
_log "ERROR(${FUNCNAME[0]})" "The kube-vip IP '${BOOTSTRAP_KUBE_VIP_ADDR}' should not be the same as the IP for node '${!node_addr}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${!node_addr}" == "${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}" ]]; then
|
if [[ "${!node_addr}" == "${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}" ]]; then
|
||||||
_log "ERROR" "The k8s-gateway load balancer IP '${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}' should not be the same as the IP for node '${!node_addr}'"
|
_log "ERROR(${FUNCNAME[0]})" "The k8s-gateway load balancer IP '${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}' should not be the same as the IP for node '${!node_addr}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${!node_addr}" == "${BOOTSTRAP_METALLB_INGRESS_ADDR}" ]]; then
|
if [[ "${!node_addr}" == "${BOOTSTRAP_METALLB_INGRESS_ADDR}" ]]; then
|
||||||
_log "ERROR" "The ingress load balancer IP '${BOOTSTRAP_METALLB_INGRESS_ADDR}' should not be the same as the IP for node '${!node_addr}'"
|
_log "ERROR(${FUNCNAME[0]})" "The ingress load balancer IP '${BOOTSTRAP_METALLB_INGRESS_ADDR}' should not be the same as the IP for node '${!node_addr}'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ssh -q -o BatchMode=yes -o ConnectTimeout=5 "${!node_username}"@"${!var}" "true"; then
|
if ssh -q -o BatchMode=yes -o ConnectTimeout=5 "${!node_username}"@"${!var}" "true"; then
|
||||||
_log "INFO" "SSH into host '${!var}' with username '${!node_username}' was successfull"
|
_log "INFO(${FUNCNAME[0]})" "SSH into host '${!var}' with username '${!node_username}' was successfull"
|
||||||
else
|
else
|
||||||
_log "ERROR" "SSH into host '${!var}' with username '${!node_username}'was NOT successful, did you copy over your SSH key?"
|
_log "ERROR(${FUNCNAME[0]})" "SSH into host '${!var}' with username '${!node_username}'was NOT successful, did you copy over your SSH key?"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_success() {
|
verify_success() {
|
||||||
_log "INFO" "All checks passed!"
|
_log "INFO(${FUNCNAME[0]})" "All checks passed!"
|
||||||
_log "INFO" "Run the script without --verify to template all the files out"
|
_log "INFO(${FUNCNAME[0]})" "Run the script without --verify to template all the files out"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,8 +444,37 @@ generate_ansible_hosts() {
|
|||||||
} > "${PROJECT_DIR}/ansible/inventory/hosts.yml"
|
} > "${PROJECT_DIR}/ansible/inventory/hosts.yml"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_github_webhook() {
|
||||||
|
_has_envar "BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET"
|
||||||
|
WEBHOOK_SECRET="${BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET}"
|
||||||
|
if [[ "${WEBHOOK_SECRET}" == "generated" ]]; then
|
||||||
|
WEBHOOK_SECRET="$(openssl rand -base64 30)"
|
||||||
|
fi
|
||||||
|
export BOOTSTRAP_FLUX_GITHUB_WEBHOOK_SECRET="${WEBHOOK_SECRET}"
|
||||||
|
_log "INFO(${FUNCNAME[0]})" "Using GitHub Token '${WEBHOOK_SECRET}' for Flux"
|
||||||
|
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/github-webhook-token-secret.sops.yaml" \
|
||||||
|
> "${PROJECT_DIR}/kubernetes/apps/flux-system/addons/webhooks/github/secret.sops.yaml"
|
||||||
|
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/flux-system/addons/webhooks/github/secret.sops.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_weave_gitops() {
|
||||||
|
_has_envar "BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD"
|
||||||
|
WEAVE_GITOPS_ADMIN_PASSWORD="${BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD}"
|
||||||
|
if [[ "${WEAVE_GITOPS_ADMIN_PASSWORD}" == "generated" ]]; then
|
||||||
|
WEAVE_GITOPS_ADMIN_PASSWORD="$(openssl rand -base64 30)"
|
||||||
|
fi
|
||||||
|
export BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD="${WEAVE_GITOPS_ADMIN_PASSWORD}"
|
||||||
|
_log "INFO(${FUNCNAME[0]})" "Using admin password '${WEAVE_GITOPS_ADMIN_PASSWORD}' for Weave Gitops"
|
||||||
|
# Convert password to bcrypt hash
|
||||||
|
# shellcheck disable=SC2155
|
||||||
|
export BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD="$(echo -n "${BOOTSTRAP_WEAVE_GITOPS_ADMIN_PASSWORD}" | gitops get bcrypt-hash)"
|
||||||
|
envsubst < "${PROJECT_DIR}/tmpl/kubernetes/weave-gitops-secret.sops.yaml" \
|
||||||
|
> "${PROJECT_DIR}/kubernetes/apps/flux-system/weave-gitops/app/secret.sops.yaml"
|
||||||
|
sops --encrypt --in-place "${PROJECT_DIR}/kubernetes/apps/flux-system/weave-gitops/app/secret.sops.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
success() {
|
success() {
|
||||||
_log "INFO" "All files have been templated, proceed to the next steps outlined in the README"
|
_log "INFO(${FUNCNAME[0]})" "All files have been templated, proceed to the next steps outlined in the README"
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user