diff --git a/src/adapters/ingresses/apig.rs b/src/adapters/ingresses/apig.rs index 3cba1c5..a4b20e0 100644 --- a/src/adapters/ingresses/apig.rs +++ b/src/adapters/ingresses/apig.rs @@ -1,9 +1,11 @@ use std::path::PathBuf; use crate::utils::load_default_aws_config; +use crate::WholePercent; use super::Ingress; use async_trait::async_trait; +use aws_sdk_apigateway::types::{Op, PatchOperation}; use miette::miette; use miette::{IntoDiagnostic, Result}; use tokio::{fs::File, io::AsyncReadExt}; @@ -73,7 +75,7 @@ impl AwsApiGateway { stage_name: &str, lambda_name: &str, lambda_version: &str, - traffic_percentage: f64, + traffic_percentage: WholePercent, ) -> Result<()> { // Update the APIG with the new lambda version self.apig_client @@ -94,8 +96,7 @@ impl AwsApiGateway { .stage_name(stage_name) .canary_settings( DeploymentCanarySettings::builder() - .percent_traffic(traffic_percentage) - .use_stage_cache(false) + .percent_traffic(traffic_percentage.into_inner() as f64) .build(), ) .send() @@ -104,6 +105,30 @@ impl AwsApiGateway { Ok(()) } + + pub async fn update_canary_traffic( + &self, + api_id: &str, + stage_name: &str, + traffic_percentage: WholePercent, + ) -> Result<()> { + let patch_op = PatchOperation::builder() + .op(Op::Replace) + .path("/canarySettings/percentTraffic") + .value(traffic_percentage.to_string()) + .build(); + + self.apig_client + .update_stage() + .rest_api_id(api_id) + .stage_name(stage_name) + .patch_operations(patch_op) + .send() + .await + .into_diagnostic()?; + + Ok(()) + } } /// given a path to a file, load it as an array of bytes. @@ -123,7 +148,20 @@ impl Ingress for AwsApiGateway { // Next, we need to create a new deployment, pointing at our // new lambda version with canary settings - self.create_apig_deployment("Releases", "prod", "releases", &lambda_version, 0.0) + self.create_apig_deployment( + "Releases", + "prod", + "releases", + &lambda_version, + WholePercent::try_new(0).into_diagnostic()?, + ) + .await?; + + Ok(()) + } + + async fn set_canary_traffic(&mut self, percent: WholePercent) -> Result<()> { + self.update_canary_traffic("Releases", "prod", percent) .await?; Ok(()) diff --git a/src/adapters/ingresses/mod.rs b/src/adapters/ingresses/mod.rs index ba015d8..d9a83bf 100644 --- a/src/adapters/ingresses/mod.rs +++ b/src/adapters/ingresses/mod.rs @@ -1,6 +1,8 @@ use async_trait::async_trait; use miette::Result; +use crate::WholePercent; + /// Ingresses are responsible for (1) controlling how much traffic the canary /// gets (hence the name ingress, since it functions like a virtual LB) and /// (2) deploying, yanking, and promoting both the canary and the baseline. @@ -12,7 +14,7 @@ pub trait Ingress { // TODO: define the other methods on this type. // async fn yank_canary(&mut self) -> Result<()>; // async fn promote_canary(&mut self) -> Result<()>; - // async fn set_canary_traffic(&mut self, percent: u8); + async fn set_canary_traffic(&mut self, percent: WholePercent) -> Result<()>; } pub struct MockIngress; @@ -22,6 +24,10 @@ impl Ingress for MockIngress { async fn deploy(&mut self) -> Result<()> { todo!() } + + async fn set_canary_traffic(&mut self, _percent: WholePercent) -> Result<()> { + todo!() + } } impl From for BoxIngress { diff --git a/src/lib.rs b/src/lib.rs index 74c79f8..5e6ccde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ pub use config::Flags; pub use pipeline::Pipeline; +pub(crate) use pipeline::WholePercent; /// An adapter connects to some observable resource (like `CloudWatch`) and /// emits events, like failed and succeeded requests. diff --git a/src/pipeline/mod.rs b/src/pipeline/mod.rs index 778f70b..3164aca 100644 --- a/src/pipeline/mod.rs +++ b/src/pipeline/mod.rs @@ -7,6 +7,8 @@ use crate::{ use bon::bon; use miette::Result; +pub(crate) use percent::WholePercent; + /// An alias for the Response Code-based monitor. pub type ResponseMonitor = Box>>; diff --git a/src/pipeline/percent.rs b/src/pipeline/percent.rs index c652d5a..109a631 100644 --- a/src/pipeline/percent.rs +++ b/src/pipeline/percent.rs @@ -22,11 +22,11 @@ impl DecimalPercent { validate(less_or_equal = 100), derive(Debug, Display, Copy, Clone, PartialEq, Eq, TryFrom, Into) )] -pub(super) struct WholePercent(u8); +pub(crate) struct WholePercent(u8); impl WholePercent { /// returns "the rest" of the whole. That is, `100 - this value`. - pub(super) fn inverse(self) -> Self { + pub(crate) fn inverse(self) -> Self { let val = u8::from(self); Self::try_from(100 - val).unwrap() }