solo_lib/sdk/qcloud/
lighthouse.rs1use std::{borrow::Borrow, result::Result::Ok};
6
7use anyhow::Result;
8use hashbrown::HashSet;
9use reqwest::Client;
10use serde::{Deserialize, Serialize};
11
12use super::util::{
13 BasicRequest, CommonResponse, Empty, MachineType, Secret, parse_response,
14 request_builder,
15};
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct Instance {
20 pub id: String,
21 pub region: String,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct FirewallRuleInfo {
26 #[serde(rename = "AppType", skip_serializing_if = "Option::is_none")]
27 pub app_type: Option<String>,
28
29 #[serde(rename = "Protocol")]
30 pub protocol: String,
31
32 #[serde(rename = "Port")]
33 pub port: String,
34
35 #[serde(rename = "CidrBlock")]
36 pub cidr_block: String,
37
38 #[serde(rename = "Action")]
39 pub action: String,
40
41 #[serde(rename = "FirewallRuleDescription")]
42 pub firewall_rule_description: String,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
46struct DescribeFirewallRulesRequest {
47 #[serde(rename = "InstanceId")]
48 instance_id: String,
49 #[serde(rename = "Offset")]
50 offset: i32,
51 #[serde(rename = "Limit")]
52 limit: i32,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct DescribeFirewallRulesResponse {
57 #[serde(rename = "FirewallRuleSet")]
58 pub firewall_rule_set: Vec<FirewallRuleInfo>,
59 #[serde(rename = "FirewallVersion")]
60 pub firewall_version: i32,
61 #[serde(rename = "TotalCount")]
62 pub total_count: i32,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
66struct ModifyFirewallRulesRequest {
67 #[serde(rename = "InstanceId")]
68 instance_id: String,
69 #[serde(rename = "FirewallRules")]
70 firewall_rules: Vec<FirewallRuleInfo>,
71}
72
73pub async fn go(
113 client: &Client,
114 instance: impl Borrow<Instance>,
115 secret: impl Borrow<Secret>,
116 current_ip: &str,
117 matched_descriptions: &[String],
118) -> Result<()> {
119 let response =
120 list_rules(client, instance.borrow(), secret.borrow()).await?;
121 let firewall_rules = &response.response.data.firewall_rule_set;
122 let (firewall_rules, require_update) =
123 compare_rules(firewall_rules, current_ip, matched_descriptions);
124 if require_update {
125 modify_rules(
126 client,
127 instance.borrow(),
128 secret.borrow(),
129 &firewall_rules,
130 )
131 .await?;
132 }
133 Ok(())
134}
135
136pub async fn list_rules(
141 client: &Client,
142 instance: impl Borrow<Instance>,
143 secret: impl Borrow<Secret>,
144) -> Result<CommonResponse<DescribeFirewallRulesResponse>> {
145 let instance = instance.borrow();
146
147 let request = DescribeFirewallRulesRequest {
148 instance_id: instance.id.clone(),
149 offset: 0,
150 limit: 100,
151 };
152 let payload = serde_json::to_string(&request)?;
153 let basic_request = BasicRequest {
154 machine_type: MachineType::Lighthouse,
155 action: "DescribeFirewallRules",
156 payload,
157 region: instance.region.clone(),
158 secret: secret.borrow(),
159 };
160 let request = request_builder(client, basic_request)?;
161 let result = client.execute(request).await?;
162 let result = result.text().await?;
163
164 parse_response::<CommonResponse<DescribeFirewallRulesResponse>>(&result)
165}
166
167pub fn compare_rules(
172 firewall_rules: &[FirewallRuleInfo],
173 current_ip: &str,
174 matched_descriptions: &[String],
175) -> (Vec<FirewallRuleInfo>, bool) {
176 let matched_set: HashSet<&str> =
177 matched_descriptions.iter().map(|s| s.as_str()).collect();
178
179 let mut require_update = false;
180 let modified_rules: Vec<FirewallRuleInfo> = firewall_rules
181 .iter()
182 .map(|rule| {
183 if matched_set.contains(rule.firewall_rule_description.as_str()) {
184 if rule.cidr_block != current_ip {
185 require_update = true;
186 FirewallRuleInfo {
187 cidr_block: current_ip.into(),
188 ..rule.clone()
189 }
190 } else {
191 rule.clone()
192 }
193 } else {
194 rule.clone()
195 }
196 })
197 .collect();
198
199 (modified_rules, require_update)
200}
201
202pub async fn modify_rules(
207 client: &Client,
208 instance: impl Borrow<Instance>,
209 secret: impl Borrow<Secret>,
210 firewall_rules: &[FirewallRuleInfo],
211) -> Result<CommonResponse<Empty>> {
212 let instance = instance.borrow();
213
214 let firewall_rules: Vec<FirewallRuleInfo> = firewall_rules
215 .iter()
216 .cloned()
217 .map(|mut rule| {
218 rule.app_type = None;
219 rule
220 })
221 .collect();
222
223 let request = ModifyFirewallRulesRequest {
224 instance_id: instance.id.clone(),
225 firewall_rules,
226 };
227
228 let payload = serde_json::to_string(&request)?;
229 let basic_request = BasicRequest {
230 machine_type: MachineType::Lighthouse,
231 action: "ModifyFirewallRules",
232 payload,
233 region: instance.region.clone(),
234 secret: secret.borrow(),
235 };
236
237 let request = request_builder(client, basic_request)?;
238 let result = client.execute(request).await?;
239 let result = result.text().await?;
240
241 parse_response::<CommonResponse<Empty>>(&result)
242}