Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fastly_acl hostcalls #438

Merged
merged 2 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ async fn create_execution_context(

if let Some(config_path) = args.config_path() {
let config = FastlyConfig::from_file(config_path)?;
let acls = config.acls();
let backends = config.backends();
let device_detection = config.device_detection();
let geolocation = config.geolocation();
Expand All @@ -321,6 +322,7 @@ async fn create_execution_context(
let backend_names = itertools::join(backends.keys(), ", ");

ctx = ctx
.with_acls(acls.clone())
.with_backends(backends.clone())
.with_device_detection(device_detection.clone())
.with_geolocation(geolocation.clone())
Expand Down
113 changes: 113 additions & 0 deletions cli/tests/integration/acl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use crate::{common::Test, common::TestResult, viceroy_test};
use hyper::{body::to_bytes, StatusCode};
use viceroy_lib::config::FastlyConfig;
use viceroy_lib::error::{AclConfigError, FastlyConfigError};

viceroy_test!(acl_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "acl"
description = "acl test"
authors = ["Test User <[email protected]>"]
language = "rust"
[local_server]
acls.my-acl-1 = "../test-fixtures/data/my-acl-1.json"
acls.my-acl-2 = {file = "../test-fixtures/data/my-acl-2.json"}
"#;

let resp = Test::using_fixture("acl.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.log_stderr()
.log_stdout()
.against_empty()
.await?;

assert_eq!(resp.status(), StatusCode::OK);
assert!(to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty());

Ok(())
});

fn bad_config_test(local_server_fragment: &str) -> Result<FastlyConfig, FastlyConfigError> {
let toml = format!(
r#"
name = "acl"
description = "acl test"
authors = ["Test User <[email protected]>"]
language = "rust"
[local_server]
{}
"#,
local_server_fragment
);

toml.parse::<FastlyConfig>()
}

#[tokio::test(flavor = "multi_thread")]
async fn bad_config_invalid_path() -> TestResult {
const TOML_FRAGMENT: &str = "acls.bad = 1";
match bad_config_test(TOML_FRAGMENT) {
Err(FastlyConfigError::InvalidAclDefinition {
err: AclConfigError::InvalidType,
..
}) => (),
Err(_) => panic!(
"expected a FastlyConfigError::InvalidAclDefinition with AclConfigError::InvalidType"
),
_ => panic!("Expected an error"),
}
Ok(())
}

#[tokio::test(flavor = "multi_thread")]
async fn bad_config_missing_key() -> TestResult {
const TOML_FRAGMENT: &str = "acls.bad = { \"other\" = true }";
match bad_config_test(TOML_FRAGMENT) {
Err(FastlyConfigError::InvalidAclDefinition {
err: AclConfigError::MissingFile,
..
}) => (),
Err(_) => panic!(
"expected a FastlyConfigError::InvalidAclDefinition with AclConfigError::MissingFile"
),
_ => panic!("Expected an error"),
}
Ok(())
}

#[tokio::test(flavor = "multi_thread")]
async fn bad_config_missing_file() -> TestResult {
const TOML_FRAGMENT: &str = "acls.bad = \"/does/not/exist\"";
match bad_config_test(TOML_FRAGMENT) {
Err(FastlyConfigError::InvalidAclDefinition {
err: AclConfigError::IoError(_),
..
}) => (),
Err(_) => panic!(
"expected a FastlyConfigError::InvalidAclDefinition with AclConfigError::IoError"
),
_ => panic!("Expected an error"),
}
Ok(())
}

#[tokio::test(flavor = "multi_thread")]
async fn bad_config_invalid_json() -> TestResult {
const TOML_FRAGMENT: &str = "acls.bad = \"../Cargo.toml\"";
match bad_config_test(TOML_FRAGMENT) {
Err(FastlyConfigError::InvalidAclDefinition {
err: AclConfigError::JsonError(_),
..
}) => (),
Err(_) => panic!(
"expected a FastlyConfigError::InvalidAclDefinition with AclConfigError::JsonError"
),
_ => panic!("Expected an error"),
}
Ok(())
}
7 changes: 6 additions & 1 deletion cli/tests/integration/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use viceroy_lib::config::UnknownImportBehavior;
use viceroy_lib::{
body::Body,
config::{
DeviceDetection, Dictionaries, FastlyConfig, Geolocation, ObjectStores, SecretStores,
Acls, DeviceDetection, Dictionaries, FastlyConfig, Geolocation, ObjectStores, SecretStores,
},
ExecuteCtx, ProfilingStrategy, ViceroyService,
};
Expand Down Expand Up @@ -77,6 +77,7 @@ pub type TestResult = Result<(), Error>;
/// A builder for running individual requests through a wasm fixture.
pub struct Test {
module_path: PathBuf,
acls: Acls,
backends: TestBackends,
device_detection: DeviceDetection,
dictionaries: Dictionaries,
Expand All @@ -99,6 +100,7 @@ impl Test {

Self {
module_path,
acls: Acls::new(),
backends: TestBackends::new(),
device_detection: DeviceDetection::new(),
dictionaries: Dictionaries::new(),
Expand All @@ -121,6 +123,7 @@ impl Test {

Self {
module_path,
acls: Acls::new(),
backends: TestBackends::new(),
device_detection: DeviceDetection::new(),
dictionaries: Dictionaries::new(),
Expand All @@ -140,6 +143,7 @@ impl Test {
pub fn using_fastly_toml(self, fastly_toml: &str) -> Result<Self, Error> {
let config = fastly_toml.parse::<FastlyConfig>()?;
Ok(Self {
acls: config.acls().to_owned(),
backends: TestBackends::from_backend_configs(config.backends()),
device_detection: config.device_detection().to_owned(),
dictionaries: config.dictionaries().to_owned(),
Expand Down Expand Up @@ -328,6 +332,7 @@ impl Test {
self.unknown_import_behavior,
self.adapt_component,
)?
.with_acls(self.acls.clone())
.with_backends(self.backends.backend_configs().await)
.with_dictionaries(self.dictionaries.clone())
.with_device_detection(self.device_detection.clone())
Expand Down
1 change: 1 addition & 0 deletions cli/tests/integration/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod acl;
mod args;
mod async_io;
mod body;
Expand Down
66 changes: 59 additions & 7 deletions crates/adapter/src/fastly/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,20 @@ pub enum HttpKeepaliveMode {
NoKeepalive = 1,
}

pub type PendingObjectStoreLookupHandle = u32;
pub type PendingObjectStoreInsertHandle = u32;
pub type AclHandle = u32;
pub type AsyncItemHandle = u32;
pub type BodyHandle = u32;
pub type DictionaryHandle = u32;
pub type KVStoreHandle = u32;
pub type PendingObjectStoreDeleteHandle = u32;
pub type PendingObjectStoreInsertHandle = u32;
pub type PendingObjectStoreListHandle = u32;
pub type BodyHandle = u32;
pub type PendingObjectStoreLookupHandle = u32;
pub type PendingRequestHandle = u32;
pub type RequestHandle = u32;
pub type ResponseHandle = u32;
pub type DictionaryHandle = u32;
pub type KVStoreHandle = u32;
pub type SecretStoreHandle = u32;
pub type SecretHandle = u32;
pub type AsyncItemHandle = u32;
pub type SecretStoreHandle = u32;

const INVALID_HANDLE: u32 = u32::MAX - 1;

Expand Down Expand Up @@ -303,6 +304,57 @@ pub struct InspectConfig {
pub workspace_len: u32,
}

pub mod fastly_acl {
use super::*;
use crate::bindings::fastly::api::acl;
use core::slice;

#[export_name = "fastly_acl#open"]
pub fn open(
acl_name_ptr: *const u8,
acl_name_len: usize,
acl_handle_out: *mut AclHandle,
) -> FastlyStatus {
let acl_name = unsafe { slice::from_raw_parts(acl_name_ptr, acl_name_len) };
match acl::open(acl_name) {
Ok(res) => {
unsafe {
*acl_handle_out = res;
}
FastlyStatus::OK
}
Err(e) => e.into(),
}
}

#[export_name = "fastly_acl#lookup"]
pub fn lookup(
acl_handle: acl::AclHandle,
ip_octets: *const u8,
ip_len: usize,
body_handle_out: *mut BodyHandle,
acl_error_out: *mut acl::AclError,
) -> FastlyStatus {
let ip = unsafe { slice::from_raw_parts(ip_octets, ip_len) };
match acl::lookup(acl_handle, ip, u64::try_from(ip_len).trapping_unwrap()) {
Ok((Some(body_handle), acl_error)) => {
unsafe {
*body_handle_out = body_handle;
*acl_error_out = acl_error;
}
FastlyStatus::OK
}
Ok((None, acl_error)) => {
unsafe {
*acl_error_out = acl_error;
}
FastlyStatus::OK
}
Err(e) => e.into(),
}
}
}

pub mod fastly_abi {
use super::*;

Expand Down
16 changes: 16 additions & 0 deletions lib/compute-at-edge-abi/compute-at-edge.witx
Original file line number Diff line number Diff line change
Expand Up @@ -1142,3 +1142,19 @@
(result $err (expected $vcpu_ms (error $fastly_status)))
)
)

(module $fastly_acl
(@interface func (export "open")
(param $name string)
(result $err (expected $acl_handle (error $fastly_status)))
)

(@interface func (export "lookup")
(param $acl $acl_handle)
(param $ip_octets (@witx const_pointer (@witx char8)))
(param $ip_len (@witx usize))
(param $body_handle_out (@witx pointer $body_handle))
(param $acl_error_out (@witx pointer $acl_error))
(result $err (expected (error $fastly_status)))
)
)
16 changes: 16 additions & 0 deletions lib/compute-at-edge-abi/typenames.witx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@
(typename $secret_store_handle (handle))
;;; A handle to an individual secret.
(typename $secret_handle (handle))
;;; A handle to an ACL.
(typename $acl_handle (handle))
;;; A handle to an object supporting generic async operations.
;;; Can be either a `body_handle` or a `pending_request_handle`.
;;;
Expand Down Expand Up @@ -491,3 +493,17 @@
;;; This will map to the api's 429 codes
$too_many_requests
))

(typename $acl_error
(enum (@witx tag u32)
;;; The $acl_error has not been initialized.
$uninitialized
;;; There was no error.
$ok
;;; This will map to the api's 204 code.
;;; It indicates that the request succeeded, yet returned nothing.
$no_content
;;; This will map to the api's 429 code.
;;; Too many requests have been made.
$too_many_requests
))
Binary file modified lib/data/viceroy-component-adapter.wasm
Binary file not shown.
Loading
Loading