4
4
5
5
use std:: ffi:: { CString , OsStr , OsString } ;
6
6
use std:: io:: Seek ;
7
+ use std:: os:: fd:: RawFd ;
7
8
use std:: os:: unix:: process:: CommandExt ;
8
9
use std:: process:: Command ;
9
10
@@ -25,6 +26,8 @@ use serde::{Deserialize, Serialize};
25
26
26
27
use crate :: deploy:: RequiredHostSpec ;
27
28
use crate :: lints;
29
+ use crate :: progress_jsonl;
30
+ use crate :: progress_jsonl:: ProgressWriter ;
28
31
use crate :: spec:: Host ;
29
32
use crate :: spec:: ImageReference ;
30
33
use crate :: utils:: sigpolicy_from_opts;
@@ -52,6 +55,10 @@ pub(crate) struct UpgradeOpts {
52
55
/// a userspace-only restart.
53
56
#[ clap( long, conflicts_with = "check" ) ]
54
57
pub ( crate ) apply : bool ,
58
+
59
+ /// Pipe download progress to this fd in a jsonl format.
60
+ #[ clap( long) ]
61
+ pub ( crate ) json_fd : Option < RawFd > ,
55
62
}
56
63
57
64
/// Perform an switch operation
@@ -101,6 +108,10 @@ pub(crate) struct SwitchOpts {
101
108
102
109
/// Target image to use for the next boot.
103
110
pub ( crate ) target : String ,
111
+
112
+ /// Pipe download progress to this fd in a jsonl format.
113
+ #[ clap( long) ]
114
+ pub ( crate ) json_fd : Option < RawFd > ,
104
115
}
105
116
106
117
/// Options controlling rollback
@@ -644,6 +655,12 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
644
655
let ( booted_deployment, _deployments, host) =
645
656
crate :: status:: get_status_require_booted ( sysroot) ?;
646
657
let imgref = host. spec . image . as_ref ( ) ;
658
+ let prog = opts
659
+ . json_fd
660
+ . map ( progress_jsonl:: ProgressWriter :: from_raw_fd)
661
+ . transpose ( ) ?
662
+ . unwrap_or_default ( ) ;
663
+
647
664
// If there's no specified image, let's be nice and check if the booted system is using rpm-ostree
648
665
if imgref. is_none ( ) {
649
666
let booted_incompatible = host
@@ -700,7 +717,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
700
717
}
701
718
}
702
719
} else {
703
- let fetched = crate :: deploy:: pull ( repo, imgref, None , opts. quiet ) . await ?;
720
+ let fetched = crate :: deploy:: pull ( repo, imgref, None , opts. quiet , prog . clone ( ) ) . await ?;
704
721
let staged_digest = staged_image. map ( |s| s. digest ( ) . expect ( "valid digest in status" ) ) ;
705
722
let fetched_digest = & fetched. manifest_digest ;
706
723
tracing:: debug!( "staged: {staged_digest:?}" ) ;
@@ -723,7 +740,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
723
740
println ! ( "No update available." )
724
741
} else {
725
742
let osname = booted_deployment. osname ( ) ;
726
- crate :: deploy:: stage ( sysroot, & osname, & fetched, & spec) . await ?;
743
+ crate :: deploy:: stage ( sysroot, & osname, & fetched, & spec, prog . clone ( ) ) . await ?;
727
744
changed = true ;
728
745
if let Some ( prev) = booted_image. as_ref ( ) {
729
746
if let Some ( fetched_manifest) = fetched. get_manifest ( repo) ? {
@@ -759,6 +776,11 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
759
776
) ;
760
777
let target = ostree_container:: OstreeImageReference { sigverify, imgref } ;
761
778
let target = ImageReference :: from ( target) ;
779
+ let prog = opts
780
+ . json_fd
781
+ . map ( progress_jsonl:: ProgressWriter :: from_raw_fd)
782
+ . transpose ( ) ?
783
+ . unwrap_or_default ( ) ;
762
784
763
785
// If we're doing an in-place mutation, we shortcut most of the rest of the work here
764
786
if opts. mutate_in_place {
@@ -794,7 +816,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
794
816
}
795
817
let new_spec = RequiredHostSpec :: from_spec ( & new_spec) ?;
796
818
797
- let fetched = crate :: deploy:: pull ( repo, & target, None , opts. quiet ) . await ?;
819
+ let fetched = crate :: deploy:: pull ( repo, & target, None , opts. quiet , prog . clone ( ) ) . await ?;
798
820
799
821
if !opts. retain {
800
822
// By default, we prune the previous ostree ref so it will go away after later upgrades
@@ -808,7 +830,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
808
830
}
809
831
810
832
let stateroot = booted_deployment. osname ( ) ;
811
- crate :: deploy:: stage ( sysroot, & stateroot, & fetched, & new_spec) . await ?;
833
+ crate :: deploy:: stage ( sysroot, & stateroot, & fetched, & new_spec, prog . clone ( ) ) . await ?;
812
834
813
835
if opts. apply {
814
836
crate :: reboot:: reboot ( ) ?;
@@ -850,18 +872,20 @@ async fn edit(opts: EditOpts) -> Result<()> {
850
872
host. spec . verify_transition ( & new_host. spec ) ?;
851
873
let new_spec = RequiredHostSpec :: from_spec ( & new_host. spec ) ?;
852
874
875
+ let prog = ProgressWriter :: default ( ) ;
876
+
853
877
// We only support two state transitions right now; switching the image,
854
878
// or flipping the bootloader ordering.
855
879
if host. spec . boot_order != new_host. spec . boot_order {
856
880
return crate :: deploy:: rollback ( sysroot) . await ;
857
881
}
858
882
859
- let fetched = crate :: deploy:: pull ( repo, new_spec. image , None , opts. quiet ) . await ?;
883
+ let fetched = crate :: deploy:: pull ( repo, new_spec. image , None , opts. quiet , prog . clone ( ) ) . await ?;
860
884
861
885
// TODO gc old layers here
862
886
863
887
let stateroot = booted_deployment. osname ( ) ;
864
- crate :: deploy:: stage ( sysroot, & stateroot, & fetched, & new_spec) . await ?;
888
+ crate :: deploy:: stage ( sysroot, & stateroot, & fetched, & new_spec, prog . clone ( ) ) . await ?;
865
889
866
890
Ok ( ( ) )
867
891
}
0 commit comments