use crate::service::{invalid_param, missing_param};
use fakecloud_core::service::{AwsRequest, AwsServiceError};
struct OpConstraints {
required: &'static [&'static str],
required_present: &'static [&'static str],
strings: &'static [(&'static str, u64, u64)],
enums: &'static [(&'static str, &'static [&'static str])],
ranges: &'static [(&'static str, i64, i64)],
}
pub(crate) fn prevalidate(action: &str, req: &AwsRequest) -> Result<(), AwsServiceError> {
let Some(spec) = lookup(action) else {
return Ok(());
};
for name in spec.required {
match req.query_params.get(*name) {
Some(value) if !value.is_empty() => {}
_ => {
let prefix = format!("{name}.");
let has_list_member = req.query_params.keys().any(|k| k.starts_with(&prefix));
if !has_list_member {
return Err(missing_param(name));
}
}
}
}
for name in spec.required_present {
if !req.query_params.contains_key(*name) {
let prefix = format!("{name}.");
let has_list_member = req.query_params.keys().any(|k| k.starts_with(&prefix));
if !has_list_member {
return Err(missing_param(name));
}
}
}
for (name, min, max) in spec.strings {
if let Some(value) = req.query_params.get(*name) {
if value.is_empty() && *min == 0 {
continue;
}
let len = value.chars().count() as u64;
if len < *min || len > *max {
return Err(invalid_param(&format!(
"{name} length {len} is outside the valid range {min}-{max}",
)));
}
}
}
for (name, allowed) in spec.enums {
if let Some(value) = req.query_params.get(*name) {
if value.is_empty() {
continue;
}
if !allowed.iter().any(|a| *a == value) {
return Err(invalid_param(&format!(
"{name} value '{value}' is not one of the supported enum values",
)));
}
}
}
for (name, lo, hi) in spec.ranges {
if let Some(value) = req.query_params.get(*name) {
if value.is_empty() {
continue;
}
match value.parse::<i64>() {
Ok(parsed) if parsed >= *lo && parsed <= *hi => {}
Ok(parsed) => {
return Err(invalid_param(&format!(
"{name} value {parsed} is outside the valid range {lo}-{hi}",
)));
}
Err(_) => {
return Err(invalid_param(&format!(
"{name} value '{value}' is not a valid integer",
)));
}
}
}
}
Ok(())
}
fn lookup(action: &str) -> Option<OpConstraints> {
Some(match action {
"AddRoleToDBCluster" => OpConstraints {
required: &["DBClusterIdentifier", "RoleArn"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"AddRoleToDBInstance" => OpConstraints {
required: &["DBInstanceIdentifier", "RoleArn", "FeatureName"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"RemoveRoleFromDBCluster" => OpConstraints {
required: &["DBClusterIdentifier", "RoleArn"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"RemoveRoleFromDBInstance" => OpConstraints {
required: &["DBInstanceIdentifier", "RoleArn", "FeatureName"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"AddSourceIdentifierToSubscription" => OpConstraints {
required: &["SubscriptionName", "SourceIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"RemoveSourceIdentifierFromSubscription" => OpConstraints {
required: &["SubscriptionName", "SourceIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CancelExportTask" => OpConstraints {
required: &["ExportTaskIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CopyDBClusterParameterGroup" => OpConstraints {
required: &[
"SourceDBClusterParameterGroupIdentifier",
"TargetDBClusterParameterGroupIdentifier",
"TargetDBClusterParameterGroupDescription",
],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CopyDBParameterGroup" => OpConstraints {
required: &[
"SourceDBParameterGroupIdentifier",
"TargetDBParameterGroupIdentifier",
"TargetDBParameterGroupDescription",
],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CopyDBSnapshot" => OpConstraints {
required: &["SourceDBSnapshotIdentifier", "TargetDBSnapshotIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CopyOptionGroup" => OpConstraints {
required: &[
"SourceOptionGroupIdentifier",
"TargetOptionGroupIdentifier",
"TargetOptionGroupDescription",
],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CreateCustomDBEngineVersion" => OpConstraints {
required: &["Engine", "EngineVersion"],
required_present: &[],
strings: &[
("DatabaseInstallationFilesS3BucketName", 3, 63),
("DatabaseInstallationFilesS3Prefix", 1, 255),
("Description", 1, 1000),
("Engine", 1, 35),
("EngineVersion", 1, 60),
("ImageId", 1, 255),
("KMSKeyId", 1, 2048),
("Manifest", 1, 51000),
("SourceCustomDbEngineVersionIdentifier", 1, 255),
],
enums: &[],
ranges: &[],
},
"CreateDBCluster" => OpConstraints {
required: &["DBClusterIdentifier", "Engine"],
required_present: &[],
strings: &[("GlobalClusterIdentifier", 1, 255)],
enums: &[
("ClusterScalabilityType", &["standard", "limitless"]),
("DatabaseInsightsMode", &["standard", "advanced"]),
("MasterUserAuthenticationType", &["password", "iam-db-auth"]),
],
ranges: &[],
},
"CreateDBClusterEndpoint" => OpConstraints {
required: &[
"DBClusterIdentifier",
"DBClusterEndpointIdentifier",
"EndpointType",
],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CreateDBClusterParameterGroup" => OpConstraints {
required: &[
"DBClusterParameterGroupName",
"DBParameterGroupFamily",
"Description",
],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CreateDBProxy" => OpConstraints {
required: &["DBProxyName", "EngineFamily", "RoleArn"],
required_present: &[],
strings: &[("DBProxyName", 1, 63), ("RoleArn", 20, 2048)],
enums: &[
("EngineFamily", &["MYSQL", "POSTGRESQL", "SQLSERVER"]),
("DefaultAuthScheme", &["IAM_AUTH", "NONE"]),
("EndpointNetworkType", &["IPV4", "IPV6", "DUAL"]),
("TargetConnectionNetworkType", &["IPV4", "IPV6"]),
],
ranges: &[],
},
"CreateDBProxyEndpoint" => OpConstraints {
required: &["DBProxyName", "DBProxyEndpointName"],
required_present: &[],
strings: &[("DBProxyName", 1, 63), ("DBProxyEndpointName", 1, 63)],
enums: &[
("EndpointNetworkType", &["IPV4", "IPV6", "DUAL"]),
("TargetRole", &["READ_WRITE", "READ_ONLY", "UNKNOWN"]),
],
ranges: &[],
},
"DeleteDBProxy" => OpConstraints {
required: &["DBProxyName"],
required_present: &[],
strings: &[("DBProxyName", 1, 63)],
enums: &[],
ranges: &[],
},
"DeleteDBProxyEndpoint" => OpConstraints {
required: &["DBProxyEndpointName"],
required_present: &[],
strings: &[("DBProxyEndpointName", 1, 63)],
enums: &[],
ranges: &[],
},
"DescribeDBProxies" => OpConstraints {
required: &[],
required_present: &[],
strings: &[("DBProxyName", 1, 63)],
enums: &[],
ranges: &[("MaxRecords", 20, 100)],
},
"DescribeDBProxyEndpoints" => OpConstraints {
required: &[],
required_present: &[],
strings: &[("DBProxyName", 1, 63), ("DBProxyEndpointName", 1, 63)],
enums: &[],
ranges: &[("MaxRecords", 20, 100)],
},
"DescribeDBProxyTargets" => OpConstraints {
required: &["DBProxyName"],
required_present: &[],
strings: &[("DBProxyName", 1, 63), ("TargetGroupName", 1, 63)],
enums: &[],
ranges: &[("MaxRecords", 20, 100)],
},
"DescribeDBProxyTargetGroups" => OpConstraints {
required: &["DBProxyName"],
required_present: &[],
strings: &[("DBProxyName", 1, 63), ("TargetGroupName", 1, 63)],
enums: &[],
ranges: &[("MaxRecords", 20, 100)],
},
"RegisterDBProxyTargets" => OpConstraints {
required: &["DBProxyName"],
required_present: &[],
strings: &[("DBProxyName", 1, 63), ("TargetGroupName", 1, 63)],
enums: &[],
ranges: &[],
},
"DeregisterDBProxyTargets" => OpConstraints {
required: &["DBProxyName"],
required_present: &[],
strings: &[("DBProxyName", 1, 63), ("TargetGroupName", 1, 63)],
enums: &[],
ranges: &[],
},
"ModifyDBProxyTargetGroup" => OpConstraints {
required: &["TargetGroupName", "DBProxyName"],
required_present: &[],
strings: &[("DBProxyName", 1, 63), ("TargetGroupName", 1, 63)],
enums: &[],
ranges: &[],
},
"CreateDBSecurityGroup" => OpConstraints {
required: &["DBSecurityGroupName", "DBSecurityGroupDescription"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CreateDBShardGroup" => OpConstraints {
required: &["DBShardGroupIdentifier", "DBClusterIdentifier", "MaxACU"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DeleteDBShardGroup" => OpConstraints {
required: &["DBShardGroupIdentifier"],
required_present: &[],
strings: &[("DBShardGroupIdentifier", 1, 63)],
enums: &[],
ranges: &[],
},
"ModifyDBShardGroup" => OpConstraints {
required: &["DBShardGroupIdentifier"],
required_present: &[],
strings: &[("DBShardGroupIdentifier", 1, 63)],
enums: &[],
ranges: &[],
},
"RebootDBShardGroup" => OpConstraints {
required: &["DBShardGroupIdentifier"],
required_present: &[],
strings: &[("DBShardGroupIdentifier", 1, 63)],
enums: &[],
ranges: &[],
},
"DescribeDBShardGroups" => OpConstraints {
required: &[],
required_present: &[],
strings: &[("DBShardGroupIdentifier", 1, 63)],
enums: &[],
ranges: &[("MaxRecords", 20, 100)],
},
"CreateEventSubscription" => OpConstraints {
required: &["SubscriptionName", "SnsTopicArn"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CreateGlobalCluster" => OpConstraints {
required: &[],
required_present: &[],
strings: &[("GlobalClusterIdentifier", 1, 255)],
enums: &[],
ranges: &[],
},
"DeleteGlobalCluster" => OpConstraints {
required: &["GlobalClusterIdentifier"],
required_present: &[],
strings: &[("GlobalClusterIdentifier", 1, 255)],
enums: &[],
ranges: &[],
},
"ModifyGlobalCluster" => OpConstraints {
required: &["GlobalClusterIdentifier"],
required_present: &[],
strings: &[
("GlobalClusterIdentifier", 1, 255),
("NewGlobalClusterIdentifier", 1, 255),
],
enums: &[],
ranges: &[],
},
"RemoveFromGlobalCluster" => OpConstraints {
required: &["GlobalClusterIdentifier", "DbClusterIdentifier"],
required_present: &[],
strings: &[("GlobalClusterIdentifier", 1, 255)],
enums: &[],
ranges: &[],
},
"FailoverGlobalCluster" => OpConstraints {
required: &["GlobalClusterIdentifier", "TargetDbClusterIdentifier"],
required_present: &[],
strings: &[
("GlobalClusterIdentifier", 1, 255),
("TargetDbClusterIdentifier", 1, 255),
],
enums: &[],
ranges: &[],
},
"SwitchoverGlobalCluster" => OpConstraints {
required: &["GlobalClusterIdentifier", "TargetDbClusterIdentifier"],
required_present: &[],
strings: &[
("GlobalClusterIdentifier", 1, 255),
("TargetDbClusterIdentifier", 1, 255),
],
enums: &[],
ranges: &[],
},
"DescribeGlobalClusters" => OpConstraints {
required: &[],
required_present: &[],
strings: &[("GlobalClusterIdentifier", 1, 255)],
enums: &[],
ranges: &[],
},
"CreateIntegration" => OpConstraints {
required: &["SourceArn", "TargetArn", "IntegrationName"],
required_present: &[],
strings: &[
("DataFilter", 1, 25600),
("Description", 0, 1000),
("IntegrationName", 1, 63),
("SourceArn", 1, 255),
("TargetArn", 20, 2048),
],
enums: &[],
ranges: &[],
},
"DeleteIntegration" => OpConstraints {
required: &["IntegrationIdentifier"],
required_present: &[],
strings: &[("IntegrationIdentifier", 1, 255)],
enums: &[],
ranges: &[],
},
"ModifyIntegration" => OpConstraints {
required: &["IntegrationIdentifier"],
required_present: &[],
strings: &[
("IntegrationIdentifier", 1, 255),
("IntegrationName", 1, 63),
("DataFilter", 1, 25600),
("Description", 0, 1000),
],
enums: &[],
ranges: &[],
},
"CreateOptionGroup" => OpConstraints {
required: &[
"OptionGroupName",
"EngineName",
"MajorEngineVersion",
"OptionGroupDescription",
],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"CreateTenantDatabase" => OpConstraints {
required: &["DBInstanceIdentifier", "TenantDBName", "MasterUsername"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DeleteTenantDatabase" => OpConstraints {
required: &["DBInstanceIdentifier", "TenantDBName"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DeleteCustomDBEngineVersion" => OpConstraints {
required: &["Engine", "EngineVersion"],
required_present: &[],
strings: &[("Engine", 1, 35), ("EngineVersion", 1, 60)],
enums: &[],
ranges: &[],
},
"ModifyCustomDBEngineVersion" => OpConstraints {
required: &["Engine", "EngineVersion"],
required_present: &[],
strings: &[
("Engine", 1, 35),
("EngineVersion", 1, 60),
("Description", 1, 1000),
],
enums: &[(
"Status",
&["available", "inactive", "inactive-except-restore"],
)],
ranges: &[],
},
"DeleteDBClusterAutomatedBackup" => OpConstraints {
required: &["DbClusterResourceId"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DescribeDBClusterBacktracks" => OpConstraints {
required: &["DBClusterIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DescribeDBClusterSnapshotAttributes" => OpConstraints {
required: &["DBClusterSnapshotIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DescribeDBSnapshotAttributes" => OpConstraints {
required: &["DBSnapshotIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"ModifyDBClusterSnapshotAttribute" => OpConstraints {
required: &["DBClusterSnapshotIdentifier", "AttributeName"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"ModifyDBSnapshotAttribute" => OpConstraints {
required: &["DBSnapshotIdentifier", "AttributeName"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"ModifyDBClusterParameterGroup" => OpConstraints {
required: &["DBClusterParameterGroupName"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"ModifyCurrentDBClusterCapacity" => OpConstraints {
required: &["DBClusterIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"ModifyDBRecommendation" => OpConstraints {
required: &["RecommendationId"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"ModifyDBSnapshot" => OpConstraints {
required: &["DBSnapshotIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DescribeDBMajorEngineVersions" => OpConstraints {
required: &[],
required_present: &[],
strings: &[
("Engine", 1, 50),
("MajorEngineVersion", 1, 50),
("Marker", 1, 340),
],
enums: &[],
ranges: &[("MaxRecords", 20, 100)],
},
"DescribeBlueGreenDeployments" => OpConstraints {
required: &[],
required_present: &[],
strings: &[("BlueGreenDeploymentIdentifier", 1, 255)],
enums: &[],
ranges: &[("MaxRecords", 20, 100)],
},
"DescribeExportTasks" => OpConstraints {
required: &[],
required_present: &[],
strings: &[],
enums: &[("SourceType", &["SNAPSHOT", "CLUSTER"])],
ranges: &[("MaxRecords", 20, 100)],
},
"DescribeIntegrations" => OpConstraints {
required: &[],
required_present: &[],
strings: &[("IntegrationIdentifier", 1, 255), ("Marker", 1, 340)],
enums: &[],
ranges: &[],
},
"DescribeOptionGroupOptions" => OpConstraints {
required: &["EngineName"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DescribeOrderableDBInstanceOptions" => OpConstraints {
required: &["Engine"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DescribeValidDBInstanceModifications" => OpConstraints {
required: &["DBInstanceIdentifier"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DescribeEngineDefaultClusterParameters" => OpConstraints {
required: &["DBParameterGroupFamily"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DescribeEngineDefaultParameters" => OpConstraints {
required: &["DBParameterGroupFamily"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"DisableHttpEndpoint" => OpConstraints {
required: &["ResourceArn"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"EnableHttpEndpoint" => OpConstraints {
required: &["ResourceArn"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"PurchaseReservedDBInstancesOffering" => OpConstraints {
required: &[],
required_present: &["ReservedDBInstancesOfferingId"],
strings: &[],
enums: &[],
ranges: &[],
},
"RestoreDBClusterFromS3" => OpConstraints {
required: &[
"DBClusterIdentifier",
"Engine",
"MasterUsername",
"S3BucketName",
"S3IngestionRoleArn",
"SourceEngine",
"SourceEngineVersion",
],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"StartActivityStream" => OpConstraints {
required: &["ResourceArn", "KmsKeyId", "Mode"],
required_present: &[],
strings: &[],
enums: &[("Mode", &["sync", "async"])],
ranges: &[],
},
"StopActivityStream" => OpConstraints {
required: &["ResourceArn"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"ModifyActivityStream" => OpConstraints {
required: &[],
required_present: &[],
strings: &[],
enums: &[("AuditPolicyState", &["locked", "unlocked"])],
ranges: &[],
},
"StartDBInstanceAutomatedBackupsReplication" => OpConstraints {
required: &["SourceDBInstanceArn"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"StopDBInstanceAutomatedBackupsReplication" => OpConstraints {
required: &["SourceDBInstanceArn"],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
"StartExportTask" => OpConstraints {
required: &[
"ExportTaskIdentifier",
"SourceArn",
"S3BucketName",
"IamRoleArn",
"KmsKeyId",
],
required_present: &[],
strings: &[],
enums: &[],
ranges: &[],
},
_ => return None,
})
}