1
- use std:: { env:: current_dir, os:: unix:: fs:: symlink, path:: PathBuf , str :: FromStr , time:: Duration } ;
1
+ use std:: { env:: current_dir, os:: unix:: fs:: symlink, path:: PathBuf , time:: Duration } ;
2
2
3
3
use anyhow:: { anyhow, bail, Result } ;
4
4
use clap:: { Parser , ValueEnum } ;
5
5
use fleet_base:: {
6
- host:: { Config , ConfigHost } ,
6
+ host:: { Config , ConfigHost , DeployKind } ,
7
7
opts:: FleetOpts ,
8
8
} ;
9
9
use itertools:: Itertools as _;
@@ -131,6 +131,13 @@ async fn deploy_task(
131
131
specialisation : Option < String > ,
132
132
disable_rollback : bool ,
133
133
) -> Result < ( ) > {
134
+ let deploy_kind = host. deploy_kind ( ) . await ?;
135
+ if deploy_kind == DeployKind :: NixosInstall
136
+ && !matches ! ( action, DeployAction :: Boot | DeployAction :: Upload )
137
+ {
138
+ bail ! ( "nixos-install deploy kind only supports boot and upload actions" ) ;
139
+ }
140
+
134
141
let mut failed = false ;
135
142
136
143
// TODO: Lockfile, to prevent concurrent system switch?
@@ -177,39 +184,74 @@ async fn deploy_task(
177
184
}
178
185
}
179
186
}
180
-
181
- if action. should_switch_profile ( ) && !failed {
182
- info ! ( "switching system profile generation" ) ;
183
- // It would also be possible to update profile atomically during copy:
184
- // https://github.com/NixOS/nix/pull/11657
185
- let mut cmd = host. cmd ( "nix" ) . await ?;
186
- cmd. arg ( "build" ) ;
187
- cmd. comparg ( "--profile" , "/nix/var/nix/profiles/system" ) ;
188
- cmd. arg ( & built) ;
189
- if let Err ( e) = cmd. sudo ( ) . run_nix ( ) . await {
190
- error ! ( "failed to switch system profile generation: {e}" ) ;
187
+ if deploy_kind == DeployKind :: NixosInstall {
188
+ info ! (
189
+ "running nixos-install to switch profile, install bootloader, and perform activation"
190
+ ) ;
191
+ let mut cmd = host. cmd ( "nixos-install" ) . await ?;
192
+ cmd. arg ( "--system" ) . arg ( & built) . args ( [
193
+ // Channels here aren't fleet host system channels, but channels embedded in installation cd, which might be old.
194
+ // It is possible to copy host channels, but I would prefer non-flake nix just to be unsupported.
195
+ "--no-channel-copy" ,
196
+ "--root" ,
197
+ "/mnt" ,
198
+ ] ) ;
199
+ if let Err ( e) = cmd. sudo ( ) . run ( ) . await {
200
+ error ! ( "failed to execute nixos-install: {e}" ) ;
191
201
failed = true ;
192
202
}
193
- }
203
+ } else {
204
+ if action. should_switch_profile ( ) && !failed {
205
+ info ! ( "switching system profile generation" ) ;
194
206
195
- // FIXME: Connection might be disconnected after activation run
207
+ // To avoid even more problems, using nixos-install for now.
208
+ // // nix build is unable to work with --store argument for some reason, and nix until 2.26 didn't support copy with --profile argument,
209
+ // // falling back to using nix-env command
210
+ // // After stable NixOS starts using 2.26 - use `nix --store /mnt copy --from /mnt --profile ...` here, and instead of nix build below.
211
+ // let mut cmd = host.cmd("nix-env").await?;
212
+ // cmd.args([
213
+ // "--store",
214
+ // "/mnt",
215
+ // "--profile",
216
+ // "/mnt/nix/var/nix/profiles/system",
217
+ // "--set",
218
+ // ])
219
+ // .arg(&built);
220
+ // if let Err(e) = cmd.sudo().run_nix().await {
221
+ // error!("failed to switch system profile generation: {e}");
222
+ // failed = true;
223
+ // }
224
+ // It would also be possible to update profile atomically during copy:
225
+ // https://github.com/NixOS/nix/pull/11657
226
+ let mut cmd = host. nix_cmd ( ) . await ?;
227
+ cmd. arg ( "build" ) ;
228
+ cmd. comparg ( "--profile" , "/nix/var/nix/profiles/system" ) ;
229
+ cmd. arg ( & built) ;
230
+ if let Err ( e) = cmd. sudo ( ) . run_nix ( ) . await {
231
+ error ! ( "failed to switch system profile generation: {e}" ) ;
232
+ failed = true ;
233
+ }
234
+ }
196
235
197
- if action. should_activate ( ) && !failed {
198
- let _span = info_span ! ( "activating" ) . entered ( ) ;
199
- info ! ( "executing activation script" ) ;
200
- let specialised = if let Some ( specialisation) = specialisation {
201
- let mut specialised = built. join ( "specialisation" ) ;
202
- specialised. push ( specialisation) ;
203
- specialised
204
- } else {
205
- built. clone ( )
206
- } ;
207
- let switch_script = specialised. join ( "bin/switch-to-configuration" ) ;
208
- let mut cmd = host. cmd ( switch_script) . in_current_span ( ) . await ?;
209
- cmd. arg ( action. name ( ) . expect ( "upload.should_activate == false" ) ) ;
210
- if let Err ( e) = cmd. sudo ( ) . run ( ) . in_current_span ( ) . await {
211
- error ! ( "failed to activate: {e}" ) ;
212
- failed = true ;
236
+ // FIXME: Connection might be disconnected after activation run
237
+
238
+ if action. should_activate ( ) && !failed {
239
+ let _span = info_span ! ( "activating" ) . entered ( ) ;
240
+ info ! ( "executing activation script" ) ;
241
+ let specialised = if let Some ( specialisation) = specialisation {
242
+ let mut specialised = built. join ( "specialisation" ) ;
243
+ specialised. push ( specialisation) ;
244
+ specialised
245
+ } else {
246
+ built. clone ( )
247
+ } ;
248
+ let switch_script = specialised. join ( "bin/switch-to-configuration" ) ;
249
+ let mut cmd = host. cmd ( switch_script) . in_current_span ( ) . await ?;
250
+ cmd. arg ( action. name ( ) . expect ( "upload.should_activate == false" ) ) ;
251
+ if let Err ( e) = cmd. sudo ( ) . run ( ) . in_current_span ( ) . await {
252
+ error ! ( "failed to activate: {e}" ) ;
253
+ failed = true ;
254
+ }
213
255
}
214
256
}
215
257
if action. should_create_rollback_marker ( ) {
@@ -333,24 +375,6 @@ impl BuildSystems {
333
375
}
334
376
}
335
377
336
- #[ derive( Clone , PartialEq , Copy ) ]
337
- enum DeployKind {
338
- // NixOS => NixOS managed by fleet
339
- UpgradeToFleet ,
340
- // NixOS managed by fleet => NixOS managed by fleet
341
- Fleet ,
342
- }
343
- impl FromStr for DeployKind {
344
- type Err = anyhow:: Error ;
345
- fn from_str ( s : & str ) -> std:: result:: Result < Self , Self :: Err > {
346
- match s {
347
- "upgrade-to-fleet" => Ok ( Self :: UpgradeToFleet ) ,
348
- "fleet" => Ok ( Self :: Fleet ) ,
349
- v => bail ! ( "unknown deploy_kind: {v}; expected on of \" upgrade-to-fleet\" , \" fleet\" " ) ,
350
- }
351
- }
352
- }
353
-
354
378
impl Deploy {
355
379
pub async fn run ( self , config : & Config , opts : & FleetOpts ) -> Result < ( ) > {
356
380
let hosts = opts. filter_skipped ( config. list_hosts ( ) . await ?) . await ?;
@@ -367,8 +391,9 @@ impl Deploy {
367
391
let local_host = config. local_host ( ) ;
368
392
let opts = opts. clone ( ) ;
369
393
let batch = batch. clone ( ) ;
370
- let mut deploy_kind: Option < DeployKind > =
371
- opts. action_attr ( & host, "deploy_kind" ) . await ?;
394
+ if let Some ( deploy_kind) = opts. action_attr :: < DeployKind > ( & host, "deploy_kind" ) . await ? {
395
+ host. set_deploy_kind ( deploy_kind) ;
396
+ } ;
372
397
373
398
set. spawn_local (
374
399
( async move {
@@ -381,28 +406,14 @@ impl Deploy {
381
406
return ;
382
407
}
383
408
} ;
384
- if deploy_kind == None {
385
- let is_fleet_managed = match host. file_exists ( "/etc/FLEET_HOST" ) . await {
386
- Ok ( v) => v,
387
- Err ( e) => {
388
- error ! ( "failed to query remote system kind: {}" , e) ;
389
- return ;
390
- } ,
391
- } ;
392
- if !is_fleet_managed {
393
- error ! ( indoc:: indoc!{ "
394
- host is not marked as managed by fleet
395
- if you're not trying to lustrate/install system from scratch,
396
- you should either
397
- 1. manually create /etc/FLEET_HOST file on the target host,
398
- 2. use ?deploy_kind=fleet host argument if you're upgrading from older version of fleet
399
- 3. use ?deploy_kind=upgrade_to_fleet if you're upgrading from plain nixos to fleet-managed nixos
400
- " } ) ;
409
+
410
+ let deploy_kind = match host. deploy_kind ( ) . await {
411
+ Ok ( v) => v,
412
+ Err ( e) => {
413
+ error ! ( "failed to query target deploy kind: {e}" ) ;
401
414
return ;
402
415
}
403
- deploy_kind = Some ( DeployKind :: Fleet ) ;
404
- }
405
- let deploy_kind = deploy_kind. expect ( "deploy_kind is set" ) ;
416
+ } ;
406
417
407
418
// TODO: Make disable_rollback a host attribute instead
408
419
let mut disable_rollback = self . disable_rollback ;
0 commit comments