Skip to content

Commit c0dbbf9

Browse files
committed
cli: Add glcli scheduler export subcommand
This allows you to take ownership of your own node.
1 parent 06701e2 commit c0dbbf9

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed

libs/gl-cli/.kacl.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
kacl:
2+
file: CHANGELOG.md
3+
allowed_header_titles:
4+
- Changelog
5+
- Change Log
6+
allowed_version_sections:
7+
- Added
8+
- Changed
9+
- Deprecated
10+
- Removed
11+
- Fixed
12+
- Security
13+
default_content:
14+
- All notable changes to this project will be documented in this file.
15+
- 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).
16+
release:
17+
add_unreleased: True
18+
git:
19+
commit: False
20+
commit_message: "[skip ci] Releasing Changelog version {new_version}"
21+
commit_additional_files: []
22+
tag: False
23+
tag_name: "v{new_version}"
24+
tag_description: "Version v{new_version} released"
25+
links:
26+
auto_generate: False
27+
compare_versions_template: '{host}/compare/{previous_version}...{version}'
28+
unreleased_changes_template: '{host}/compare/{latest_version}...master'
29+
initial_version_template: '{host}/tree/{version}'
30+
extension:
31+
post_release_version_prefix: null
32+
issue_tracker:
33+
jira:
34+
host: null
35+
username: null
36+
password: null
37+
issue_patterns: ["[A-Z]+-[0-9]+"]
38+
comment_template: |
39+
# 🚀 New version [v{new_version}]({link})
40+
41+
A new release has been created referencing this issue. Please check it out.
42+
43+
## 🚧 Changes in this version
44+
45+
{changes}
46+
47+
## 🧭 Reference
48+
49+
Code: [Source Code Management System]({link})
50+
stash:
51+
directory: .kacl_stash
52+
always: False

libs/gl-cli/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
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).
6+
7+
## Unreleased
8+
9+
### Added
10+
11+
- Added `scheduler export` subcommand to take control of your own node.

libs/gl-cli/src/scheduler.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ pub enum Command {
5252
)]
5353
pairing_data: String,
5454
},
55+
/// Export the node from Greenlight infrastructure
56+
Export,
5557
}
5658

5759
pub async fn command_handler<P: AsRef<Path>>(cmd: Command, config: Config<P>) -> Result<()> {
@@ -76,6 +78,7 @@ pub async fn command_handler<P: AsRef<Path>>(cmd: Command, config: Config<P>) ->
7678
Command::ApprovePairing { pairing_data } => {
7779
approve_pairing_handler(config, &pairing_data).await
7880
}
81+
Command::Export => export_handler(config).await,
7982
}
8083
}
8184

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

279+
async fn export_handler<P: AsRef<Path>>(config: Config<P>) -> Result<()> {
280+
let creds_path = config.data_dir.as_ref().join(CREDENTIALS_FILE_NAME);
281+
let creds = util::read_credentials(&creds_path);
282+
if creds.is_none() {
283+
println!("Could not find credentials at {}", creds_path.display());
284+
return Err(Error::credentials_not_found(format!(
285+
"could not read from {}",
286+
creds_path.display()
287+
)));
288+
}
289+
290+
let creds = creds.unwrap(); // we checked if it is none before.
291+
let scheduler = Scheduler::new(config.network, creds)
292+
.await
293+
.map_err(|e| Error::custom(format!("Failed to create scheduler: {}", e)))?;
294+
295+
// Confirm export action with the user
296+
print!(
297+
"WARNING: Exporting your node will make it no longer schedulable on Greenlight.
298+
After export, you will need to run the node on your own infrastructure.
299+
This operation is idempotent and can be called multiple times.
300+
301+
Are you sure you want to export your node? (y/N) "
302+
);
303+
io::stdout().flush().expect("Failed to flush stdout");
304+
305+
let input = task::spawn_blocking(|| {
306+
let mut input = String::new();
307+
std::io::stdin()
308+
.read_line(&mut input)
309+
.expect("Failed to read line");
310+
input
311+
})
312+
.await
313+
.expect("Task failed");
314+
315+
if !input.trim().eq_ignore_ascii_case("y") {
316+
println!("Export cancelled.");
317+
return Ok(());
318+
}
319+
320+
// Initiate the node export
321+
let res = scheduler
322+
.export_node()
323+
.await
324+
.map_err(|e| Error::custom(format!("Failed to export node: {}", e)))?;
325+
326+
println!("Node export initiated successfully!");
327+
println!("Download the encrypted backup from: {}", res.url);
328+
println!("\nNote: After exporting, the node will no longer be schedulable on Greenlight.");
329+
println!("The backup is encrypted and can only be decrypted with your node secret.");
330+
Ok(())
331+
}
332+
276333
async fn approve_pairing_handler<P: AsRef<Path>>(
277334
config: Config<P>,
278335
pairing_data: &str,

0 commit comments

Comments
 (0)