Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions libs/gl-cli/.kacl.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
kacl:
file: CHANGELOG.md
allowed_header_titles:
- Changelog
- Change Log
allowed_version_sections:
- Added
- Changed
- Deprecated
- Removed
- Fixed
- Security
default_content:
- All notable changes to this project will be documented in this file.
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
release:
add_unreleased: True
git:
commit: False
commit_message: "[skip ci] Releasing Changelog version {new_version}"
commit_additional_files: []
tag: False
tag_name: "v{new_version}"
tag_description: "Version v{new_version} released"
links:
auto_generate: False
compare_versions_template: '{host}/compare/{previous_version}...{version}'
unreleased_changes_template: '{host}/compare/{latest_version}...master'
initial_version_template: '{host}/tree/{version}'
extension:
post_release_version_prefix: null
issue_tracker:
jira:
host: null
username: null
password: null
issue_patterns: ["[A-Z]+-[0-9]+"]
comment_template: |
# 🚀 New version [v{new_version}]({link})

A new release has been created referencing this issue. Please check it out.

## 🚧 Changes in this version

{changes}

## 🧭 Reference

Code: [Source Code Management System]({link})
stash:
directory: .kacl_stash
always: False
11 changes: 11 additions & 0 deletions libs/gl-cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Added `scheduler export` subcommand to take control of your own node.
57 changes: 57 additions & 0 deletions libs/gl-cli/src/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub enum Command {
)]
pairing_data: String,
},
/// Export the node from Greenlight infrastructure
Export,
}

pub async fn command_handler<P: AsRef<Path>>(cmd: Command, config: Config<P>) -> Result<()> {
Expand All @@ -76,6 +78,7 @@ pub async fn command_handler<P: AsRef<Path>>(cmd: Command, config: Config<P>) ->
Command::ApprovePairing { pairing_data } => {
approve_pairing_handler(config, &pairing_data).await
}
Command::Export => export_handler(config).await,
}
}

Expand Down Expand Up @@ -273,6 +276,60 @@ async fn pair_device_handler<P: AsRef<Path>>(
Err(Error::custom("Connection to scheduler has been closed"))
}

async fn export_handler<P: AsRef<Path>>(config: Config<P>) -> Result<()> {
let creds_path = config.data_dir.as_ref().join(CREDENTIALS_FILE_NAME);
let creds = util::read_credentials(&creds_path);
if creds.is_none() {
println!("Could not find credentials at {}", creds_path.display());
return Err(Error::credentials_not_found(format!(
"could not read from {}",
creds_path.display()
)));
}

let creds = creds.unwrap(); // we checked if it is none before.
let scheduler = Scheduler::new(config.network, creds)
.await
.map_err(|e| Error::custom(format!("Failed to create scheduler: {}", e)))?;

// Confirm export action with the user
print!(
"WARNING: Exporting your node will make it no longer schedulable on Greenlight.
After export, you will need to run the node on your own infrastructure.
This operation is idempotent and can be called multiple times.

Are you sure you want to export your node? (y/N) "
);
io::stdout().flush().expect("Failed to flush stdout");

let input = task::spawn_blocking(|| {
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
input
})
.await
.expect("Task failed");

if !input.trim().eq_ignore_ascii_case("y") {
println!("Export cancelled.");
return Ok(());
}

// Initiate the node export
let res = scheduler
.export_node()
.await
.map_err(|e| Error::custom(format!("Failed to export node: {}", e)))?;

println!("Node export initiated successfully!");
println!("Download the encrypted backup from: {}", res.url);
println!("\nNote: After exporting, the node will no longer be schedulable on Greenlight.");
println!("The backup is encrypted and can only be decrypted with your node secret.");
Ok(())
}

async fn approve_pairing_handler<P: AsRef<Path>>(
config: Config<P>,
pairing_data: &str,
Expand Down
Loading