Skip to main content

rs_consul/
acl.rs

1use std::time::Duration;
2
3use crate::ACLPolicy;
4use crate::ACLToken;
5use crate::Consul;
6use crate::CreateACLPolicyRequest;
7use crate::CreateACLTokenPayload;
8use crate::Function;
9use crate::Result;
10use crate::errors::ConsulError;
11
12use http::Method;
13use http_body_util::Empty;
14use http_body_util::Full;
15use http_body_util::combinators::BoxBody;
16
17use hyper::body::Buf;
18use hyper::body::Bytes;
19
20impl Consul {
21    /// Returns all ACL tokens.
22    ///
23    /// Fetches the list of ACL tokens from Consul’s `/v1/acl/tokens` endpoint.
24    /// Users can use these tokens to manage access control for Consul resources.
25    /// See the [Consul API docs](https://developer.hashicorp.com/consul/api-docs/acl/tokens#list-tokens) for more information.
26    ///
27    /// # Arguments:
28    /// - `&self` – the `Consul` client instance.
29    ///
30    /// # Errors:
31    /// - [`ConsulError::ResponseDeserializationFailed`] if the response JSON can’t be parsed.
32    pub async fn get_acl_tokens(&self) -> Result<Vec<ACLToken>> {
33        let uri = format!("{}/v1/acl/tokens", self.config.address);
34        let request = hyper::Request::builder().method(Method::GET).uri(uri);
35        let (body, _) = self
36            .execute_request(
37                request,
38                BoxBody::new(Empty::<Bytes>::new()),
39                Some(Duration::from_secs(5)),
40                crate::Function::GetAclTokens,
41            )
42            .await?;
43        serde_json::from_reader(body.reader()).map_err(ConsulError::ResponseDeserializationFailed)
44    }
45
46    /// Returns all ACL policies.
47    ///
48    /// Retrieves the list of ACL policies defined in Consul via the `/v1/acl/policies` endpoint.
49    /// ACL policies define sets of rules for tokens to grant or restrict permissions.
50    /// See the [Consul API docs](https://developer.hashicorp.com/consul/api-docs/acl/policies#list-policies) for more information.
51    ///
52    /// # Arguments:
53    /// - `&self` – the `Consul` client instance.
54    ///
55    /// # Errors:
56    /// - [`ConsulError::ResponseDeserializationFailed`] if the response JSON can’t be parsed.
57    pub async fn get_acl_policies(&self) -> Result<Vec<ACLPolicy>> {
58        let uri = format!("{}/v1/acl/policies", self.config.address);
59        let request = hyper::Request::builder().method(Method::GET).uri(uri);
60        let (body, _) = self
61            .execute_request(
62                request,
63                BoxBody::new(Empty::<Bytes>::new()),
64                Some(Duration::from_secs(5)),
65                crate::Function::GetACLPolicies,
66            )
67            .await?;
68        serde_json::from_reader(body.reader()).map_err(ConsulError::ResponseDeserializationFailed)
69    }
70
71    /// Delete an acl policy.
72    ///
73    /// Sends a `DELETE` to `/v1/acl/policy/:id` to delete an ACL policy in Consul.
74    ///
75    /// # Arguments:
76    /// - `&self` – the `Consul` client instance.  
77    /// - `id` – the policy ID.
78    ///
79    /// # Errors:
80    /// - [`ConsulError::InvalidRequest`] if the payload fails to serialize.  
81    /// - [`ConsulError::ResponseDeserializationFailed`] if the Consul response can’t be parsed.
82    pub async fn delete_acl_policy(&self, id: String) -> Result<()> {
83        let uri = format!("{}/v1/acl/policy/{}", self.config.address, id);
84        let request = hyper::Request::builder().method(Method::DELETE).uri(uri);
85        self.execute_request(
86            request,
87            BoxBody::new(Empty::<Bytes>::new()),
88            Some(Duration::from_secs(5)),
89            Function::DeleteACLPolicy,
90        )
91        .await?;
92        Ok(())
93    }
94
95    /// Creates a new ACL policy.
96    ///
97    /// Sends a `PUT` to `/v1/acl/policy` to define a new ACL policy in Consul.
98    /// ACL policies consist of rules that can be attached to tokens to control access.
99    /// See the [Consul API docs](https://developer.hashicorp.com/consul/api-docs/acl/policies#create-policy) for more information.
100    ///
101    /// # Arguments:
102    /// - `&self` – the `Consul` client instance.  
103    /// - `payload` – the [`CreateACLPolicyRequest`](crate::types::CreateACLPolicyRequest) payload.
104    ///
105    /// # Errors:
106    /// - [`ConsulError::InvalidRequest`] if the payload fails to serialize.  
107    /// - [`ConsulError::ResponseDeserializationFailed`] if the Consul response can’t be parsed.
108    pub async fn create_acl_policy(&self, payload: &CreateACLPolicyRequest) -> Result<ACLPolicy> {
109        let uri = format!("{}/v1/acl/policy", self.config.address);
110        let request = hyper::Request::builder().method(Method::PUT).uri(uri);
111        let payload = serde_json::to_string(payload).map_err(ConsulError::InvalidRequest)?;
112        let (resp, _) = self
113            .execute_request(
114                request,
115                BoxBody::new(Full::<Bytes>::new(Bytes::from(payload.into_bytes()))),
116                Some(Duration::from_secs(5)),
117                Function::CreateACLPolicy,
118            )
119            .await?;
120        serde_json::from_reader(resp.reader()).map_err(ConsulError::ResponseDeserializationFailed)
121    }
122
123    /// Creates a new ACL token.
124    ///
125    /// Sends a `PUT` to `/v1/acl/token` to generate a new token which can be attached to ACL policies.
126    /// Tokens grant the permissions defined by their associated policies.
127    /// See the [Consul API docs](https://developer.hashicorp.com/consul/api-docs/acl/tokens#create-token) for more information.
128    ///
129    /// # Arguments:
130    /// - `&self` – the `Consul` client instance.  
131    /// - `payload` – the [`CreateACLTokenPayload`](crate::CreateACLTokenPayload) payload.
132    ///
133    /// # Errors:
134    /// - [`ConsulError::InvalidRequest`] if the payload fails to serialize.  
135    /// - [`ConsulError::ResponseDeserializationFailed`] if the response JSON can’t be parsed.
136    pub async fn create_acl_token(&self, payload: &CreateACLTokenPayload) -> Result<ACLToken> {
137        let uri = format!("{}/v1/acl/token", self.config.address);
138        let request = hyper::Request::builder().method(Method::PUT).uri(uri);
139        let payload = serde_json::to_string(payload).map_err(ConsulError::InvalidRequest)?;
140        let (resp, _) = self
141            .execute_request(
142                request,
143                BoxBody::new(Full::<Bytes>::new(Bytes::from(payload.into_bytes()))),
144                Some(Duration::from_secs(5)),
145                Function::CreateACLPolicy,
146            )
147            .await?;
148        serde_json::from_reader(resp.reader()).map_err(ConsulError::ResponseDeserializationFailed)
149    }
150
151    /// Reads an ACL token.
152    ///
153    /// Fetches a single ACL token by its ID using the `/v1/acl/token/{token}` endpoint.
154    /// Useful for inspecting the token’s properties and associated policies.
155    /// See the [Consul API docs](https://developer.hashicorp.com/consul/api-docs/acl/tokens#read-token) for more information.
156    ///
157    /// # Arguments:
158    /// - `&self` – the `Consul` client instance.  
159    /// - `accessor_id` – the accessor_id to read.
160    ///
161    /// # Errors:
162    /// - [`ConsulError::ResponseDeserializationFailed`] if the response JSON can’t be parsed.
163    pub async fn read_acl_token(&self, accessor_id: String) -> Result<ACLToken> {
164        let uri = format!("{}/v1/acl/token/{}", self.config.address, accessor_id);
165        let request = hyper::Request::builder().method(Method::GET).uri(uri);
166        let (resp_body, _) = self
167            .execute_request(
168                request,
169                BoxBody::new(Empty::<Bytes>::new()),
170                Some(Duration::from_secs(5)),
171                crate::Function::ReadACLToken,
172            )
173            .await?;
174        serde_json::from_reader(resp_body.reader())
175            .map_err(ConsulError::ResponseDeserializationFailed)
176    }
177
178    /// Deletes an ACL token.
179    ///
180    /// Sends a `DELETE` to `/v1/acl/token/{token}` to remove the specified ACL token.
181    /// Returns `false` if deletion failed, in which case this method returns an error.
182    /// See the [Consul API docs](https://developer.hashicorp.com/consul/api-docs/acl/tokens#delete-token) for more information.
183    ///
184    /// # Arguments:
185    /// - `&self` – the `Consul` client instance.  
186    /// - `token` – the token ID to delete.
187    ///
188    /// # Errors:
189    /// - [`ConsulError::ResponseDeserializationFailed`] if the response JSON can’t be parsed.  
190    /// - [`ConsulError::TokenDeleteFailed`] if Consul indicates deletion did not succeed.
191    pub async fn delete_acl_token(&self, token: String) -> Result<()> {
192        let uri = format!("{}/v1/acl/token/{}", self.config.address, token);
193        let request = hyper::Request::builder().method(Method::DELETE).uri(uri);
194        let (resp_body, _) = self
195            .execute_request(
196                request,
197                BoxBody::new(Empty::<Bytes>::new()),
198                Some(Duration::from_secs(5)),
199                crate::Function::DeleteACLToken,
200            )
201            .await?;
202        let ok: bool = serde_json::from_reader(resp_body.reader())
203            .map_err(ConsulError::ResponseDeserializationFailed)?;
204        if !ok {
205            return Err(ConsulError::TokenDeleteFailed);
206        }
207        Ok(())
208    }
209}