openstack_cli_image/v2/image/file/
download.rs1use clap::Args;
23use tracing::info;
24
25use openstack_cli_core::cli::CliArgs;
26use openstack_cli_core::error::OpenStackCliError;
27use openstack_cli_core::output::OutputProcessor;
28use openstack_sdk::AsyncOpenStack;
29
30use openstack_cli_core::common::download_file;
31use openstack_sdk::api::QueryAsync;
32use openstack_sdk::api::RawQueryAsync;
33use openstack_sdk::api::find;
34use openstack_sdk::api::image::v2::image::file::download;
35use openstack_sdk::api::image::v2::image::find;
36
37#[derive(Args)]
56#[command(about = "Download binary image data")]
57pub struct FileCommand {
58 #[command(flatten)]
60 query: QueryParameters,
61
62 #[command(flatten)]
64 headers: HeaderParameters,
65
66 #[command(flatten)]
68 path: PathParameters,
69
70 #[arg(long)]
72 file: Option<String>,
73}
74
75#[derive(Args)]
77struct QueryParameters {}
78
79#[derive(Args)]
81struct HeaderParameters {
82 #[arg(long)]
85 range: Option<String>,
86}
87
88#[derive(Args)]
90struct PathParameters {
91 #[arg(
93 help_heading = "Path parameters",
94 id = "path_param_image_id",
95 value_name = "IMAGE_ID"
96 )]
97 image_id: String,
98}
99
100impl FileCommand {
101 pub async fn take_action<C: CliArgs>(
103 &self,
104 parsed_args: &C,
105 client: &mut AsyncOpenStack,
106 ) -> Result<(), OpenStackCliError> {
107 info!("Download File");
108
109 let op =
110 OutputProcessor::from_args(parsed_args, Some("image.image/file"), Some("download"));
111 op.validate_args(parsed_args)?;
112 let find_ep = find::Request::builder()
113 .id(&self.path.image_id)
114 .build()
115 .map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
116 let image_data: serde_json::Value = find(find_ep).query_async(client).await?;
117
118 let image_id = image_data["id"]
119 .as_str()
120 .ok_or_else(|| eyre::eyre!("image ID must be a string"))?
121 .to_string();
122 let image_name = image_data["name"]
123 .as_str()
124 .ok_or_else(|| eyre::eyre!("image name must be a string"))?
125 .to_string();
126
127 let ep = download::Request::builder()
128 .image_id(image_id)
129 .build()
130 .map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
131 let (headers, data) = ep.download_async(client).await?;
132
133 let size: u64 = headers
134 .get("content-length")
135 .and_then(|x| {
136 x.to_str()
137 .inspect_err(|e| {
138 tracing::warn!("content-length header cannot be treated as string: {}", e)
139 })
140 .ok()
141 })
142 .unwrap_or("0")
143 .parse()
144 .inspect_err(|e| {
145 tracing::warn!("content-length header mut represent u64 number: {}", e)
146 })
147 .unwrap_or_default();
148 download_file(self.file.clone().unwrap_or(image_name), size, data).await?;
149 op.show_command_hint()?;
151 Ok(())
152 }
153}