seaplane_cli/api/
formations.rs1use reqwest::Url;
2use seaplane::{
3 api::{
4 compute::v1::{
5 ActiveConfigurations as ActiveConfigurationsModel, Container as ContainerModel,
6 Containers as ContainersModel, FormationConfiguration as FormationConfigurationModel,
7 FormationMetadata as FormationMetadataModel, FormationNames as FormationNamesModel,
8 FormationsRequest,
9 },
10 identity::v0::AccessToken,
11 ApiErrorKind,
12 },
13 error::SeaplaneError,
14};
15use uuid::Uuid;
16
17use crate::{
18 api::request_token,
19 context::Ctx,
20 error::{CliError, Context, Result},
21 ops::formation::{Formation, FormationConfiguration, Formations},
22 printer::{Color, Pb},
23};
24
25#[derive(Debug)]
28pub struct FormationsReq {
29 api_key: String,
30 name: Option<String>,
31 token: Option<AccessToken>,
32 inner: Option<FormationsRequest>,
33 identity_url: Option<Url>,
34 compute_url: Option<Url>,
35 insecure_urls: bool,
36 invalid_certs: bool,
37}
38
39impl FormationsReq {
40 pub fn new<S: Into<String>>(ctx: &Ctx, name: Option<S>) -> Result<Self> {
45 let mut this = Self::new_delay_token(ctx)?;
46 this.name = name.map(Into::into);
47 this.refresh_token()?;
48 Ok(this)
49 }
50
51 pub fn new_delay_token(ctx: &Ctx) -> Result<Self> {
55 Ok(Self {
56 api_key: ctx.args.api_key()?.into(),
57 name: None,
58 token: None,
59 inner: None,
60 identity_url: ctx.identity_url.clone(),
61 compute_url: ctx.compute_url.clone(),
62 #[cfg(feature = "allow_insecure_urls")]
63 insecure_urls: ctx.insecure_urls,
64 #[cfg(not(feature = "allow_insecure_urls"))]
65 insecure_urls: false,
66 #[cfg(feature = "allow_invalid_certs")]
67 invalid_certs: ctx.invalid_certs,
68 #[cfg(not(feature = "allow_invalid_certs"))]
69 invalid_certs: false,
70 })
71 }
72
73 pub fn refresh_token(&mut self) -> Result<()> {
75 self.token = Some(request_token(
76 &self.api_key,
77 self.identity_url.as_ref(),
78 self.insecure_urls,
79 self.invalid_certs,
80 )?);
81 Ok(())
82 }
83
84 fn refresh_inner(&mut self) -> Result<()> {
88 let mut builder = FormationsRequest::builder().token(self.token_or_refresh()?);
89
90 #[cfg(feature = "allow_insecure_urls")]
91 {
92 builder = builder.allow_http(self.insecure_urls);
93 }
94 #[cfg(feature = "allow_invalid_certs")]
95 {
96 builder = builder.allow_invalid_certs(self.invalid_certs);
97 }
98
99 if let Some(url) = &self.compute_url {
100 builder = builder.base_url(url);
101 }
102
103 if let Some(name) = &self.name {
104 builder = builder.name(name);
105 }
106
107 self.inner = Some(builder.build().map_err(CliError::from)?);
108 Ok(())
109 }
110
111 pub fn token_or_refresh(&mut self) -> Result<&str> {
113 if self.token.is_none() {
114 self.refresh_token()?;
115 }
116 Ok(&self.token.as_ref().unwrap().token)
117 }
118
119 pub fn set_name<S: Into<String>>(&mut self, name: S) -> Result<()> {
122 self.name = Some(name.into());
123 self.refresh_inner()
124 }
125
126 pub fn get_all_formations<S: AsRef<str>>(
134 &mut self,
135 formation_names: &[S],
136 pb: &Pb,
137 ) -> Result<Formations> {
138 let mut formations = Formations::default();
139 for name in formation_names {
140 let name = name.as_ref();
141 self.set_name(name)?;
142 pb.set_message(format!("Syncing Formation {name}..."));
143 let mut formation = Formation::new(name);
144
145 let cfg_uuids = self
146 .list_configuration_ids()
147 .context("Context: failed to retrieve Formation Configuration IDs\n")?;
148 let active_cfgs = self
149 .get_active_configurations()
150 .context("Context: failed to retrieve Active Formation Configurations\n")?;
151
152 pb.set_message(format!("Syncing Formation {name} Configurations..."));
153 for uuid in cfg_uuids.into_iter() {
154 let cfg_model = self
155 .get_configuration(uuid)
156 .context("Context: failed to retrieve Formation Configuration\n\tUUID: ")
157 .with_color_context(|| (Color::Yellow, format!("{uuid}\n")))?;
158
159 let cfg = FormationConfiguration::with_uuid(uuid, cfg_model);
160 let is_active = active_cfgs.iter().any(|ac| ac.uuid() == &uuid);
161 formation.local.insert(cfg.id);
162 if is_active {
163 formation.in_air.insert(cfg.id);
164 } else {
165 formation.grounded.insert(cfg.id);
166 }
167 formations.configurations.push(cfg);
168 }
169
170 if !formation.is_empty() {
171 formations.formations.push(formation);
172 }
173 }
174
175 Ok(formations)
176 }
177
178 pub fn get_formation_names(&mut self) -> Result<Vec<String>> {
183 Ok(if let Some(name) = &self.name {
184 vec![name.to_owned()]
185 } else {
186 self.list_names()
188 .context("Context: failed to retrieve Formation Instance names\n")?
189 .into_inner()
190 })
191 }
192}
193
194impl FormationsReq {
196 pub fn list_names(&mut self) -> Result<FormationNamesModel> { maybe_retry!(self.list_names()) }
197
198 pub fn get_metadata(&mut self) -> Result<FormationMetadataModel> {
199 maybe_retry!(self.get_metadata())
200 }
201 pub fn create(
202 &mut self,
203 configuration: &FormationConfigurationModel,
204 active: bool,
205 ) -> Result<Vec<Uuid>> {
206 maybe_retry!(self.create(configuration, active))
207 }
208 pub fn clone_from(&mut self, source_name: &str, active: bool) -> Result<Vec<Uuid>> {
209 maybe_retry!(self.clone_from(source_name, active))
210 }
211 pub fn delete(&mut self, force: bool) -> Result<Vec<Uuid>> { maybe_retry!(self.delete(force)) }
212 pub fn get_active_configurations(&mut self) -> Result<ActiveConfigurationsModel> {
213 maybe_retry!(self.get_active_configurations())
214 }
215 pub fn stop(&mut self) -> Result<()> { maybe_retry!(self.stop()) }
216 pub fn set_active_configurations(
217 &mut self,
218 configs: &ActiveConfigurationsModel,
219 force: bool,
220 ) -> Result<()> {
221 maybe_retry!(self.set_active_configurations(configs, force))
222 }
223 pub fn get_containers(&mut self) -> Result<ContainersModel> {
224 maybe_retry!(self.get_containers())
225 }
226 pub fn get_container(&mut self, container_id: Uuid) -> Result<ContainerModel> {
227 maybe_retry!(self.get_container(container_id))
228 }
229 pub fn get_configuration(&mut self, uuid: Uuid) -> Result<FormationConfigurationModel> {
230 maybe_retry!(self.get_configuration(uuid))
231 }
232 pub fn list_configuration_ids(&mut self) -> Result<Vec<Uuid>> {
233 maybe_retry!(self.list_configuration_ids())
234 }
235 pub fn remove_configuration(&mut self, uuid: Uuid, force: bool) -> Result<Uuid> {
236 maybe_retry!(self.remove_configuration(uuid, force))
237 }
238 pub fn add_configuration(
239 &mut self,
240 configuration: &FormationConfigurationModel,
241 active: bool,
242 ) -> Result<Uuid> {
243 maybe_retry!(self.add_configuration(configuration, active))
244 }
245}