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

providers: Add "akamai" provider #1062

Merged
merged 1 commit into from
Apr 20, 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
3 changes: 3 additions & 0 deletions docs/platforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ By default Afterburn uses the Ignition platform ID to detect the environment whe

The following platforms are supported, with a different set of features available on each:

* akamai
- Attributes
- SSH Keys
* aliyun
- Attributes
- SSH Keys
Expand Down
2 changes: 2 additions & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ nav_order: 8

Major changes:

- Add support for Akamai Connected Cloud (Linode)

Minor changes:

Packaging changes:
Expand Down
14 changes: 14 additions & 0 deletions docs/usage/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ which wants to make use of Afterburn metadata must explicitly pull it in using e

Cloud providers with supported metadata endpoints and their respective attributes are listed below.

* akamai
- AFTERBURN_AKAMAI_INSTANCE_HOST_UUID
- AFTERBURN_AKAMAI_INSTANCE_ID
- AFTERBURN_AKAMAI_INSTANCE_LABEL
- AFTERBURN_AKAMAI_INSTANCE_REGION
- AFTERBURN_AKAMAI_INSTANCE_TAGS
- AFTERBURN_AKAMAI_INSTANCE_TYPE
- AFTERBURN_AKAMAI_IPV6_LINK_LOCAL
- AFTERBURN_AKAMAI_IPV6_RANGE_0
- AFTERBURN_AKAMAI_IPV6_SHARED_RANGE_0
- AFTERBURN_AKAMAI_IPV6_SLAAC
- AFTERBURN_AKAMAI_PRIVATE_IPV4_0
- AFTERBURN_AKAMAI_PUBLIC_IPV4_0
- AFTERBURN_AKAMAI_SHARED_IPV4_0
* aliyun
- AFTERBURN_ALIYUN_EIPV4
- AFTERBURN_ALIYUN_HOSTNAME
Expand Down
2 changes: 2 additions & 0 deletions src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use anyhow::{bail, Result};

use crate::providers;
use crate::providers::akamai::AkamaiProvider;
use crate::providers::aliyun::AliyunProvider;
use crate::providers::aws::AwsProvider;
use crate::providers::cloudstack::configdrive::ConfigDrive;
Expand Down Expand Up @@ -49,6 +50,7 @@ macro_rules! box_result {
/// to the provider-specific fetch logic.
pub fn fetch_metadata(provider: &str) -> Result<Box<dyn providers::MetadataProvider>> {
match provider {
"akamai" => box_result!(AkamaiProvider::try_new()?),
"aliyun" => box_result!(AliyunProvider::try_new()?),
"aws" => box_result!(AwsProvider::try_new()?),
"azure" => box_result!(Azure::try_new()?),
Expand Down
104 changes: 104 additions & 0 deletions src/providers/akamai/mock_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use crate::providers::akamai::{AkamaiProvider, TOKEN_TTL};
use crate::providers::MetadataProvider;
use mockito::{self};

#[test]
fn test_attributes() {
let mut server = mockito::Server::new();
let token = "deadbeefcafebabe";

// Mock the PUT /v1/token endpoint.
let put_v1_token = server
.mock("PUT", "/v1/token")
.match_header("metadata-token-expiry-seconds", TOKEN_TTL)
.with_body(token)
.expect_at_least(1)
.create();

// Mock the GET /v1/instance endpoint.
let instance_metadata = r#"{
"id": 12345678,
"label": "my-linode",
"region": "us-ord",
"type": "g6-nanode-1",
"specs": {
"vcpus": 1,
"memory": 1024,
"gpus": 0,
"transfer": 1000,
"disk": 25600
},
"backups": {
"enabled": false,
"status": null
},
"host_uuid": "a631b16d14534d84e2830da16d1b28e1d08d24df",
"tags": ["foo", "bar", "baz"]
}"#;

let get_v1_instance = server
.mock("GET", "/v1/instance")
.match_header("Accept", "application/json")
.match_header("metadata-token", token)
.with_body(instance_metadata)
.create();

// Mock the /v1/network endpoint.
let network_metadata = r#"{
"interfaces": [
{
"id": 12345678,
"purpose": "public",
"label": null,
"ipam_address": null
}
],
"ipv4": {
"public": [
"1.2.3.4/32"
],
"private": [
"192.168.1.1/32"
],
"shared": []
},
"ipv6": {
"slaac": "2600:3c06::f03c:94ff:fecb:c10b/128",
"ranges": [],
"link_local": "fe80::f03c:94ff:fecb:c10b/128",
"shared_ranges": []
}
}"#;

let get_v1_network = server
.mock("GET", "/v1/network")
.match_header("Accept", "application/json")
.match_header("metadata-token", token)
.with_body(network_metadata)
.create();

let provider = AkamaiProvider::with_base_url(server.url()).unwrap();
let attrs = provider.attributes();

// Assert that our endpoints were called.
put_v1_token.assert();
get_v1_instance.assert();
get_v1_network.assert();

let actual = attrs.unwrap();
let expected = maplit::hashmap! {
"AKAMAI_INSTANCE_ID".to_string() => "12345678".to_string(),
"AKAMAI_INSTANCE_HOST_UUID".to_string() => "a631b16d14534d84e2830da16d1b28e1d08d24df".to_string(),
"AKAMAI_INSTANCE_LABEL".to_string() => "my-linode".to_string(),
"AKAMAI_INSTANCE_REGION".to_string() => "us-ord".to_string(),
"AKAMAI_INSTANCE_TYPE".to_string() => "g6-nanode-1".to_string(),
"AKAMAI_INSTANCE_TAGS".to_string() => "foo:bar:baz".to_string(),
"AKAMAI_PUBLIC_IPV4_0".to_string() => "1.2.3.4/32".to_string(),
"AKAMAI_PRIVATE_IPV4_0".to_string() => "192.168.1.1/32".to_string(),
"AKAMAI_IPV6_SLAAC".to_string() => "2600:3c06::f03c:94ff:fecb:c10b/128".to_string(),
"AKAMAI_IPV6_LINK_LOCAL".to_string() => "fe80::f03c:94ff:fecb:c10b/128".to_string(),
};
assert_eq!(expected, actual);

server.reset();
}
Loading
Loading