Skip to content

Commit 1a2d35b

Browse files
ysndrbalsoft
andcommitted
Add multi node support
Run multiple deployments in sequence Resolve targets later Extend context by deployed flake Apply clippy suggestions Add revoke command builder Track succeeded deploys Add revoke function Register revoke error as deploy error Prepare revoke command in activate Extend logger to handle revoke Implement revoke command client side Run revoke on previously suceeded Control whether to override by flag Adhere profile configuration auto_rollback setting Cargo fmt Correctly provide profile path to activation script when revoking Document multi flake mode in README Resolve a typo in README.md Co-authored-by: notgne2 <gen2@gen2.space> Use existing teminology rename revoke_suceeded -> rollback_suceeded Use more open CLI argument name `targets` instead of `flakes` Document name changes in README Add sudo command support for revokes Call run_deploy with `dry_active` flag Test revoke commands contains sudo Set default temp_path in activate binary Require temp_path for wait and activate subcommands Add copyright comment Address review change requests Fix typo in README Co-authored-by: Alexander Bantyev <balsoft@balsoft.ru>
1 parent 70d71b3 commit 1a2d35b

File tree

5 files changed

+399
-142
lines changed

5 files changed

+399
-142
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: 34 additions & 6 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)]
@@ -429,6 +442,16 @@ pub async fn activate(
429442
Ok(())
430443
}
431444

445+
#[derive(Error, Debug)]
446+
pub enum RevokeError {
447+
#[error("There was an error de-activating after an error was encountered: {0}")]
448+
DeactivateError(#[from] DeactivateError),
449+
}
450+
async fn revoke(profile_path: String) -> Result<(), RevokeError> {
451+
deactivate(profile_path.as_str()).await?;
452+
Ok(())
453+
}
454+
432455
#[tokio::main]
433456
async fn main() -> Result<(), Box<dyn std::error::Error>> {
434457
// Ensure that this process stays alive after the SSH connection dies
@@ -447,6 +470,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
447470
match opts.subcmd {
448471
SubCommand::Activate(_) => deploy::LoggerType::Activate,
449472
SubCommand::Wait(_) => deploy::LoggerType::Wait,
473+
SubCommand::Revoke(_) => deploy::LoggerType::Revoke,
450474
},
451475
)?;
452476

@@ -455,15 +479,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
455479
activate_opts.profile_path,
456480
activate_opts.closure,
457481
activate_opts.auto_rollback,
458-
opts.temp_path,
482+
activate_opts.temp_path,
459483
activate_opts.confirm_timeout,
460484
activate_opts.magic_rollback,
461485
activate_opts.dry_activate,
462486
)
463487
.await
464488
.map_err(|x| Box::new(x) as Box<dyn std::error::Error>),
465489

466-
SubCommand::Wait(wait_opts) => wait(opts.temp_path, wait_opts.closure)
490+
SubCommand::Wait(wait_opts) => wait(wait_opts.temp_path, wait_opts.closure)
491+
.await
492+
.map_err(|x| Box::new(x) as Box<dyn std::error::Error>),
493+
494+
SubCommand::Revoke(revoke_opts) => revoke(revoke_opts.profile_path)
467495
.await
468496
.map_err(|x| Box::new(x) as Box<dyn std::error::Error>),
469497
};

0 commit comments

Comments
 (0)