use crate::error::Error;
use crate::types::*;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
pub struct FakeCloud {
base_url: String,
client: reqwest::Client,
}
impl FakeCloud {
pub fn new(base_url: &str) -> Self {
Self {
base_url: base_url.trim_end_matches('/').to_string(),
client: reqwest::Client::new(),
}
}
pub async fn health(&self) -> Result<HealthResponse, Error> {
let resp = self
.client
.get(format!("{}/_fakecloud/health", self.base_url))
.send()
.await?;
Self::parse(resp).await
}
pub async fn reset(&self) -> Result<ResetResponse, Error> {
let resp = self
.client
.post(format!("{}/_reset", self.base_url))
.send()
.await?;
Self::parse(resp).await
}
pub async fn create_admin(
&self,
account_id: &str,
user_name: &str,
) -> Result<CreateAdminResponse, Error> {
let resp = self
.client
.post(format!("{}/_fakecloud/iam/create-admin", self.base_url))
.json(&CreateAdminRequest {
account_id: account_id.to_string(),
user_name: user_name.to_string(),
})
.send()
.await?;
Self::parse(resp).await
}
pub async fn reset_service(&self, service: &str) -> Result<ResetServiceResponse, Error> {
let resp = self
.client
.post(format!("{}/_fakecloud/reset/{}", self.base_url, service))
.send()
.await?;
Self::parse(resp).await
}
pub async fn reset_service_for_account(
&self,
service: &str,
account_id: &str,
) -> Result<ResetServiceResponse, Error> {
let resp = self
.client
.post(format!(
"{}/_fakecloud/reset/{}/{}",
self.base_url, service, account_id
))
.send()
.await?;
Self::parse(resp).await
}
pub fn lambda(&self) -> LambdaClient<'_> {
LambdaClient { fc: self }
}
pub fn ses(&self) -> SesClient<'_> {
SesClient { fc: self }
}
pub fn sns(&self) -> SnsClient<'_> {
SnsClient { fc: self }
}
pub fn sqs(&self) -> SqsClient<'_> {
SqsClient { fc: self }
}
pub fn events(&self) -> EventsClient<'_> {
EventsClient { fc: self }
}
pub fn s3(&self) -> S3Client<'_> {
S3Client { fc: self }
}
pub fn dynamodb(&self) -> DynamoDbClient<'_> {
DynamoDbClient { fc: self }
}
pub fn secretsmanager(&self) -> SecretsManagerClient<'_> {
SecretsManagerClient { fc: self }
}
pub fn cognito(&self) -> CognitoClient<'_> {
CognitoClient { fc: self }
}
pub fn rds(&self) -> RdsClient<'_> {
RdsClient { fc: self }
}
pub fn ec2(&self) -> Ec2Client<'_> {
Ec2Client { fc: self }
}
pub fn elasticache(&self) -> ElastiCacheClient<'_> {
ElastiCacheClient { fc: self }
}
pub fn apigatewayv2(&self) -> ApiGatewayV2Client<'_> {
ApiGatewayV2Client { fc: self }
}
pub fn stepfunctions(&self) -> StepFunctionsClient<'_> {
StepFunctionsClient { fc: self }
}
pub fn bedrock(&self) -> BedrockClient<'_> {
BedrockClient { fc: self }
}
pub fn bedrock_agent(&self) -> BedrockAgentClient<'_> {
BedrockAgentClient { fc: self }
}
pub fn bedrock_agent_runtime(&self) -> BedrockAgentRuntimeClient<'_> {
BedrockAgentRuntimeClient { fc: self }
}
pub fn ecs(&self) -> EcsClient<'_> {
EcsClient { fc: self }
}
pub fn application_autoscaling(&self) -> ApplicationAutoScalingClient<'_> {
ApplicationAutoScalingClient { fc: self }
}
pub fn athena(&self) -> AthenaClient<'_> {
AthenaClient { fc: self }
}
pub fn organizations(&self) -> OrganizationsClient<'_> {
OrganizationsClient { fc: self }
}
pub fn acm(&self) -> AcmClient<'_> {
AcmClient { fc: self }
}
pub fn ecr(&self) -> EcrClient<'_> {
EcrClient { fc: self }
}
pub fn elbv2(&self) -> Elbv2Client<'_> {
Elbv2Client { fc: self }
}
pub fn glue(&self) -> GlueClient<'_> {
GlueClient { fc: self }
}
pub fn cloudwatch(&self) -> CloudWatchClient<'_> {
CloudWatchClient { fc: self }
}
pub fn firehose(&self) -> FirehoseClient<'_> {
FirehoseClient { fc: self }
}
pub fn logs(&self) -> LogsClient<'_> {
LogsClient { fc: self }
}
pub fn route53(&self) -> Route53Client<'_> {
Route53Client { fc: self }
}
pub fn scheduler(&self) -> SchedulerClient<'_> {
SchedulerClient { fc: self }
}
pub fn ssm(&self) -> SsmClient<'_> {
SsmClient { fc: self }
}
pub fn kms(&self) -> KmsClient<'_> {
KmsClient { fc: self }
}
pub fn wafv2(&self) -> WafV2Client<'_> {
WafV2Client { fc: self }
}
pub fn cloudfront(&self) -> CloudFrontClient<'_> {
CloudFrontClient { fc: self }
}
async fn parse<T: serde::de::DeserializeOwned>(resp: reqwest::Response) -> Result<T, Error> {
let status = resp.status().as_u16();
if !resp.status().is_success() {
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api { status, body });
}
Ok(resp.json::<T>().await?)
}
}
pub struct Ec2Client<'a> {
fc: &'a FakeCloud,
}
impl Ec2Client<'_> {
pub async fn get_instances(&self) -> Result<Ec2InstancesResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/ec2/instances", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_instance_networks(&self) -> Result<Ec2InstanceNetworksResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ec2/instance-networks",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct RdsClient<'a> {
fc: &'a FakeCloud,
}
impl RdsClient<'_> {
pub async fn get_instances(&self) -> Result<RdsInstancesResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/rds/instances", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn lambda_invoke(
&self,
req: &RdsLambdaInvokeRequest,
) -> Result<RdsLambdaInvokeResponse, Error> {
let resp = self
.fc
.client
.post(format!("{}/_fakecloud/rds/lambda-invoke", self.fc.base_url))
.json(req)
.send()
.await?;
let status = resp.status().as_u16();
if status == 502 || resp.status().is_success() {
return Ok(resp.json::<RdsLambdaInvokeResponse>().await?);
}
let body = resp.text().await.unwrap_or_default();
Err(Error::Api { status, body })
}
pub async fn s3_import(&self, req: &RdsS3ImportRequest) -> Result<RdsS3ImportResponse, Error> {
let resp = self
.fc
.client
.post(format!("{}/_fakecloud/rds/s3-import", self.fc.base_url))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn s3_export(&self, req: &RdsS3ExportRequest) -> Result<RdsS3ExportResponse, Error> {
let resp = self
.fc
.client
.post(format!("{}/_fakecloud/rds/s3-export", self.fc.base_url))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct ElastiCacheClient<'a> {
fc: &'a FakeCloud,
}
impl ElastiCacheClient<'_> {
pub async fn get_clusters(&self) -> Result<ElastiCacheClustersResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/elasticache/clusters",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_replication_groups(
&self,
) -> Result<ElastiCacheReplicationGroupsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/elasticache/replication-groups",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_serverless_caches(
&self,
) -> Result<ElastiCacheServerlessCachesResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/elasticache/serverless-caches",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_acls(&self) -> Result<ElastiCacheAclsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/elasticache/acls", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct LambdaClient<'a> {
fc: &'a FakeCloud,
}
impl LambdaClient<'_> {
pub async fn get_invocations(&self) -> Result<LambdaInvocationsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/lambda/invocations",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_warm_containers(&self) -> Result<WarmContainersResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/lambda/warm-containers",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn evict_container(
&self,
function_name: &str,
) -> Result<EvictContainerResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/lambda/{}/evict-container",
self.fc.base_url, function_name
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn download_function_code(
&self,
account_id: &str,
function_name: &str,
qualifier_or_latest: &str,
) -> Result<Vec<u8>, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/lambda/function-code/{}/{}/{}.zip",
self.fc.base_url, account_id, function_name, qualifier_or_latest
))
.send()
.await?;
let status = resp.status().as_u16();
if !resp.status().is_success() {
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api { status, body });
}
Ok(resp.bytes().await?.to_vec())
}
pub async fn download_layer_content(
&self,
account_id: &str,
layer_name: &str,
version: i64,
) -> Result<Vec<u8>, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/lambda/layer-content/{}/{}/{}.zip",
self.fc.base_url, account_id, layer_name, version
))
.send()
.await?;
let status = resp.status().as_u16();
if !resp.status().is_success() {
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api { status, body });
}
Ok(resp.bytes().await?.to_vec())
}
}
pub struct SesClient<'a> {
fc: &'a FakeCloud,
}
impl SesClient<'_> {
pub async fn get_emails(&self) -> Result<SesEmailsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/ses/emails", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn simulate_inbound(
&self,
req: &InboundEmailRequest,
) -> Result<InboundEmailResponse, Error> {
let resp = self
.fc
.client
.post(format!("{}/_fakecloud/ses/inbound", self.fc.base_url))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_metrics(&self) -> Result<SesMetricsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/ses/metrics", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_bounces(&self) -> Result<SesBouncesResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/ses/bounces", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn set_sandbox(&self, sandbox: bool) -> Result<SesSandboxResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/ses/account/sandbox",
self.fc.base_url
))
.json(&SesSandboxRequest { sandbox })
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_event_destination_deliveries(
&self,
) -> Result<SesEventDestinationDeliveriesResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ses/event-destinations/deliveries",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_dkim_public_key(
&self,
identity: &str,
) -> Result<SesDkimPublicKeyResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ses/identities/{}/dkim-public-key",
self.fc.base_url, identity
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn set_mail_from_status(
&self,
identity: &str,
status: &str,
) -> Result<SesMailFromStatusResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/ses/identities/{}/mail-from-status",
self.fc.base_url, identity
))
.json(&SesMailFromStatusRequest {
status: status.to_string(),
})
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_message_insights(
&self,
message_id: &str,
) -> Result<SesMessageInsightsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ses/messages/{}/insights",
self.fc.base_url, message_id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_smtp_submissions(&self) -> Result<SesSmtpSubmissionsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ses/smtp/submissions",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct SnsClient<'a> {
fc: &'a FakeCloud,
}
impl SnsClient<'_> {
pub async fn get_messages(&self) -> Result<SnsMessagesResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/sns/messages", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_pending_confirmations(&self) -> Result<PendingConfirmationsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/sns/pending-confirmations",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn confirm_subscription(
&self,
req: &ConfirmSubscriptionRequest,
) -> Result<ConfirmSubscriptionResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/sns/confirm-subscription",
self.fc.base_url
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn cert_pem(&self) -> Result<String, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/sns/cert.pem", self.fc.base_url))
.send()
.await?;
let status = resp.status().as_u16();
if !resp.status().is_success() {
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api { status, body });
}
Ok(resp.text().await?)
}
pub async fn sms(&self) -> Result<SnsSmsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/sns/sms", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct SqsClient<'a> {
fc: &'a FakeCloud,
}
impl SqsClient<'_> {
pub async fn get_messages(&self) -> Result<SqsMessagesResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/sqs/messages", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn tick_expiration(&self) -> Result<ExpirationTickResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/sqs/expiration-processor/tick",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn force_dlq(&self, queue_name: &str) -> Result<ForceDlqResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/sqs/{}/force-dlq",
self.fc.base_url, queue_name
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct ApplicationAutoScalingClient<'a> {
fc: &'a FakeCloud,
}
impl ApplicationAutoScalingClient<'_> {
pub async fn tick(&self) -> Result<AppAsTickResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/application-autoscaling/tick",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn scheduled_tick(&self) -> Result<AppAsScheduledTickResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/application-autoscaling/scheduled-tick",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct EventsClient<'a> {
fc: &'a FakeCloud,
}
impl EventsClient<'_> {
pub async fn get_history(&self) -> Result<EventHistoryResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/events/history", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn fire_rule(&self, req: &FireRuleRequest) -> Result<FireRuleResponse, Error> {
let resp = self
.fc
.client
.post(format!("{}/_fakecloud/events/fire-rule", self.fc.base_url))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct S3Client<'a> {
fc: &'a FakeCloud,
}
impl S3Client<'_> {
pub async fn get_notifications(&self) -> Result<S3NotificationsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/s3/notifications", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn tick_lifecycle(&self) -> Result<LifecycleTickResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/s3/lifecycle-processor/tick",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_access_points(&self) -> Result<S3AccessPointsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/s3/access-points", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_object_lambda_responses(
&self,
) -> Result<S3ObjectLambdaResponsesResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/s3/object-lambda-responses",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct DynamoDbClient<'a> {
fc: &'a FakeCloud,
}
impl DynamoDbClient<'_> {
pub async fn tick_ttl(&self) -> Result<TtlTickResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/dynamodb/ttl-processor/tick",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct SecretsManagerClient<'a> {
fc: &'a FakeCloud,
}
impl SecretsManagerClient<'_> {
pub async fn tick_rotation(&self) -> Result<RotationTickResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/secretsmanager/rotation-scheduler/tick",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct CognitoClient<'a> {
fc: &'a FakeCloud,
}
impl CognitoClient<'_> {
pub async fn get_user_codes(
&self,
pool_id: &str,
username: &str,
) -> Result<UserConfirmationCodes, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/cognito/confirmation-codes/{}/{}",
self.fc.base_url, pool_id, username
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_confirmation_codes(&self) -> Result<ConfirmationCodesResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/cognito/confirmation-codes",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn confirm_user(
&self,
req: &ConfirmUserRequest,
) -> Result<ConfirmUserResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/cognito/confirm-user",
self.fc.base_url
))
.json(req)
.send()
.await?;
let status = resp.status().as_u16();
let body: ConfirmUserResponse = resp.json().await?;
if status >= 400 {
return Err(Error::Api {
status,
body: body.error.unwrap_or_default(),
});
}
Ok(body)
}
pub async fn get_tokens(&self) -> Result<TokensResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/cognito/tokens", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn expire_tokens(
&self,
req: &ExpireTokensRequest,
) -> Result<ExpireTokensResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/cognito/expire-tokens",
self.fc.base_url
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_auth_events(&self) -> Result<AuthEventsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/cognito/auth-events",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_pre_token_gen_invocations(
&self,
) -> Result<PreTokenGenInvocationsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/cognito/pretokengen/invocations",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn mint_authorization_code(
&self,
req: &MintAuthorizationCodeRequest,
) -> Result<MintAuthorizationCodeResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/cognito/authorization-codes",
self.fc.base_url
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn set_compromised_passwords(
&self,
req: &CognitoCompromisedPasswordsRequest,
) -> Result<CompromisedPasswordsResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/cognito/compromised-passwords",
self.fc.base_url
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_webauthn_credentials(&self) -> Result<WebAuthnCredentialsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/cognito/webauthn-credentials",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct ApiGatewayV2Client<'a> {
fc: &'a FakeCloud,
}
impl ApiGatewayV2Client<'_> {
pub async fn get_requests(&self) -> Result<ApiGatewayV2RequestsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/apigatewayv2/requests",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn connections(&self) -> Result<ApiGatewayV2ConnectionsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/apigatewayv2/connections",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn mtls_info(&self, name: &str) -> Result<serde_json::Value, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/apigatewayv2/domain-names/{}/mtls-info",
self.fc.base_url, name
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub fn ws_url(&self, api_id: &str, stage: Option<&str>) -> String {
let base = self
.fc
.base_url
.replacen("https://", "wss://", 1)
.replacen("http://", "ws://", 1);
let url = reqwest::Url::parse(&format!("{}/_fakecloud/apigatewayv2/ws/{}", base, api_id))
.expect("base url + api id form a valid URL");
match stage {
Some(s) => {
let mut u = url;
u.query_pairs_mut().append_pair("stage", s);
u.to_string()
}
None => url.to_string(),
}
}
}
pub struct StepFunctionsClient<'a> {
fc: &'a FakeCloud,
}
impl StepFunctionsClient<'_> {
pub async fn get_executions(&self) -> Result<StepFunctionsExecutionsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/stepfunctions/executions",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_sync_executions(&self) -> Result<StepFunctionsSyncExecutionsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/stepfunctions/sync-executions",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn enqueue_activity_task(
&self,
req: &SfnEnqueueActivityTaskRequest,
) -> Result<SfnEnqueueActivityTaskResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/stepfunctions/enqueue-activity-task",
self.fc.base_url
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_execution_tree(
&self,
execution_arn: &str,
) -> Result<StepFunctionsExecutionTreeResponse, Error> {
let mut encoded = String::with_capacity(execution_arn.len());
for b in execution_arn.bytes() {
match b {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
encoded.push(b as char);
}
_ => encoded.push_str(&format!("%{:02X}", b)),
}
}
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/stepfunctions/execution-tree/{}",
self.fc.base_url, encoded
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct BedrockClient<'a> {
fc: &'a FakeCloud,
}
impl BedrockClient<'_> {
pub async fn get_invocations(&self) -> Result<BedrockInvocationsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/bedrock/invocations",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn set_model_response(
&self,
model_id: &str,
response: &str,
) -> Result<BedrockModelResponseConfig, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/bedrock/models/{}/response",
self.fc.base_url, model_id
))
.header("content-type", "text/plain")
.body(response.to_string())
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn set_response_rules(
&self,
model_id: &str,
rules: &[BedrockResponseRule],
) -> Result<BedrockModelResponseConfig, Error> {
let body = serde_json::json!({ "rules": rules });
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/bedrock/models/{}/responses",
self.fc.base_url, model_id
))
.json(&body)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn clear_response_rules(
&self,
model_id: &str,
) -> Result<BedrockModelResponseConfig, Error> {
let resp = self
.fc
.client
.delete(format!(
"{}/_fakecloud/bedrock/models/{}/responses",
self.fc.base_url, model_id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn queue_fault(
&self,
rule: &BedrockFaultRule,
) -> Result<BedrockStatusResponse, Error> {
let resp = self
.fc
.client
.post(format!("{}/_fakecloud/bedrock/faults", self.fc.base_url))
.json(rule)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_faults(&self) -> Result<BedrockFaultsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/bedrock/faults", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn clear_faults(&self) -> Result<BedrockStatusResponse, Error> {
let resp = self
.fc
.client
.delete(format!("{}/_fakecloud/bedrock/faults", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct BedrockAgentClient<'a> {
fc: &'a FakeCloud,
}
impl BedrockAgentClient<'_> {
pub async fn get_agents(&self) -> Result<BedrockAgentAgentsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/bedrock-agent/agents",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct BedrockAgentRuntimeClient<'a> {
fc: &'a FakeCloud,
}
impl BedrockAgentRuntimeClient<'_> {
pub async fn get_invocations(&self) -> Result<BedrockAgentRuntimeInvocationsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/bedrock-agent-runtime/invocations",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct EcsClient<'a> {
fc: &'a FakeCloud,
}
impl EcsClient<'_> {
pub async fn get_clusters(&self) -> Result<EcsClustersResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/ecs/clusters", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_tasks(
&self,
cluster: Option<&str>,
status: Option<&str>,
) -> Result<EcsTasksResponse, Error> {
fn encode(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for b in s.bytes() {
match b {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
out.push(b as char);
}
_ => out.push_str(&format!("%{:02X}", b)),
}
}
out
}
let mut url = format!("{}/_fakecloud/ecs/tasks", self.fc.base_url);
let mut sep = '?';
if let Some(c) = cluster {
url.push(sep);
url.push_str("cluster=");
url.push_str(&encode(c));
sep = '&';
}
if let Some(s) = status {
url.push(sep);
url.push_str("status=");
url.push_str(&encode(s));
}
let resp = self.fc.client.get(url).send().await?;
FakeCloud::parse(resp).await
}
pub async fn get_task_logs(&self, task_id: &str) -> Result<EcsTaskLogsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ecs/tasks/{}/logs",
self.fc.base_url, task_id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn force_stop_task(&self, task_id: &str) -> Result<EcsTask, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/ecs/tasks/{}/force-stop",
self.fc.base_url, task_id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn mark_task_failed(
&self,
task_id: &str,
req: &EcsMarkFailedRequest,
) -> Result<EcsTask, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/ecs/tasks/{}/mark-failed",
self.fc.base_url, task_id
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_events(&self) -> Result<EcsEventsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/ecs/events", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_metadata_by_arn(&self, task_arn: &str) -> Result<serde_json::Value, Error> {
let mut encoded = String::with_capacity(task_arn.len());
for b in task_arn.bytes() {
match b {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
encoded.push(b as char);
}
_ => encoded.push_str(&format!("%{:02X}", b)),
}
}
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ecs/metadata/{}",
self.fc.base_url, encoded
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn task_credentials(
&self,
task_id: &str,
) -> Result<EcsTaskCredentialsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ecs/creds/{}",
self.fc.base_url, task_id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn task_metadata_v3(&self, task_id: &str) -> Result<serde_json::Value, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ecs/v3/{}",
self.fc.base_url, task_id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn task_metadata_v4(&self, task_id: &str) -> Result<serde_json::Value, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ecs/v4/{}",
self.fc.base_url, task_id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct Route53Client<'a> {
fc: &'a FakeCloud,
}
impl Route53Client<'_> {
pub async fn dnssec_material(
&self,
zone_id: &str,
) -> Result<Route53DnssecMaterialResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/route53/zones/{}/dnssec",
self.fc.base_url, zone_id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn dnssec_sign(
&self,
zone_id: &str,
req: &Route53DnssecSignRequest,
) -> Result<Route53DnssecSignResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/route53/zones/{}/dnssec/sign",
self.fc.base_url, zone_id
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct AthenaClient<'a> {
fc: &'a FakeCloud,
}
impl AthenaClient<'_> {
pub async fn get_named_queries(&self) -> Result<AthenaNamedQueriesResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/athena/named-queries",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct OrganizationsClient<'a> {
fc: &'a FakeCloud,
}
impl OrganizationsClient<'_> {
pub async fn get_accounts(&self) -> Result<OrganizationsAccountsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/organizations/accounts",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_responsibility_transfers(
&self,
) -> Result<OrganizationsResponsibilityTransfersResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/organizations/responsibility-transfers",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct AcmClient<'a> {
fc: &'a FakeCloud,
}
impl AcmClient<'_> {
fn certificate_id(arn_or_id: &str) -> String {
match arn_or_id.rfind("certificate/") {
Some(idx) => arn_or_id[idx + "certificate/".len()..].to_string(),
None => arn_or_id.to_string(),
}
}
pub async fn set_certificate_status(
&self,
arn_or_id: &str,
req: &AcmCertificateStatusRequest,
) -> Result<(), Error> {
let id = Self::certificate_id(arn_or_id);
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/acm/certificates/{}/status",
self.fc.base_url, id
))
.json(req)
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status().as_u16();
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api { status, body });
}
Ok(())
}
pub async fn get_certificate_chain_info(
&self,
arn_or_id: &str,
) -> Result<AcmCertificateChainInfo, Error> {
let id = Self::certificate_id(arn_or_id);
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/acm/certificates/{}/chain-info",
self.fc.base_url, id
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn approve_certificate(&self, arn_or_id: &str) -> Result<(), Error> {
let id = Self::certificate_id(arn_or_id);
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/acm/certificates/{}/approve",
self.fc.base_url, id
))
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status().as_u16();
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api { status, body });
}
Ok(())
}
}
pub struct EcrClient<'a> {
fc: &'a FakeCloud,
}
impl EcrClient<'_> {
pub async fn get_images(&self) -> Result<EcrImagesResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/ecr/images", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_repositories(&self) -> Result<EcrRepositoriesResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/ecr/repositories", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_pull_through_rules(&self) -> Result<EcrPullThroughRulesResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/ecr/pull-through-rules",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct Elbv2Client<'a> {
fc: &'a FakeCloud,
}
impl Elbv2Client<'_> {
pub async fn get_load_balancers(&self) -> Result<Elbv2LoadBalancersResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/elbv2/load-balancers",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_listeners(&self) -> Result<Elbv2ListenersResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/elbv2/listeners", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_rules(&self) -> Result<Elbv2RulesResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/elbv2/rules", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_target_groups(&self) -> Result<Elbv2TargetGroupsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/elbv2/target-groups",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn flush_access_logs(&self) -> Result<Elbv2AccessLogsFlushResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/elbv2/access-logs/flush",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct GlueClient<'a> {
fc: &'a FakeCloud,
}
impl GlueClient<'_> {
pub async fn get_jobs(&self) -> Result<GlueJobsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/glue/jobs", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_job_runs(&self, job_name: Option<&str>) -> Result<GlueJobRunsResponse, Error> {
fn encode(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for b in s.bytes() {
match b {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
out.push(b as char);
}
_ => out.push_str(&format!("%{:02X}", b)),
}
}
out
}
let mut url = format!("{}/_fakecloud/glue/job-runs", self.fc.base_url);
if let Some(name) = job_name {
url.push_str("?job_name=");
url.push_str(&encode(name));
}
let resp = self.fc.client.get(url).send().await?;
FakeCloud::parse(resp).await
}
pub async fn get_crawlers(&self) -> Result<GlueCrawlersResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/glue/crawlers", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct CloudWatchClient<'a> {
fc: &'a FakeCloud,
}
impl CloudWatchClient<'_> {
pub async fn get_alarms(&self) -> Result<CloudWatchAlarmsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/cloudwatch/alarms", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_metrics(&self) -> Result<CloudWatchMetricsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/cloudwatch/metrics",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct FirehoseClient<'a> {
fc: &'a FakeCloud,
}
impl FirehoseClient<'_> {
pub async fn get_delivery_streams(&self) -> Result<FirehoseDeliveryStreamsResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/firehose/delivery-streams",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct LogsClient<'a> {
fc: &'a FakeCloud,
}
impl LogsClient<'_> {
pub async fn inject_anomaly(
&self,
req: &LogsAnomalyInjectRequest,
) -> Result<LogsAnomalyInjectResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/logs/anomalies/inject",
self.fc.base_url
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_delivery_config(&self) -> Result<LogsDeliveryConfigResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/logs/delivery-config",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn get_field_indexes(
&self,
log_group_name: &str,
) -> Result<LogsFieldIndexesResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/logs/field-indexes/{}",
self.fc.base_url,
utf8_percent_encode(log_group_name, NON_ALPHANUMERIC)
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
impl Route53Client<'_> {
pub async fn set_health_check_status(
&self,
id: &str,
req: &Route53HealthCheckStatusRequest,
) -> Result<(), Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/route53/health-checks/{}/status",
self.fc.base_url, id
))
.json(req)
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status().as_u16();
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api { status, body });
}
Ok(())
}
}
pub struct SchedulerClient<'a> {
fc: &'a FakeCloud,
}
impl SchedulerClient<'_> {
pub async fn get_schedules(&self) -> Result<SchedulerSchedulesResponse, Error> {
let resp = self
.fc
.client
.get(format!(
"{}/_fakecloud/scheduler/schedules",
self.fc.base_url
))
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn fire_schedule(
&self,
group: &str,
name: &str,
) -> Result<FireScheduleResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/scheduler/fire/{}/{}",
self.fc.base_url, group, name
))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct SsmClient<'a> {
fc: &'a FakeCloud,
}
impl SsmClient<'_> {
pub async fn set_command_status(
&self,
command_id: &str,
req: &SetSsmCommandStatusRequest,
) -> Result<SetSsmCommandStatusResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/ssm/commands/{}/status",
self.fc.base_url, command_id
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
pub async fn fail_command(
&self,
command_id: &str,
req: Option<&FailSsmCommandRequest>,
) -> Result<FailSsmCommandResponse, Error> {
let mut builder = self.fc.client.post(format!(
"{}/_fakecloud/ssm/commands/{}/fail",
self.fc.base_url, command_id
));
if let Some(body) = req {
builder = builder.json(body);
}
let resp = builder.send().await?;
FakeCloud::parse(resp).await
}
pub async fn parameter_policy_events(
&self,
account_id: Option<&str>,
) -> Result<SsmParameterPolicyEventsResponse, Error> {
let mut url = format!(
"{}/_fakecloud/ssm/parameter-policy-events",
self.fc.base_url
);
if let Some(id) = account_id {
url.push_str("?accountId=");
url.push_str(id);
}
let resp = self.fc.client.get(url).send().await?;
FakeCloud::parse(resp).await
}
pub async fn inject_session(
&self,
req: &InjectSsmSessionRequest,
) -> Result<InjectSsmSessionResponse, Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/ssm/sessions/inject",
self.fc.base_url
))
.json(req)
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct KmsClient<'a> {
fc: &'a FakeCloud,
}
impl KmsClient<'_> {
pub async fn usage(&self) -> Result<KmsUsageResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/kms/usage", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct WafV2Client<'a> {
fc: &'a FakeCloud,
}
impl WafV2Client<'_> {
pub async fn evaluate(&self, body: &serde_json::Value) -> Result<serde_json::Value, Error> {
let resp = self
.fc
.client
.post(format!("{}/_fakecloud/wafv2/evaluate", self.fc.base_url))
.json(body)
.send()
.await?;
FakeCloud::parse(resp).await
}
}
pub struct CloudFrontClient<'a> {
fc: &'a FakeCloud,
}
impl CloudFrontClient<'_> {
pub async fn set_distribution_status(
&self,
distribution_id: &str,
req: &CloudFrontDistributionStatusRequest,
) -> Result<(), Error> {
let resp = self
.fc
.client
.post(format!(
"{}/_fakecloud/cloudfront/distributions/{}/status",
self.fc.base_url, distribution_id
))
.json(req)
.send()
.await?;
let status = resp.status().as_u16();
if !resp.status().is_success() {
let body = resp.text().await.unwrap_or_default();
return Err(Error::Api { status, body });
}
Ok(())
}
}
impl Elbv2Client<'_> {
pub async fn waf_counts(&self) -> Result<Elbv2WafCountsResponse, Error> {
let resp = self
.fc
.client
.get(format!("{}/_fakecloud/elbv2/waf-counts", self.fc.base_url))
.send()
.await?;
FakeCloud::parse(resp).await
}
}