Skip to content

Commit

Permalink
feat: idempotency for node deployment
Browse files Browse the repository at this point in the history
The introduction of the node manager broke the idempotent nature of the deployment process.

Now, when the genesis node is being created, it will only be created if there's not already an
existing genesis node. With respect to the remaining nodes, they use a count value to determine
whether any more need to be added. If the count is satisfied, the task to add the nodes will be
skipped.

The commit also introduced an argument to supply a custom build of the node manager using a URL.
This was useful for testing out experimental features of the node manager.
  • Loading branch information
jacderida committed Jan 21, 2024
1 parent d9b7b7b commit bed9c31
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ tar = "0.4"
tempfile = "3.8.0"
tokio = { version = "1.26", features = ["full"] }
tokio-stream = "0.1.14"
url = "2.5.0"

[dev-dependencies]
httpmock = "0.6"
48 changes: 41 additions & 7 deletions resources/ansible/roles/node/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,27 @@
dest: "{{ node_manager_archive_dest_path }}"
remote_src: True

#
# Setup genesis node on genesis run
#
- name: check if genesis node is already set up
become: True
ansible.builtin.command: safenode-manager status --json
register: genesis_status
when: is_genesis

- name: parse genesis node status
set_fact:
genesis_exists: "{{ (genesis_status.stdout | from_json | selectattr('genesis', 'equalto', true) | list | length) > 0 }}"
when: is_genesis and genesis_status.stdout != ""

- name: add genesis node service
become: True
ansible.builtin.command:
# The `omit` filter is used to remove the `--version` argument if the
# `node_version` variable is not defined. If the argv would be otherwise
# defined as '', the command would fail as it doesn't expect an empty
# argument, so it's omitted instead.
argv: "{{ command_args | reject('equalto', omit) | list }}"
vars:
command_args:
Expand All @@ -34,23 +53,38 @@
- --port={{ genesis_port }}
- --rpc-port={{ genesis_rpc_port }}
- "{{ ('--url=' + node_archive_url) if node_archive_url is defined else omit }}"
when: is_genesis
when: is_genesis and not genesis_exists | default(false)

#
# Setup remaining nodes on non-genesis run
#
- name: check current number of node services
become: True
ansible.builtin.command: safenode-manager status --json
register: node_status

- name: calculate current non-genesis node count
set_fact:
current_node_count: "{{ (node_status.stdout | from_json | selectattr('genesis', 'equalto', false) | list | length) }}"
when: node_status.stdout != ""

- name: calculate number of nodes to add
set_fact:
nodes_to_add: "{{ node_instance_count | int - current_node_count | int }}"
when: current_node_count is defined

- name: add node services
become: True
ansible.builtin.command:
# The `omit` filter is used to remove the `--version` argument if the
# `node_version` variable is not defined. If the argv would be otherwise
# defined as '', the command would fail as it doesn't expect an empty
# argument, so it's omitted instead.
argv: "{{ command_args | reject('equalto', omit) | list }}"
vars:
command_args:
- "{{ node_manager_archive_dest_path }}/safenode-manager"
- add
- "--count={{ node_instance_count }}"
- "--count={{ nodes_to_add }}"
- "--peer={{ genesis_multiaddr }}"
- "{{ ('--url=' + node_archive_url) if node_archive_url is defined else omit }}"
when: not is_genesis
when: not is_genesis and nodes_to_add | default(0) | int > 0

- name: start the node services
become: True
Expand Down
12 changes: 12 additions & 0 deletions src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
print_duration, SnCodebaseType, TestnetDeploy,
};
use std::{net::SocketAddr, path::PathBuf, time::Instant};
use url::Url;

pub struct DeployCmd {
testnet_deploy: TestnetDeploy,
Expand All @@ -17,6 +18,7 @@ pub struct DeployCmd {
vm_count: u16,
logstash_details: (String, Vec<SocketAddr>),
sn_codebase_type: SnCodebaseType,
node_manager_url: Option<Url>,
}

impl DeployCmd {
Expand All @@ -28,6 +30,7 @@ impl DeployCmd {
vm_count: u16,
logstash_details: (String, Vec<SocketAddr>),
sn_codebase_type: SnCodebaseType,
node_manager_url: Option<Url>,
) -> Self {
Self {
testnet_deploy,
Expand All @@ -36,6 +39,7 @@ impl DeployCmd {
vm_count,
logstash_details,
sn_codebase_type,
node_manager_url,
}
}

Expand Down Expand Up @@ -366,6 +370,14 @@ impl DeployCmd {
};
Self::add_value(&mut extra_vars, "node_archive_url", &node_archive_url);

if let Some(node_manager_url) = self.node_manager_url.as_ref() {
Self::add_value(
&mut extra_vars,
"node_manager_archive_url",
node_manager_url.as_ref(),
);
}

let (logstash_stack_name, logstash_hosts) = &self.logstash_details;
Self::add_value(&mut extra_vars, "logstash_stack_name", logstash_stack_name);
extra_vars.push_str("\"logstash_hosts\": [");
Expand Down
14 changes: 13 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use sn_testnet_deploy::{
setup::setup_dotenv_file, CloudProvider, DeploymentInventory, SnCodebaseType,
TestnetDeployBuilder,
};
use url::Url;

pub fn parse_provider(val: &str) -> Result<CloudProvider> {
match val {
Expand Down Expand Up @@ -109,6 +110,11 @@ enum Commands {
/// --branch and --repo-owner arguments. You can only supply version numbers or a custom
/// branch, not both.
safenode_version: Option<String>,
/// Optionally supply the URL of a gzipped tar archive containing a node manager binary.
///
/// Useful for testing experimental versions of the node manager.
#[arg(long)]
node_manager_url: Option<String>,
},
Inventory {
/// The name of the environment
Expand Down Expand Up @@ -303,7 +309,7 @@ async fn main() -> Result<()> {
logstash_stack_name,
safe_version,
safenode_version,
..
node_manager_url,
}) => {
let sn_codebase_type = get_sn_codebase_type(
branch,
Expand Down Expand Up @@ -343,13 +349,19 @@ async fn main() -> Result<()> {
let stack_hosts = logstash_deploy
.get_stack_hosts(&logstash_stack_name)
.await?;
let node_manager_url = if let Some(node_manager_url) = node_manager_url {
Some(Url::parse(&node_manager_url)?)
} else {
None
};
let deploy_cmd = DeployCmd::new(
testnet_deploy,
name,
node_count,
vm_count,
(logstash_stack_name, stack_hosts),
sn_codebase_type,
node_manager_url,
);
deploy_cmd.execute().await?;
Ok(())
Expand Down

0 comments on commit bed9c31

Please sign in to comment.