1use crate::client::ObjectstoreClient;
4use crate::response::get_content_text;
5use anyhow::{bail, Context as _, Result};
6use derive_builder::Builder;
7use reqwest::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE};
8use serde::{Deserialize, Serialize};
9use serde_aux::field_attributes::deserialize_default_from_null;
10
11#[derive(Builder, Clone, Debug, Default, Deserialize, Serialize)]
13#[builder(setter(skip))]
14#[serde(
15 rename_all(serialize = "snake_case", deserialize = "camelCase"),
16 rename(serialize = "tenant_create")
17)]
18pub struct Tenant {
19 #[serde(deserialize_with = "deserialize_default_from_null")]
21 pub name: String,
22 #[builder(setter(into))]
24 #[serde(rename(serialize = "account_id"))]
25 pub id: String,
26 #[serde(deserialize_with = "deserialize_default_from_null")]
28 pub link: String,
29 #[serde(deserialize_with = "deserialize_default_from_null")]
31 pub creation_time: String,
32 #[serde(deserialize_with = "deserialize_default_from_null")]
34 pub inactive: bool,
35 #[serde(deserialize_with = "deserialize_default_from_null")]
37 pub global: bool,
38 #[serde(deserialize_with = "deserialize_default_from_null")]
40 pub remote: bool,
41 #[serde(deserialize_with = "deserialize_default_from_null")]
44 pub internal: bool,
45 pub tenant_default_vpool: String,
46 #[builder(setter(skip = false), default = "false")]
48 pub is_encryption_enabled: bool,
49 #[builder(setter(skip = false), default)]
51 pub default_bucket_block_size: i64,
52 #[builder(setter(skip = false), default = "false")]
54 pub is_compliance_enabled: bool,
55 pub hard_quota_in_g_b: i64,
56 pub soft_quota_in_g_b: i64,
57 pub hard_quota_in_count: i64,
58 pub soft_quota_in_count: i64,
59 #[builder(setter(into))]
62 pub alias: String,
63}
64
65#[derive(Debug, Serialize, Deserialize)]
66#[serde(
67 rename_all(serialize = "snake_case", deserialize = "camelCase"),
68 rename(serialize = "tenant_update")
69)]
70struct TenantUpdate {
71 pub alias: String,
72 pub default_bucket_block_size: i64,
73}
74
75#[derive(Debug, Deserialize)]
76#[serde(rename_all = "camelCase")]
77struct ListTenantsResponse {
78 pub tenant: Vec<Tenant>,
79 #[serde(rename = "Filter")]
80 pub filter: String,
81 #[serde(rename = "NextMarker")]
82 pub next_marker: Option<String>,
83 #[serde(rename = "MaxTenants")]
84 pub max_tenants: Option<u32>,
85 pub next_page_link: Option<String>,
86}
87
88impl Tenant {
89 pub(crate) fn create(client: &mut ObjectstoreClient, tenant: Tenant) -> Result<Tenant> {
90 let request_url = format!("{}object/tenants/tenant", client.endpoint,);
91 let body = quick_xml::se::to_string(&tenant)?;
92 let resp = client
93 .management_client
94 .http_client
95 .post(request_url)
96 .header(ACCEPT, "application/json")
97 .header(
98 AUTHORIZATION,
99 client.management_client.access_token.as_ref().unwrap(),
100 )
101 .header(CONTENT_TYPE, "application/xml")
102 .header("X-EMC-Override", "true")
103 .body(body)
104 .send()?;
105 let text = get_content_text(resp)?;
106 let resp: Tenant = serde_json::from_str(&text).with_context(|| {
107 format!("Unable to deserialise CreateTenant. Body was: \"{}\"", text)
108 })?;
109 Ok(resp)
110 }
111
112 pub(crate) fn update(client: &mut ObjectstoreClient, tenant: Tenant) -> Result<()> {
113 let request_url = format!("{}object/tenants/tenant/{}", client.endpoint, tenant.id);
114 let tenant_update = TenantUpdate {
115 alias: tenant.alias,
116 default_bucket_block_size: tenant.default_bucket_block_size,
117 };
118 let body = quick_xml::se::to_string(&tenant_update)?;
119 let resp = client
120 .management_client
121 .http_client
122 .put(request_url)
123 .header(ACCEPT, "application/json")
124 .header(
125 AUTHORIZATION,
126 client.management_client.access_token.as_ref().unwrap(),
127 )
128 .header(CONTENT_TYPE, "application/xml")
129 .header("X-EMC-Override", "true")
130 .body(body)
131 .send()?;
132 if !resp.status().is_success() {
133 bail!("Request failed: {}", resp.text()?);
134 }
135 Ok(())
136 }
137
138 pub(crate) fn get(client: &mut ObjectstoreClient, name: &str) -> Result<Tenant> {
139 let request_url = format!("{}object/tenants/tenant/{}", client.endpoint, name,);
140 let resp = client
141 .management_client
142 .http_client
143 .get(request_url)
144 .header(ACCEPT, "application/json")
145 .header(
146 AUTHORIZATION,
147 client.management_client.access_token.as_ref().unwrap(),
148 )
149 .send()?;
150 let text = get_content_text(resp)?;
151 let resp: Tenant = serde_json::from_str(&text)
152 .with_context(|| format!("Unable to deserialise GetTenant. Body was: \"{}\"", text))?;
153 Ok(resp)
154 }
155
156 pub(crate) fn delete(client: &mut ObjectstoreClient, name: &str) -> Result<()> {
157 let request_url = format!("{}object/tenants/tenant/{}/delete", client.endpoint, name,);
158 let resp = client
159 .management_client
160 .http_client
161 .post(request_url)
162 .header(ACCEPT, "application/json")
163 .header(
164 AUTHORIZATION,
165 client.management_client.access_token.as_ref().unwrap(),
166 )
167 .header("X-EMC-Override", "true")
168 .send()?;
169 if !resp.status().is_success() {
170 bail!("Request failed: {}", resp.text()?);
171 }
172 Ok(())
173 }
174
175 pub(crate) fn list(client: &mut ObjectstoreClient, name_prefix: &str) -> Result<Vec<Tenant>> {
176 let request_url = format!("{}object/tenants", client.endpoint,);
177 let mut req = client
178 .management_client
179 .http_client
180 .get(request_url)
181 .header(ACCEPT, "application/json")
182 .header(
183 AUTHORIZATION,
184 client.management_client.access_token.as_ref().unwrap(),
185 );
186 if !name_prefix.is_empty() {
187 req = req.query(&[("name", name_prefix)]);
188 }
189 let response = req.send()?;
190 let text = get_content_text(response)?;
191 let mut resp: ListTenantsResponse = serde_json::from_str(&text).with_context(|| {
192 format!(
193 "Unable to deserialise ListTenantsResponse. Body was: \"{}\"",
194 text
195 )
196 })?;
197 let mut tenants: Vec<Tenant> = vec![];
198 tenants.extend(resp.tenant);
199 while let Some(marker) = resp.next_marker {
200 let request_url = format!("{}object/tenants?marker={}", client.endpoint, marker,);
201 let mut req = client
202 .management_client
203 .http_client
204 .get(request_url)
205 .header(ACCEPT, "application/json")
206 .header(
207 AUTHORIZATION,
208 client.management_client.access_token.as_ref().unwrap(),
209 );
210 if !name_prefix.is_empty() {
211 req = req.query(&[("name", name_prefix)]);
212 }
213 let response = req.send()?;
214 let text = get_content_text(response)?;
215 resp = serde_json::from_str(&text).with_context(|| {
216 format!(
217 "Unable to deserialise ListTenantsResponse. Body was: \"{}\"",
218 text
219 )
220 })?;
221 tenants.extend(resp.tenant);
222 }
223 Ok(tenants)
224 }
225}