Skip to content

Commit 0fc8dea

Browse files
committed
Merge branch 'feature/multi-node'
2 parents 70d71b3 + 1d88b84 commit 0fc8dea

File tree

5 files changed

+404
-143
lines changed

5 files changed

+404
-143
lines changed

README.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<!--
22
SPDX-FileCopyrightText: 2020 Serokell <https://serokell.io/>
3+
SPDX-FileCopyrightText: 2021 Yannik Sander <contact@ysndr.de>
34
45
SPDX-License-Identifier: MPL-2.0
56
-->
@@ -16,18 +17,26 @@ Questions? Need help? Join us on Matrix: [`#deploy-rs:matrix.org`](https://matri
1617

1718
Basic usage: `deploy [options] <flake>`.
1819

19-
The given flake can be just a source `my-flake`, or optionally specify the node to deploy `my-flake#my-node`, or specify a profile too `my-flake#my-node.my-profile`. If your profile or node name has a `.` in it, simply wrap it in quotes, and the flake path in quotes (to avoid shell escaping), for example `'my-flake."myserver.com".system'`.
20+
Using this method all profiles specified in the given `<flake>` will be deployed (taking into account the [`profilesOrder`](#node)).
21+
22+
Optionally the flake can be constrained to deploy just a single node (`my-flake#my-node`) or a profile (`my-flake#my-node.my-profile`).
23+
24+
If your profile or node name has a . in it, simply wrap it in quotes, and the flake path in quotes (to avoid shell escaping), for example 'my-flake."myserver.com".system'.
25+
26+
Any "extra" arguments will be passed into the Nix calls, so for instance to deploy an impure profile, you may use `deploy . -- --impure` (note the explicit flake path is necessary for doing this).
2027

2128
You can try out this tool easily with `nix run`:
2229
- `nix run github:serokell/deploy-rs your-flake`
2330

24-
Any "extra" arguments will be passed into the Nix calls, so for instance to deploy an impure profile, you may use `deploy . -- --impure` (note the explicit flake path is necessary for doing this).
31+
In you want to deploy multiple flakes or a subset of profiles with one invocation, instead of calling `deploy <flake>` you can issue `deploy --targets <flake> [<flake> ...]` where `<flake>` is supposed to take the same format as discussed before.
32+
33+
Running in this mode, if any of the deploys fails, the deploy will be aborted and all successful deploys rolled back. `--rollback-succeeded false` can be used to override this behavior, otherwise the `auto-rollback` argument takes precedent.
2534

2635
If you require a signing key to push closures to your server, specify the path to it in the `LOCAL_KEY` environment variable.
2736

2837
Check out `deploy --help` for CLI flags! Remember to check there before making one-time changes to things like hostnames.
2938

30-
There is also an `activate` binary though this should be ignored, it is only used internally and for testing/hacking purposes.
39+
There is also an `activate` binary though this should be ignored, it is only used internally (on the deployed system) and for testing/hacking purposes.
3140

3241
## Ideas
3342

@@ -79,7 +88,7 @@ A basic example of a flake that works with `deploy-rs` and deploys a simple NixO
7988

8089
### Profile
8190

82-
This is the core of how `deploy-rs` was designed, any number of these can run on a node, as any user (see further down for specifying user information). If you want to mimick the behaviour of traditional tools like NixOps or Morph, try just defining one `profile` called `system`, as root, containing a nixosSystem, and you can even similarly use [home-manager](https://github.com/nix-community/home-manager) on any non-privileged user.
91+
This is the core of how `deploy-rs` was designed, any number of these can run on a node, as any user (see further down for specifying user information). If you want to mimic the behaviour of traditional tools like NixOps or Morph, try just defining one `profile` called `system`, as root, containing a nixosSystem, and you can even similarly use [home-manager](https://github.com/nix-community/home-manager) on any non-privileged user.
8392

8493
```nix
8594
{
@@ -128,7 +137,7 @@ This is the top level attribute containing all of the options for this tool
128137
{
129138
nodes = {
130139
# Definition format shown above
131-
my-node = {};
140+
my-node = {};
132141
another-node = {};
133142
};
134143

src/bin/activate.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-FileCopyrightText: 2020 Serokell <https://serokell.io/>
22
// SPDX-FileCopyrightText: 2020 Andreas Fuchs <asf@boinkor.net>
3+
// SPDX-FileCopyrightText: 2021 Yannik Sander <contact@ysndr.de>
34
//
45
// SPDX-License-Identifier: MPL-2.0
56

@@ -33,10 +34,6 @@ struct Opts {
3334
#[clap(long)]
3435
log_dir: Option<String>,
3536

36-
/// Path for any temporary files that may be needed during activation
37-
#[clap(long)]
38-
temp_path: String,
39-
4037
#[clap(subcommand)]
4138
subcmd: SubCommand,
4239
}
@@ -45,6 +42,7 @@ struct Opts {
4542
enum SubCommand {
4643
Activate(ActivateOpts),
4744
Wait(WaitOpts),
45+
Revoke(RevokeOpts),
4846
}
4947

5048
/// Activate a profile
@@ -70,13 +68,28 @@ struct ActivateOpts {
7068
/// Show what will be activated on the machines
7169
#[clap(long)]
7270
dry_activate: bool,
71+
72+
/// Path for any temporary files that may be needed during activation
73+
#[clap(long)]
74+
temp_path: String,
7375
}
7476

7577
/// Activate a profile
7678
#[derive(Clap, Debug)]
7779
struct WaitOpts {
7880
/// The closure to wait for
7981
closure: String,
82+
83+
/// Path for any temporary files that may be needed during activation
84+
#[clap(long)]
85+
temp_path: String,
86+
}
87+
88+
/// Activate a profile
89+
#[derive(Clap, Debug)]
90+
struct RevokeOpts {
91+
/// The profile path to revoke
92+
profile_path: String,
8093
}
8194

8295
#[derive(Error, Debug)]
@@ -377,7 +390,11 @@ pub async fn activate(
377390

378391
debug!("Running activation script");
379392

380-
let activation_location = if dry_activate { &closure } else { &profile_path };
393+
let activation_location = if dry_activate {
394+
&closure
395+
} else {
396+
&profile_path
397+
};
381398

382399
let activate_status = match Command::new(format!("{}/deploy-rs-activate", activation_location))
383400
.env("PROFILE", activation_location)
@@ -429,6 +446,16 @@ pub async fn activate(
429446
Ok(())
430447
}
431448

449+
#[derive(Error, Debug)]
450+
pub enum RevokeError {
451+
#[error("There was an error de-activating after an error was encountered: {0}")]
452+
DeactivateError(#[from] DeactivateError),
453+
}
454+
async fn revoke(profile_path: String) -> Result<(), RevokeError> {
455+
deactivate(profile_path.as_str()).await?;
456+
Ok(())
457+
}
458+
432459
#[tokio::main]
433460
async fn main() -> Result<(), Box<dyn std::error::Error>> {
434461
// Ensure that this process stays alive after the SSH connection dies
@@ -447,6 +474,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
447474
match opts.subcmd {
448475
SubCommand::Activate(_) => deploy::LoggerType::Activate,
449476
SubCommand::Wait(_) => deploy::LoggerType::Wait,
477+
SubCommand::Revoke(_) => deploy::LoggerType::Revoke,
450478
},
451479
)?;
452480

@@ -455,15 +483,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
455483
activate_opts.profile_path,
456484
activate_opts.closure,
457485
activate_opts.auto_rollback,
458-
opts.temp_path,
486+
activate_opts.temp_path,
459487
activate_opts.confirm_timeout,
460488
activate_opts.magic_rollback,
461489
activate_opts.dry_activate,
462490
)
463491
.await
464492
.map_err(|x| Box::new(x) as Box<dyn std::error::Error>),
465493

466-
SubCommand::Wait(wait_opts) => wait(opts.temp_path, wait_opts.closure)
494+
SubCommand::Wait(wait_opts) => wait(wait_opts.temp_path, wait_opts.closure)
495+
.await
496+
.map_err(|x| Box::new(x) as Box<dyn std::error::Error>),
497+
498+
SubCommand::Revoke(revoke_opts) => revoke(revoke_opts.profile_path)
467499
.await
468500
.map_err(|x| Box::new(x) as Box<dyn std::error::Error>),
469501
};

0 commit comments

Comments
 (0)