From 557d1782b20977513f106c4d7776a2e30c2d560c Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 18 Sep 2024 18:43:46 +0000 Subject: [PATCH 01/28] Integrate config tool into setupOS --- ic-os/components/misc/config.sh | 12 ++ .../setupos-scripts/check-config.sh | 33 ++++ .../setupos-scripts/check-hardware.sh | 11 +- .../setupos-scripts/check-network.sh | 66 +++----- .../components/setupos-scripts/config.service | 6 +- ic-os/components/setupos-scripts/config.sh | 120 -------------- ic-os/components/setupos-scripts/functions.sh | 2 +- .../setupos-scripts/install-guestos.sh | 3 +- .../setupos-scripts/install-hostos.sh | 3 +- .../components/setupos-scripts/setup-disk.sh | 3 +- .../setupos-scripts/setup-hostos-config.sh | 44 +++-- ic-os/components/setupos-scripts/setupos.sh | 3 +- ic-os/components/setupos.bzl | 4 +- ic-os/setupos/defs.bzl | 1 + rs/ic_os/network/src/info.rs | 154 ------------------ rs/ic_os/network/src/interfaces.rs | 4 +- rs/ic_os/network/src/lib.rs | 25 ++- rs/ic_os/network/src/systemd.rs | 21 ++- rs/ic_os/os_tools/hostos_tool/src/main.rs | 126 ++++++++------ rs/ic_os/os_tools/setupos_tool/src/main.rs | 95 +++++------ 20 files changed, 270 insertions(+), 466 deletions(-) create mode 100644 ic-os/components/misc/config.sh create mode 100644 ic-os/components/setupos-scripts/check-config.sh delete mode 100755 ic-os/components/setupos-scripts/config.sh delete mode 100644 rs/ic_os/network/src/info.rs diff --git a/ic-os/components/misc/config.sh b/ic-os/components/misc/config.sh new file mode 100644 index 00000000000..21151813cc8 --- /dev/null +++ b/ic-os/components/misc/config.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Shared config utilities. + +# Retrieves a value from the config.json file using a JSON path. +# Arguments: +# $1 - JSON path to the desired value (e.g., '.icos_settings.node_operator_private_key_path') +function get_config_value() { + local CONFIG_FILE="/var/ic/config/config.json" + local key=$1 + jq -r "${key}" "${CONFIG_FILE}" +} diff --git a/ic-os/components/setupos-scripts/check-config.sh b/ic-os/components/setupos-scripts/check-config.sh new file mode 100644 index 00000000000..b826345a4c5 --- /dev/null +++ b/ic-os/components/setupos-scripts/check-config.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -o nounset +set -o pipefail + +source /opt/ic/bin/config.sh +source /opt/ic/bin/functions.sh + +SHELL="/bin/bash" +PATH="/sbin:/bin:/usr/sbin:/usr/bin" + +check_config_file() { + echo "* Checking Config..." + local CONFIG_FILE="/var/ic/config/config.json" + + if [ -f "${CONFIG_FILE}" ]; then + local config_contents=$(cat "${CONFIG_FILE}") + echo -e "Configuration file '${CONFIG_FILE}' exists.\n" + echo -e "File contents:\n${config_contents}" + else + local service_logs=$(journalctl -u config.service --no-pager) + local log_message="Error creating SetupOS configuration. Configuration file '${CONFIG_FILE}' does not exist.\n\nConfig.service logs:\n${service_logs}" + + log_and_halt_installation_on_error 1 "${log_message}" + fi +} + +# Establish run order +main() { + check_config_file +} + +main diff --git a/ic-os/components/setupos-scripts/check-hardware.sh b/ic-os/components/setupos-scripts/check-hardware.sh index 97770a9d8bd..3d77b7ac2cb 100644 --- a/ic-os/components/setupos-scripts/check-hardware.sh +++ b/ic-os/components/setupos-scripts/check-hardware.sh @@ -3,6 +3,9 @@ set -o nounset set -o pipefail +source /opt/ic/bin/config.sh +source /opt/ic/bin/functions.sh + SHELL="/bin/bash" PATH="/sbin:/bin:/usr/sbin:/usr/bin" @@ -30,8 +33,6 @@ GEN2_MINIMUM_AGGREGATE_DISK_SIZE=32000000000000 GEN1_MINIMUM_DISK_SIZE=3200000000000 GEN1_MINIMUM_AGGREGATE_DISK_SIZE=32000000000000 -CONFIG_DIR="/var/ic/config" - function check_generation() { echo "* Checking Generation..." @@ -247,7 +248,10 @@ function verify_disks() { function verify_deployment_path() { echo "* Verifying deployment path..." - if [[ ${GENERATION} == 2 ]] && [[ ! -f "${CONFIG_DIR}/node_operator_private_key.pem" ]]; then + + local node_operator_key_path=$(get_config_value '.icos_settings.node_operator_private_key_path') + + if [[ ${GENERATION} == 2 ]] && [[ ! -f "${node_operator_key_path}" ]]; then echo -e "\n\n\n\n\n\n" echo -e "\033[1;31mWARNING: Gen2 hardware detected but no Node Operator Private Key found.\033[0m" echo -e "\033[1;31mGen2 hardware should be deployed using the Gen2 Node Deployment method.\033[0m" @@ -261,7 +265,6 @@ function verify_deployment_path() { # Establish run order main() { - source /opt/ic/bin/functions.sh log_start "$(basename $0)" check_generation verify_cpu diff --git a/ic-os/components/setupos-scripts/check-network.sh b/ic-os/components/setupos-scripts/check-network.sh index 057a9ef56dd..8eb9932a420 100755 --- a/ic-os/components/setupos-scripts/check-network.sh +++ b/ic-os/components/setupos-scripts/check-network.sh @@ -3,25 +3,19 @@ set -o nounset set -o pipefail +source /opt/ic/bin/config.sh +source /opt/ic/bin/functions.sh + SHELL="/bin/bash" PATH="/sbin:/bin:/usr/sbin:/usr/bin" -CONFIG="${CONFIG:=/var/ic/config/config.ini}" -DEPLOYMENT="${DEPLOYMENT:=/data/deployment.json}" - -function read_variables() { - # Read limited set of keys. Be extra-careful quoting values as it could - # otherwise lead to executing arbitrary shell code! - while IFS="=" read -r key value; do - case "$key" in - "ipv6_prefix") ipv6_prefix="${value}" ;; - "ipv6_gateway") ipv6_gateway="${value}" ;; - "ipv4_address") ipv4_address="${value}" ;; - "ipv4_prefix_length") ipv4_prefix_length="${value}" ;; - "ipv4_gateway") ipv4_gateway="${value}" ;; - "domain") domain="${value}" ;; - esac - done <"${CONFIG}" +function read_config_variables() { + ipv6_prefix=$(get_config_value '.network_settings.ipv6_prefix') + ipv6_gateway=$(get_config_value '.network_settings.ipv6_gateway') + ipv4_address=$(get_config_value '.network_settings.ipv4_address') + ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_prefix_length') + ipv4_gateway=$(get_config_value '.network_settings.ipv4_gateway') + domain=$(get_config_value '.network_settings.domain') } # WARNING: Uses 'eval' for command execution. @@ -168,45 +162,36 @@ function ping_ipv6_gateway() { echo " " } -function assemble_nns_nodes_list() { - NNS_URL_STRING=$(/opt/ic/bin/fetch-property.sh --key=.nns.url --config=${DEPLOYMENT}) - NNS_URL_LIST=$(echo $NNS_URL_STRING | sed 's@,@ @g') -} - function query_nns_nodes() { echo "* Querying NNS nodes..." - i=0 - success=0 - nodes=$(echo ${NNS_URL_LIST} | wc -w) - # At least one of the provided URLs needs to work. - verify=1 - for url in $(echo $NNS_URL_LIST); do + local nns_urls=($(get_config_value '.icos_settings.nns_urls' | jq -r '.[]')) + local success=false + + for url in "${nns_urls[@]}"; do # When running against testnets, we need to ignore self signed certs # with `--insecure`. This check is only meant to confirm from SetupOS # that NNS urls are reachable, so we do not mind that it is "weak". - curl --insecure --head --connect-timeout 3 --silent ${url} >/dev/null 2>&1 - if [ "${?}" -ne 0 ]; then - echo " fail: ${url}" - else + if curl --insecure --head --connect-timeout 3 --silent "${url}" >/dev/null 2>&1; then echo " okay: ${url}" - success=$((${success} + 1)) - fi - i=$((${i} + 1)) - if [ ${success} -ge ${verify} ]; then - echo " success" + success=true break - elif [ ${i} -eq ${nodes} ]; then - log_and_halt_installation_on_error "1" "Unable to query enough healthy NNS nodes." + else + echo " fail: ${url}" fi done + + if $success; then + echo " success" + else + log_and_halt_installation_on_error "1" "Unable to query enough healthy NNS nodes." + fi } # Establish run order main() { - source /opt/ic/bin/functions.sh log_start "$(basename $0)" - read_variables + read_config_variables get_network_settings print_network_settings @@ -217,7 +202,6 @@ main() { fi ping_ipv6_gateway - assemble_nns_nodes_list query_nns_nodes log_end "$(basename $0)" } diff --git a/ic-os/components/setupos-scripts/config.service b/ic-os/components/setupos-scripts/config.service index 2db6cdf7dc0..f35bbae5eb3 100644 --- a/ic-os/components/setupos-scripts/config.service +++ b/ic-os/components/setupos-scripts/config.service @@ -6,9 +6,9 @@ Before=setupos.service [Service] Type=oneshot RemainAfterExit=true -ExecStart=/opt/ic/bin/output-wrapper.sh /dev/ttyS0 /opt/ic/bin/config.sh -StandardOutput=tty -StandardError=tty +ExecStart=/opt/ic/bin/config create-setupos-config +StandardOutput=journal+console +StandardError=journal+console [Install] WantedBy=multi-user.target diff --git a/ic-os/components/setupos-scripts/config.sh b/ic-os/components/setupos-scripts/config.sh deleted file mode 100755 index 0b13fb29296..00000000000 --- a/ic-os/components/setupos-scripts/config.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env bash - -set -o nounset -set -o pipefail - -SHELL="/bin/bash" -PATH="/sbin:/bin:/usr/sbin:/usr/bin" - -CONFIG_DIR="/config" -CONFIG_TMP="/var/ic/config" -CONFIG_INI="${CONFIG_DIR}/config.ini" -CONFIG_INI_CLONE="${CONFIG_TMP}/config.ini" -SSH_AUTHORIZED_KEYS="${CONFIG_DIR}/ssh_authorized_keys" -SSH_AUTHORIZED_KEYS_CLONE="${CONFIG_TMP}/ssh_authorized_keys" - -# Define empty variables so they are not unset -ipv6_prefix="" -ipv6_gateway="" - -function print_config_file() { - if [ -e "${CONFIG_INI}" ]; then - echo "Found ${CONFIG_INI}. Contents:" - cat "${CONFIG_INI}" - else - log_and_halt_installation_on_error "1" "config.ini not found. Please copy a valid config.ini to the SetupOS installer config partition." - fi - -} - -function create_config_tmp() { - if [ ! -e "${CONFIG_TMP}" ]; then - # Create fresh config tmp directory - mkdir -p "${CONFIG_TMP}" - log_and_halt_installation_on_error "${?}" "Unable to create new '${CONFIG_TMP}' directory." - fi -} - -function clone_config() { - cp "${CONFIG_INI}" "${CONFIG_INI_CLONE}" - log_and_halt_installation_on_error "${?}" "Unable to copy 'config.ini' configuration file." - - if [ ! -f "${CONFIG_INI_CLONE}" ]; then - log_and_halt_installation_on_error "1" "Cloned 'config.ini' configuration file does not exist." - fi - - if [ -f "${CONFIG_DIR}/node_operator_private_key.pem" ]; then - cp ${CONFIG_DIR}/node_operator_private_key.pem ${CONFIG_TMP}/node_operator_private_key.pem - log_and_halt_installation_on_error "${?}" "Unable to copy 'node_operator_private_key.pem' configuration file." - fi - - if [ -d "${SSH_AUTHORIZED_KEYS}" ]; then - cp -r "${SSH_AUTHORIZED_KEYS}" "${CONFIG_TMP}" - log_and_halt_installation_on_error "${?}" "Unable to copy 'ssh_authorized_keys' directory." - else - log_and_halt_installation_on_error "1" "Unable to read 'ssh_authorized_keys' directory." - fi - - if [ ! -d "${SSH_AUTHORIZED_KEYS_CLONE}" ]; then - log_and_halt_installation_on_error "1" "Cloned 'ssh_authorized_keys' directory does not exist." - fi -} - -function normalize_config() { - CONFIG_VAR=$(cat "${CONFIG_INI_CLONE}" | tr '\r' '\n') - echo "${CONFIG_VAR}" >"${CONFIG_INI_CLONE}" - - sed -i 's/#.*$//g' "${CONFIG_INI_CLONE}" - log_and_halt_installation_on_error "${?}" "Unable to remove comments from 'config.ini'." - - sed -i 's/"//g' "${CONFIG_INI_CLONE}" - log_and_halt_installation_on_error "${?}" "Unable to replace double-quote characters in 'config.ini'." - - sed -i "s/'//g" "${CONFIG_INI_CLONE}" - log_and_halt_installation_on_error "${?}" "Unable to replace single-quote characters in 'config.ini'." - - sed -i 's/.*/\L&/' "${CONFIG_INI_CLONE}" - log_and_halt_installation_on_error "${?}" "Unable to convert upper- to lower-case in 'config.ini'." - - sed -i '/^$/d' "${CONFIG_INI_CLONE}" - log_and_halt_installation_on_error "${?}" "Unable to remove empty lines in 'config.ini'." - - echo -e '\n' >>"${CONFIG_INI_CLONE}" - log_and_halt_installation_on_error "${?}" "Unable to inject extra new-line at the end of 'config.ini'." -} - -function read_variables() { - # Read limited set of keys. Be extra-careful quoting values as it could - # otherwise lead to executing arbitrary shell code! - while IFS="=" read -r key value; do - case "$key" in - "ipv6_prefix") ipv6_prefix="${value}" ;; - "ipv6_gateway") ipv6_gateway="${value}" ;; - esac - done <"${CONFIG_INI_CLONE}" -} - -function verify_variables() { - if [ -z "${ipv6_prefix}" ]; then - log_and_halt_installation_on_error "1" "Variable 'ipv6_prefix' is not defined in 'config.ini'." - fi - - if [ -z "${ipv6_gateway}" ]; then - log_and_halt_installation_on_error "1" "Variable 'ipv6_gateway' is not defined in 'config.ini'." - fi -} - -# Establish run order -main() { - source /opt/ic/bin/functions.sh - log_start "$(basename $0)" - print_config_file - create_config_tmp - clone_config - normalize_config - read_variables - verify_variables - log_end "$(basename $0)" -} - -main diff --git a/ic-os/components/setupos-scripts/functions.sh b/ic-os/components/setupos-scripts/functions.sh index c058b1885c2..4e63bf0782e 100755 --- a/ic-os/components/setupos-scripts/functions.sh +++ b/ic-os/components/setupos-scripts/functions.sh @@ -23,7 +23,7 @@ function log_and_halt_installation_on_error() { echo " ERROR" echo "--------------------------------------------------------------------------------" echo -e "\n\n" - echo "${log_message}" + echo -e "${log_message}" echo -e "\n\n" echo "--------------------------------------------------------------------------------" echo " ERROR" diff --git a/ic-os/components/setupos-scripts/install-guestos.sh b/ic-os/components/setupos-scripts/install-guestos.sh index 2311c3ba9c3..3e24773234d 100755 --- a/ic-os/components/setupos-scripts/install-guestos.sh +++ b/ic-os/components/setupos-scripts/install-guestos.sh @@ -3,6 +3,8 @@ set -o nounset set -o pipefail +source /opt/ic/bin/functions.sh + SHELL="/bin/bash" PATH="/sbin:/bin:/usr/sbin:/usr/bin" @@ -34,7 +36,6 @@ function install_guestos() { # Establish run order main() { - source /opt/ic/bin/functions.sh log_start "$(basename $0)" install_guestos log_end "$(basename $0)" diff --git a/ic-os/components/setupos-scripts/install-hostos.sh b/ic-os/components/setupos-scripts/install-hostos.sh index bb3d3b2f424..4557a02957c 100755 --- a/ic-os/components/setupos-scripts/install-hostos.sh +++ b/ic-os/components/setupos-scripts/install-hostos.sh @@ -3,6 +3,8 @@ set -o nounset set -o pipefail +source /opt/ic/bin/functions.sh + SHELL="/bin/bash" PATH="/sbin:/bin:/usr/sbin:/usr/bin" @@ -101,7 +103,6 @@ function resize_partition() { # Establish run order main() { - source /opt/ic/bin/functions.sh log_start "$(basename $0)" install_hostos configure_efi diff --git a/ic-os/components/setupos-scripts/setup-disk.sh b/ic-os/components/setupos-scripts/setup-disk.sh index f7546bec499..38437fcf20b 100755 --- a/ic-os/components/setupos-scripts/setup-disk.sh +++ b/ic-os/components/setupos-scripts/setup-disk.sh @@ -3,6 +3,8 @@ set -o nounset set -o pipefail +source /opt/ic/bin/functions.sh + SHELL="/bin/bash" PATH="/sbin:/bin:/usr/sbin:/usr/bin" @@ -60,7 +62,6 @@ function setup_storage() { # Establish run order main() { - source /opt/ic/bin/functions.sh log_start "$(basename $0)" purge_partitions setup_storage diff --git a/ic-os/components/setupos-scripts/setup-hostos-config.sh b/ic-os/components/setupos-scripts/setup-hostos-config.sh index 1fc04a959fc..181eb119487 100755 --- a/ic-os/components/setupos-scripts/setup-hostos-config.sh +++ b/ic-os/components/setupos-scripts/setup-hostos-config.sh @@ -3,9 +3,12 @@ set -o nounset set -o pipefail +source /opt/ic/bin/config.sh +source /opt/ic/bin/functions.sh + SHELL="/bin/bash" PATH="/sbin:/bin:/usr/sbin:/usr/bin" -CONFIG_DIR="/var/ic/config" +CONFIG_DIR="/config" function mount_config_partition() { echo "* Mounting hostOS config partition..." @@ -27,19 +30,27 @@ function copy_config_files() { fi echo "* Copying SSH authorized keys..." - if [ -d "${CONFIG_DIR}/ssh_authorized_keys" ]; then - cp -r ${CONFIG_DIR}/ssh_authorized_keys /media/ - log_and_halt_installation_on_error "${?}" "Unable to copy SSH authorized keys to hostOS config partition." + ssh_authorized_keys=$(get_config_value '.icos_settings.ssh_authorized_keys_path') + if [ -n "${ssh_authorized_keys}" ] && [ "${ssh_authorized_keys}" != "null" ]; then + if [ -d "${ssh_authorized_keys}" ]; then + cp -a "${ssh_authorized_keys}" /media/ + log_and_halt_installation_on_error "${?}" "Unable to copy SSH authorized keys to hostOS config partition." + else + log_and_halt_installation_on_error "1" "Directory '${ssh_authorized_keys}' does not exist." + fi else - log_and_halt_installation_on_error "1" "Directory 'ssh_authorized_keys' does not exist." + echo >&2 "Warning: SSH authorized keys path is not configured." fi echo "* Copying node operator private key..." - if [ -f "${CONFIG_DIR}/node_operator_private_key.pem" ]; then - cp ${CONFIG_DIR}/node_operator_private_key.pem /media/ + node_operator_private_key_path=$(get_config_value '.icos_settings.node_operator_private_key_path') + if [ "${node_operator_private_key_path}" != "null" ] && [ -f "${node_operator_private_key_path}" ]; then + cp "${node_operator_private_key_path}" /media/ log_and_halt_installation_on_error "${?}" "Unable to copy node operator private key to hostOS config partition." + elif [ "${node_operator_private_key_path}" = "null" ]; then + echo >&2 "Warning: Node operator private key path is not configured." else - echo "node_operator_private_key.pem does not exist, requiring HSM." + echo >&2 "Warning: node_operator_private_key.pem does not exist, requiring HSM." fi echo "* Copying deployment.json to config partition..." @@ -47,8 +58,22 @@ function copy_config_files() { log_and_halt_installation_on_error "${?}" "Unable to copy deployment.json to hostOS config partition." echo "* Copying NNS public key to hostOS config partition..." - cp /data/nns_public_key.pem /media/ + nns_public_key_path=$(get_config_value '.icos_settings.nns_public_key_path') + cp "${nns_public_key_path}" /media/ log_and_halt_installation_on_error "${?}" "Unable to copy NNS public key to hostOS config partition." + + echo "* Converting 'config.json' to hostOS config file 'config-hostos.json'..." + /opt/ic/bin/config generate-hostos-config + log_and_halt_installation_on_error "${?}" "Unable to generate hostos configuration." + + # TODO: NODE-1466: Configuration revamp (HostOS and GuestOS integration) + # echo "* Copying 'config-hostos.json' to hostOS config partition..." + # if [ -f "/var/ic/config/config-hostos.json" ]; then + # cp /var/ic/config/config-hostos.json /media/config.json + # log_and_halt_installation_on_error "${?}" "Unable to copy 'config-hostos.json' to hostOS config partition." + # else + # log_and_halt_installation_on_error "1" "Configuration file 'config-hostos.json' does not exist." + # fi } function insert_hsm_if_necessary() { @@ -82,7 +107,6 @@ function unmount_config_partition() { # Establish run order main() { - source /opt/ic/bin/functions.sh log_start "$(basename $0)" mount_config_partition copy_config_files diff --git a/ic-os/components/setupos-scripts/setupos.sh b/ic-os/components/setupos-scripts/setupos.sh index 413f6453c1e..67fcbeedc77 100755 --- a/ic-os/components/setupos-scripts/setupos.sh +++ b/ic-os/components/setupos-scripts/setupos.sh @@ -3,6 +3,8 @@ set -o nounset set -o pipefail +source /opt/ic/bin/functions.sh + SHELL="/bin/bash" PATH="/sbin:/bin:/usr/sbin:/usr/bin" @@ -34,7 +36,6 @@ function reboot_setupos() { # Establish run order main() { - source /opt/ic/bin/functions.sh log_start "$(basename $0)" start_setupos /opt/ic/bin/check-setupos-age.sh diff --git a/ic-os/components/setupos.bzl b/ic-os/components/setupos.bzl index ed99261edb2..81def999eeb 100644 --- a/ic-os/components/setupos.bzl +++ b/ic-os/components/setupos.bzl @@ -5,7 +5,7 @@ Enumerate every component file dependency for SetupOS component_files = { # setupos-scripts Label("setupos-scripts/check-setupos-age.sh"): "/opt/ic/bin/check-setupos-age.sh", - Label("setupos-scripts/config.sh"): "/opt/ic/bin/config.sh", + Label("setupos-scripts/check-config.sh"): "/opt/ic/bin/check-config.sh", Label("setupos-scripts/setup-hostos-config.sh"): "/opt/ic/bin/setup-hostos-config.sh", Label("setupos-scripts/setup-disk.sh"): "/opt/ic/bin/setup-disk.sh", Label("setupos-scripts/functions.sh"): "/opt/ic/bin/functions.sh", @@ -26,9 +26,9 @@ component_files = { # misc Label("misc/logging.sh"): "/opt/ic/bin/logging.sh", + Label("misc/config.sh"): "/opt/ic/bin/config.sh", Label("misc/chrony/chrony.conf"): "/etc/chrony/chrony.conf", Label("misc/chrony/chrony-var.service"): "/etc/systemd/system/chrony-var.service", - Label("misc/fetch-property.sh"): "/opt/ic/bin/fetch-property.sh", Label("misc/serial-getty@/setupos/serial-getty@.service"): "/etc/systemd/system/serial-getty@.service", Label("monitoring/journald.conf"): "/etc/systemd/journald.conf", diff --git a/ic-os/setupos/defs.bzl b/ic-os/setupos/defs.bzl index 325ebb995fa..6483645fd41 100644 --- a/ic-os/setupos/defs.bzl +++ b/ic-os/setupos/defs.bzl @@ -31,6 +31,7 @@ def image_deps(mode, _malicious = False): "bootfs": {}, "rootfs": { "//rs/ic_os/release:setupos_tool": "/opt/ic/bin/setupos_tool:0755", + "//rs/ic_os/release:config": "/opt/ic/bin/config:0755", }, # Set various configuration values diff --git a/rs/ic_os/network/src/info.rs b/rs/ic_os/network/src/info.rs deleted file mode 100644 index 88109c8e71a..00000000000 --- a/rs/ic_os/network/src/info.rs +++ /dev/null @@ -1,154 +0,0 @@ -use std::net::Ipv6Addr; - -use anyhow::{bail, Context, Result}; - -use config::config_ini::ConfigMap; - -#[derive(Debug)] -pub struct NetworkInfo { - // Config files can specify ipv6 prefix, address and prefix, or just address. - // ipv6_address takes precedence. Some tests provide only the address. - // Should be kept as a string until parsing later. - pub ipv6_prefix: Option, - pub ipv6_address: Option, - pub ipv6_subnet: u8, - pub ipv6_gateway: Ipv6Addr, -} - -fn is_valid_prefix(ipv6_prefix: &str) -> bool { - ipv6_prefix.len() <= 19 && format!("{ipv6_prefix}::").parse::().is_ok() -} - -impl NetworkInfo { - pub fn from_config_map(config_map: &ConfigMap) -> Result { - // Per PFOPS - this will never not be 64 - let ipv6_subnet = 64_u8; - - let ipv6_prefix = match config_map.get("ipv6_prefix") { - Some(ipv6_prefix) => { - // Prefix should have a max length of 19 ("1234:6789:1234:6789") - // It could have fewer characters though. Parsing as an ip address with trailing '::' should work. - if !is_valid_prefix(ipv6_prefix) { - bail!("Invalid ipv6 prefix: {}", ipv6_prefix); - } - Some(ipv6_prefix.clone()) - } - None => None, - }; - - // Optional ipv6_address - for testing. Takes precedence over ipv6_prefix. - let ipv6_address = match config_map.get("ipv6_address") { - Some(address) => { - // ipv6_address might be formatted with the trailing suffix. Remove it. - let ipv6_subnet = format!("/{}", ipv6_subnet); - let address = address.strip_suffix(&ipv6_subnet).unwrap_or(address); - let address = address - .parse::() - .context(format!("Invalid ipv6 address: {}", address))?; - Some(address) - } - None => None, - }; - - if ipv6_address.is_none() && ipv6_prefix.is_none() { - bail!("Missing config parameter: need at least one of ipv6_prefix or ipv6_address"); - } - - let ipv6_gateway = config_map - .get("ipv6_gateway") - .context("Missing config parameter: ipv6_gateway")?; - let ipv6_gateway = ipv6_gateway - .parse::() - .context(format!("Invalid ipv6 address: {}", ipv6_gateway))?; - - Ok(NetworkInfo { - ipv6_prefix, - ipv6_subnet, - ipv6_gateway, - ipv6_address, - }) - } -} - -#[cfg(test)] -pub mod tests { - use std::collections::HashMap; - - use super::*; - #[test] - fn test_is_valid_prefix() { - assert!(is_valid_prefix("2a00:1111:1111:1111")); - assert!(is_valid_prefix("2a00:111:11:11")); - assert!(is_valid_prefix("2602:fb2b:100:10")); - } - - #[test] - fn test_from_config_map() { - // Example config.ini - let config_map = HashMap::from([ - ("ipv6_prefix".to_string(), "2a00:fb01:400:100".to_string()), - ( - "ipv6_gateway".to_string(), - "2a00:fb01:400:100::1".to_string(), - ), - ]); - assert!(NetworkInfo::from_config_map(&config_map).is_ok()); - - // With ipv6_address and ipv6_prefix - let config_map = HashMap::from([ - ("ipv6_prefix".to_string(), "2a00:fb01:400:100".to_string()), - ( - "ipv6_gateway".to_string(), - "2a00:fb01:400:100::1".to_string(), - ), - ( - "ipv6_address".to_string(), - "2a00:fb01:400:100::3".to_string(), - ), - ]); - assert!(NetworkInfo::from_config_map(&config_map).is_ok()); - - // No subnet - let config_map = HashMap::from([ - ("ipv6_prefix".to_string(), "2a00:fb01:400:100".to_string()), - ( - "ipv6_gateway".to_string(), - "2a00:fb01:400:100::1".to_string(), - ), - ]); - assert!(NetworkInfo::from_config_map(&config_map).is_ok()); - - // Need address or prefix - let config_map = HashMap::from([ - ( - "ipv6_address".to_string(), - "2a00:fb01:400:100::1".to_string(), - ), - ( - "ipv6_gateway".to_string(), - "2a00:fb01:400:100::1".to_string(), - ), - ]); - assert!(NetworkInfo::from_config_map(&config_map).is_ok()); - - // Need prefix or address, gateway - let config_map = HashMap::from([( - "ipv6_gateway".to_string(), - "2a00:fb01:400:100::1".to_string(), - )]); - assert!(NetworkInfo::from_config_map(&config_map).is_err()); - let config_map = - HashMap::from([("ipv6_prefix".to_string(), "2a00:fb01:400:100".to_string())]); - assert!(NetworkInfo::from_config_map(&config_map).is_err()); - - // With ipv6_address with subnet len - let config_map = HashMap::from([ - ( - "ipv6_gateway".to_string(), - "2a00:fb01:400:100::1".to_string(), - ), - ("ipv6_address".to_string(), "fd00:2:1:1::11/64".to_string()), - ]); - assert!(NetworkInfo::from_config_map(&config_map).is_ok()); - } -} diff --git a/rs/ic_os/network/src/interfaces.rs b/rs/ic_os/network/src/interfaces.rs index 2b7895be1bf..3f041e3856f 100644 --- a/rs/ic_os/network/src/interfaces.rs +++ b/rs/ic_os/network/src/interfaces.rs @@ -22,11 +22,11 @@ pub struct Interface { pub fn has_ipv6_connectivity( interface: &Interface, generated_ipv6: &Ipv6Addr, - ipv6_subnet: u8, + ipv6_prefix_length: u8, ping_target: &str, ) -> Result { // Format with the prefix length - let ip = format!("{}/{}", generated_ipv6, ipv6_subnet); + let ip = format!("{}/{}", generated_ipv6, ipv6_prefix_length); let interface_down_func = || { eprintln!("Removing ip address and bringing interface down"); get_command_stdout("ip", ["addr", "del", &ip, "dev", &interface.name])?; diff --git a/rs/ic_os/network/src/lib.rs b/rs/ic_os/network/src/lib.rs index 2e8f130fdd5..caa65ca1642 100644 --- a/rs/ic_os/network/src/lib.rs +++ b/rs/ic_os/network/src/lib.rs @@ -5,11 +5,10 @@ use anyhow::{Context, Result}; use crate::mac_address::generate_mac_address; use crate::node_type::NodeType; use crate::systemd::generate_systemd_config_files; -use info::NetworkInfo; +use config::types::NetworkSettings; use ipv6::generate_ipv6_address; use mac_address::FormattedMacAddress; -pub mod info; pub mod interfaces; pub mod ipv6; pub mod mac_address; @@ -19,25 +18,25 @@ pub mod systemd; /// Write SetupOS or HostOS systemd network configuration. /// Requires superuser permissions to run `ipmitool` and write to the systemd directory pub fn generate_network_config( - network_info: &NetworkInfo, - mgmt_mac: Option<&str>, - deployment_name: Option<&str>, + network_settings: &NetworkSettings, + deployment_name: &str, node_type: NodeType, output_directory: &Path, ) -> Result<()> { - if let Some(address) = network_info.ipv6_address { + if let Some(address) = network_settings.ipv6_address { eprintln!("Found ipv6 address in config"); - return generate_systemd_config_files(output_directory, network_info, None, &address); + return generate_systemd_config_files(output_directory, network_settings, None, &address); }; - let deployment_name = deployment_name - .context("Error: Deployment name not found when attempting to generate mac address")?; - - let mac = generate_mac_address(deployment_name, &node_type, mgmt_mac)?; + let mac = generate_mac_address( + deployment_name, + &node_type, + network_settings.mgmt_mac.as_deref(), + )?; eprintln!("Using generated mac (unformatted) {}", mac.get()); eprintln!("Generating ipv6 address"); - let ipv6_prefix = network_info + let ipv6_prefix = network_settings .ipv6_prefix .clone() .context("ipv6_prefix required in config to generate ipv6 address")?; @@ -47,7 +46,7 @@ pub fn generate_network_config( let formatted_mac = FormattedMacAddress::from(&mac); generate_systemd_config_files( output_directory, - network_info, + network_settings, Some(&formatted_mac), &ipv6_address, ) diff --git a/rs/ic_os/network/src/systemd.rs b/rs/ic_os/network/src/systemd.rs index d2e1c2685c6..bd58f0f2916 100644 --- a/rs/ic_os/network/src/systemd.rs +++ b/rs/ic_os/network/src/systemd.rs @@ -5,9 +5,9 @@ use std::process::Command; use anyhow::{Context, Result}; -use crate::info::NetworkInfo; use crate::interfaces::{get_interfaces, has_ipv6_connectivity, Interface}; use crate::mac_address::FormattedMacAddress; +use config::types::NetworkSettings; pub static DEFAULT_SYSTEMD_NETWORK_DIR: &str = "/run/systemd/network"; @@ -149,7 +149,7 @@ fn generate_and_write_systemd_files( pub fn generate_systemd_config_files( output_directory: &Path, - network_info: &NetworkInfo, + network_settings: &NetworkSettings, generated_mac: Option<&FormattedMacAddress>, ipv6_address: &Ipv6Addr, ) -> Result<()> { @@ -157,13 +157,18 @@ pub fn generate_systemd_config_files( interfaces.sort_by(|a, b| a.speed_mbps.cmp(&b.speed_mbps)); eprintln!("Interfaces sorted by speed: {:?}", interfaces); - let ping_target = network_info.ipv6_gateway.to_string(); + let ping_target = network_settings.ipv6_gateway.to_string(); // old nodes are still configured with a local IPv4 interface connection // local IPv4 interfaces must be filtered out let ipv6_interfaces: Vec<&Interface> = interfaces .iter() .filter(|i| { - match has_ipv6_connectivity(i, ipv6_address, network_info.ipv6_subnet, &ping_target) { + match has_ipv6_connectivity( + i, + ipv6_address, + network_settings.ipv6_prefix_length, + &ping_target, + ) { Ok(result) => result, Err(e) => { eprintln!("Error testing connectivity on {}: {}", &i.name, e); @@ -183,13 +188,17 @@ pub fn generate_systemd_config_files( eprintln!("Using fastest interface: {:?}", fastest_interface); // Format the ip address to include the subnet length. See `man systemd.network`. - let ipv6_address = format!("{}/{}", &ipv6_address.to_string(), network_info.ipv6_subnet); + let ipv6_address = format!( + "{}/{}", + &ipv6_address.to_string(), + network_settings.ipv6_prefix_length + ); generate_and_write_systemd_files( output_directory, fastest_interface, generated_mac, &ipv6_address, - &network_info.ipv6_gateway.to_string(), + &network_settings.ipv6_gateway.to_string(), )?; print!("Restarting systemd networkd"); diff --git a/rs/ic_os/os_tools/hostos_tool/src/main.rs b/rs/ic_os/os_tools/hostos_tool/src/main.rs index c05a053ca42..20442549009 100644 --- a/rs/ic_os/os_tools/hostos_tool/src/main.rs +++ b/rs/ic_os/os_tools/hostos_tool/src/main.rs @@ -3,11 +3,11 @@ use std::path::Path; use anyhow::{anyhow, Context, Result}; use clap::{Parser, Subcommand}; -use config::config_ini::config_map_from_path; +use config::config_ini::get_config_ini_settings; use config::deployment_json::get_deployment_settings; +use config::types::NetworkSettings; use config::{DEFAULT_HOSTOS_CONFIG_INI_FILE_PATH, DEFAULT_HOSTOS_DEPLOYMENT_JSON_PATH}; use network::generate_network_config; -use network::info::NetworkInfo; use network::ipv6::generate_ipv6_address; use network::mac_address::{generate_mac_address, FormattedMacAddress}; use network::node_type::NodeType; @@ -56,78 +56,102 @@ pub fn main() -> Result<()> { match opts.command { Some(Commands::GenerateNetworkConfig { output_directory }) => { - let config_map = config_map_from_path(Path::new(&opts.config)) - .context("Please specify a valid config file with '--config'")?; - eprintln!("Using config: {:?}", config_map); - - let network_info = NetworkInfo::from_config_map(&config_map)?; - eprintln!("Network info config: {:?}", &network_info); - - let deployment_settings = get_deployment_settings(Path::new(&opts.deployment_file)); - - let deployment_name: Option<&str> = match &deployment_settings { - Ok(deployment) => Some(deployment.deployment.name.as_str()), - Err(e) => { - eprintln!("Error retrieving deployment file: {e}. Continuing without it"); - None - } - }; - - let mgmt_mac: Option<&str> = match &deployment_settings { - Ok(deployment) => deployment.deployment.mgmt_mac.as_deref(), - Err(_) => None, + let config_ini_settings = get_config_ini_settings(Path::new(&opts.config))?; + + let deployment_json_settings = + get_deployment_settings(Path::new(&opts.deployment_file))?; + eprintln!("Deployment config: {:?}", deployment_json_settings); + + // TODO: NODE-1466: Remove in configuration revamp (HostOS and GuestOS integration). + // Once HostOS is using the config struct, all config will be contained there + // and we won't need to read config.ini and deployment.json directly. + let network_settings = NetworkSettings { + ipv6_prefix: config_ini_settings.ipv6_prefix, + ipv6_address: config_ini_settings.ipv6_address, + ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, + ipv6_gateway: config_ini_settings.ipv6_gateway, + ipv4_address: config_ini_settings.ipv4_address, + ipv4_gateway: config_ini_settings.ipv4_gateway, + ipv4_prefix_length: config_ini_settings.ipv4_prefix_length, + domain: config_ini_settings.domain, + mgmt_mac: deployment_json_settings.deployment.mgmt_mac, }; + eprintln!("Network settings config: {:?}", &network_settings); generate_network_config( - &network_info, - mgmt_mac, - deployment_name, + &network_settings, + deployment_json_settings.deployment.name.as_str(), NodeType::HostOS, Path::new(&output_directory), ) } Some(Commands::GenerateIpv6Address { node_type }) => { - let deployment_settings = get_deployment_settings(Path::new(&opts.deployment_file)) - .context("Please specify a valid deployment file with '--deployment-file'")?; - eprintln!("Deployment config: {:?}", deployment_settings); - - let config_map = config_map_from_path(Path::new(&opts.config)) - .context("Please specify a valid config file with '--config'")?; - eprintln!("Using config: {:?}", config_map); - - let network_info = NetworkInfo::from_config_map(&config_map)?; - eprintln!("Network info config: {:?}", &network_info); + let config_ini_settings = get_config_ini_settings(Path::new(&opts.config))?; + + let deployment_json_settings = + get_deployment_settings(Path::new(&opts.deployment_file))?; + eprintln!("Deployment config: {:?}", deployment_json_settings); + + // TODO: NODE-1466: Remove in configuration revamp (HostOS and GuestOS integration). + // Once HostOS is using the config struct, all config will be contained there + // and we won't need to read config.ini and deployment.json directly. + let network_settings = NetworkSettings { + ipv6_prefix: config_ini_settings.ipv6_prefix, + ipv6_address: config_ini_settings.ipv6_address, + ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, + ipv6_gateway: config_ini_settings.ipv6_gateway, + ipv4_address: config_ini_settings.ipv4_address, + ipv4_gateway: config_ini_settings.ipv4_gateway, + ipv4_prefix_length: config_ini_settings.ipv4_prefix_length, + domain: config_ini_settings.domain, + mgmt_mac: deployment_json_settings.deployment.mgmt_mac, + }; + eprintln!("Network settings config: {:?}", &network_settings); let node_type = node_type.parse::()?; let mac = generate_mac_address( - &deployment_settings.deployment.name, + &deployment_json_settings.deployment.name, &node_type, - deployment_settings.deployment.mgmt_mac.as_deref(), + network_settings.mgmt_mac.as_deref(), )?; - let ipv6_prefix = network_info + let ipv6_prefix = network_settings .ipv6_prefix .context("ipv6_prefix required in config to generate ipv6 address")?; let ipv6_address = generate_ipv6_address(&ipv6_prefix, &mac)?; - println!("{}", to_cidr(ipv6_address, network_info.ipv6_subnet)); + println!( + "{}", + to_cidr(ipv6_address, network_settings.ipv6_prefix_length) + ); Ok(()) } Some(Commands::GenerateMacAddress { node_type }) => { - let config_map = config_map_from_path(Path::new(&opts.config)) - .context("Please specify a valid config file with '--config'")?; - eprintln!("Using config: {:?}", config_map); - - let network_info = NetworkInfo::from_config_map(&config_map)?; - eprintln!("Network info config: {:?}", &network_info); - - let deployment_settings = get_deployment_settings(Path::new(&opts.deployment_file)) - .context("Please specify a valid deployment file with '--deployment-file'")?; - eprintln!("Deployment config: {:?}", deployment_settings); + let config_ini_settings = get_config_ini_settings(Path::new(&opts.config))?; + + let deployment_json_settings = + get_deployment_settings(Path::new(&opts.deployment_file))?; + eprintln!("Deployment config: {:?}", deployment_json_settings); + + // TODO: NODE-1466: Remove in configuration revamp (HostOS and GuestOS integration). + // Once HostOS is using the config struct, all config will be contained there + // and we won't need to read config.ini and deployment.json directly. + let network_settings = NetworkSettings { + ipv6_prefix: config_ini_settings.ipv6_prefix, + ipv6_address: config_ini_settings.ipv6_address, + ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, + ipv6_gateway: config_ini_settings.ipv6_gateway, + ipv4_address: config_ini_settings.ipv4_address, + ipv4_gateway: config_ini_settings.ipv4_gateway, + ipv4_prefix_length: config_ini_settings.ipv4_prefix_length, + domain: config_ini_settings.domain, + mgmt_mac: deployment_json_settings.deployment.mgmt_mac, + }; + eprintln!("Network settings config: {:?}", &network_settings); let node_type = node_type.parse::()?; let mac = generate_mac_address( - &deployment_settings.deployment.name, + &deployment_json_settings.deployment.name, &node_type, - deployment_settings.deployment.mgmt_mac.as_deref(), + network_settings.mgmt_mac.as_deref(), )?; let mac = FormattedMacAddress::from(&mac); println!("{}", mac.get()); diff --git a/rs/ic_os/os_tools/setupos_tool/src/main.rs b/rs/ic_os/os_tools/setupos_tool/src/main.rs index 0bcda31d0ba..bc88fb501a0 100644 --- a/rs/ic_os/os_tools/setupos_tool/src/main.rs +++ b/rs/ic_os/os_tools/setupos_tool/src/main.rs @@ -1,13 +1,14 @@ use std::path::Path; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; use clap::{Parser, Subcommand}; -use config::config_ini::config_map_from_path; -use config::deployment_json::get_deployment_settings; -use config::{DEFAULT_SETUPOS_CONFIG_INI_FILE_PATH, DEFAULT_SETUPOS_DEPLOYMENT_JSON_PATH}; +use config::types::SetupOSConfig; +use config::{ + deserialize_config, DEFAULT_SETUPOS_CONFIG_INI_FILE_PATH, DEFAULT_SETUPOS_CONFIG_OBJECT_PATH, + DEFAULT_SETUPOS_DEPLOYMENT_JSON_PATH, +}; use network::generate_network_config; -use network::info::NetworkInfo; use network::ipv6::generate_ipv6_address; use network::mac_address::{generate_mac_address, FormattedMacAddress}; use network::node_type::NodeType; @@ -55,79 +56,63 @@ pub fn main() -> Result<()> { match opts.command { Some(Commands::GenerateNetworkConfig { output_directory }) => { - let config_map = config_map_from_path(Path::new(&opts.config)) - .context("Please specify a valid config file with '--config'")?; - eprintln!("Using config: {:?}", config_map); - - let network_info = NetworkInfo::from_config_map(&config_map)?; - eprintln!("Network info config: {:?}", &network_info); - - let deployment_settings = get_deployment_settings(Path::new(&opts.deployment_file)); - let deployment_name: Option<&str> = match &deployment_settings { - Ok(deployment) => Some(deployment.deployment.name.as_str()), - Err(e) => { - eprintln!("Error retrieving deployment file: {e}. Continuing without it"); - None - } - }; - - let mgmt_mac: Option<&str> = match &deployment_settings { - Ok(deployment) => deployment.deployment.mgmt_mac.as_deref(), - Err(_) => None, - }; + let setup_config: SetupOSConfig = + deserialize_config(DEFAULT_SETUPOS_CONFIG_OBJECT_PATH)?; + + eprintln!( + "Network settings config: {:?}", + &setup_config.network_settings + ); generate_network_config( - &network_info, - mgmt_mac, - deployment_name, + &setup_config.network_settings, + &setup_config.icos_settings.hostname, NodeType::SetupOS, Path::new(&output_directory), ) } Some(Commands::GenerateIpv6Address { node_type }) => { - let deployment_settings = get_deployment_settings(Path::new(&opts.deployment_file)) - .context("Please specify a valid deployment file with '--deployment-file'")?; - eprintln!("Deployment config: {:?}", deployment_settings); - - let config_map = config_map_from_path(Path::new(&opts.config)) - .context("Please specify a valid config file with '--config'")?; - eprintln!("Using config: {:?}", config_map); - - let network_info = NetworkInfo::from_config_map(&config_map)?; - eprintln!("Network info config: {:?}", &network_info); + let setup_config: SetupOSConfig = + deserialize_config(DEFAULT_SETUPOS_CONFIG_OBJECT_PATH)?; let node_type = node_type.parse::()?; let mac = generate_mac_address( - &deployment_settings.deployment.name, + &setup_config.icos_settings.hostname, &node_type, - deployment_settings.deployment.mgmt_mac.as_deref(), + setup_config.network_settings.mgmt_mac.as_deref(), )?; - let ipv6_prefix = network_info - .ipv6_prefix - .context("ipv6_prefix required in config to generate ipv6 address")?; + let ipv6_prefix = setup_config.network_settings.ipv6_prefix.ok_or_else(|| { + anyhow!("ipv6_prefix required in config to generate ipv6 address") + })?; let ipv6_address = generate_ipv6_address(&ipv6_prefix, &mac)?; - println!("{}", to_cidr(ipv6_address, network_info.ipv6_subnet)); + println!( + "{}", + to_cidr( + ipv6_address, + setup_config.network_settings.ipv6_prefix_length + ) + ); + Ok(()) } Some(Commands::GenerateMacAddress { node_type }) => { - let config_map = config_map_from_path(Path::new(&opts.config)) - .context("Please specify a valid config file with '--config'")?; - eprintln!("Using config: {:?}", config_map); + let setup_config: SetupOSConfig = + deserialize_config(DEFAULT_SETUPOS_CONFIG_OBJECT_PATH)?; - let network_info = NetworkInfo::from_config_map(&config_map)?; - eprintln!("Network info config: {:?}", &network_info); - - let deployment_settings = get_deployment_settings(Path::new(&opts.deployment_file)) - .context("Please specify a valid deployment file with '--deployment-file'")?; - eprintln!("Deployment config: {:?}", deployment_settings); + eprintln!( + "Network settings config: {:?}", + &setup_config.network_settings + ); let node_type = node_type.parse::()?; + let mac = generate_mac_address( - &deployment_settings.deployment.name, + &setup_config.icos_settings.hostname, &node_type, - deployment_settings.deployment.mgmt_mac.as_deref(), + setup_config.network_settings.mgmt_mac.as_deref(), )?; + let mac = FormattedMacAddress::from(&mac); println!("{}", mac.get()); Ok(()) From b56317904e8f212e20a9a47a469d63e752ee8c83 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 18 Sep 2024 21:22:45 +0000 Subject: [PATCH 02/28] Partially update configuration documentation --- .../guestos/bootstrap-ic-node.sh | 2 - ic-os/docs/Configuration.adoc | 65 ++++++++++++++----- ic-os/docs/README.adoc | 1 - ic-os/guestos/docs/Boot.adoc | 6 +- ic-os/guestos/docs/ConfigStore.adoc | 45 ------------- ic-os/guestos/docs/DiskLayout.adoc | 2 - ic-os/guestos/docs/README.adoc | 1 - 7 files changed, 53 insertions(+), 69 deletions(-) delete mode 100644 ic-os/guestos/docs/ConfigStore.adoc diff --git a/ic-os/components/init/bootstrap-ic-node/guestos/bootstrap-ic-node.sh b/ic-os/components/init/bootstrap-ic-node/guestos/bootstrap-ic-node.sh index 6b1f5f8b134..08bfc78ba45 100755 --- a/ic-os/components/init/bootstrap-ic-node/guestos/bootstrap-ic-node.sh +++ b/ic-os/components/init/bootstrap-ic-node/guestos/bootstrap-ic-node.sh @@ -3,8 +3,6 @@ # Provision a node based on an injected "ic-bootstrap.tar" file. This script # is meant to be run as a prerequisite before launching orchestrator/replica. # -# The configuration format is described in guestos/docs/ConfigStore.adoc -# # The tar file can be supplied using one of two methods: # - as "ic-bootstrap.tar" stored on a (virtual) removable media attached # on first boot diff --git a/ic-os/docs/Configuration.adoc b/ic-os/docs/Configuration.adoc index d505d0359b3..8d42ce11442 100644 --- a/ic-os/docs/Configuration.adoc +++ b/ic-os/docs/Configuration.adoc @@ -2,27 +2,25 @@ Each IC-OS has a 100 MB config partition. All IC-OS config partitions are initialized to be empty, except for SetupOS. -In production, configuration is propagated from a partition on the USB installer through each of SetupOS, HostOS and GuestOS: +In production, configuration is propagated from a partition on the USB installer through each of SetupOS, HostOS and GuestOS. +This process is controlled by the (link:../../rs/ic_os/config/README.md[ic-os config tool]) and an assortment of bash scripts. -* SetupOS reads and validates its configuration files from `/config/` -* SetupOS copies sanitized configuration files from `/config/` to `/var/ic/config/` -* SetupOS copies its configuration files from `/var/ic/config/` to the HostOS config partition. -* HostOS reads the configuration files from `/boot/config`. These files are used to populate the GuestOS config partition through a more complicated process described below. +All access to the config partition should be done through the ic-os config tool. -== Detailed configuration steps +== User-facing configuration files -=== SetupOS -> HostOS - -SetupOS validates, sanitizes, and copies all of its configuration files to the HostOS config partition: +SetupOS constructs its config struct from the following user-facing configuration files: config.ini # Data center-specific network settings ssh_authorized_keys # SSH private keys node_operator_private_key.pem # Node Operator private key created in the Node Provider onboarding deployment.json # Deployment-specific configurations nns_public_key.pem # NNS public key -Refer to link:../../rs/ic_os/config/README.md[rs/ic_os/config] & link:../components/setupos-scripts/setup-hostos-config.sh[setup-hostos-config.sh] +Refer to link:../../rs/ic_os/config/README.md[rs/ic_os/config] and link:../components/setupos-scripts/setup-hostos-config.sh[setup-hostos-config.sh] for more details. + +== HostOS -> GuestOS -=== HostOS -> GuestOS +TODO: update... HostOS builds the "bootstrap config image". Refer to link:../components/hostos-scripts/build-bootstrap-config-image.sh[build-bootstrap-config-image.sh] @@ -44,14 +42,32 @@ GuestOS only reads a predefined set of files from the bootstrap config image (i. [NOTE] The reason for the bootstrap config image redirection is to ensure that GuestOS maintains control over what goes onto its config partition. Theoretically, a malicious Node Technician could modify their HostOS image and place any file onto the bootstrap config image. However, GuestOS will only copy a predefined set of files to its config partition. -== GuestOS configuration files +== GuestOS config partition + +TODO: update... + +The config partition stores information that must be preserved across system upgrades and needs to be available during early boot time. Consequently, this information cannot reside within the encrypted payload data partition. + +Currently, all contents in the config partition are stored as plain-text without integrity protection. + +These files are stored in `/boot/config` or `/var/lib/ic`. To see where each configuration file is stored, refer to link:../../components/init/bootstrap-ic-node/guestos/bootstrap-ic-node.sh[bootstrap-ic-node] -To learn more about the GuestOS configuration files, link:../guestos/docs/ConfigStore.adoc[see the GuestOS ConfigStore.adoc] +=== CONFIGURED file + +This file serves as a tag to indicate that the one-time bootstrap configuration has been completed. If the `/boot/config/CONFIGURED` file is not present, the boot sequence will search for a virtual USB stick (the bootstrap config image) containing the injected configuration files, and create the file. + +=== store.keyfile + +This file contains the key material used to derive the wrapping key for all block device encryption. The `store.keyfile` is created during the first boot, and encrypted partitions are configured with it. + +In the absence of a sealing key (which will be available in SEV-protected trusted execution environments), the `store.keyfile` is stored as plain-text. Once a sealing key becomes available, it should be used to wrap the contents of this file. == Implementation notes === Guidance for adding configuration bits +TODO: update... + To add a new configuration file/directory: 1. Add handling to `build-bootstrap-config-image.sh` to include the new file/directory in the bootstrap config image. @@ -72,10 +88,10 @@ Consider that values may be controlled by an attacker on boot. Bootstrapping a n *Interpretation of configuration bits*: Any script or service in the system may pull configuration bits out of /boot/config to customize its behavior. E.g. if adding parameter-driven customization of ic.json5, then augment the generate-replica-config.sh script to pull the configuration values and substitute them into the generated configuration. -*Documentation*: Please keep documentation up-to-date (link:ConfigStore-SetupOSHostOS.adoc[SetupOS/HostOS config store], link:../guestos/docs/ConfigStore.adoc[GuestOS config store]) - === Testing +TODO: update... + * *bootstrap-ic-node.sh* can be temporarily tweaked (internally adapt paths, then run the process_bootstrap function): ** run stand-alone ** verify that the config image is unpacked @@ -86,3 +102,22 @@ Consider that values may be controlled by an attacker on boot. Bootstrapping a n * *generate-replica-config.sh* can be run stand-alone to verify that it produces the intended ic.json5 configuration from the template. After all is done, it is advised to prepare a configuration for a single node and boot it in a VM before conducting testnet deployments. + +=== Injecting external state + +TODO: update... + +*Typical bootstrap process:* On first boot, the system will perform technical initialization (filesystems, etc.) and afterwards, initialize itself to act as a node in the IC. The node is initialized using key generation on the node itself (such that the private key never leaves the node) and through joining the IC (the node gets the rest of its state via joining the IC). "Registration" to the target IC is initiated by the node itself by sending a Node Operator-signed "join" request to its NNS. + +However, the typical bootstrap process can be modified such that the node is initialized using externally generated private keys and an externally generated initial state. All "registration" to the target IC is assumed to have been performed by other means. + +The behavior is triggered through the presence of the following files: + +- ic_crypto +- ic_registry_local_store + +This behavior is suitable for the following use cases: + +- Bootstrapping an IC instance: In this case, suitable state for all nodes is generated by ic-prep and then distributed across multiple nodes. This is used, for example, during testnet setup. + +- Externally controlled join of a node to a subnet: In this case, ic-prep is used to prepare key material to the node, while ic-admin is used to modify the target NNS such that it "accepts" the new node as part of the IC. diff --git a/ic-os/docs/README.adoc b/ic-os/docs/README.adoc index 966475c5c75..09ef5d3c9a8 100644 --- a/ic-os/docs/README.adoc +++ b/ic-os/docs/README.adoc @@ -7,4 +7,3 @@ Refer to detailed documentation on: * link:Components{outfilesuffix}[Components] * link:SELinux{outfilesuffix}[SELinux security policy] * link:Configuration{outfilesuffix}[Configuration] -* link:ConfigStore-SetupOSHostOS{outfilesuffix}[SetupOS and HostOS config store] diff --git a/ic-os/guestos/docs/Boot.adoc b/ic-os/guestos/docs/Boot.adoc index a744509ec75..aa4e4803926 100644 --- a/ic-os/guestos/docs/Boot.adoc +++ b/ic-os/guestos/docs/Boot.adoc @@ -57,7 +57,7 @@ not held in +/etc/fstab+ but is generated by the shell script Afterwards, the first three partitions are mounted as +/boot/efi+, +/boot/grub+ and +/boot/config+, respectively. The +config+ partition is used as (small) store for data that is preserved across upgrades -and is available at early boot time already (see link:ConfigStore{outfilesuffix}[config store]). +and is available at early boot time already. == Save machine-id @@ -167,8 +167,8 @@ depends on mount of all filesystems. This is only executed once on first boot after provisioning. It looks for a "virtual USB stick" attached to the VM that contains a tar file with initial configuration -for parts of the system (see link:ConfigStore{outfilesuffix}[config store] for a description). Required -files in the +config+ partition as well as payload store are created. +for parts of the system. Required files in the +config+ partition as well as +payload store are created. == Deploy updated ssh account keys diff --git a/ic-os/guestos/docs/ConfigStore.adoc b/ic-os/guestos/docs/ConfigStore.adoc deleted file mode 100644 index f0d0c8e382d..00000000000 --- a/ic-os/guestos/docs/ConfigStore.adoc +++ /dev/null @@ -1,45 +0,0 @@ -= GuestOS Config Store - -This document calls out some of the contents of the GuestOS *config* partition (*/dev/vda3* in the GuestOS disk image). The config partition stores information that must be preserved across system upgrades and needs to be available during early boot time. Consequently, this information cannot reside within the encrypted payload data partition. - -Currently, all contents in the config partition are stored as plain-text without integrity protection. - -These files are stored in `/boot/config` or `/var/lib/ic`. To see where each configuration file is stored, refer to link:../../components/init/bootstrap-ic-node/guestos/bootstrap-ic-node.sh[bootstrap-ic-node] - -== Production configuration files - -Not all configuration files and directories are required for GuestOS to run in production, as certain configuration files exist solely for testing and development purposes. - -The following files and directories *are* required for GuestOS to run in production. - -=== CONFIGURED - -This file serves as a tag to indicate that the one-time bootstrap configuration has been completed. If the `/boot/config/CONFIGURED` file is not present, the boot sequence will search for a virtual USB stick (the bootstrap config image) containing the injected configuration files, and create the file. - -=== store.keyfile - -This file contains the key material used to derive the wrapping key for all block device encryption. The `store.keyfile` is created during the first boot, and encrypted partitions are configured with it. - -In the absence of a sealing key (which will be available in SEV-protected trusted execution environments), the `store.keyfile` is stored as plain-text. Once a sealing key becomes available, it should be used to wrap the contents of this file. - -== Development configuration files - -These configuration files should only be used for development and testing purposes. - -== Injecting external state - -*Typical bootstrap process:* On first boot, the system will perform technical initialization (filesystems, etc.) and afterwards, initialize itself to act as a node in the IC. The node is initialized using key generation on the node itself (such that the private key never leaves the node) and through joining the IC (the node gets the rest of its state via joining the IC). "Registration" to the target IC is initiated by the node itself by sending a Node Operator-signed "join" request to its NNS. - -However, the typical bootstrap process can be modified such that the node is initialized using externally generated private keys and an externally generated initial state. All "registration" to the target IC is assumed to have been performed by other means. - -The behavior is triggered through the presence of the following files: - -- ic_crypto -- ic_registry_local_store - -This behavior is suitable for the following use cases: - -- Bootstrapping an IC instance: In this case, suitable state for all nodes is generated by ic-prep and then distributed across multiple nodes. This is used, for example, during testnet setup. - -- Externally controlled join of a node to a subnet: In this case, ic-prep is used to prepare key material to the node, while ic-admin is used to modify the target NNS such that it "accepts" the new node as part of the IC. - diff --git a/ic-os/guestos/docs/DiskLayout.adoc b/ic-os/guestos/docs/DiskLayout.adoc index 8a690680b9d..13dbcbd99f5 100644 --- a/ic-os/guestos/docs/DiskLayout.adoc +++ b/ic-os/guestos/docs/DiskLayout.adoc @@ -41,8 +41,6 @@ tampering). == *config* System config store Contains the config store persisted across system upgrades. -See link:ConfigStore{outfilesuffix}[config store] for a -specification of its contents. == *A_boot* / *B_boot* Boot partition for system A/B diff --git a/ic-os/guestos/docs/README.adoc b/ic-os/guestos/docs/README.adoc index 4caa2719d2c..92e95a07169 100644 --- a/ic-os/guestos/docs/README.adoc +++ b/ic-os/guestos/docs/README.adoc @@ -3,7 +3,6 @@ Refer to detailed documentation on: * link:DiskLayout{outfilesuffix}[Disk layout] -* link:ConfigStore{outfilesuffix}[GuestOS config store] * link:Boot{outfilesuffix}[Boot sequence] * link:SELinux{outfilesuffix}[SELinux security policy] * link:Interface{outfilesuffix}[GuestOS input/output interface] \ No newline at end of file From a268059dbeb3e9640e419832ca2765dd6a13a64d Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Tue, 24 Sep 2024 22:13:30 +0000 Subject: [PATCH 03/28] Create ICOSDevSettings and move mgmt_mac to struct --- rs/ic_os/config/src/lib.rs | 9 +++++---- rs/ic_os/config/src/main.rs | 16 ++++++++++------ rs/ic_os/config/src/types.rs | 11 ++++++++--- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/rs/ic_os/config/src/lib.rs b/rs/ic_os/config/src/lib.rs index c49f689cb53..a1bc0051f08 100644 --- a/rs/ic_os/config/src/lib.rs +++ b/rs/ic_os/config/src/lib.rs @@ -47,8 +47,8 @@ mod tests { use super::*; use std::path::PathBuf; use types::{ - GuestOSConfig, GuestOSSettings, GuestosDevConfig, HostOSConfig, HostOSSettings, - ICOSSettings, Logging, NetworkSettings, SetupOSConfig, SetupOSSettings, + GuestOSConfig, GuestOSSettings, GuestosDevSettings, HostOSConfig, HostOSSettings, + ICOSDevSettings, ICOSSettings, Logging, NetworkSettings, SetupOSConfig, SetupOSSettings, }; #[test] @@ -62,7 +62,6 @@ mod tests { ipv4_gateway: None, ipv4_prefix_length: None, domain: None, - mgmt_mac: None, }; let logging = Logging { elasticsearch_hosts: [ @@ -74,6 +73,7 @@ mod tests { .join(" "), elasticsearch_tags: None, }; + let icos_dev_settings = ICOSDevSettings { mgmt_mac: None }; let icos_settings = ICOSSettings { logging, nns_public_key_path: PathBuf::from("/path/to/key"), @@ -81,6 +81,7 @@ mod tests { hostname: "mainnet".to_string(), node_operator_private_key_path: None, ssh_authorized_keys_path: None, + icos_dev_settings, }; let setupos_settings = SetupOSSettings; let hostos_settings = HostOSSettings { @@ -92,7 +93,7 @@ mod tests { ic_crypto_path: None, ic_state_path: None, ic_registry_local_store_path: None, - guestos_dev: GuestosDevConfig::default(), + guestos_dev_settings: GuestosDevSettings::default(), }; let setupos_config_struct = SetupOSConfig { diff --git a/rs/ic_os/config/src/main.rs b/rs/ic_os/config/src/main.rs index 65e825ee95c..10cf5b8c95d 100644 --- a/rs/ic_os/config/src/main.rs +++ b/rs/ic_os/config/src/main.rs @@ -7,8 +7,8 @@ use std::fs::File; use std::path::{Path, PathBuf}; use config::types::{ - GuestOSSettings, HostOSConfig, HostOSSettings, ICOSSettings, Logging, NetworkSettings, - SetupOSConfig, SetupOSSettings, + GuestOSSettings, HostOSConfig, HostOSSettings, ICOSDevSettings, ICOSSettings, Logging, + NetworkSettings, SetupOSConfig, SetupOSSettings, }; #[derive(Subcommand)] @@ -75,9 +75,6 @@ pub fn main() -> Result<()> { verbose, } = config_ini_settings; - // get deployment.json variables - let deployment_json_settings = get_deployment_settings(&deployment_json_path)?; - let network_settings = NetworkSettings { ipv6_prefix, ipv6_address, @@ -87,14 +84,20 @@ pub fn main() -> Result<()> { ipv4_gateway, ipv4_prefix_length, domain, - mgmt_mac: deployment_json_settings.deployment.mgmt_mac, }; + // get deployment.json variables + let deployment_json_settings = get_deployment_settings(&deployment_json_path)?; + let logging = Logging { elasticsearch_hosts: deployment_json_settings.logging.hosts.to_string(), elasticsearch_tags: None, }; + let icos_dev_settings = ICOSDevSettings { + mgmt_mac: deployment_json_settings.deployment.mgmt_mac, + }; + let icos_settings = ICOSSettings { logging, nns_public_key_path: nns_public_key_path.to_path_buf(), @@ -106,6 +109,7 @@ pub fn main() -> Result<()> { ssh_authorized_keys_path: ssh_authorized_keys_path .exists() .then_some(ssh_authorized_keys_path), + icos_dev_settings, }; let setupos_settings = SetupOSSettings; diff --git a/rs/ic_os/config/src/types.rs b/rs/ic_os/config/src/types.rs index 7562b55e12e..f293f8b187e 100644 --- a/rs/ic_os/config/src/types.rs +++ b/rs/ic_os/config/src/types.rs @@ -58,12 +58,12 @@ pub struct GuestOSSettings { /// When given, this provides the initial state of the registry. /// If not given, the node will fetch (initial) registry state from the NNS. pub ic_registry_local_store_path: Option, - pub guestos_dev: GuestosDevConfig, + pub guestos_dev_settings: GuestosDevSettings, } /// GuestOS development configuration. These settings are strictly used for development images. #[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)] -pub struct GuestosDevConfig { +pub struct GuestosDevSettings { pub backup_spool: Option, pub malicious_behavior: Option, pub query_stats_epoch_length: Option, @@ -93,7 +93,6 @@ pub struct NetworkSettings { pub ipv4_gateway: Option, pub ipv4_prefix_length: Option, pub domain: Option, - pub mgmt_mac: Option, } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -114,6 +113,12 @@ pub struct ICOSSettings { /// backup and readonly can only be modified via an NNS proposal /// and are in place for subnet recovery or issue debugging purposes. pub ssh_authorized_keys_path: Option, + pub icos_dev_settings: ICOSDevSettings, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct ICOSDevSettings { + pub mgmt_mac: Option, } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] From e1aaf28e0c991fdbfa28c1f40639be1465d4f2c7 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 25 Sep 2024 14:19:35 +0000 Subject: [PATCH 04/28] Update name of GuestOSDevSettings for consistency --- rs/ic_os/config/src/lib.rs | 4 ++-- rs/ic_os/config/src/types.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rs/ic_os/config/src/lib.rs b/rs/ic_os/config/src/lib.rs index a1bc0051f08..d51e9a774a3 100644 --- a/rs/ic_os/config/src/lib.rs +++ b/rs/ic_os/config/src/lib.rs @@ -47,7 +47,7 @@ mod tests { use super::*; use std::path::PathBuf; use types::{ - GuestOSConfig, GuestOSSettings, GuestosDevSettings, HostOSConfig, HostOSSettings, + GuestOSConfig, GuestOSDevSettings, GuestOSSettings, HostOSConfig, HostOSSettings, ICOSDevSettings, ICOSSettings, Logging, NetworkSettings, SetupOSConfig, SetupOSSettings, }; @@ -93,7 +93,7 @@ mod tests { ic_crypto_path: None, ic_state_path: None, ic_registry_local_store_path: None, - guestos_dev_settings: GuestosDevSettings::default(), + guestos_dev_settings: GuestOSDevSettings::default(), }; let setupos_config_struct = SetupOSConfig { diff --git a/rs/ic_os/config/src/types.rs b/rs/ic_os/config/src/types.rs index f293f8b187e..33caf0f3d7c 100644 --- a/rs/ic_os/config/src/types.rs +++ b/rs/ic_os/config/src/types.rs @@ -58,12 +58,12 @@ pub struct GuestOSSettings { /// When given, this provides the initial state of the registry. /// If not given, the node will fetch (initial) registry state from the NNS. pub ic_registry_local_store_path: Option, - pub guestos_dev_settings: GuestosDevSettings, + pub guestos_dev_settings: GuestOSDevSettings, } /// GuestOS development configuration. These settings are strictly used for development images. #[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)] -pub struct GuestosDevSettings { +pub struct GuestOSDevSettings { pub backup_spool: Option, pub malicious_behavior: Option, pub query_stats_epoch_length: Option, From 1723eb1cea731ce6f006917e4b31379ba4bf0e8a Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 25 Sep 2024 19:17:06 +0000 Subject: [PATCH 05/28] Update query_stats_epoch_length and BackupSpoolSettings to hold u64 --- rs/ic_os/config/src/types.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rs/ic_os/config/src/types.rs b/rs/ic_os/config/src/types.rs index 33caf0f3d7c..628b7e6ce4e 100644 --- a/rs/ic_os/config/src/types.rs +++ b/rs/ic_os/config/src/types.rs @@ -66,7 +66,7 @@ pub struct GuestOSSettings { pub struct GuestOSDevSettings { pub backup_spool: Option, pub malicious_behavior: Option, - pub query_stats_epoch_length: Option, + pub query_stats_epoch_length: Option, pub bitcoind_addr: Option, pub jaeger_addr: Option, pub socks_proxy: Option, @@ -76,9 +76,9 @@ pub struct GuestOSDevSettings { #[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)] pub struct BackupSpoolSettings { /// The maximum age of any file or directory kept in the backup spool. - pub backup_retention_time_seconds: Option, + pub backup_retention_time_seconds: Option, /// The interval at which the backup spool directory will be scanned for files to delete. - pub backup_purging_interval_seconds: Option, + pub backup_purging_interval_seconds: Option, } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] From 5e883bda7fac6ee206af0e3b3615036910d8c549 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 26 Sep 2024 19:43:06 +0000 Subject: [PATCH 06/28] Remove repeat code --- ic-os/components/setupos-scripts/check-network.sh | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ic-os/components/setupos-scripts/check-network.sh b/ic-os/components/setupos-scripts/check-network.sh index 79f16c68f97..8eb9932a420 100755 --- a/ic-os/components/setupos-scripts/check-network.sh +++ b/ic-os/components/setupos-scripts/check-network.sh @@ -172,16 +172,12 @@ function query_nns_nodes() { # When running against testnets, we need to ignore self signed certs # with `--insecure`. This check is only meant to confirm from SetupOS # that NNS urls are reachable, so we do not mind that it is "weak". - if curl --insecure --head --connect-timeout 3 --silent "${url}" >/dev/null 2>&1; then if curl --insecure --head --connect-timeout 3 --silent "${url}" >/dev/null 2>&1; then echo " okay: ${url}" success=true - success=true break else echo " fail: ${url}" - else - echo " fail: ${url}" fi done @@ -190,12 +186,6 @@ function query_nns_nodes() { else log_and_halt_installation_on_error "1" "Unable to query enough healthy NNS nodes." fi - - if $success; then - echo " success" - else - log_and_halt_installation_on_error "1" "Unable to query enough healthy NNS nodes." - fi } # Establish run order From 4517b6376d265161e0689fb9d5426dc6681bfc3f Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 26 Sep 2024 21:03:55 +0000 Subject: [PATCH 07/28] Revert "Merge branch 'master' into andrew/config-revamp-integration" This reverts commit cddb7f34fd1a42db20d2a225dfbc7eabbb947379, reversing changes made to 5e883bda7fac6ee206af0e3b3615036910d8c549. --- .../setup-hostname/hostos/setup-hostname.sh | 1 + .../guestos/guestos.xml.template | 2 +- .../hostos-scripts/guestos/qemu-cpu.xml | 2 +- .../hostos-scripts/libvirt/setup-libvirt.sh | 3 - ic-os/defs.bzl | 2 + ic-os/hostos/context/Dockerfile | 13 +++-- ic-os/hostos/context/docker-base.dev | 2 +- ic-os/hostos/context/docker-base.prod | 2 +- rs/ic_os/config/src/config_ini.rs | 55 +++++++++++++++---- rs/ic_os/config/src/lib.rs | 5 +- rs/ic_os/config/src/main.rs | 2 + rs/ic_os/config/src/types.rs | 5 +- rs/ic_os/network/src/lib.rs | 12 +++- 13 files changed, 78 insertions(+), 28 deletions(-) diff --git a/ic-os/components/early-boot/setup-hostname/hostos/setup-hostname.sh b/ic-os/components/early-boot/setup-hostname/hostos/setup-hostname.sh index 52322805d19..e4d35fbf0d6 100755 --- a/ic-os/components/early-boot/setup-hostname/hostos/setup-hostname.sh +++ b/ic-os/components/early-boot/setup-hostname/hostos/setup-hostname.sh @@ -61,6 +61,7 @@ function read_variables() { case "$key" in "ipv6_prefix") ipv6_prefix="${value}" ;; "ipv6_gateway") ipv6_gateway="${value}" ;; + "ipv6_address") ipv6_address="${value}" ;; "hostname") hostname="${value}" ;; esac done <"${CONFIG}" diff --git a/ic-os/components/hostos-scripts/guestos/guestos.xml.template b/ic-os/components/hostos-scripts/guestos/guestos.xml.template index bb58840fb0b..0e94d406d57 100755 --- a/ic-os/components/hostos-scripts/guestos/guestos.xml.template +++ b/ic-os/components/hostos-scripts/guestos/guestos.xml.template @@ -15,7 +15,7 @@ hvm - /usr/share/OVMF/OVMF_CODE_4M.fd + /usr/share/OVMF/OVMF_CODE.fd /var/lib/libvirt/qemu/nvram/guestos_VARS.fd diff --git a/ic-os/components/hostos-scripts/guestos/qemu-cpu.xml b/ic-os/components/hostos-scripts/guestos/qemu-cpu.xml index fd50c03a79e..3013b06373d 100644 --- a/ic-os/components/hostos-scripts/guestos/qemu-cpu.xml +++ b/ic-os/components/hostos-scripts/guestos/qemu-cpu.xml @@ -1 +1 @@ - + diff --git a/ic-os/components/hostos-scripts/libvirt/setup-libvirt.sh b/ic-os/components/hostos-scripts/libvirt/setup-libvirt.sh index c2b8b8d2017..5525702d98a 100755 --- a/ic-os/components/hostos-scripts/libvirt/setup-libvirt.sh +++ b/ic-os/components/hostos-scripts/libvirt/setup-libvirt.sh @@ -5,6 +5,3 @@ set -e # Create space for libvirt to manage its config mount --bind /run/libvirt /etc/libvirt - -# Set up log directory, because it will not create it alone -mkdir -p /var/log/libvirt/qemu diff --git a/ic-os/defs.bzl b/ic-os/defs.bzl index 5f2a4384cfd..5a4e614c977 100644 --- a/ic-os/defs.bzl +++ b/ic-os/defs.bzl @@ -148,6 +148,8 @@ def icos_build( "/run", "/boot", "/var", + "/usr/lib/firmware/brcm/brcmfmac43430a0-sdio.ONDA-V80 PLUS.txt", + "/usr/lib/firmware/brcm/brcmfmac43455-sdio.MINIX-NEO Z83-4.txt", "/usr/lib/firmware/brcm/brcmfmac43241b4-sdio.Intel Corp.-VALLEYVIEW C0 PLATFORM.txt.zst", "/usr/lib/firmware/brcm/brcmfmac43340-sdio.ASUSTeK COMPUTER INC.-TF103CE.txt.zst", "/usr/lib/firmware/brcm/brcmfmac43362-sdio.ASUSTeK COMPUTER INC.-ME176C.txt.zst", diff --git a/ic-os/hostos/context/Dockerfile b/ic-os/hostos/context/Dockerfile index 621c23eeda6..5b3374fe043 100644 --- a/ic-os/hostos/context/Dockerfile +++ b/ic-os/hostos/context/Dockerfile @@ -29,7 +29,7 @@ RUN sed -e '/.*pam_motd.so.*/d' -i /etc/pam.d/login && \ # but this is per system (so backups are not persisted across upgrades) # and thus not very useful, and /etc is read-only. # So simply suppress generating backups. -RUN sed -e 's/\(# \)\?\(backup *= *\)[01]/\20/' -e 's/\(# \)\?\(archive *= *\)[01]/\20/' -i /etc/lvm/lvm.conf +RUN sed -e 's/\(backup *= *\)1/\10/' -e 's/\(archive *= *\)1/\10/' -i /etc/lvm/lvm.conf # Deactivate systemd userdb. We don't use it. RUN sed -e 's/ *systemd//' -i /etc/nsswitch.conf @@ -39,7 +39,7 @@ RUN localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 # Clear files that may lead to indeterministic build. RUN apt-get clean && \ - find /usr/lib/python3.12 -name "*.pyc" | xargs rm && \ + find /usr/lib/python3.8 -name "*.pyc" | xargs rm && \ find /usr/lib/python3 -name "*.pyc" | xargs rm && \ find /usr/share/python3 -name "*.pyc" | xargs rm && \ truncate --size 0 /etc/machine-id @@ -91,7 +91,6 @@ RUN systemctl enable \ chrony \ libvirtd \ nftables \ - ssh \ systemd-journal-gatewayd \ systemd-networkd \ systemd-networkd-wait-online \ @@ -118,8 +117,14 @@ RUN rm -rf \ /usr/local/share/qemu/edk2-arm-code.fd \ /usr/local/share/qemu/edk2-arm-vars.fd +# Add user/group entries specified here: /usr/lib/sysusers.d/systemd.conf E.g., systemd-timesync/coredump +RUN systemd-sysusers && \ + # Fix reproducibility issue. Notes in hostos/context/Dockerfile + usermod -p '!!' systemd-timesync && \ + usermod -p '!!' systemd-coredump + # Set /bin/sh to point to /bin/bash instead of the default /bin/dash -RUN ln -sf bash /usr/bin/sh +RUN echo "set dash/sh false" | debconf-communicate && dpkg-reconfigure -fnoninteractive dash # Group accounts to which parts of the runtime state are assigned such that # user accounts can be granted individual access rights. diff --git a/ic-os/hostos/context/docker-base.dev b/ic-os/hostos/context/docker-base.dev index 6b56f76b0ae..cd5decc792b 100644 --- a/ic-os/hostos/context/docker-base.dev +++ b/ic-os/hostos/context/docker-base.dev @@ -1 +1 @@ -ghcr.io/dfinity/hostos-base-dev@sha256:e133ba80d1d291fff89fe9e60f3fbf9285095d9c15a51a1297e314d0f9fe837c +ghcr.io/dfinity/hostos-base-dev@sha256:a6e8e7ab7abf682c80dfd717d36ac027213f757ddad415c66080ac4314639590 diff --git a/ic-os/hostos/context/docker-base.prod b/ic-os/hostos/context/docker-base.prod index a18a83e2197..0c1ef008b24 100644 --- a/ic-os/hostos/context/docker-base.prod +++ b/ic-os/hostos/context/docker-base.prod @@ -1 +1 @@ -ghcr.io/dfinity/hostos-base@sha256:13ae203beb66cdb2ac198ea2441e82b6fb36b93c4e337ccbc32383de49ad7f88 +ghcr.io/dfinity/hostos-base@sha256:5e93fb6cadecd22b838a8e442ed88d3c77ac5626651ee139559150d2a77a6743 diff --git a/rs/ic_os/config/src/config_ini.rs b/rs/ic_os/config/src/config_ini.rs index 4bc6c92219c..d90a77d95be 100644 --- a/rs/ic_os/config/src/config_ini.rs +++ b/rs/ic_os/config/src/config_ini.rs @@ -9,7 +9,8 @@ use anyhow::{Context, Result}; pub type ConfigMap = HashMap; pub struct ConfigIniSettings { - pub ipv6_prefix: String, + pub ipv6_prefix: Option, + pub ipv6_address: Option, pub ipv6_prefix_length: u8, pub ipv6_gateway: Ipv6Addr, pub ipv4_address: Option, @@ -30,18 +31,34 @@ pub fn get_config_ini_settings(config_file_path: &Path) -> Result() + .context(format!("Invalid IPv6 address: {}", address)) + }) + .transpose()?; + + if ipv6_address.is_none() && ipv6_prefix.is_none() { + bail!("Missing config parameter: need at least one of ipv6_prefix or ipv6_address"); + } + let ipv6_gateway = config_map .get("ipv6_gateway") .context("Missing config parameter: ipv6_gateway")? @@ -90,6 +107,7 @@ pub fn get_config_ini_settings(config_file_path: &Path) -> Result()? + ); assert_eq!( config_ini_settings.ipv6_gateway, "2a00:fb01:400:200::1".parse::()? @@ -268,6 +291,16 @@ mod tests { assert_eq!(config_ini_settings.domain, Some("example.com".to_string())); assert!(!config_ini_settings.verbose); + // Test ipv6_address without ipv6_prefix_length length + let mut temp_file = NamedTempFile::new()?; + writeln!(temp_file, "ipv6_address=2a00:fb01:400:200::")?; + let config_ini_settings = get_config_ini_settings(temp_file_path)?; + assert_eq!( + config_ini_settings.ipv6_address.unwrap(), + "2a00:fb01:400:200::".parse::()? + ); + assert_eq!(config_ini_settings.ipv6_prefix_length, 64); + // Test missing ipv6 let mut temp_file = NamedTempFile::new()?; writeln!(temp_file, "ipv4_address=212.71.124.178")?; @@ -278,7 +311,7 @@ mod tests { let result = get_config_ini_settings(temp_file_path); assert!(result.is_err()); - // Test invalid IPv6 prefix + // Test invalid IPv6 address let mut temp_file = NamedTempFile::new()?; writeln!(temp_file, "ipv6_prefix=invalid_ipv6_prefix")?; writeln!(temp_file, "ipv6_gateway=2001:db8:85a3:0000::1")?; @@ -290,7 +323,7 @@ mod tests { let result = get_config_ini_settings(temp_file_path); assert!(result.is_err()); - // Test missing prefix + // Test missing prefix and address let mut temp_file = NamedTempFile::new()?; writeln!(temp_file, "ipv6_gateway=2001:db8:85a3:0000::1")?; let result = get_config_ini_settings(temp_file_path); diff --git a/rs/ic_os/config/src/lib.rs b/rs/ic_os/config/src/lib.rs index 2e4cf733440..c49f689cb53 100644 --- a/rs/ic_os/config/src/lib.rs +++ b/rs/ic_os/config/src/lib.rs @@ -54,9 +54,10 @@ mod tests { #[test] fn test_serialize_and_deserialize() { let network_settings = NetworkSettings { - ipv6_prefix: "2a00:fb01:400:200".to_string(), + ipv6_prefix: None, + ipv6_address: None, ipv6_prefix_length: 64_u8, - ipv6_gateway: "2a00:fb01:400:200::1".parse().unwrap(), + ipv6_gateway: "2001:db8::1".parse().unwrap(), ipv4_address: None, ipv4_gateway: None, ipv4_prefix_length: None, diff --git a/rs/ic_os/config/src/main.rs b/rs/ic_os/config/src/main.rs index ba0dde4f2b3..65e825ee95c 100644 --- a/rs/ic_os/config/src/main.rs +++ b/rs/ic_os/config/src/main.rs @@ -65,6 +65,7 @@ pub fn main() -> Result<()> { let config_ini_settings = get_config_ini_settings(&config_ini_path)?; let ConfigIniSettings { ipv6_prefix, + ipv6_address, ipv6_prefix_length, ipv6_gateway, ipv4_address, @@ -79,6 +80,7 @@ pub fn main() -> Result<()> { let network_settings = NetworkSettings { ipv6_prefix, + ipv6_address, ipv6_prefix_length, ipv6_gateway, ipv4_address, diff --git a/rs/ic_os/config/src/types.rs b/rs/ic_os/config/src/types.rs index 5940a7dc1ea..7562b55e12e 100644 --- a/rs/ic_os/config/src/types.rs +++ b/rs/ic_os/config/src/types.rs @@ -83,7 +83,10 @@ pub struct BackupSpoolSettings { #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct NetworkSettings { - pub ipv6_prefix: String, + // Config.ini can specify ipv6_prefix and ipv6_gateway, or just an ipv6_address. + // ipv6_address takes precedence. Some tests provide only ipv6_address. + pub ipv6_prefix: Option, + pub ipv6_address: Option, pub ipv6_prefix_length: u8, pub ipv6_gateway: Ipv6Addr, pub ipv4_address: Option, diff --git a/rs/ic_os/network/src/lib.rs b/rs/ic_os/network/src/lib.rs index 8538df3eab4..caa65ca1642 100644 --- a/rs/ic_os/network/src/lib.rs +++ b/rs/ic_os/network/src/lib.rs @@ -23,10 +23,16 @@ pub fn generate_network_config( node_type: NodeType, output_directory: &Path, ) -> Result<()> { - let deployment_name = deployment_name - .context("Error: Deployment name not found when attempting to generate mac address")?; + if let Some(address) = network_settings.ipv6_address { + eprintln!("Found ipv6 address in config"); + return generate_systemd_config_files(output_directory, network_settings, None, &address); + }; - let mac = generate_mac_address(deployment_name, &node_type, mgmt_mac)?; + let mac = generate_mac_address( + deployment_name, + &node_type, + network_settings.mgmt_mac.as_deref(), + )?; eprintln!("Using generated mac (unformatted) {}", mac.get()); eprintln!("Generating ipv6 address"); From 4cd274284405678d9f955261dec0dd14bec77734 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 26 Sep 2024 21:05:39 +0000 Subject: [PATCH 08/28] Revert "Revert "Merge branch 'master' into andrew/config-revamp-integration"" This reverts commit 4517b6376d265161e0689fb9d5426dc6681bfc3f. --- .../setup-hostname/hostos/setup-hostname.sh | 1 - .../guestos/guestos.xml.template | 2 +- .../hostos-scripts/guestos/qemu-cpu.xml | 2 +- .../hostos-scripts/libvirt/setup-libvirt.sh | 3 + ic-os/defs.bzl | 2 - ic-os/hostos/context/Dockerfile | 13 ++--- ic-os/hostos/context/docker-base.dev | 2 +- ic-os/hostos/context/docker-base.prod | 2 +- rs/ic_os/config/src/config_ini.rs | 55 ++++--------------- rs/ic_os/config/src/lib.rs | 5 +- rs/ic_os/config/src/main.rs | 2 - rs/ic_os/config/src/types.rs | 5 +- rs/ic_os/network/src/lib.rs | 12 +--- 13 files changed, 28 insertions(+), 78 deletions(-) diff --git a/ic-os/components/early-boot/setup-hostname/hostos/setup-hostname.sh b/ic-os/components/early-boot/setup-hostname/hostos/setup-hostname.sh index e4d35fbf0d6..52322805d19 100755 --- a/ic-os/components/early-boot/setup-hostname/hostos/setup-hostname.sh +++ b/ic-os/components/early-boot/setup-hostname/hostos/setup-hostname.sh @@ -61,7 +61,6 @@ function read_variables() { case "$key" in "ipv6_prefix") ipv6_prefix="${value}" ;; "ipv6_gateway") ipv6_gateway="${value}" ;; - "ipv6_address") ipv6_address="${value}" ;; "hostname") hostname="${value}" ;; esac done <"${CONFIG}" diff --git a/ic-os/components/hostos-scripts/guestos/guestos.xml.template b/ic-os/components/hostos-scripts/guestos/guestos.xml.template index 0e94d406d57..bb58840fb0b 100755 --- a/ic-os/components/hostos-scripts/guestos/guestos.xml.template +++ b/ic-os/components/hostos-scripts/guestos/guestos.xml.template @@ -15,7 +15,7 @@ hvm - /usr/share/OVMF/OVMF_CODE.fd + /usr/share/OVMF/OVMF_CODE_4M.fd /var/lib/libvirt/qemu/nvram/guestos_VARS.fd diff --git a/ic-os/components/hostos-scripts/guestos/qemu-cpu.xml b/ic-os/components/hostos-scripts/guestos/qemu-cpu.xml index 3013b06373d..fd50c03a79e 100644 --- a/ic-os/components/hostos-scripts/guestos/qemu-cpu.xml +++ b/ic-os/components/hostos-scripts/guestos/qemu-cpu.xml @@ -1 +1 @@ - + diff --git a/ic-os/components/hostos-scripts/libvirt/setup-libvirt.sh b/ic-os/components/hostos-scripts/libvirt/setup-libvirt.sh index 5525702d98a..c2b8b8d2017 100755 --- a/ic-os/components/hostos-scripts/libvirt/setup-libvirt.sh +++ b/ic-os/components/hostos-scripts/libvirt/setup-libvirt.sh @@ -5,3 +5,6 @@ set -e # Create space for libvirt to manage its config mount --bind /run/libvirt /etc/libvirt + +# Set up log directory, because it will not create it alone +mkdir -p /var/log/libvirt/qemu diff --git a/ic-os/defs.bzl b/ic-os/defs.bzl index 5a4e614c977..5f2a4384cfd 100644 --- a/ic-os/defs.bzl +++ b/ic-os/defs.bzl @@ -148,8 +148,6 @@ def icos_build( "/run", "/boot", "/var", - "/usr/lib/firmware/brcm/brcmfmac43430a0-sdio.ONDA-V80 PLUS.txt", - "/usr/lib/firmware/brcm/brcmfmac43455-sdio.MINIX-NEO Z83-4.txt", "/usr/lib/firmware/brcm/brcmfmac43241b4-sdio.Intel Corp.-VALLEYVIEW C0 PLATFORM.txt.zst", "/usr/lib/firmware/brcm/brcmfmac43340-sdio.ASUSTeK COMPUTER INC.-TF103CE.txt.zst", "/usr/lib/firmware/brcm/brcmfmac43362-sdio.ASUSTeK COMPUTER INC.-ME176C.txt.zst", diff --git a/ic-os/hostos/context/Dockerfile b/ic-os/hostos/context/Dockerfile index 5b3374fe043..621c23eeda6 100644 --- a/ic-os/hostos/context/Dockerfile +++ b/ic-os/hostos/context/Dockerfile @@ -29,7 +29,7 @@ RUN sed -e '/.*pam_motd.so.*/d' -i /etc/pam.d/login && \ # but this is per system (so backups are not persisted across upgrades) # and thus not very useful, and /etc is read-only. # So simply suppress generating backups. -RUN sed -e 's/\(backup *= *\)1/\10/' -e 's/\(archive *= *\)1/\10/' -i /etc/lvm/lvm.conf +RUN sed -e 's/\(# \)\?\(backup *= *\)[01]/\20/' -e 's/\(# \)\?\(archive *= *\)[01]/\20/' -i /etc/lvm/lvm.conf # Deactivate systemd userdb. We don't use it. RUN sed -e 's/ *systemd//' -i /etc/nsswitch.conf @@ -39,7 +39,7 @@ RUN localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 # Clear files that may lead to indeterministic build. RUN apt-get clean && \ - find /usr/lib/python3.8 -name "*.pyc" | xargs rm && \ + find /usr/lib/python3.12 -name "*.pyc" | xargs rm && \ find /usr/lib/python3 -name "*.pyc" | xargs rm && \ find /usr/share/python3 -name "*.pyc" | xargs rm && \ truncate --size 0 /etc/machine-id @@ -91,6 +91,7 @@ RUN systemctl enable \ chrony \ libvirtd \ nftables \ + ssh \ systemd-journal-gatewayd \ systemd-networkd \ systemd-networkd-wait-online \ @@ -117,14 +118,8 @@ RUN rm -rf \ /usr/local/share/qemu/edk2-arm-code.fd \ /usr/local/share/qemu/edk2-arm-vars.fd -# Add user/group entries specified here: /usr/lib/sysusers.d/systemd.conf E.g., systemd-timesync/coredump -RUN systemd-sysusers && \ - # Fix reproducibility issue. Notes in hostos/context/Dockerfile - usermod -p '!!' systemd-timesync && \ - usermod -p '!!' systemd-coredump - # Set /bin/sh to point to /bin/bash instead of the default /bin/dash -RUN echo "set dash/sh false" | debconf-communicate && dpkg-reconfigure -fnoninteractive dash +RUN ln -sf bash /usr/bin/sh # Group accounts to which parts of the runtime state are assigned such that # user accounts can be granted individual access rights. diff --git a/ic-os/hostos/context/docker-base.dev b/ic-os/hostos/context/docker-base.dev index cd5decc792b..6b56f76b0ae 100644 --- a/ic-os/hostos/context/docker-base.dev +++ b/ic-os/hostos/context/docker-base.dev @@ -1 +1 @@ -ghcr.io/dfinity/hostos-base-dev@sha256:a6e8e7ab7abf682c80dfd717d36ac027213f757ddad415c66080ac4314639590 +ghcr.io/dfinity/hostos-base-dev@sha256:e133ba80d1d291fff89fe9e60f3fbf9285095d9c15a51a1297e314d0f9fe837c diff --git a/ic-os/hostos/context/docker-base.prod b/ic-os/hostos/context/docker-base.prod index 0c1ef008b24..a18a83e2197 100644 --- a/ic-os/hostos/context/docker-base.prod +++ b/ic-os/hostos/context/docker-base.prod @@ -1 +1 @@ -ghcr.io/dfinity/hostos-base@sha256:5e93fb6cadecd22b838a8e442ed88d3c77ac5626651ee139559150d2a77a6743 +ghcr.io/dfinity/hostos-base@sha256:13ae203beb66cdb2ac198ea2441e82b6fb36b93c4e337ccbc32383de49ad7f88 diff --git a/rs/ic_os/config/src/config_ini.rs b/rs/ic_os/config/src/config_ini.rs index d90a77d95be..4bc6c92219c 100644 --- a/rs/ic_os/config/src/config_ini.rs +++ b/rs/ic_os/config/src/config_ini.rs @@ -9,8 +9,7 @@ use anyhow::{Context, Result}; pub type ConfigMap = HashMap; pub struct ConfigIniSettings { - pub ipv6_prefix: Option, - pub ipv6_address: Option, + pub ipv6_prefix: String, pub ipv6_prefix_length: u8, pub ipv6_gateway: Ipv6Addr, pub ipv4_address: Option, @@ -31,34 +30,18 @@ pub fn get_config_ini_settings(config_file_path: &Path) -> Result() - .context(format!("Invalid IPv6 address: {}", address)) - }) - .transpose()?; - - if ipv6_address.is_none() && ipv6_prefix.is_none() { - bail!("Missing config parameter: need at least one of ipv6_prefix or ipv6_address"); - } - let ipv6_gateway = config_map .get("ipv6_gateway") .context("Missing config parameter: ipv6_gateway")? @@ -107,7 +90,6 @@ pub fn get_config_ini_settings(config_file_path: &Path) -> Result()? - ); assert_eq!( config_ini_settings.ipv6_gateway, "2a00:fb01:400:200::1".parse::()? @@ -291,16 +268,6 @@ mod tests { assert_eq!(config_ini_settings.domain, Some("example.com".to_string())); assert!(!config_ini_settings.verbose); - // Test ipv6_address without ipv6_prefix_length length - let mut temp_file = NamedTempFile::new()?; - writeln!(temp_file, "ipv6_address=2a00:fb01:400:200::")?; - let config_ini_settings = get_config_ini_settings(temp_file_path)?; - assert_eq!( - config_ini_settings.ipv6_address.unwrap(), - "2a00:fb01:400:200::".parse::()? - ); - assert_eq!(config_ini_settings.ipv6_prefix_length, 64); - // Test missing ipv6 let mut temp_file = NamedTempFile::new()?; writeln!(temp_file, "ipv4_address=212.71.124.178")?; @@ -311,7 +278,7 @@ mod tests { let result = get_config_ini_settings(temp_file_path); assert!(result.is_err()); - // Test invalid IPv6 address + // Test invalid IPv6 prefix let mut temp_file = NamedTempFile::new()?; writeln!(temp_file, "ipv6_prefix=invalid_ipv6_prefix")?; writeln!(temp_file, "ipv6_gateway=2001:db8:85a3:0000::1")?; @@ -323,7 +290,7 @@ mod tests { let result = get_config_ini_settings(temp_file_path); assert!(result.is_err()); - // Test missing prefix and address + // Test missing prefix let mut temp_file = NamedTempFile::new()?; writeln!(temp_file, "ipv6_gateway=2001:db8:85a3:0000::1")?; let result = get_config_ini_settings(temp_file_path); diff --git a/rs/ic_os/config/src/lib.rs b/rs/ic_os/config/src/lib.rs index c49f689cb53..2e4cf733440 100644 --- a/rs/ic_os/config/src/lib.rs +++ b/rs/ic_os/config/src/lib.rs @@ -54,10 +54,9 @@ mod tests { #[test] fn test_serialize_and_deserialize() { let network_settings = NetworkSettings { - ipv6_prefix: None, - ipv6_address: None, + ipv6_prefix: "2a00:fb01:400:200".to_string(), ipv6_prefix_length: 64_u8, - ipv6_gateway: "2001:db8::1".parse().unwrap(), + ipv6_gateway: "2a00:fb01:400:200::1".parse().unwrap(), ipv4_address: None, ipv4_gateway: None, ipv4_prefix_length: None, diff --git a/rs/ic_os/config/src/main.rs b/rs/ic_os/config/src/main.rs index 65e825ee95c..ba0dde4f2b3 100644 --- a/rs/ic_os/config/src/main.rs +++ b/rs/ic_os/config/src/main.rs @@ -65,7 +65,6 @@ pub fn main() -> Result<()> { let config_ini_settings = get_config_ini_settings(&config_ini_path)?; let ConfigIniSettings { ipv6_prefix, - ipv6_address, ipv6_prefix_length, ipv6_gateway, ipv4_address, @@ -80,7 +79,6 @@ pub fn main() -> Result<()> { let network_settings = NetworkSettings { ipv6_prefix, - ipv6_address, ipv6_prefix_length, ipv6_gateway, ipv4_address, diff --git a/rs/ic_os/config/src/types.rs b/rs/ic_os/config/src/types.rs index 7562b55e12e..5940a7dc1ea 100644 --- a/rs/ic_os/config/src/types.rs +++ b/rs/ic_os/config/src/types.rs @@ -83,10 +83,7 @@ pub struct BackupSpoolSettings { #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct NetworkSettings { - // Config.ini can specify ipv6_prefix and ipv6_gateway, or just an ipv6_address. - // ipv6_address takes precedence. Some tests provide only ipv6_address. - pub ipv6_prefix: Option, - pub ipv6_address: Option, + pub ipv6_prefix: String, pub ipv6_prefix_length: u8, pub ipv6_gateway: Ipv6Addr, pub ipv4_address: Option, diff --git a/rs/ic_os/network/src/lib.rs b/rs/ic_os/network/src/lib.rs index caa65ca1642..8538df3eab4 100644 --- a/rs/ic_os/network/src/lib.rs +++ b/rs/ic_os/network/src/lib.rs @@ -23,16 +23,10 @@ pub fn generate_network_config( node_type: NodeType, output_directory: &Path, ) -> Result<()> { - if let Some(address) = network_settings.ipv6_address { - eprintln!("Found ipv6 address in config"); - return generate_systemd_config_files(output_directory, network_settings, None, &address); - }; + let deployment_name = deployment_name + .context("Error: Deployment name not found when attempting to generate mac address")?; - let mac = generate_mac_address( - deployment_name, - &node_type, - network_settings.mgmt_mac.as_deref(), - )?; + let mac = generate_mac_address(deployment_name, &node_type, mgmt_mac)?; eprintln!("Using generated mac (unformatted) {}", mac.get()); eprintln!("Generating ipv6 address"); From d622da8334a79f0fa494ee1ce55dcaf4701d3399 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 26 Sep 2024 21:13:35 +0000 Subject: [PATCH 09/28] Fix merge errors --- rs/ic_os/network/src/lib.rs | 16 +++++++--------- rs/ic_os/os_tools/hostos_tool/src/main.rs | 10 ++-------- rs/ic_os/os_tools/setupos_tool/src/main.rs | 6 ++---- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/rs/ic_os/network/src/lib.rs b/rs/ic_os/network/src/lib.rs index 8538df3eab4..3bfa6b0529c 100644 --- a/rs/ic_os/network/src/lib.rs +++ b/rs/ic_os/network/src/lib.rs @@ -1,6 +1,6 @@ use std::path::Path; -use anyhow::{Context, Result}; +use anyhow::Result; use crate::mac_address::generate_mac_address; use crate::node_type::NodeType; @@ -23,17 +23,15 @@ pub fn generate_network_config( node_type: NodeType, output_directory: &Path, ) -> Result<()> { - let deployment_name = deployment_name - .context("Error: Deployment name not found when attempting to generate mac address")?; - - let mac = generate_mac_address(deployment_name, &node_type, mgmt_mac)?; + let mac = generate_mac_address( + deployment_name, + &node_type, + network_settings.mgmt_mac.as_deref(), + )?; eprintln!("Using generated mac (unformatted) {}", mac.get()); eprintln!("Generating ipv6 address"); - let ipv6_prefix = network_settings - .ipv6_prefix - .clone() - .context("ipv6_prefix required in config to generate ipv6 address")?; + let ipv6_prefix = network_settings.ipv6_prefix.clone(); let ipv6_address = generate_ipv6_address(&ipv6_prefix, &mac)?; eprintln!("Using ipv6 address: {}", ipv6_address); diff --git a/rs/ic_os/os_tools/hostos_tool/src/main.rs b/rs/ic_os/os_tools/hostos_tool/src/main.rs index 20442549009..90c60d1b042 100644 --- a/rs/ic_os/os_tools/hostos_tool/src/main.rs +++ b/rs/ic_os/os_tools/hostos_tool/src/main.rs @@ -1,6 +1,6 @@ use std::path::Path; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; use clap::{Parser, Subcommand}; use config::config_ini::get_config_ini_settings; @@ -67,7 +67,6 @@ pub fn main() -> Result<()> { // and we won't need to read config.ini and deployment.json directly. let network_settings = NetworkSettings { ipv6_prefix: config_ini_settings.ipv6_prefix, - ipv6_address: config_ini_settings.ipv6_address, ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, ipv6_gateway: config_ini_settings.ipv6_gateway, ipv4_address: config_ini_settings.ipv4_address, @@ -97,7 +96,6 @@ pub fn main() -> Result<()> { // and we won't need to read config.ini and deployment.json directly. let network_settings = NetworkSettings { ipv6_prefix: config_ini_settings.ipv6_prefix, - ipv6_address: config_ini_settings.ipv6_address, ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, ipv6_gateway: config_ini_settings.ipv6_gateway, ipv4_address: config_ini_settings.ipv4_address, @@ -114,10 +112,7 @@ pub fn main() -> Result<()> { &node_type, network_settings.mgmt_mac.as_deref(), )?; - let ipv6_prefix = network_settings - .ipv6_prefix - .context("ipv6_prefix required in config to generate ipv6 address")?; - let ipv6_address = generate_ipv6_address(&ipv6_prefix, &mac)?; + let ipv6_address = generate_ipv6_address(&network_settings.ipv6_prefix, &mac)?; println!( "{}", to_cidr(ipv6_address, network_settings.ipv6_prefix_length) @@ -136,7 +131,6 @@ pub fn main() -> Result<()> { // and we won't need to read config.ini and deployment.json directly. let network_settings = NetworkSettings { ipv6_prefix: config_ini_settings.ipv6_prefix, - ipv6_address: config_ini_settings.ipv6_address, ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, ipv6_gateway: config_ini_settings.ipv6_gateway, ipv4_address: config_ini_settings.ipv4_address, diff --git a/rs/ic_os/os_tools/setupos_tool/src/main.rs b/rs/ic_os/os_tools/setupos_tool/src/main.rs index 77063696d0f..3d2994f26c2 100644 --- a/rs/ic_os/os_tools/setupos_tool/src/main.rs +++ b/rs/ic_os/os_tools/setupos_tool/src/main.rs @@ -78,10 +78,8 @@ pub fn main() -> Result<()> { &node_type, setup_config.network_settings.mgmt_mac.as_deref(), )?; - let ipv6_prefix = setup_config.network_settings.ipv6_prefix.ok_or_else(|| { - anyhow!("ipv6_prefix required in config to generate ipv6 address") - })?; - let ipv6_address = generate_ipv6_address(&ipv6_prefix, &mac)?; + let ipv6_address = + generate_ipv6_address(&setup_config.network_settings.ipv6_prefix, &mac)?; println!( "{}", to_cidr( From 514c2315b1769ca7241ad804accd51329264dc3c Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 26 Sep 2024 21:17:13 +0000 Subject: [PATCH 10/28] Remove unnecessary ipv6_prefix declaration --- rs/ic_os/network/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rs/ic_os/network/src/lib.rs b/rs/ic_os/network/src/lib.rs index 3bfa6b0529c..ecd945d9c53 100644 --- a/rs/ic_os/network/src/lib.rs +++ b/rs/ic_os/network/src/lib.rs @@ -31,8 +31,7 @@ pub fn generate_network_config( eprintln!("Using generated mac (unformatted) {}", mac.get()); eprintln!("Generating ipv6 address"); - let ipv6_prefix = network_settings.ipv6_prefix.clone(); - let ipv6_address = generate_ipv6_address(&ipv6_prefix, &mac)?; + let ipv6_address = generate_ipv6_address(&network_settings.ipv6_prefix, &mac)?; eprintln!("Using ipv6 address: {}", ipv6_address); let formatted_mac = FormattedMacAddress::from(&mac); From 40480c5f6ec6d931ab8dadbf1eca4aaaa60b797c Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Mon, 30 Sep 2024 15:21:32 +0000 Subject: [PATCH 11/28] Fix ownership error --- rs/ic_os/os_tools/setupos_tool/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ic_os/os_tools/setupos_tool/src/main.rs b/rs/ic_os/os_tools/setupos_tool/src/main.rs index 1f3b8f8be10..dec348a556f 100644 --- a/rs/ic_os/os_tools/setupos_tool/src/main.rs +++ b/rs/ic_os/os_tools/setupos_tool/src/main.rs @@ -60,7 +60,7 @@ pub fn main() -> Result<()> { &setup_config.network_settings ); - let mgmt_mac = match setup_config.network_settings.mgmt_mac { + let mgmt_mac = match setup_config.network_settings.mgmt_mac.as_ref() { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( From 168f175ea60f237fabccba065608c6b0c06ba61e Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Mon, 30 Sep 2024 15:25:58 +0000 Subject: [PATCH 12/28] Re-add node_type parsing and fix formatting --- rs/ic_os/os_tools/hostos_tool/src/main.rs | 2 +- rs/ic_os/os_tools/setupos_tool/src/main.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rs/ic_os/os_tools/hostos_tool/src/main.rs b/rs/ic_os/os_tools/hostos_tool/src/main.rs index dc873d01cfb..d072d0a524f 100644 --- a/rs/ic_os/os_tools/hostos_tool/src/main.rs +++ b/rs/ic_os/os_tools/hostos_tool/src/main.rs @@ -123,6 +123,7 @@ pub fn main() -> Result<()> { }; eprintln!("Network settings config: {:?}", &network_settings); + let node_type = node_type.parse::()?; let mgmt_mac = match network_settings.mgmt_mac.as_ref() { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; @@ -171,7 +172,6 @@ pub fn main() -> Result<()> { eprintln!("Network settings config: {:?}", &network_settings); let node_type = node_type.parse::()?; - let mgmt_mac = match network_settings.mgmt_mac.as_ref() { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; diff --git a/rs/ic_os/os_tools/setupos_tool/src/main.rs b/rs/ic_os/os_tools/setupos_tool/src/main.rs index dec348a556f..e53d6cf220e 100644 --- a/rs/ic_os/os_tools/setupos_tool/src/main.rs +++ b/rs/ic_os/os_tools/setupos_tool/src/main.rs @@ -94,7 +94,6 @@ pub fn main() -> Result<()> { ); let node_type = node_type.parse::()?; - let mgmt_mac = match setup_config.network_settings.mgmt_mac { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; From 881e95e5c1dec714b534a1cb1b220ed55ffbc0c5 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Mon, 30 Sep 2024 17:47:29 +0000 Subject: [PATCH 13/28] Create NetworkSettings enums --- rs/ic_os/config/src/lib.rs | 19 +++++++-------- rs/ic_os/config/src/main.rs | 38 +++++++++++++++++++----------- rs/ic_os/config/src/types.rs | 45 +++++++++++++++++++++++++++--------- 3 files changed, 67 insertions(+), 35 deletions(-) diff --git a/rs/ic_os/config/src/lib.rs b/rs/ic_os/config/src/lib.rs index c75ebb58d5c..d10ef35b8e4 100644 --- a/rs/ic_os/config/src/lib.rs +++ b/rs/ic_os/config/src/lib.rs @@ -46,21 +46,18 @@ pub fn deserialize_config Deserialize<'de>>(file_path: &str) -> Resu mod tests { use super::*; use std::path::PathBuf; - use types::{ - GuestOSConfig, GuestOSDevSettings, GuestOSSettings, HostOSConfig, HostOSSettings, - ICOSDevSettings, ICOSSettings, Logging, NetworkSettings, SetupOSConfig, SetupOSSettings, - }; + use types::*; #[test] fn test_serialize_and_deserialize() { + let ipv6_config = Ipv6Config::Deterministic(DeterministicIpv6Config { + prefix: "2a00:fb01:400:200".to_string(), + prefix_length: 64_u8, + gateway: "2a00:fb01:400:200::1".parse().unwrap(), + }); let network_settings = NetworkSettings { - ipv6_prefix: "2a00:fb01:400:200".to_string(), - ipv6_prefix_length: 64_u8, - ipv6_gateway: "2a00:fb01:400:200::1".parse().unwrap(), - ipv4_address: None, - ipv4_gateway: None, - ipv4_prefix_length: None, - domain: None, + ipv6_config, + ipv4_config: None, }; let logging = Logging { elasticsearch_hosts: [ diff --git a/rs/ic_os/config/src/main.rs b/rs/ic_os/config/src/main.rs index 5e7b1ac54ba..ca8c3ebe86b 100644 --- a/rs/ic_os/config/src/main.rs +++ b/rs/ic_os/config/src/main.rs @@ -6,10 +6,7 @@ use config::serialize_and_write_config; use std::fs::File; use std::path::{Path, PathBuf}; -use config::types::{ - GuestOSSettings, HostOSConfig, HostOSSettings, ICOSDevSettings, ICOSSettings, Logging, - NetworkSettings, SetupOSConfig, SetupOSSettings, -}; +use config::types::*; #[derive(Subcommand)] pub enum Commands { @@ -62,7 +59,6 @@ pub fn main() -> Result<()> { setupos_config_json_path, }) => { // get config.ini settings - let config_ini_settings = get_config_ini_settings(&config_ini_path)?; let ConfigIniSettings { ipv6_prefix, ipv6_prefix_length, @@ -72,16 +68,32 @@ pub fn main() -> Result<()> { ipv4_prefix_length, domain, verbose, - } = config_ini_settings; + } = get_config_ini_settings(&config_ini_path)?; + + // create NetworkSettings + let deterministic_config = DeterministicIpv6Config { + prefix: ipv6_prefix, + prefix_length: ipv6_prefix_length, + gateway: ipv6_gateway, + }; + + let ipv4_config = + if let (Some(address), Some(gateway), Some(prefix_length), Some(domain)) = + (ipv4_address, ipv4_gateway, ipv4_prefix_length, domain) + { + Some(Ipv4Config { + address, + gateway, + prefix_length, + domain, + }) + } else { + None + }; let network_settings = NetworkSettings { - ipv6_prefix, - ipv6_prefix_length, - ipv6_gateway, - ipv4_address, - ipv4_gateway, - ipv4_prefix_length, - domain, + ipv6_config: Ipv6Config::Deterministic(deterministic_config), + ipv4_config, }; // get deployment.json variables diff --git a/rs/ic_os/config/src/types.rs b/rs/ic_os/config/src/types.rs index 975b1093f2f..96ee595d615 100644 --- a/rs/ic_os/config/src/types.rs +++ b/rs/ic_os/config/src/types.rs @@ -81,17 +81,6 @@ pub struct BackupSpoolSettings { pub backup_purging_interval_seconds: Option, } -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub struct NetworkSettings { - pub ipv6_prefix: String, - pub ipv6_prefix_length: u8, - pub ipv6_gateway: Ipv6Addr, - pub ipv4_address: Option, - pub ipv4_gateway: Option, - pub ipv4_prefix_length: Option, - pub domain: Option, -} - #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct ICOSSettings { pub logging: Logging, @@ -125,3 +114,37 @@ pub struct Logging { /// Space-separated list of tags to apply to exported log records. pub elasticsearch_tags: Option, } + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct NetworkSettings { + pub ipv6_config: Ipv6Config, + pub ipv4_config: Option, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Ipv4Config { + pub address: Ipv4Addr, + pub gateway: Ipv4Addr, + pub prefix_length: u8, + pub domain: String, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub enum Ipv6Config { + Deterministic(DeterministicIpv6Config), + Fixed(FixedIpv6Config), + RouterAdvertisement, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct DeterministicIpv6Config { + pub prefix: String, + pub prefix_length: u8, + pub gateway: Ipv6Addr, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct FixedIpv6Config { + pub address: Ipv6Addr, + pub gateway: Ipv6Addr, +} From 26324e44385e9017d7c8730923c81bd5fbc0170e Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Mon, 30 Sep 2024 17:53:44 +0000 Subject: [PATCH 14/28] Print SetupOSConfig --- rs/ic_os/config/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rs/ic_os/config/src/main.rs b/rs/ic_os/config/src/main.rs index ca8c3ebe86b..10f989f04dc 100644 --- a/rs/ic_os/config/src/main.rs +++ b/rs/ic_os/config/src/main.rs @@ -143,6 +143,7 @@ pub fn main() -> Result<()> { hostos_settings, guestos_settings, }; + println!("SetupOSConfig: {:?}", setupos_config); let setupos_config_json_path = Path::new(&setupos_config_json_path); serialize_and_write_config(setupos_config_json_path, &setupos_config)?; From c3dd639bb1baec0d85204644a5ec8b3999d8ffa1 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Wed, 2 Oct 2024 22:46:58 +0000 Subject: [PATCH 15/28] Fix errors after merging config tool refactor --- rs/ic_os/network/src/lib.rs | 31 ++++--- rs/ic_os/network/src/systemd.rs | 17 ++-- rs/ic_os/os_tools/hostos_tool/src/main.rs | 97 ++++++++++++++-------- rs/ic_os/os_tools/setupos_tool/src/main.rs | 30 ++++--- 4 files changed, 107 insertions(+), 68 deletions(-) diff --git a/rs/ic_os/network/src/lib.rs b/rs/ic_os/network/src/lib.rs index 081d2cb9fe4..01147f7a06e 100644 --- a/rs/ic_os/network/src/lib.rs +++ b/rs/ic_os/network/src/lib.rs @@ -1,10 +1,10 @@ use std::path::Path; -use anyhow::Result; +use anyhow::{anyhow, Result}; use crate::mac_address::UnformattedMacAddress; use crate::systemd::generate_systemd_config_files; -use config::types::NetworkSettings; +use config::types::{Ipv6Config, NetworkSettings}; use ipv6::generate_ipv6_address; use mac_address::FormattedMacAddress; @@ -22,14 +22,23 @@ pub fn generate_network_config( output_directory: &Path, ) -> Result<()> { eprintln!("Generating ipv6 address"); - let ipv6_address = generate_ipv6_address(&network_settings.ipv6_prefix, &generated_mac)?; - eprintln!("Using ipv6 address: {}", ipv6_address); - let formatted_mac = FormattedMacAddress::from(&generated_mac); - generate_systemd_config_files( - output_directory, - network_settings, - Some(&formatted_mac), - &ipv6_address, - ) + match &network_settings.ipv6_config { + Ipv6Config::RouterAdvertisement => { + Err(anyhow!("IC-OS router advertisement is not yet supported")) + } + Ipv6Config::Fixed(_) => Err(anyhow!("Fixed IP configuration is not yet supported")), + Ipv6Config::Deterministic(ipv6_config) => { + let ipv6_address = generate_ipv6_address(&ipv6_config.prefix, &generated_mac)?; + eprintln!("Using ipv6 address: {}", ipv6_address); + + let formatted_mac = FormattedMacAddress::from(&generated_mac); + generate_systemd_config_files( + output_directory, + ipv6_config, + Some(&formatted_mac), + &ipv6_address, + ) + } + } } diff --git a/rs/ic_os/network/src/systemd.rs b/rs/ic_os/network/src/systemd.rs index bd58f0f2916..e2d49cf247b 100644 --- a/rs/ic_os/network/src/systemd.rs +++ b/rs/ic_os/network/src/systemd.rs @@ -7,7 +7,7 @@ use anyhow::{Context, Result}; use crate::interfaces::{get_interfaces, has_ipv6_connectivity, Interface}; use crate::mac_address::FormattedMacAddress; -use config::types::NetworkSettings; +use config::types::DeterministicIpv6Config; pub static DEFAULT_SYSTEMD_NETWORK_DIR: &str = "/run/systemd/network"; @@ -149,7 +149,7 @@ fn generate_and_write_systemd_files( pub fn generate_systemd_config_files( output_directory: &Path, - network_settings: &NetworkSettings, + ipv6_config: &DeterministicIpv6Config, generated_mac: Option<&FormattedMacAddress>, ipv6_address: &Ipv6Addr, ) -> Result<()> { @@ -157,18 +157,13 @@ pub fn generate_systemd_config_files( interfaces.sort_by(|a, b| a.speed_mbps.cmp(&b.speed_mbps)); eprintln!("Interfaces sorted by speed: {:?}", interfaces); - let ping_target = network_settings.ipv6_gateway.to_string(); + let ping_target = ipv6_config.gateway.to_string(); // old nodes are still configured with a local IPv4 interface connection // local IPv4 interfaces must be filtered out let ipv6_interfaces: Vec<&Interface> = interfaces .iter() .filter(|i| { - match has_ipv6_connectivity( - i, - ipv6_address, - network_settings.ipv6_prefix_length, - &ping_target, - ) { + match has_ipv6_connectivity(i, ipv6_address, ipv6_config.prefix_length, &ping_target) { Ok(result) => result, Err(e) => { eprintln!("Error testing connectivity on {}: {}", &i.name, e); @@ -191,14 +186,14 @@ pub fn generate_systemd_config_files( let ipv6_address = format!( "{}/{}", &ipv6_address.to_string(), - network_settings.ipv6_prefix_length + ipv6_config.prefix_length ); generate_and_write_systemd_files( output_directory, fastest_interface, generated_mac, &ipv6_address, - &network_settings.ipv6_gateway.to_string(), + &ipv6_config.gateway.to_string(), )?; print!("Restarting systemd networkd"); diff --git a/rs/ic_os/os_tools/hostos_tool/src/main.rs b/rs/ic_os/os_tools/hostos_tool/src/main.rs index d072d0a524f..89177373147 100644 --- a/rs/ic_os/os_tools/hostos_tool/src/main.rs +++ b/rs/ic_os/os_tools/hostos_tool/src/main.rs @@ -5,7 +5,7 @@ use clap::{Parser, Subcommand}; use config::config_ini::get_config_ini_settings; use config::deployment_json::get_deployment_settings; -use config::types::NetworkSettings; +use config::types::{DeterministicIpv6Config, Ipv4Config, Ipv6Config, NetworkSettings}; use config::{DEFAULT_HOSTOS_CONFIG_INI_FILE_PATH, DEFAULT_HOSTOS_DEPLOYMENT_JSON_PATH}; use network::generate_network_config; use network::ipv6::generate_ipv6_address; @@ -66,18 +66,26 @@ pub fn main() -> Result<()> { // Once HostOS is using the config struct, all config will be contained there // and we won't need to read config.ini and deployment.json directly. let network_settings = NetworkSettings { - ipv6_prefix: config_ini_settings.ipv6_prefix, - ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, - ipv6_gateway: config_ini_settings.ipv6_gateway, - ipv4_address: config_ini_settings.ipv4_address, - ipv4_gateway: config_ini_settings.ipv4_gateway, - ipv4_prefix_length: config_ini_settings.ipv4_prefix_length, - domain: config_ini_settings.domain, - mgmt_mac: deployment_json_settings.deployment.mgmt_mac, + ipv6_config: Ipv6Config::Deterministic(DeterministicIpv6Config { + prefix: config_ini_settings.ipv6_prefix, + prefix_length: config_ini_settings.ipv6_prefix_length, + gateway: config_ini_settings.ipv6_gateway, + }), + ipv4_config: config_ini_settings + .ipv4_address + .zip(config_ini_settings.ipv4_gateway) + .zip(config_ini_settings.ipv4_prefix_length) + .zip(config_ini_settings.domain) + .map(|(((address, gateway), prefix_length), domain)| Ipv4Config { + address, + gateway, + prefix_length, + domain, + }), }; eprintln!("Network settings config: {:?}", &network_settings); - let mgmt_mac = match network_settings.mgmt_mac.as_ref() { + let mgmt_mac = match deployment_json_settings.deployment.mgmt_mac.as_ref() { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( @@ -112,19 +120,27 @@ pub fn main() -> Result<()> { // Once HostOS is using the config struct, all config will be contained there // and we won't need to read config.ini and deployment.json directly. let network_settings = NetworkSettings { - ipv6_prefix: config_ini_settings.ipv6_prefix, - ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, - ipv6_gateway: config_ini_settings.ipv6_gateway, - ipv4_address: config_ini_settings.ipv4_address, - ipv4_gateway: config_ini_settings.ipv4_gateway, - ipv4_prefix_length: config_ini_settings.ipv4_prefix_length, - domain: config_ini_settings.domain, - mgmt_mac: deployment_json_settings.deployment.mgmt_mac, + ipv6_config: Ipv6Config::Deterministic(DeterministicIpv6Config { + prefix: config_ini_settings.ipv6_prefix, + prefix_length: config_ini_settings.ipv6_prefix_length, + gateway: config_ini_settings.ipv6_gateway, + }), + ipv4_config: config_ini_settings + .ipv4_address + .zip(config_ini_settings.ipv4_gateway) + .zip(config_ini_settings.ipv4_prefix_length) + .zip(config_ini_settings.domain) + .map(|(((address, gateway), prefix_length), domain)| Ipv4Config { + address, + gateway, + prefix_length, + domain, + }), }; eprintln!("Network settings config: {:?}", &network_settings); let node_type = node_type.parse::()?; - let mgmt_mac = match network_settings.mgmt_mac.as_ref() { + let mgmt_mac = match deployment_json_settings.deployment.mgmt_mac.as_ref() { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( @@ -141,12 +157,17 @@ pub fn main() -> Result<()> { &node_type, )?; eprintln!("Using generated mac (unformatted) {}", generated_mac); - let ipv6_address = - generate_ipv6_address(&network_settings.ipv6_prefix, &generated_mac)?; - println!( - "{}", - to_cidr(ipv6_address, network_settings.ipv6_prefix_length) - ); + + let ipv6_config = + if let Ipv6Config::Deterministic(ipv6_config) = &network_settings.ipv6_config { + ipv6_config + } else { + return Err(anyhow!("Ipv6Config is not of type Deterministic")); + }; + + let ipv6_address = generate_ipv6_address(&ipv6_config.prefix, &generated_mac)?; + println!("{}", to_cidr(ipv6_address, ipv6_config.prefix_length)); + Ok(()) } Some(Commands::GenerateMacAddress { node_type }) => { @@ -160,19 +181,27 @@ pub fn main() -> Result<()> { // Once HostOS is using the config struct, all config will be contained there // and we won't need to read config.ini and deployment.json directly. let network_settings = NetworkSettings { - ipv6_prefix: config_ini_settings.ipv6_prefix, - ipv6_prefix_length: config_ini_settings.ipv6_prefix_length, - ipv6_gateway: config_ini_settings.ipv6_gateway, - ipv4_address: config_ini_settings.ipv4_address, - ipv4_gateway: config_ini_settings.ipv4_gateway, - ipv4_prefix_length: config_ini_settings.ipv4_prefix_length, - domain: config_ini_settings.domain, - mgmt_mac: deployment_json_settings.deployment.mgmt_mac, + ipv6_config: Ipv6Config::Deterministic(DeterministicIpv6Config { + prefix: config_ini_settings.ipv6_prefix, + prefix_length: config_ini_settings.ipv6_prefix_length, + gateway: config_ini_settings.ipv6_gateway, + }), + ipv4_config: config_ini_settings + .ipv4_address + .zip(config_ini_settings.ipv4_gateway) + .zip(config_ini_settings.ipv4_prefix_length) + .zip(config_ini_settings.domain) + .map(|(((address, gateway), prefix_length), domain)| Ipv4Config { + address, + gateway, + prefix_length, + domain, + }), }; eprintln!("Network settings config: {:?}", &network_settings); let node_type = node_type.parse::()?; - let mgmt_mac = match network_settings.mgmt_mac.as_ref() { + let mgmt_mac = match deployment_json_settings.deployment.mgmt_mac.as_ref() { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( diff --git a/rs/ic_os/os_tools/setupos_tool/src/main.rs b/rs/ic_os/os_tools/setupos_tool/src/main.rs index e53d6cf220e..2178d6e5ead 100644 --- a/rs/ic_os/os_tools/setupos_tool/src/main.rs +++ b/rs/ic_os/os_tools/setupos_tool/src/main.rs @@ -3,7 +3,7 @@ use std::path::Path; use anyhow::{anyhow, Result}; use clap::{Parser, Subcommand}; -use config::types::SetupOSConfig; +use config::types::{Ipv6Config, SetupOSConfig}; use config::{ deserialize_config, DEFAULT_SETUPOS_CONFIG_INI_FILE_PATH, DEFAULT_SETUPOS_CONFIG_OBJECT_PATH, DEFAULT_SETUPOS_DEPLOYMENT_JSON_PATH, @@ -60,7 +60,12 @@ pub fn main() -> Result<()> { &setup_config.network_settings ); - let mgmt_mac = match setup_config.network_settings.mgmt_mac.as_ref() { + let mgmt_mac = match setup_config + .icos_settings + .icos_dev_settings + .mgmt_mac + .as_ref() + { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( @@ -94,7 +99,7 @@ pub fn main() -> Result<()> { ); let node_type = node_type.parse::()?; - let mgmt_mac = match setup_config.network_settings.mgmt_mac { + let mgmt_mac = match setup_config.icos_settings.icos_dev_settings.mgmt_mac { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( @@ -109,15 +114,16 @@ pub fn main() -> Result<()> { generate_mac_address(&mgmt_mac, &setup_config.icos_settings.hostname, &node_type)?; eprintln!("Using generated mac (unformatted) {}", generated_mac); - let ipv6_address = - generate_ipv6_address(&setup_config.network_settings.ipv6_prefix, &generated_mac)?; - println!( - "{}", - to_cidr( - ipv6_address, - setup_config.network_settings.ipv6_prefix_length - ) - ); + let ipv6_config = if let Ipv6Config::Deterministic(ipv6_config) = + &setup_config.network_settings.ipv6_config + { + ipv6_config + } else { + return Err(anyhow!("Ipv6Config is not of type Deterministic")); + }; + + let ipv6_address = generate_ipv6_address(&ipv6_config.prefix, &generated_mac)?; + println!("{}", to_cidr(ipv6_address, ipv6_config.prefix_length)); Ok(()) } From ef606d07576a97d19c5b3495cd6b9224cafa962e Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 19:26:41 +0000 Subject: [PATCH 16/28] Copy config-hostos.json to HostOS --- .../setupos-scripts/setup-hostos-config.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/ic-os/components/setupos-scripts/setup-hostos-config.sh b/ic-os/components/setupos-scripts/setup-hostos-config.sh index 181eb119487..d1308c49495 100755 --- a/ic-os/components/setupos-scripts/setup-hostos-config.sh +++ b/ic-os/components/setupos-scripts/setup-hostos-config.sh @@ -66,14 +66,13 @@ function copy_config_files() { /opt/ic/bin/config generate-hostos-config log_and_halt_installation_on_error "${?}" "Unable to generate hostos configuration." - # TODO: NODE-1466: Configuration revamp (HostOS and GuestOS integration) - # echo "* Copying 'config-hostos.json' to hostOS config partition..." - # if [ -f "/var/ic/config/config-hostos.json" ]; then - # cp /var/ic/config/config-hostos.json /media/config.json - # log_and_halt_installation_on_error "${?}" "Unable to copy 'config-hostos.json' to hostOS config partition." - # else - # log_and_halt_installation_on_error "1" "Configuration file 'config-hostos.json' does not exist." - # fi + echo "* Copying 'config-hostos.json' to hostOS config partition..." + if [ -f "/var/ic/config/config-hostos.json" ]; then + cp /var/ic/config/config-hostos.json /media/config.json + log_and_halt_installation_on_error "${?}" "Unable to copy 'config-hostos.json' to hostOS config partition." + else + log_and_halt_installation_on_error "1" "Configuration file 'config-hostos.json' does not exist." + fi } function insert_hsm_if_necessary() { From e08ab58d0caca3ade68b4b5dc7542f08ba7769f0 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 19:26:55 +0000 Subject: [PATCH 17/28] Update GenerateIpv6Address error message --- rs/ic_os/os_tools/hostos_tool/src/main.rs | 4 +++- rs/ic_os/os_tools/setupos_tool/src/main.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/rs/ic_os/os_tools/hostos_tool/src/main.rs b/rs/ic_os/os_tools/hostos_tool/src/main.rs index 89177373147..3362ae50051 100644 --- a/rs/ic_os/os_tools/hostos_tool/src/main.rs +++ b/rs/ic_os/os_tools/hostos_tool/src/main.rs @@ -162,7 +162,9 @@ pub fn main() -> Result<()> { if let Ipv6Config::Deterministic(ipv6_config) = &network_settings.ipv6_config { ipv6_config } else { - return Err(anyhow!("Ipv6Config is not of type Deterministic")); + return Err(anyhow!( + "Ipv6Config is not of type Deterministic. Cannot generate IPv6 address." + )); }; let ipv6_address = generate_ipv6_address(&ipv6_config.prefix, &generated_mac)?; diff --git a/rs/ic_os/os_tools/setupos_tool/src/main.rs b/rs/ic_os/os_tools/setupos_tool/src/main.rs index 2178d6e5ead..bd809ee697a 100644 --- a/rs/ic_os/os_tools/setupos_tool/src/main.rs +++ b/rs/ic_os/os_tools/setupos_tool/src/main.rs @@ -119,7 +119,9 @@ pub fn main() -> Result<()> { { ipv6_config } else { - return Err(anyhow!("Ipv6Config is not of type Deterministic")); + return Err(anyhow!( + "Ipv6Config is not of type Deterministic. Cannot generate IPv6 address." + )); }; let ipv6_address = generate_ipv6_address(&ipv6_config.prefix, &generated_mac)?; From 5f262b5b2d5a21fc7388900cdfc7c2954a922471 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 19:27:08 +0000 Subject: [PATCH 18/28] Add log_start and log_end to check-config.sh --- ic-os/components/setupos-scripts/check-config.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ic-os/components/setupos-scripts/check-config.sh b/ic-os/components/setupos-scripts/check-config.sh index b826345a4c5..fa20310e9fc 100644 --- a/ic-os/components/setupos-scripts/check-config.sh +++ b/ic-os/components/setupos-scripts/check-config.sh @@ -27,7 +27,9 @@ check_config_file() { # Establish run order main() { + log_start "$(basename $0)" check_config_file + log_end "$(basename $0)" } main From 664ed5bfd22699e73a1f217a82ba85ff10cfe7de Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 19:29:13 +0000 Subject: [PATCH 19/28] Rename setupos_config --- rs/ic_os/os_tools/setupos_tool/src/main.rs | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/rs/ic_os/os_tools/setupos_tool/src/main.rs b/rs/ic_os/os_tools/setupos_tool/src/main.rs index bd809ee697a..152c6c48e24 100644 --- a/rs/ic_os/os_tools/setupos_tool/src/main.rs +++ b/rs/ic_os/os_tools/setupos_tool/src/main.rs @@ -52,15 +52,15 @@ pub fn main() -> Result<()> { match opts.command { Some(Commands::GenerateNetworkConfig { output_directory }) => { - let setup_config: SetupOSConfig = + let setupos_config: SetupOSConfig = deserialize_config(DEFAULT_SETUPOS_CONFIG_OBJECT_PATH)?; eprintln!( "Network settings config: {:?}", - &setup_config.network_settings + &setupos_config.network_settings ); - let mgmt_mac = match setup_config + let mgmt_mac = match setupos_config .icos_settings .icos_dev_settings .mgmt_mac @@ -78,28 +78,28 @@ pub fn main() -> Result<()> { }; let generated_mac = generate_mac_address( &mgmt_mac, - &setup_config.icos_settings.hostname, + &setupos_config.icos_settings.hostname, &NodeType::SetupOS, )?; eprintln!("Using generated mac (unformatted) {}", generated_mac); generate_network_config( - &setup_config.network_settings, + &setupos_config.network_settings, generated_mac, Path::new(&output_directory), ) } Some(Commands::GenerateIpv6Address { node_type }) => { - let setup_config: SetupOSConfig = + let setupos_config: SetupOSConfig = deserialize_config(DEFAULT_SETUPOS_CONFIG_OBJECT_PATH)?; eprintln!( "Network settings config: {:?}", - &setup_config.network_settings + &setupos_config.network_settings ); let node_type = node_type.parse::()?; - let mgmt_mac = match setup_config.icos_settings.icos_dev_settings.mgmt_mac { + let mgmt_mac = match setupos_config.icos_settings.icos_dev_settings.mgmt_mac { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( @@ -110,12 +110,15 @@ pub fn main() -> Result<()> { } None => get_ipmi_mac()?, }; - let generated_mac = - generate_mac_address(&mgmt_mac, &setup_config.icos_settings.hostname, &node_type)?; + let generated_mac = generate_mac_address( + &mgmt_mac, + &setupos_config.icos_settings.hostname, + &node_type, + )?; eprintln!("Using generated mac (unformatted) {}", generated_mac); let ipv6_config = if let Ipv6Config::Deterministic(ipv6_config) = - &setup_config.network_settings.ipv6_config + &setupos_config.network_settings.ipv6_config { ipv6_config } else { From 328305eabfbbf9d49f3eb2615976003e58026479 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 19:40:13 +0000 Subject: [PATCH 20/28] Use hostos config object in HostOS tool --- rs/ic_os/config/src/lib.rs | 1 + rs/ic_os/os_tools/hostos_tool/src/main.rs | 184 ++++++++-------------- 2 files changed, 69 insertions(+), 116 deletions(-) diff --git a/rs/ic_os/config/src/lib.rs b/rs/ic_os/config/src/lib.rs index d10ef35b8e4..1b80cd41bc9 100644 --- a/rs/ic_os/config/src/lib.rs +++ b/rs/ic_os/config/src/lib.rs @@ -18,6 +18,7 @@ pub static DEFAULT_SETUPOS_NODE_OPERATOR_PRIVATE_KEY_PATH: &str = pub static DEFAULT_SETUPOS_HOSTOS_CONFIG_OBJECT_PATH: &str = "/var/ic/config/config-hostos.json"; +pub static DEFAULT_HOSTOS_CONFIG_OBJECT_PATH: &str = "/boot/config/config-hostos.json"; pub static DEFAULT_HOSTOS_CONFIG_INI_FILE_PATH: &str = "/boot/config/config.ini"; pub static DEFAULT_HOSTOS_DEPLOYMENT_JSON_PATH: &str = "/boot/config/deployment.json"; diff --git a/rs/ic_os/os_tools/hostos_tool/src/main.rs b/rs/ic_os/os_tools/hostos_tool/src/main.rs index 3362ae50051..dd2ea5c60f6 100644 --- a/rs/ic_os/os_tools/hostos_tool/src/main.rs +++ b/rs/ic_os/os_tools/hostos_tool/src/main.rs @@ -3,10 +3,11 @@ use std::path::Path; use anyhow::{anyhow, Result}; use clap::{Parser, Subcommand}; -use config::config_ini::get_config_ini_settings; -use config::deployment_json::get_deployment_settings; -use config::types::{DeterministicIpv6Config, Ipv4Config, Ipv6Config, NetworkSettings}; -use config::{DEFAULT_HOSTOS_CONFIG_INI_FILE_PATH, DEFAULT_HOSTOS_DEPLOYMENT_JSON_PATH}; +use config::types::{HostOSConfig, Ipv6Config}; +use config::{ + deserialize_config, DEFAULT_HOSTOS_CONFIG_INI_FILE_PATH, DEFAULT_HOSTOS_CONFIG_OBJECT_PATH, + DEFAULT_HOSTOS_DEPLOYMENT_JSON_PATH, +}; use network::generate_network_config; use network::ipv6::generate_ipv6_address; use network::mac_address::{generate_mac_address, get_ipmi_mac, FormattedMacAddress}; @@ -56,36 +57,20 @@ pub fn main() -> Result<()> { match opts.command { Some(Commands::GenerateNetworkConfig { output_directory }) => { - let config_ini_settings = get_config_ini_settings(Path::new(&opts.config))?; - - let deployment_json_settings = - get_deployment_settings(Path::new(&opts.deployment_file))?; - eprintln!("Deployment config: {:?}", deployment_json_settings); - - // TODO: NODE-1466: Remove in configuration revamp (HostOS and GuestOS integration). - // Once HostOS is using the config struct, all config will be contained there - // and we won't need to read config.ini and deployment.json directly. - let network_settings = NetworkSettings { - ipv6_config: Ipv6Config::Deterministic(DeterministicIpv6Config { - prefix: config_ini_settings.ipv6_prefix, - prefix_length: config_ini_settings.ipv6_prefix_length, - gateway: config_ini_settings.ipv6_gateway, - }), - ipv4_config: config_ini_settings - .ipv4_address - .zip(config_ini_settings.ipv4_gateway) - .zip(config_ini_settings.ipv4_prefix_length) - .zip(config_ini_settings.domain) - .map(|(((address, gateway), prefix_length), domain)| Ipv4Config { - address, - gateway, - prefix_length, - domain, - }), - }; - eprintln!("Network settings config: {:?}", &network_settings); - - let mgmt_mac = match deployment_json_settings.deployment.mgmt_mac.as_ref() { + let hostos_config: HostOSConfig = + deserialize_config(DEFAULT_HOSTOS_CONFIG_OBJECT_PATH)?; + + eprintln!( + "Network settings config: {:?}", + &hostos_config.network_settings + ); + + let mgmt_mac = match hostos_config + .icos_settings + .icos_dev_settings + .mgmt_mac + .as_ref() + { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( @@ -96,51 +81,35 @@ pub fn main() -> Result<()> { } None => get_ipmi_mac()?, }; + let generated_mac = generate_mac_address( &mgmt_mac, - deployment_json_settings.deployment.name.as_str(), + &hostos_config.icos_settings.hostname, &NodeType::HostOS, )?; eprintln!("Using generated mac (unformatted) {}", generated_mac); generate_network_config( - &network_settings, + &hostos_config.network_settings, generated_mac, Path::new(&output_directory), ) } Some(Commands::GenerateIpv6Address { node_type }) => { - let config_ini_settings = get_config_ini_settings(Path::new(&opts.config))?; - - let deployment_json_settings = - get_deployment_settings(Path::new(&opts.deployment_file))?; - eprintln!("Deployment config: {:?}", deployment_json_settings); - - // TODO: NODE-1466: Remove in configuration revamp (HostOS and GuestOS integration). - // Once HostOS is using the config struct, all config will be contained there - // and we won't need to read config.ini and deployment.json directly. - let network_settings = NetworkSettings { - ipv6_config: Ipv6Config::Deterministic(DeterministicIpv6Config { - prefix: config_ini_settings.ipv6_prefix, - prefix_length: config_ini_settings.ipv6_prefix_length, - gateway: config_ini_settings.ipv6_gateway, - }), - ipv4_config: config_ini_settings - .ipv4_address - .zip(config_ini_settings.ipv4_gateway) - .zip(config_ini_settings.ipv4_prefix_length) - .zip(config_ini_settings.domain) - .map(|(((address, gateway), prefix_length), domain)| Ipv4Config { - address, - gateway, - prefix_length, - domain, - }), - }; - eprintln!("Network settings config: {:?}", &network_settings); - - let node_type = node_type.parse::()?; - let mgmt_mac = match deployment_json_settings.deployment.mgmt_mac.as_ref() { + let hostos_config: HostOSConfig = + deserialize_config(DEFAULT_HOSTOS_CONFIG_OBJECT_PATH)?; + + eprintln!( + "Network settings config: {:?}", + &hostos_config.network_settings + ); + + let mgmt_mac = match hostos_config + .icos_settings + .icos_dev_settings + .mgmt_mac + .as_ref() + { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( @@ -151,21 +120,21 @@ pub fn main() -> Result<()> { } None => get_ipmi_mac()?, }; - let generated_mac = generate_mac_address( - &mgmt_mac, - deployment_json_settings.deployment.name.as_str(), - &node_type, - )?; + let node_type = node_type.parse::()?; + + let generated_mac = + generate_mac_address(&mgmt_mac, &hostos_config.icos_settings.hostname, &node_type)?; eprintln!("Using generated mac (unformatted) {}", generated_mac); - let ipv6_config = - if let Ipv6Config::Deterministic(ipv6_config) = &network_settings.ipv6_config { - ipv6_config - } else { - return Err(anyhow!( - "Ipv6Config is not of type Deterministic. Cannot generate IPv6 address." - )); - }; + let ipv6_config = if let Ipv6Config::Deterministic(ipv6_config) = + &hostos_config.network_settings.ipv6_config + { + ipv6_config + } else { + return Err(anyhow!( + "Ipv6Config is not of type Deterministic. Cannot generate IPv6 address." + )); + }; let ipv6_address = generate_ipv6_address(&ipv6_config.prefix, &generated_mac)?; println!("{}", to_cidr(ipv6_address, ipv6_config.prefix_length)); @@ -173,37 +142,20 @@ pub fn main() -> Result<()> { Ok(()) } Some(Commands::GenerateMacAddress { node_type }) => { - let config_ini_settings = get_config_ini_settings(Path::new(&opts.config))?; - - let deployment_json_settings = - get_deployment_settings(Path::new(&opts.deployment_file))?; - eprintln!("Deployment config: {:?}", deployment_json_settings); - - // TODO: NODE-1466: Remove in configuration revamp (HostOS and GuestOS integration). - // Once HostOS is using the config struct, all config will be contained there - // and we won't need to read config.ini and deployment.json directly. - let network_settings = NetworkSettings { - ipv6_config: Ipv6Config::Deterministic(DeterministicIpv6Config { - prefix: config_ini_settings.ipv6_prefix, - prefix_length: config_ini_settings.ipv6_prefix_length, - gateway: config_ini_settings.ipv6_gateway, - }), - ipv4_config: config_ini_settings - .ipv4_address - .zip(config_ini_settings.ipv4_gateway) - .zip(config_ini_settings.ipv4_prefix_length) - .zip(config_ini_settings.domain) - .map(|(((address, gateway), prefix_length), domain)| Ipv4Config { - address, - gateway, - prefix_length, - domain, - }), - }; - eprintln!("Network settings config: {:?}", &network_settings); - - let node_type = node_type.parse::()?; - let mgmt_mac = match deployment_json_settings.deployment.mgmt_mac.as_ref() { + let hostos_config: HostOSConfig = + deserialize_config(DEFAULT_HOSTOS_CONFIG_OBJECT_PATH)?; + + eprintln!( + "Network settings config: {:?}", + &hostos_config.network_settings + ); + + let mgmt_mac = match hostos_config + .icos_settings + .icos_dev_settings + .mgmt_mac + .as_ref() + { Some(config_mac) => { let mgmt_mac = FormattedMacAddress::try_from(config_mac.as_str())?; eprintln!( @@ -214,11 +166,11 @@ pub fn main() -> Result<()> { } None => get_ipmi_mac()?, }; - let generated_mac = generate_mac_address( - &mgmt_mac, - deployment_json_settings.deployment.name.as_str(), - &node_type, - )?; + let node_type = node_type.parse::()?; + + let generated_mac = + generate_mac_address(&mgmt_mac, &hostos_config.icos_settings.hostname, &node_type)?; + eprintln!("Using generated mac (unformatted) {}", generated_mac); println!("{}", generated_mac); Ok(()) From 83ab1d092bcd9e18d2bb42425f2928ad7160f443 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 20:44:55 +0000 Subject: [PATCH 21/28] Create separate config.sh for hostos and setupos --- ic-os/components/hostos.bzl | 1 + ic-os/components/misc/config/hostos-config.sh | 12 ++++++++++++ .../{config.sh => config/setupos-config copy.sh} | 0 ic-os/components/setupos.bzl | 2 +- 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 ic-os/components/misc/config/hostos-config.sh rename ic-os/components/misc/{config.sh => config/setupos-config copy.sh} (100%) diff --git a/ic-os/components/hostos.bzl b/ic-os/components/hostos.bzl index c40901fbcaa..7d074a4d5f4 100644 --- a/ic-os/components/hostos.bzl +++ b/ic-os/components/hostos.bzl @@ -48,6 +48,7 @@ component_files = { Label("early-boot/initramfs-tools/hostos/set-machine-id/set-machine-id"): "/etc/initramfs-tools/scripts/init-bottom/set-machine-id/set-machine-id", # misc + Label("misc/config/hostos-config.sh"): "/opt/ic/bin/config.sh", Label("misc/logging.sh"): "/opt/ic/bin/logging.sh", Label("misc/metrics.sh"): "/opt/ic/bin/metrics.sh", Label("misc/fetch-property.sh"): "/opt/ic/bin/fetch-property.sh", diff --git a/ic-os/components/misc/config/hostos-config.sh b/ic-os/components/misc/config/hostos-config.sh new file mode 100644 index 00000000000..831d04cbc28 --- /dev/null +++ b/ic-os/components/misc/config/hostos-config.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Shared config utilities. + +# Retrieves a value from the config.json file using a JSON path. +# Arguments: +# $1 - JSON path to the desired value (e.g., '.icos_settings.node_operator_private_key_path') +function get_config_value() { + local CONFIG_FILE="/boot/config/config.json" + local key=$1 + jq -r "${key}" "${CONFIG_FILE}" +} diff --git a/ic-os/components/misc/config.sh b/ic-os/components/misc/config/setupos-config copy.sh similarity index 100% rename from ic-os/components/misc/config.sh rename to ic-os/components/misc/config/setupos-config copy.sh diff --git a/ic-os/components/setupos.bzl b/ic-os/components/setupos.bzl index c55ea1715b8..1c2afa576b3 100644 --- a/ic-os/components/setupos.bzl +++ b/ic-os/components/setupos.bzl @@ -26,7 +26,7 @@ component_files = { # misc Label("misc/logging.sh"): "/opt/ic/bin/logging.sh", - Label("misc/config.sh"): "/opt/ic/bin/config.sh", + Label("misc/config/setupos-config.sh"): "/opt/ic/bin/config.sh", Label("misc/chrony/chrony.conf"): "/etc/chrony/chrony.conf", Label("misc/chrony/chrony-var.service"): "/etc/systemd/system/chrony-var.service", Label("misc/serial-getty@/setupos/serial-getty@.service"): "/etc/systemd/system/serial-getty@.service", From f915d288b62381aa90eb2de50de980b126cfc515 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 20:45:14 +0000 Subject: [PATCH 22/28] Fix reference to DEFAULT_HOSTOS_CONFIG_OBJECT_PATH --- rs/ic_os/config/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/ic_os/config/src/lib.rs b/rs/ic_os/config/src/lib.rs index 1b80cd41bc9..40014d8e590 100644 --- a/rs/ic_os/config/src/lib.rs +++ b/rs/ic_os/config/src/lib.rs @@ -18,7 +18,7 @@ pub static DEFAULT_SETUPOS_NODE_OPERATOR_PRIVATE_KEY_PATH: &str = pub static DEFAULT_SETUPOS_HOSTOS_CONFIG_OBJECT_PATH: &str = "/var/ic/config/config-hostos.json"; -pub static DEFAULT_HOSTOS_CONFIG_OBJECT_PATH: &str = "/boot/config/config-hostos.json"; +pub static DEFAULT_HOSTOS_CONFIG_OBJECT_PATH: &str = "/boot/config/config.json"; pub static DEFAULT_HOSTOS_CONFIG_INI_FILE_PATH: &str = "/boot/config/config.ini"; pub static DEFAULT_HOSTOS_DEPLOYMENT_JSON_PATH: &str = "/boot/config/deployment.json"; From c098cf47e228a4f173516b990ffce260f7e5b68e Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 20:45:35 +0000 Subject: [PATCH 23/28] Update verbose-logging to use config object --- .../verbose-logging/verbose-logging.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/ic-os/components/hostos-scripts/verbose-logging/verbose-logging.sh b/ic-os/components/hostos-scripts/verbose-logging/verbose-logging.sh index a8ff2e9b2cd..979464d0777 100644 --- a/ic-os/components/hostos-scripts/verbose-logging/verbose-logging.sh +++ b/ic-os/components/hostos-scripts/verbose-logging/verbose-logging.sh @@ -1,18 +1,8 @@ #!/bin/bash -CONFIG="${CONFIG:=/boot/config/config.ini}" +source /opt/ic/bin/config.sh -function read_variables() { - # Read limited set of keys. Be extra-careful quoting values as it could - # otherwise lead to executing arbitrary shell code! - while IFS="=" read -r key value; do - case "$key" in - "verbose") verbose="${value}" ;; - esac - done <"${CONFIG}" -} - -read_variables +verbose=$(get_config_value '.hostos_settings.verbose') if [[ "${verbose,,}" == "true" ]]; then echo "##########################################" >/dev/tty1 From 47d9b4efc7bdcf21563f79956511d288ae99c265 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 20:46:22 +0000 Subject: [PATCH 24/28] Update generate-guestos-config to use config object and delete unused fetch-mgmt-mac.sh --- .../check_file_references.py | 7 +- .../build-bootstrap-config-image.sh | 12 +-- .../dev-generate-guestos-config.sh | 75 +++++--------- .../generate-guestos-config.sh | 63 +++++------- .../hostos-scripts/misc/fetch-mgmt-mac.sh | 2 - ic-os/components/hostos.bzl | 1 - ic-os/components/misc/fetch-property.sh | 98 ------------------- 7 files changed, 56 insertions(+), 202 deletions(-) delete mode 100755 ic-os/components/misc/fetch-property.sh diff --git a/ic-os/components/conformance_tests/check_file_references.py b/ic-os/components/conformance_tests/check_file_references.py index cd91b8723e7..6009ff44384 100755 --- a/ic-os/components/conformance_tests/check_file_references.py +++ b/ic-os/components/conformance_tests/check_file_references.py @@ -11,12 +11,7 @@ import tarfile import tempfile -ALLOWED_UNDECLARED_DEPENDENCIES = { - "ic-os/components/misc/fetch-property.sh": { - # fetch-property.sh checks existence of metrics.sh - "/opt/ic/bin/metrics.sh", - } -} +ALLOWED_UNDECLARED_DEPENDENCIES = {} # Check file patterns /opt/ic/... COMPONENT_FILE_PATTERN = r"/opt/ic/[^\s'\"},)]+" diff --git a/ic-os/components/hostos-scripts/build-bootstrap-config-image.sh b/ic-os/components/hostos-scripts/build-bootstrap-config-image.sh index ec1f21cfd1e..2f759d4e199 100755 --- a/ic-os/components/hostos-scripts/build-bootstrap-config-image.sh +++ b/ic-os/components/hostos-scripts/build-bootstrap-config-image.sh @@ -63,7 +63,7 @@ options may be specified: (make sure to quote the argument string so it appears as a single argument to the script, e.g. --elasticsearch_tags "testnet1 slo") - --nns_url url + --nns_urls urls URL of NNS nodes for sign up or registry access. Can be multiple nodes separated by commas. @@ -122,7 +122,7 @@ function build_ic_bootstrap_tar() { local IPV6_ADDRESS IPV6_GATEWAY DOMAIN HOSTNAME local IC_CRYPTO IC_STATE IC_REGISTRY_LOCAL_STORE - local NNS_URL NNS_PUBLIC_KEY NODE_OPERATOR_PRIVATE_KEY + local NNS_URLS NNS_PUBLIC_KEY NODE_OPERATOR_PRIVATE_KEY local BACKUP_RETENTION_TIME_SECS BACKUP_PURGING_INTERVAL_SECS local ELASTICSEARCH_HOSTS ELASTICSEARCH_TAGS local ACCOUNTS_SSH_AUTHORIZED_KEYS @@ -170,8 +170,8 @@ function build_ic_bootstrap_tar() { --elasticsearch_tags) ELASTICSEARCH_TAGS="$2" ;; - --nns_url) - NNS_URL="$2" + --nns_urls) + NNS_URLS="$2" ;; --nns_public_key) NNS_PUBLIC_KEY="$2" @@ -237,8 +237,8 @@ EOF if [ "${NNS_PUBLIC_KEY}" != "" ]; then cp "${NNS_PUBLIC_KEY}" "${BOOTSTRAP_TMPDIR}/nns_public_key.pem" fi - if [ "${NNS_URL}" != "" ]; then - echo "nns_url=${NNS_URL}" >"${BOOTSTRAP_TMPDIR}/nns.conf" + if [ "${NNS_URLS}" != "" ]; then + echo "nns_url=${NNS_URLS}" >"${BOOTSTRAP_TMPDIR}/nns.conf" fi if [ "${BACKUP_RETENTION_TIME_SECS}" != "" ] || [ "${BACKUP_PURGING_INTERVAL_SECS}" != "" ]; then echo "backup_retention_time_secs=${BACKUP_RETENTION_TIME_SECS}" >"${BOOTSTRAP_TMPDIR}/backup.conf" diff --git a/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh b/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh index 49276f8719b..c1a2f809cb0 100755 --- a/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh +++ b/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh @@ -4,6 +4,7 @@ set -e # Generate the GuestOS configuration. +source /opt/ic/bin/logging.sh # Source the functions required for writing metrics source /opt/ic/bin/metrics.sh @@ -12,21 +13,11 @@ SCRIPT="$(basename $0)[$$]" # Get keyword arguments for argument in "${@}"; do case ${argument} in - -c=* | --config=*) - CONFIG="${argument#*=}" - shift - ;; - -d=* | --deployment=*) - DEPLOYMENT="${argument#*=}" - shift - ;; -h | --help) echo 'Usage: Generate GuestOS Configuration Arguments: - -c=, --config= specify the config.ini configuration file (Default: /boot/config/config.ini) - -d=, --deployment= specify the deployment.json configuration file (Default: /boot/config/deployment.json) -h, --help show this help message and exit -i=, --input= specify the input template file (Default: /opt/ic/share/guestos.xml.template) -m=, --media= specify the config media image file (Default: /run/ic-node/config.img) @@ -54,47 +45,35 @@ Arguments: done function validate_arguments() { - if [ "${CONFIG}" == "" -o "${DEPLOYMENT}" == "" -o "${INPUT}" == "" -o "${OUTPUT}" == "" ]; then + if [ "${INPUT}" == "" -o "${OUTPUT}" == "" ]; then $0 --help fi } # Set arguments if undefined -CONFIG="${CONFIG:=/boot/config/config.ini}" -DEPLOYMENT="${DEPLOYMENT:=/boot/config/deployment.json}" INPUT="${INPUT:=/opt/ic/share/guestos.xml.template}" MEDIA="${MEDIA:=/run/ic-node/config.img}" OUTPUT="${OUTPUT:=/var/lib/libvirt/guestos.xml}" -write_log() { - local message=$1 - - if [ -t 1 ]; then - echo "${SCRIPT} ${message}" >/dev/stdout - fi - - logger -t ${SCRIPT} "${message}" -} - -function read_variables() { - # Read limited set of keys. Be extra-careful quoting values as it could - # otherwise lead to executing arbitrary shell code! - while IFS="=" read -r key value; do - case "$key" in - "ipv6_prefix") ipv6_prefix="${value}" ;; - "ipv6_gateway") ipv6_gateway="${value}" ;; - "ipv4_address") ipv4_address="${value}" ;; - "ipv4_prefix_length") ipv4_prefix_length="${value}" ;; - "ipv4_gateway") ipv4_gateway="${value}" ;; - "domain") domain="${value}" ;; - esac - done <"${CONFIG}" +function read_config_variables() { + ipv6_prefix=$(get_config_value '.network_settings.ipv6_prefix') + ipv6_gateway=$(get_config_value '.network_settings.ipv6_gateway') + ipv4_address=$(get_config_value '.network_settings.ipv4_address') + ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_prefix_length') + ipv4_gateway=$(get_config_value '.network_settings.ipv4_gateway') + domain=$(get_config_value '.network_settings.domain') + elasticsearch_hosts=$(get_config_value '.icos_settings.logging.elasticsearch_hosts') + nns_public_key=$(get_config_value '.icos_settings.nns_public_key_path') + nns_urls=$(get_config_value '.icos_settings.nns_urls') + node_operator_private_key=$(get_config_value '.icos_settings.node_operator_private_key_path') + vm_memory=$(get_config_value '.hostos_settings.vm_memory') + vm_cpu=$(get_config_value '.hostos_settings.vm_cpu') } function assemble_config_media() { cmd=(/opt/ic/bin/build-bootstrap-config-image.sh ${MEDIA}) - cmd+=(--nns_public_key "/boot/config/nns_public_key.pem") - cmd+=(--elasticsearch_hosts "$(/opt/ic/bin/fetch-property.sh --key=.logging.hosts --metric=hostos_logging_hosts --config=${DEPLOYMENT})") + cmd+=(--nns_public_key "$nns_public_key") + cmd+=(--elasticsearch_hosts "$elasticsearch_hosts") cmd+=(--ipv6_address "$(/opt/ic/bin/hostos_tool generate-ipv6-address --node-type GuestOS)") cmd+=(--ipv6_gateway "${ipv6_gateway}") if [[ -n "$ipv4_address" && -n "$ipv4_prefix_length" && -n "$ipv4_gateway" && -n "$domain" ]]; then @@ -102,12 +81,12 @@ function assemble_config_media() { cmd+=(--ipv4_gateway "${ipv4_gateway}") cmd+=(--domain "${domain}") fi + # todo: can I use the fetch-mgmt-mac in hostos tool? cmd+=(--hostname "guest-$(/opt/ic/bin/fetch-mgmt-mac.sh | sed 's/://g')") - cmd+=(--nns_url "$(/opt/ic/bin/fetch-property.sh --key=.nns.url --metric=hostos_nns_url --config=${DEPLOYMENT})") - if [ -f "/boot/config/node_operator_private_key.pem" ]; then - cmd+=(--node_operator_private_key "/boot/config/node_operator_private_key.pem") + cmd+=(--nns_urls "$nns_urls") + if [ -f "$node_operator_private_key" ]; then + cmd+=(--node_operator_private_key "$node_operator_private_key") fi - cmd+=(--accounts_ssh_authorized_keys "/boot/config/ssh_authorized_keys") # Run the above command @@ -116,22 +95,19 @@ function assemble_config_media() { } function generate_guestos_config() { - RESOURCES_MEMORY=$(/opt/ic/bin/fetch-property.sh --key=.resources.memory --metric=hostos_resources_memory --config=${DEPLOYMENT}) + # todo: can I use the generate mac address in hostos tool? MAC_ADDRESS=$(/opt/ic/bin/hostos_tool generate-mac-address --node-type GuestOS) - # NOTE: `fetch-property` will error if the target is not found. Here we - # only want to act when the field is set. - CPU_MODE=$(jq -r ".resources.cpu" ${DEPLOYMENT}) CPU_DOMAIN="kvm" CPU_SPEC="/opt/ic/share/kvm-cpu.xml" - if [ "${CPU_MODE}" == "qemu" ]; then + if [ "${vm_cpu}" == "qemu" ]; then CPU_DOMAIN="qemu" CPU_SPEC="/opt/ic/share/qemu-cpu.xml" fi if [ ! -f "${OUTPUT}" ]; then mkdir -p "$(dirname "$OUTPUT")" - sed -e "s@{{ resources_memory }}@${RESOURCES_MEMORY}@" \ + sed -e "s@{{ resources_memory }}@${vm_memory}@" \ -e "s@{{ mac_address }}@${MAC_ADDRESS}@" \ -e "s@{{ cpu_domain }}@${CPU_DOMAIN}@" \ -e "/{{ cpu_spec }}/{r ${CPU_SPEC}" -e "d" -e "}" \ @@ -152,9 +128,8 @@ function generate_guestos_config() { } function main() { - # Establish run order validate_arguments - read_variables + read_config_variables assemble_config_media generate_guestos_config } diff --git a/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh b/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh index cca55130bf4..439c19fc4a2 100755 --- a/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh +++ b/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh @@ -13,21 +13,11 @@ SCRIPT="$(basename $0)[$$]" # Get keyword arguments for argument in "${@}"; do case ${argument} in - -c=* | --config=*) - CONFIG="${argument#*=}" - shift - ;; - -d=* | --deployment=*) - DEPLOYMENT="${argument#*=}" - shift - ;; -h | --help) echo 'Usage: Generate GuestOS Configuration Arguments: - -c=, --config= specify the config.ini configuration file (Default: /boot/config/config.ini) - -d=, --deployment= specify the deployment.json configuration file (Default: /boot/config/deployment.json) -h, --help show this help message and exit -i=, --input= specify the input template file (Default: /opt/ic/share/guestos.xml.template) -m=, --media= specify the config media image file (Default: /run/ic-node/config.img) @@ -55,37 +45,35 @@ Arguments: done function validate_arguments() { - if [ "${CONFIG}" == "" -o "${DEPLOYMENT}" == "" -o "${INPUT}" == "" -o "${OUTPUT}" == "" ]; then + if [ "${INPUT}" == "" -o "${OUTPUT}" == "" ]; then $0 --help fi } # Set arguments if undefined -CONFIG="${CONFIG:=/boot/config/config.ini}" -DEPLOYMENT="${DEPLOYMENT:=/boot/config/deployment.json}" INPUT="${INPUT:=/opt/ic/share/guestos.xml.template}" MEDIA="${MEDIA:=/run/ic-node/config.img}" OUTPUT="${OUTPUT:=/var/lib/libvirt/guestos.xml}" -function read_variables() { - # Read limited set of keys. Be extra-careful quoting values as it could - # otherwise lead to executing arbitrary shell code! - while IFS="=" read -r key value; do - case "$key" in - "ipv6_prefix") ipv6_prefix="${value}" ;; - "ipv6_gateway") ipv6_gateway="${value}" ;; - "ipv4_address") ipv4_address="${value}" ;; - "ipv4_prefix_length") ipv4_prefix_length="${value}" ;; - "ipv4_gateway") ipv4_gateway="${value}" ;; - "domain") domain="${value}" ;; - esac - done <"${CONFIG}" +function read_config_variables() { + ipv6_prefix=$(get_config_value '.network_settings.ipv6_prefix') + ipv6_gateway=$(get_config_value '.network_settings.ipv6_gateway') + ipv4_address=$(get_config_value '.network_settings.ipv4_address') + ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_prefix_length') + ipv4_gateway=$(get_config_value '.network_settings.ipv4_gateway') + domain=$(get_config_value '.network_settings.domain') + elasticsearch_hosts=$(get_config_value '.icos_settings.logging.elasticsearch_hosts') + nns_public_key=$(get_config_value '.icos_settings.nns_public_key_path') + nns_urls=$(get_config_value '.icos_settings.nns_urls') + node_operator_private_key=$(get_config_value '.icos_settings.node_operator_private_key_path') + vm_memory=$(get_config_value '.hostos_settings.vm_memory') + vm_cpu=$(get_config_value '.hostos_settings.vm_cpu') } function assemble_config_media() { cmd=(/opt/ic/bin/build-bootstrap-config-image.sh ${MEDIA}) - cmd+=(--nns_public_key "/boot/config/nns_public_key.pem") - cmd+=(--elasticsearch_hosts "$(/opt/ic/bin/fetch-property.sh --key=.logging.hosts --metric=hostos_logging_hosts --config=${DEPLOYMENT})") + cmd+=(--nns_public_key "$nns_public_key") + cmd+=(--elasticsearch_hosts "$elasticsearch_hosts") cmd+=(--ipv6_address "$(/opt/ic/bin/hostos_tool generate-ipv6-address --node-type GuestOS)") cmd+=(--ipv6_gateway "${ipv6_gateway}") if [[ -n "$ipv4_address" && -n "$ipv4_prefix_length" && -n "$ipv4_gateway" && -n "$domain" ]]; then @@ -93,10 +81,11 @@ function assemble_config_media() { cmd+=(--ipv4_gateway "${ipv4_gateway}") cmd+=(--domain "${domain}") fi + # todo: can I use the fetch-mgmt-mac in hostos tool? cmd+=(--hostname "guest-$(/opt/ic/bin/fetch-mgmt-mac.sh | sed 's/://g')") - cmd+=(--nns_url "$(/opt/ic/bin/fetch-property.sh --key=.nns.url --metric=hostos_nns_url --config=${DEPLOYMENT})") - if [ -f "/boot/config/node_operator_private_key.pem" ]; then - cmd+=(--node_operator_private_key "/boot/config/node_operator_private_key.pem") + cmd+=(--nns_urls "$nns_urls") + if [ -f "$node_operator_private_key" ]; then + cmd+=(--node_operator_private_key "$node_operator_private_key") fi # Run the above command @@ -105,22 +94,19 @@ function assemble_config_media() { } function generate_guestos_config() { - RESOURCES_MEMORY=$(/opt/ic/bin/fetch-property.sh --key=.resources.memory --metric=hostos_resources_memory --config=${DEPLOYMENT}) + # todo: can I use the generate mac address in hostos tool? MAC_ADDRESS=$(/opt/ic/bin/hostos_tool generate-mac-address --node-type GuestOS) - # NOTE: `fetch-property` will error if the target is not found. Here we - # only want to act when the field is set. - CPU_MODE=$(jq -r ".resources.cpu" ${DEPLOYMENT}) CPU_DOMAIN="kvm" CPU_SPEC="/opt/ic/share/kvm-cpu.xml" - if [ "${CPU_MODE}" == "qemu" ]; then + if [ "${vm_cpu}" == "qemu" ]; then CPU_DOMAIN="qemu" CPU_SPEC="/opt/ic/share/qemu-cpu.xml" fi if [ ! -f "${OUTPUT}" ]; then mkdir -p "$(dirname "$OUTPUT")" - sed -e "s@{{ resources_memory }}@${RESOURCES_MEMORY}@" \ + sed -e "s@{{ resources_memory }}@${vm_memory}@" \ -e "s@{{ mac_address }}@${MAC_ADDRESS}@" \ -e "s@{{ cpu_domain }}@${CPU_DOMAIN}@" \ -e "/{{ cpu_spec }}/{r ${CPU_SPEC}" -e "d" -e "}" \ @@ -141,9 +127,8 @@ function generate_guestos_config() { } function main() { - # Establish run order validate_arguments - read_variables + read_config_variables assemble_config_media generate_guestos_config } diff --git a/ic-os/components/hostos-scripts/misc/fetch-mgmt-mac.sh b/ic-os/components/hostos-scripts/misc/fetch-mgmt-mac.sh index c469920801a..80ee8abde7b 100755 --- a/ic-os/components/hostos-scripts/misc/fetch-mgmt-mac.sh +++ b/ic-os/components/hostos-scripts/misc/fetch-mgmt-mac.sh @@ -58,8 +58,6 @@ function fetch_mgmt_mac() { function main() { # Establish run order - # NOTE: `fetch-property` will error if the target is not found. Here we - # only want to act when the field is set. MGMT_MAC=$(jq -r ".deployment.mgmt_mac" ${DEPLOYMENT}) if [ -z "${MGMT_MAC}" ] || [ "${MGMT_MAC}" = "null" ]; then diff --git a/ic-os/components/hostos.bzl b/ic-os/components/hostos.bzl index 7d074a4d5f4..424df253a0c 100644 --- a/ic-os/components/hostos.bzl +++ b/ic-os/components/hostos.bzl @@ -51,7 +51,6 @@ component_files = { Label("misc/config/hostos-config.sh"): "/opt/ic/bin/config.sh", Label("misc/logging.sh"): "/opt/ic/bin/logging.sh", Label("misc/metrics.sh"): "/opt/ic/bin/metrics.sh", - Label("misc/fetch-property.sh"): "/opt/ic/bin/fetch-property.sh", Label("misc/vsock/vsock-agent.service"): "/etc/systemd/system/vsock-agent.service", Label("misc/vsock/10-vhost-vsock.rules"): "/etc/udev/rules.d/10-vhost-vsock.rules", Label("misc/chrony/chrony.conf"): "/etc/chrony/chrony.conf", diff --git a/ic-os/components/misc/fetch-property.sh b/ic-os/components/misc/fetch-property.sh deleted file mode 100755 index 46c6d2a2eeb..00000000000 --- a/ic-os/components/misc/fetch-property.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail - -# Fetch configuration property - -source /opt/ic/bin/logging.sh - -SCRIPT="$(basename $0)[$$]" - -# Get keyword arguments -for argument in "${@}"; do - case ${argument} in - -c=* | --config=*) - CONFIG="${argument#*=}" - shift - ;; - -h | --help) - echo 'Usage: -Fetch Configuration Property - -Arguments: - -c=, --config= mandatory: specify the configuration file to read from - -h, --help show this help message and exit - -k=, --key= mandatory: specify the property key - -m=, --metric= optional: specify the metric name (required if metrics.sh exists) -' - exit 1 - ;; - -k=* | --key=*) - KEY="${argument#*=}" - shift - ;; - -m=* | --metric=*) - METRIC="${argument#*=}" - shift - ;; - *) - echo "Error: Argument is not supported." - exit 1 - ;; - esac -done - -function validate_arguments() { - if [ -z "${CONFIG}" ] || [ -z "${KEY}" ]; then - $0 --help - fi - - if [ -f "/opt/ic/bin/metrics.sh" ] && [ -z "${METRIC:-}" ]; then - echo "Error: METRIC is required when metrics.sh exists." - exit 1 - fi -} - -try_write_metric() { - local name=$1 - local value=$2 - local help=$3 - local type=$4 - - # metrics.sh is required for writing metrics - # metrics.sh only exists on HostOS and GuestOS, not SetupOS - if [ -f "/opt/ic/bin/metrics.sh" ]; then - source "/opt/ic/bin/metrics.sh" - write_metric "${name}" "${value}" "${help}" "${type}" - fi -} - -function fetch_property() { - PROPERTY=$(jq -r "$(echo ${KEY})" ${CONFIG}) - - if [ -z "${PROPERTY}" ] || [ "${PROPERTY}" == "null" ]; then - write_log "ERROR: Unable to fetch property: ${KEY}" - try_write_metric "$(echo ${METRIC:-})" \ - "1" \ - "Property: $(echo ${KEY})" \ - "gauge" - exit 1 - else - write_log "Using property: ${PROPERTY}" - try_write_metric "$(echo ${METRIC:-})" \ - "0" \ - "Property: $(echo ${KEY})" \ - "gauge" - echo "${PROPERTY}" - fi -} - -function main() { - # Establish run order - validate_arguments - fetch_property -} - -main From f327c2dec2208aab86e6f5a96d0cb0948fabf668 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 20:47:21 +0000 Subject: [PATCH 25/28] Remove unused SCRIPT variable --- .../generate-guestos-config/dev-generate-guestos-config.sh | 2 -- .../generate-guestos-config/generate-guestos-config.sh | 2 -- 2 files changed, 4 deletions(-) diff --git a/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh b/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh index c1a2f809cb0..738f92467b0 100755 --- a/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh +++ b/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh @@ -8,8 +8,6 @@ source /opt/ic/bin/logging.sh # Source the functions required for writing metrics source /opt/ic/bin/metrics.sh -SCRIPT="$(basename $0)[$$]" - # Get keyword arguments for argument in "${@}"; do case ${argument} in diff --git a/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh b/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh index 439c19fc4a2..8c48d47b518 100755 --- a/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh +++ b/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh @@ -8,8 +8,6 @@ source /opt/ic/bin/logging.sh # Source the functions required for writing metrics source /opt/ic/bin/metrics.sh -SCRIPT="$(basename $0)[$$]" - # Get keyword arguments for argument in "${@}"; do case ${argument} in From 379e4a2919940d06e54735e5c4f3fed32c5450d6 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 20:52:34 +0000 Subject: [PATCH 26/28] Clean up generate-guestos-config --- .../generate-guestos-config/dev-generate-guestos-config.sh | 4 ++-- .../generate-guestos-config/generate-guestos-config.sh | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh b/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh index 738f92467b0..e102c4c945f 100755 --- a/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh +++ b/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh @@ -66,6 +66,7 @@ function read_config_variables() { node_operator_private_key=$(get_config_value '.icos_settings.node_operator_private_key_path') vm_memory=$(get_config_value '.hostos_settings.vm_memory') vm_cpu=$(get_config_value '.hostos_settings.vm_cpu') + ssh_authorized_keys=$(get_config_value '.icos_settings.ssh_authorized_keys_path') } function assemble_config_media() { @@ -85,7 +86,7 @@ function assemble_config_media() { if [ -f "$node_operator_private_key" ]; then cmd+=(--node_operator_private_key "$node_operator_private_key") fi - cmd+=(--accounts_ssh_authorized_keys "/boot/config/ssh_authorized_keys") + cmd+=(--accounts_ssh_authorized_keys "$ssh_authorized_keys") # Run the above command "${cmd[@]}" @@ -93,7 +94,6 @@ function assemble_config_media() { } function generate_guestos_config() { - # todo: can I use the generate mac address in hostos tool? MAC_ADDRESS=$(/opt/ic/bin/hostos_tool generate-mac-address --node-type GuestOS) CPU_DOMAIN="kvm" diff --git a/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh b/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh index 8c48d47b518..64e34dc78c5 100755 --- a/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh +++ b/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh @@ -92,7 +92,6 @@ function assemble_config_media() { } function generate_guestos_config() { - # todo: can I use the generate mac address in hostos tool? MAC_ADDRESS=$(/opt/ic/bin/hostos_tool generate-mac-address --node-type GuestOS) CPU_DOMAIN="kvm" From 42ac934a98276ff91573354532c9c29d0de6f295 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 21:19:24 +0000 Subject: [PATCH 27/28] Fix setupos-config name --- .../misc/config/{setupos-config copy.sh => setupos-config.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ic-os/components/misc/config/{setupos-config copy.sh => setupos-config.sh} (100%) diff --git a/ic-os/components/misc/config/setupos-config copy.sh b/ic-os/components/misc/config/setupos-config.sh similarity index 100% rename from ic-os/components/misc/config/setupos-config copy.sh rename to ic-os/components/misc/config/setupos-config.sh From 59e327f2d3b3b0fa1aef55fa997656d663b4fd42 Mon Sep 17 00:00:00 2001 From: Andrew Battat Date: Thu, 3 Oct 2024 21:45:01 +0000 Subject: [PATCH 28/28] Fix networking read_config_variables --- .../dev-generate-guestos-config.sh | 12 +++++------ .../generate-guestos-config.sh | 12 +++++------ .../setupos-scripts/check-network.sh | 20 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh b/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh index e102c4c945f..667ad867150 100755 --- a/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh +++ b/ic-os/components/hostos-scripts/generate-guestos-config/dev-generate-guestos-config.sh @@ -54,12 +54,12 @@ MEDIA="${MEDIA:=/run/ic-node/config.img}" OUTPUT="${OUTPUT:=/var/lib/libvirt/guestos.xml}" function read_config_variables() { - ipv6_prefix=$(get_config_value '.network_settings.ipv6_prefix') - ipv6_gateway=$(get_config_value '.network_settings.ipv6_gateway') - ipv4_address=$(get_config_value '.network_settings.ipv4_address') - ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_prefix_length') - ipv4_gateway=$(get_config_value '.network_settings.ipv4_gateway') - domain=$(get_config_value '.network_settings.domain') + ipv6_prefix=$(get_config_value '.network_settings.ipv6_config.Deterministic.prefix') + ipv6_gateway=$(get_config_value '.network_settings.ipv6_config.Deterministic.gateway') + ipv4_address=$(get_config_value '.network_settings.ipv4_config.address') + ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_config.prefix_length') + ipv4_gateway=$(get_config_value '.network_settings.ipv4_config.gateway') + domain=$(get_config_value '.network_settings.ipv4_config.domain') elasticsearch_hosts=$(get_config_value '.icos_settings.logging.elasticsearch_hosts') nns_public_key=$(get_config_value '.icos_settings.nns_public_key_path') nns_urls=$(get_config_value '.icos_settings.nns_urls') diff --git a/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh b/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh index 64e34dc78c5..ae1613a4756 100755 --- a/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh +++ b/ic-os/components/hostos-scripts/generate-guestos-config/generate-guestos-config.sh @@ -54,12 +54,12 @@ MEDIA="${MEDIA:=/run/ic-node/config.img}" OUTPUT="${OUTPUT:=/var/lib/libvirt/guestos.xml}" function read_config_variables() { - ipv6_prefix=$(get_config_value '.network_settings.ipv6_prefix') - ipv6_gateway=$(get_config_value '.network_settings.ipv6_gateway') - ipv4_address=$(get_config_value '.network_settings.ipv4_address') - ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_prefix_length') - ipv4_gateway=$(get_config_value '.network_settings.ipv4_gateway') - domain=$(get_config_value '.network_settings.domain') + ipv6_prefix=$(get_config_value '.network_settings.ipv6_config.Deterministic.prefix') + ipv6_gateway=$(get_config_value '.network_settings.ipv6_config.Deterministic.gateway') + ipv4_address=$(get_config_value '.network_settings.ipv4_config.address') + ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_config.prefix_length') + ipv4_gateway=$(get_config_value '.network_settings.ipv4_config.gateway') + domain=$(get_config_value '.network_settings.ipv4_config.domain') elasticsearch_hosts=$(get_config_value '.icos_settings.logging.elasticsearch_hosts') nns_public_key=$(get_config_value '.icos_settings.nns_public_key_path') nns_urls=$(get_config_value '.icos_settings.nns_urls') diff --git a/ic-os/components/setupos-scripts/check-network.sh b/ic-os/components/setupos-scripts/check-network.sh index 8eb9932a420..e008004cdc3 100755 --- a/ic-os/components/setupos-scripts/check-network.sh +++ b/ic-os/components/setupos-scripts/check-network.sh @@ -10,12 +10,12 @@ SHELL="/bin/bash" PATH="/sbin:/bin:/usr/sbin:/usr/bin" function read_config_variables() { - ipv6_prefix=$(get_config_value '.network_settings.ipv6_prefix') - ipv6_gateway=$(get_config_value '.network_settings.ipv6_gateway') - ipv4_address=$(get_config_value '.network_settings.ipv4_address') - ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_prefix_length') - ipv4_gateway=$(get_config_value '.network_settings.ipv4_gateway') - domain=$(get_config_value '.network_settings.domain') + ipv6_prefix=$(get_config_value '.network_settings.ipv6_config.Deterministic.prefix') + ipv6_gateway=$(get_config_value '.network_settings.ipv6_config.Deterministic.gateway') + ipv4_address=$(get_config_value '.network_settings.ipv4_config.address') + ipv4_prefix_length=$(get_config_value '.network_settings.ipv4_config.prefix_length') + ipv4_gateway=$(get_config_value '.network_settings.ipv4_config.gateway') + domain=$(get_config_value '.network_settings.ipv4_config.domain') } # WARNING: Uses 'eval' for command execution. @@ -115,20 +115,20 @@ function validate_domain_name() { IFS='.' read -ra domain_parts <<<"${domain}" if [ ${#domain_parts[@]} -lt 2 ]; then - log_and_halt_installation_on_error 1 "Domain validation error: less than two domain parts in domain" + log_and_halt_installation_on_error 1 "Domain validation error: less than two domain parts in domain: ${domain}" fi for domain_part in "${domain_parts[@]}"; do if [ -z "$domain_part" ] || [ ${#domain_part} -gt 63 ]; then - log_and_halt_installation_on_error 1 "Domain validation error: domain part length violation" + log_and_halt_installation_on_error 1 "Domain validation error: domain part length violation: ${domain_part}" fi if [[ $domain_part == -* ]] || [[ $domain_part == *- ]]; then - log_and_halt_installation_on_error 1 "Domain validation error: domain part starts or ends with a hyphen" + log_and_halt_installation_on_error 1 "Domain validation error: domain part starts or ends with a hyphen: ${domain_part}" fi if ! [[ $domain_part =~ ^[a-zA-Z0-9-]+$ ]]; then - log_and_halt_installation_on_error 1 "Domain validation error: invalid characters in domain part" + log_and_halt_installation_on_error 1 "Domain validation error: invalid characters in domain part: ${domain_part}" fi done }