Найти тему
Один Rust не п...Rust

AWS Rust Terraform

Для чего нужна данная статья? :
- Создать AWS Lambda на Rust.

- Развернуть приложение в AWS с помощью Terraform.

Зачем Вам это уметь? :

- Собрать воедино разные компоненты системы из разных облачных сред.

Пример.

aws sts get-caller-identity --profile <your_profile>

cargo new rust-aws-lambda

cd rust-aws-lambda

src/main.rs

fn say_hello(name: Option<&str>) -> String {

match name {

Some(name) => format!("Hello, {}!", name),

None => "Hello, stranger!".to_string(), }

}
fn main() {

let response = say_hello(Some("world"));

println!("{}", response);

}

Среда выполнения Rust для Lambda выглядит следующим образом: лучше всего взаимодействовать с помощью Cargo Lambda.

Этот инструмент позволит вам собрать и запустить функцию локально. Его также можно использовать для начальной загрузки лямбды или ее развертывания.

Rust AWS SDK не реализует sso_session пока. Поддержка может появиться в ближайшее время.

Ознакомьтесь с установкой :

pip3 install cargo-lambda

Среда выполнения Lambda ожидает асинхронную функцию, которая принимает в качестве параметра a и возвращает некоторый JSON.

cargo add lambda_runtime tokio serde_json

async fn run_lambda(event: LambdaEvent<Value>) -> Result<Value, Error> { let (event, _context) = event.into_parts();
let name = match event["name"].as_str() {

Some(name) => name,

None => return Err(Error::new(ErrorKind::InvalidInput, "Name is required")),

};
let result = say_hello(name);

Ok(json!(result))

}

Главная функция должна быть обновлена для запуска обёртки, которая требует, чтобы она была асинхронной и возвращала Result.

#[tokio::main] async fn main() -> Result<(), Error> { lambda_runtime::run(service_fn(run_lambda)).await?;

Ok(())

}

cargo lambda watch

cargo lambda invoke rust-aws-lambda --data-ascii '{}'

cargo lambda invoke rust-aws-lambda --data-ascii '{ "name": "world" }'

Для того чтобы основная функция возвращала структуру, которая может быть сериализована в JSON, добавим код.

cargo add serde

#[derive(Debug, PartialEq, serde::Serialize)] struct HelloResponse {

message: String, }
fn say_hello(name: Option<&str>) -> HelloResponse {

let name = match name { Some(name) => name,

None => "stranger", };
HelloResponse { message: format!("Hello, {name}!"), }

}

Добавим трассировку.

cargo add tracing --features log

cargo add tracing-subscriber --features fmt,env-filter

async fn main() -> Result<(), Error> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.with_ansi(false) // no colors as they look messed up in Cloudwatch
.init()?;
// [...]
Ok(())
}

Создадим диапазон для каждого вызова лямбды и любого события журнала, отправленного из в рамках этой функции будет назначена соответствующему диапазону.

#[tracing::instrument()]
async fn run_lambda(event: LambdaEvent<Value>) -> Result<Value, Error> {
let (event, context) = event.into_parts();
tracing::info!(event = ?event, context = ?context);
// [...]
Ok(())
}

Создадим файл terraform.

module "lambda_function" {

source = "terraform-aws-modules/lambda/aws"

function_name = "rust-aws-lambda"

description = "AWS Lambda in Rust with Terraform" runtime = "provided.al2" architectures = ["arm64"]

handler = "bootstrap"

create_package = false

local_existing_package = "../target/lambda/rust-aws-lambda/bootstrap.zip"}

cargo lambda build --release --arm64 --output-format zip

terraform -chdir=infra init AWS_PROFILE=<your_profile>

terraform -chdir=infra plan

AWS_PROFILE=<your_profile> terraform -chdir=infra apply