openstack/compute/
keypairs.rs1use async_trait::async_trait;
18use futures::stream::{Stream, TryStreamExt};
19
20use super::super::common::{KeyPairRef, Refresh, ResourceIterator, ResourceQuery};
21use super::super::session::Session;
22use super::super::utils::Query;
23use super::super::{Error, ErrorKind, Result};
24use super::{api, protocol};
25
26#[derive(Clone, Debug)]
28pub struct KeyPair {
29 session: Session,
30 inner: protocol::KeyPair,
31}
32
33#[derive(Clone, Debug)]
35pub struct KeyPairQuery {
36 session: Session,
37 query: Query,
38 can_paginate: bool,
39}
40
41#[derive(Clone, Debug)]
43pub struct NewKeyPair {
44 session: Session,
45 inner: protocol::KeyPairCreate,
46}
47
48impl KeyPair {
49 pub(crate) async fn new<Id: AsRef<str>>(session: Session, id: Id) -> Result<KeyPair> {
51 let inner = api::get_keypair(&session, id).await?;
52 Ok(KeyPair { session, inner })
53 }
54
55 pub async fn delete(self) -> Result<()> {
57 api::delete_keypair(&self.session, &self.inner.name).await
58 }
59
60 transparent_property! {
61 #[doc = "Key pair fingerprint."]
62 fingerprint: ref String
63 }
64
65 transparent_property! {
66 #[doc = "Key pair type, if available."]
67 key_type: Option<protocol::KeyPairType>
68 }
69
70 transparent_property! {
71 #[doc = "Key pair name."]
72 name: ref String
73 }
74
75 transparent_property! {
76 #[doc = "Public key."]
77 public_key: ref String
78 }
79}
80
81#[async_trait]
82impl Refresh for KeyPair {
83 async fn refresh(&mut self) -> Result<()> {
85 self.inner = api::get_keypair(&self.session, &self.inner.name).await?;
86 Ok(())
87 }
88}
89
90impl KeyPairQuery {
91 pub(crate) fn new(session: Session) -> KeyPairQuery {
92 KeyPairQuery {
93 session,
94 query: Query::new(),
95 can_paginate: true,
96 }
97 }
98
99 pub fn with_marker<T: Into<String>>(mut self, marker: T) -> Self {
103 self.can_paginate = false;
104 self.query.push_str("marker", marker);
105 self
106 }
107
108 pub fn with_limit(mut self, limit: usize) -> Self {
112 self.can_paginate = false;
113 self.query.push("limit", limit);
114 self
115 }
116
117 pub fn into_stream(self) -> impl Stream<Item = Result<KeyPair>> {
124 debug!("Fetching key pairs with {:?}", self.query);
125 ResourceIterator::new(self).into_stream()
126 }
127
128 pub async fn all(self) -> Result<Vec<KeyPair>> {
132 self.into_stream().try_collect().await
133 }
134
135 pub async fn one(mut self) -> Result<KeyPair> {
140 debug!("Fetching one key pair with {:?}", self.query);
141 if self.can_paginate {
142 self.query.push("limit", 2);
145 }
146
147 ResourceIterator::new(self).one().await
148 }
149}
150
151impl NewKeyPair {
152 pub(crate) fn new(session: Session, name: String) -> NewKeyPair {
154 NewKeyPair {
155 session,
156 inner: protocol::KeyPairCreate::new(name),
157 }
158 }
159
160 pub async fn create(self) -> Result<KeyPair> {
164 if self.inner.public_key.is_none() {
165 return Err(Error::new(
166 ErrorKind::InvalidInput,
167 "Public key contents is required",
168 ));
169 };
170
171 let keypair = api::create_keypair(&self.session, self.inner).await?;
172 Ok(KeyPair {
173 session: self.session,
174 inner: keypair,
175 })
176 }
177
178 pub async fn generate(mut self) -> Result<(KeyPair, String)> {
182 self.inner.public_key = None;
183
184 let mut keypair = api::create_keypair(&self.session, self.inner).await?;
185 if let Some(private_key) = keypair.private_key.take() {
186 let result = KeyPair {
187 session: self.session,
188 inner: keypair,
189 };
190
191 Ok((result, private_key))
192 } else {
193 Err(Error::new(
194 ErrorKind::InvalidResponse,
195 "Missing private key in the response",
196 ))
197 }
198 }
199
200 creation_inner_field! {
201 #[doc = "Set type of the key pair."]
202 set_key_type, with_key_type -> key_type: optional protocol::KeyPairType
203 }
204
205 creation_inner_field! {
206 #[doc = "Set name of the key pair."]
207 set_name, with_name -> name: String
208 }
209
210 creation_inner_field! {
211 #[doc = "Set name of the key pair."]
212 set_public_key, with_public_key -> public_key: optional String
213 }
214}
215
216#[async_trait]
217impl ResourceQuery for KeyPairQuery {
218 type Item = KeyPair;
219
220 const DEFAULT_LIMIT: usize = 50;
221
222 async fn can_paginate(&self) -> Result<bool> {
223 if self.can_paginate {
224 api::supports_keypair_pagination(&self.session).await
225 } else {
226 Ok(false)
227 }
228 }
229
230 fn extract_marker(&self, resource: &Self::Item) -> String {
231 resource.name().clone()
232 }
233
234 async fn fetch_chunk(
235 &self,
236 limit: Option<usize>,
237 marker: Option<String>,
238 ) -> Result<Vec<Self::Item>> {
239 let query = self.query.with_marker_and_limit(limit, marker);
240 Ok(api::list_keypairs(&self.session, &query)
241 .await?
242 .into_iter()
243 .map(|item| KeyPair {
244 session: self.session.clone(),
245 inner: item,
246 })
247 .collect())
248 }
249}
250
251impl From<KeyPair> for KeyPairRef {
252 fn from(value: KeyPair) -> KeyPairRef {
253 KeyPairRef::new_verified(value.inner.name)
254 }
255}
256
257#[cfg(feature = "compute")]
258impl KeyPairRef {
259 pub(crate) async fn into_verified(self, session: &Session) -> Result<KeyPairRef> {
261 Ok(if self.verified {
262 self
263 } else {
264 KeyPairRef::new_verified(api::get_keypair(session, &self.value).await?.name)
265 })
266 }
267}