Skip to content

Commit

Permalink
(BOUN-1005) Add domain at node registration
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolay-komarevskiy committed Jan 22, 2024
1 parent 357fb6e commit 69386e1
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 60 deletions.
3 changes: 3 additions & 0 deletions ic-os/guestos/rootfs/opt/ic/bin/generate-replica-config.sh
Expand Up @@ -78,6 +78,7 @@ function read_network_variables() {
"ipv4_name_servers") ipv4_name_servers="${value}" ;;
"ipv4_address") ipv4_address="${value}" ;;
"ipv4_gateway") ipv4_gateway="${value}" ;;
"domain") domain="${value}" ;;
esac
done <"$1"
}
Expand Down Expand Up @@ -204,6 +205,7 @@ IPV6_ADDRESS="${ipv6_address%/*}"
IPV6_ADDRESS="${IPV6_ADDRESS:-$(get_if_address_retries 6 ${INTERFACE} 12)}"
IPV4_ADDRESS="${ipv4_address:-}"
IPV4_GATEWAY="${ipv4_gateway:-}"
DOMAIN="${domain:-}"
NNS_URL="${nns_url:-http://[::1]:8080}"
NODE_INDEX="${node_index:-0}"
# Default value is 24h
Expand Down Expand Up @@ -239,6 +241,7 @@ fi
sed -e "s@{{ ipv6_address }}@${IPV6_ADDRESS}@" \
-e "s@{{ ipv4_address }}@${IPV4_ADDRESS}@" \
-e "s@{{ ipv4_gateway }}@${IPV4_GATEWAY}@" \
-e "s@{{ domain }}@${DOMAIN}@" \
-e "s@{{ nns_url }}@${NNS_URL}@" \
-e "s@{{ node_index }}@${NODE_INDEX}@" \
-e "s@{{ backup_retention_time_secs }}@${BACKUP_RETENTION_TIME_SECS}@" \
Expand Down
5 changes: 5 additions & 0 deletions ic-os/guestos/rootfs/opt/ic/share/ic.json5.template
Expand Up @@ -21,6 +21,11 @@
public_gateway: "{{ ipv4_gateway }}",
},

// ============================================
// Configuration of the domain name
// ============================================
domain: "{{ domain }}",

// ============================================
// Configuration of registry client
// ============================================
Expand Down
4 changes: 3 additions & 1 deletion ic-os/hostos/rootfs/opt/ic/bin/generate-guestos-config.sh
Expand Up @@ -94,6 +94,7 @@ function read_variables() {
"ipv4_address") ipv4_address="${value}" ;;
"ipv4_prefix_length") ipv4_prefix_length="${value}" ;;
"ipv4_gateway") ipv4_gateway="${value}" ;;
"domain") domain="${value}" ;;
esac
done <"${CONFIG}"
}
Expand All @@ -105,9 +106,10 @@ function assemble_config_media() {
cmd+=(--ipv6_address "$(/opt/ic/bin/hostos_tool generate-ipv6-address --node-type GuestOS)")
cmd+=(--ipv6_gateway "${ipv6_gateway}")
cmd+=(--ipv6_name_servers "$(/opt/ic/bin/fetch-property.sh --key=.dns.name_servers --metric=hostos_ipv6_dns_name_servers --config=${DEPLOYMENT})")
if [[ -n "$ipv4_address" && -n "$ipv4_prefix_length" && -n "$ipv4_gateway" ]]; then
if [[ -n "$ipv4_address" && -n "$ipv4_prefix_length" && -n "$ipv4_gateway" && -n "$domain" ]]; then
cmd+=(--ipv4_address "${ipv4_address}/${ipv4_prefix_length}")
cmd+=(--ipv4_gateway "${ipv4_gateway}")
cmd+=(--domain "${domain}")
fi
cmd+=(--ipv4_name_servers "$(/opt/ic/bin/fetch-property.sh --key=.dns.ipv4_name_servers --metric=hostos_ipv4_dns_name_servers --config=${DEPLOYMENT})")
cmd+=(--hostname "guest-$(/opt/ic/bin/fetch-mgmt-mac.sh | sed 's/://g')")
Expand Down
10 changes: 9 additions & 1 deletion ic-os/scripts/build-bootstrap-config-image.sh
Expand Up @@ -45,6 +45,9 @@ options may be specified:
--ipv4_gateway a.b.c.d
(optional) Default IPv4 gateway (e.g. 18.208.190.33).
--domain domain
(optional) The domain name to assign to the guest.
--hostname name
Name to assign to the host. Will be used in logging.
Expand Down Expand Up @@ -133,7 +136,7 @@ function build_ic_bootstrap_tar() {
local OUT_FILE="$1"
shift

local IPV6_ADDRESS IPV6_GATEWAY IPV6_NAME_SERVERS IPV4_NAME_SERVERS HOSTNAME
local IPV6_ADDRESS IPV6_GATEWAY IPV6_NAME_SERVERS IPV4_NAME_SERVERS DOMAIN HOSTNAME
local IC_CRYPTO IC_REGISTRY_LOCAL_STORE
local NNS_URL NNS_PUBLIC_KEY NODE_OPERATOR_PRIVATE_KEY
local BACKUP_RETENTION_TIME_SECS BACKUP_PURGING_INTERVAL_SECS
Expand All @@ -149,6 +152,7 @@ function build_ic_bootstrap_tar() {
break
fi
case "$1" in

--ipv6_address)
IPV6_ADDRESS="$2"
;;
Expand All @@ -167,6 +171,9 @@ function build_ic_bootstrap_tar() {
--ipv4_gateway)
IPV4_GATEWAY="$2"
;;
--domain)
DOMAIN="$2"
;;
--hostname)
HOSTNAME="$2"
;;
Expand Down Expand Up @@ -242,6 +249,7 @@ ipv4_name_servers=$IPV4_NAME_SERVERS
hostname=$HOSTNAME
${IPV4_ADDRESS:+ipv4_address=$IPV4_ADDRESS}
${IPV4_GATEWAY:+ipv4_gateway=$IPV4_GATEWAY}
${DOMAIN:+domain=$DOMAIN}
EOF
if [ "${ELASTICSEARCH_HOSTS}" != "" ]; then
echo "elasticsearch_hosts=$ELASTICSEARCH_HOSTS" >"${BOOTSTRAP_TMPDIR}/filebeat.conf"
Expand Down
30 changes: 29 additions & 1 deletion ic-os/setupos/rootfs/opt/ic/bin/network.sh
Expand Up @@ -20,6 +20,7 @@ function read_variables() {
"ipv4_address") ipv4_address="${value}" ;;
"ipv4_prefix_length") ipv4_prefix_length="${value}" ;;
"ipv4_gateway") ipv4_gateway="${value}" ;;
"domain") domain="${value}" ;;
esac
done <"${CONFIG}"
}
Expand Down Expand Up @@ -124,10 +125,11 @@ function print_network_settings() {
echo " IPv6 Prefix : ${ipv6_prefix}"
echo " IPv6 Subnet : ${ipv6_subnet}"
echo " IPv6 Gateway: ${ipv6_gateway}"
if [[ -n ${ipv4_address} && -n ${ipv4_prefix_length} && -n ${ipv4_gateway} ]]; then
if [[ -n ${ipv4_address} && -n ${ipv4_prefix_length} && -n ${ipv4_gateway} && -n ${domain} ]]; then
echo " IPv4 Address: ${ipv4_address}"
echo " IPv4 Prefix Length: ${ipv4_prefix_length}"
echo " IPv4 Gateway: ${ipv4_gateway}"
echo " Domain name : ${domain}"
fi
echo " "

Expand All @@ -144,6 +146,31 @@ function print_network_settings() {
echo " "
}

function validate_domain_name() {
local domain_part
local -a domain_parts

IFS='.' read -ra domain_parts <<<"${domain}"

if [ ${#domain_parts[@]} -lt 2 ]; then
log_and_reboot_on_error 1 "Domain validation error: less than two domain parts in domain"
fi

for domain_part in "${domain_parts[@]}"; do
if [ -z "$domain_part" ] || [ ${#domain_part} -gt 63 ]; then
log_and_reboot_on_error 1 "Domain validation error: domain part length violation"
fi

if [[ $domain_part == -* ]] || [[ $domain_part == *- ]]; then
log_and_reboot_on_error 1 "Domain validation error: domain part starts or ends with a hyphen"
fi

if ! [[ $domain_part =~ ^[a-zA-Z0-9-]+$ ]]; then
log_and_reboot_on_error 1 "Domain validation error: invalid characters in domain part"
fi
done
}

function setup_ipv4_network() {
echo "* Setting up IPv4 network..."

Expand Down Expand Up @@ -216,6 +243,7 @@ main() {
print_network_settings

if [[ -n ${ipv4_address} && -n ${ipv4_prefix_length} && -n ${ipv4_gateway} ]]; then
validate_domain_name
setup_ipv4_network
ping_ipv4_gateway
fi
Expand Down
4 changes: 4 additions & 0 deletions rs/config/src/config.rs
Expand Up @@ -53,6 +53,7 @@ pub struct Config {
pub adapters_config: AdaptersConfig,
pub bitcoin_payload_builder_config: BitcoinPayloadBuilderConfig,
pub ipv4_config: IPv4Config,
pub domain: String,
}

/// Mirrors the Config struct except that fields are made optional. This is
Expand All @@ -78,6 +79,7 @@ pub struct ConfigOptional {
pub adapters_config: Option<AdaptersConfig>,
pub bitcoin_payload_builder_config: Option<BitcoinPayloadBuilderConfig>,
pub ipv4_config: Option<IPv4Config>,
pub domain: Option<String>,
}

impl Config {
Expand Down Expand Up @@ -108,6 +110,7 @@ impl Config {
adapters_config: AdaptersConfig::default(),
bitcoin_payload_builder_config: BitcoinPayloadBuilderConfig::default(),
ipv4_config: IPv4Config::default(),
domain: String::default(),
}
}

Expand Down Expand Up @@ -164,6 +167,7 @@ impl Config {
.bitcoin_payload_builder_config
.unwrap_or(default.bitcoin_payload_builder_config),
ipv4_config: cfg.ipv4_config.unwrap_or(default.ipv4_config),
domain: cfg.domain.unwrap_or_default(),
})
}

Expand Down
4 changes: 4 additions & 0 deletions rs/config/src/config_sample.rs
Expand Up @@ -88,6 +88,10 @@ pub const SAMPLE_CONFIG: &str = r#"
public_gateway: "",
},
// ============================================
// Configuration of the domain name
// ============================================
domain: "",
// ============================================
// Configuration of registry client
// ============================================
registry_client: {
Expand Down
1 change: 1 addition & 0 deletions rs/nns/test_utils/src/registry.rs
Expand Up @@ -824,6 +824,7 @@ pub fn prepare_add_node_payload(mutation_id: u8) -> (AddNodePayload, ValidNodePu
prometheus_metrics_endpoint: "".to_string(),
chip_id: None,
public_ipv4_config: None,
domain: None,
};

(payload, node_public_keys)
Expand Down
18 changes: 17 additions & 1 deletion rs/orchestrator/src/registration.rs
Expand Up @@ -30,8 +30,10 @@ use ic_sys::utility_command::UtilityCommand;
use ic_types::{crypto::KeyPurpose, messages::MessageId, NodeId, RegistryVersion, SubnetId};
use prost::Message;
use rand::prelude::*;
use registry_canister::mutations::do_update_node_directly::UpdateNodeDirectlyPayload;
use registry_canister::mutations::node_management::do_add_node::AddNodePayload;
use registry_canister::mutations::{
common::is_valid_domain, do_update_node_directly::UpdateNodeDirectlyPayload,
};
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use std::{net::IpAddr, str::FromStr};
Expand Down Expand Up @@ -212,6 +214,8 @@ impl NodeRegistration {
chip_id: get_snp_chip_id().expect("Failed to retrieve chip_id from snp firmware"),
prometheus_metrics_endpoint: "".to_string(),
public_ipv4_config: ipv4_config_to_vec(&self.log, &self.node_config.ipv4_config),
domain: process_domain_name(&self.log, &self.node_config.domain)
.expect("Domain name is invalid"),
}
}

Expand Down Expand Up @@ -645,6 +649,18 @@ fn ipv4_config_to_vec(log: &ReplicaLogger, ipv4_config: &IPv4Config) -> Option<V
None
}

fn process_domain_name(log: &ReplicaLogger, domain: &str) -> OrchestratorResult<Option<String>> {
info!(log, "Reading domain name for registration");
match domain {
"" => Ok(None),
domain if is_valid_domain(domain) => Ok(Some(domain.into())),
_ => Err(OrchestratorError::invalid_configuration_error(format!(
"Provided domain name {} is invalid",
domain
))),
}
}

/// Create a nonce to be included with the ingress message sent to the node
/// handler.
fn generate_nonce() -> Vec<u8> {
Expand Down
1 change: 1 addition & 0 deletions rs/registry/canister/canister/registry.did
Expand Up @@ -17,6 +17,7 @@ type AddNodePayload = record {
prometheus_metrics_endpoint : text;
http_endpoint : text;
idkg_dealing_encryption_pk : opt vec nat8;
domain : opt text;
public_ipv4_config : opt vec text;
xnet_endpoint : text;
chip_id : opt vec nat8;
Expand Down
26 changes: 20 additions & 6 deletions rs/registry/canister/src/mutations/node_management/do_add_node.rs
@@ -1,4 +1,4 @@
use crate::{common::LOG_PREFIX, registry::Registry};
use crate::{common::LOG_PREFIX, mutations::common::is_valid_domain, registry::Registry};

use std::net::SocketAddr;

Expand Down Expand Up @@ -77,9 +77,21 @@ impl Registry {
// 4. Validate keys and get the node id
let (node_id, valid_pks) = valid_keys_from_payload(&payload)?;

//5. Validate the domain is valid
let domain: Option<String> = payload
.domain
.as_ref()
.map(|domain| {
if !is_valid_domain(domain) {
return Err(format!("Domain name {domain} has invalid format"));
}
Ok(domain.clone())
})
.transpose()?;

println!("{}do_add_node: The node id is {:?}", LOG_PREFIX, node_id);

// 5. create the Node Record
// 6. create the Node Record
let node_record = NodeRecord {
xnet: Some(connection_endpoint_from_string(&payload.xnet_endpoint)),
http: Some(connection_endpoint_from_string(&payload.http_endpoint)),
Expand All @@ -90,21 +102,21 @@ impl Registry {
.public_ipv4_config
.clone()
.map(make_valid_node_ivp4_config_or_panic),
domain: None,
domain,
};

// 6. Insert node, public keys, and crypto keys
// 7. Insert node, public keys, and crypto keys
let mut mutations = make_add_node_registry_mutations(node_id, node_record, valid_pks);

// Update the Node Operator record
// 8. Update the Node Operator record
node_operator_record.node_allowance -= 1;

let update_node_operator_record =
make_update_node_operator_mutation(caller, &node_operator_record);

mutations.push(update_node_operator_record);

// 8. Check invariants before applying mutations
// 9. Check invariants before applying mutations
self.maybe_apply_mutation_internal(mutations);

println!("{}do_add_node finished: {:?}", LOG_PREFIX, payload);
Expand Down Expand Up @@ -134,6 +146,7 @@ pub struct AddNodePayload {
pub prometheus_metrics_endpoint: String,

pub public_ipv4_config: Option<Vec<String>>,
pub domain: Option<String>,
}

/// Parses the ConnectionEndpoint string
Expand Down Expand Up @@ -318,6 +331,7 @@ mod tests {
prometheus_metrics_endpoint: "".to_string(),
chip_id: None,
public_ipv4_config: None,
domain: None,
};
}

Expand Down
12 changes: 12 additions & 0 deletions rs/tests/src/driver/bootstrap.rs
Expand Up @@ -257,6 +257,7 @@ pub fn setup_and_start_vms_k8s(
&node,
malicious_behaviour,
None,
None,
&t_env,
&group_name,
)?;
Expand Down Expand Up @@ -313,13 +314,15 @@ pub fn setup_and_start_vms(
let ic_name = ic.name();
let malicious_behaviour = ic.get_malicious_behavior_of_node(node.node_id);
let ipv4_config = ic.get_ipv4_config_of_node(node.node_id);
let domain = ic.get_domain_of_node(node.node_id);
nodes_info.insert(node.node_id, malicious_behaviour.clone());
join_handles.push(thread::spawn(move || {
create_config_disk_image(
&ic_name,
&node,
malicious_behaviour,
ipv4_config,
domain,
&t_env,
&group_name,
)?;
Expand Down Expand Up @@ -420,6 +423,7 @@ pub fn create_config_disk_image(
node: &InitializedNode,
malicious_behavior: Option<MaliciousBehaviour>,
ipv4_config: Option<Ipv4Config>,
domain: Option<String>,
test_env: &TestEnv,
group_name: &str,
) -> anyhow::Result<()> {
Expand Down Expand Up @@ -477,6 +481,14 @@ pub fn create_config_disk_image(
.arg(ipv4_config.gateway_ip_addr.to_string());
}

if let Some(domain) = domain {
info!(
test_env.logger(),
"Node with id={} has domain_name {}", node.node_id, domain,
);
cmd.arg("--domain").arg(domain);
}

let ssh_authorized_pub_keys_dir: PathBuf = test_env.get_path(SSH_AUTHORIZED_PUB_KEYS_DIR);
if ssh_authorized_pub_keys_dir.exists() {
cmd.arg("--accounts_ssh_authorized_keys")
Expand Down

0 comments on commit 69386e1

Please sign in to comment.