diff options
Diffstat (limited to 'src/zencompute')
| -rw-r--r-- | src/zencompute/cloudmetadata.cpp | 18 | ||||
| -rw-r--r-- | src/zencompute/include/zencompute/cloudmetadata.h | 12 | ||||
| -rw-r--r-- | src/zencompute/include/zencompute/mockimds.h | 100 | ||||
| -rw-r--r-- | src/zencompute/testing/mockimds.cpp | 205 |
4 files changed, 6 insertions, 329 deletions
diff --git a/src/zencompute/cloudmetadata.cpp b/src/zencompute/cloudmetadata.cpp index 65bac895f..eb4c05f9f 100644 --- a/src/zencompute/cloudmetadata.cpp +++ b/src/zencompute/cloudmetadata.cpp @@ -23,22 +23,6 @@ static constexpr std::string_view kImdsEndpoint = "http://169.254.169.254"; // is a local service on the hypervisor so 200ms is generous for actual cloud VMs. static constexpr auto kImdsTimeout = std::chrono::milliseconds{200}; -std::string_view -ToString(CloudProvider Provider) -{ - switch (Provider) - { - case CloudProvider::AWS: - return "AWS"; - case CloudProvider::Azure: - return "Azure"; - case CloudProvider::GCP: - return "GCP"; - default: - return "None"; - } -} - CloudMetadata::CloudMetadata(std::filesystem::path DataDir) : CloudMetadata(std::move(DataDir), std::string(kImdsEndpoint)) { } @@ -610,7 +594,7 @@ CloudMetadata::PollGCPTermination() #if ZEN_WITH_TESTS -# include <zencompute/mockimds.h> +# include <zenutil/cloud/mockimds.h> # include <zencore/filesystem.h> # include <zencore/testing.h> diff --git a/src/zencompute/include/zencompute/cloudmetadata.h b/src/zencompute/include/zencompute/cloudmetadata.h index a5bc5a34d..3b9642ac3 100644 --- a/src/zencompute/include/zencompute/cloudmetadata.h +++ b/src/zencompute/include/zencompute/cloudmetadata.h @@ -2,6 +2,8 @@ #pragma once +#include <zenutil/cloud/cloudprovider.h> + #include <zencore/compactbinarybuilder.h> #include <zencore/logging.h> #include <zencore/thread.h> @@ -13,16 +15,6 @@ namespace zen::compute { -enum class CloudProvider -{ - None, - AWS, - Azure, - GCP -}; - -std::string_view ToString(CloudProvider Provider); - /** Snapshot of detected cloud instance properties. */ struct CloudInstanceInfo { diff --git a/src/zencompute/include/zencompute/mockimds.h b/src/zencompute/include/zencompute/mockimds.h index 521722e63..704306913 100644 --- a/src/zencompute/include/zencompute/mockimds.h +++ b/src/zencompute/include/zencompute/mockimds.h @@ -1,102 +1,6 @@ // Copyright Epic Games, Inc. All Rights Reserved. +// Moved to zenutil — this header is kept for backward compatibility. #pragma once -#include <zencompute/cloudmetadata.h> -#include <zenhttp/httpserver.h> - -#include <string> - -#if ZEN_WITH_TESTS - -namespace zen::compute { - -/** - * Mock IMDS (Instance Metadata Service) for testing CloudMetadata. - * - * Implements an HttpService that responds to the same URL paths as the real - * cloud provider metadata endpoints (AWS IMDSv2, Azure IMDS, GCP metadata). - * Tests configure which provider is "active" and set the desired response - * values, then pass the mock server's address as the ImdsEndpoint to the - * CloudMetadata constructor. - * - * When a request arrives for a provider that is not the ActiveProvider, the - * mock returns 404, causing CloudMetadata to write a sentinel file and move - * on to the next provider — exactly like a failed probe on bare metal. - * - * All config fields are public and can be mutated between poll cycles to - * simulate state changes (e.g. a spot interruption appearing mid-run). - * - * Usage: - * MockImdsService Mock; - * Mock.ActiveProvider = CloudProvider::AWS; - * Mock.Aws.InstanceId = "i-test"; - * // ... stand up ASIO server, register Mock, create CloudMetadata with endpoint - */ -class MockImdsService : public HttpService -{ -public: - /** AWS IMDSv2 response configuration. */ - struct AwsConfig - { - std::string Token = "mock-aws-token-v2"; - std::string InstanceId = "i-0123456789abcdef0"; - std::string AvailabilityZone = "us-east-1a"; - std::string LifeCycle = "on-demand"; // "spot" or "on-demand" - - // Empty string → endpoint returns 404 (instance not in an ASG). - // Non-empty → returned as the response body. "InService" means healthy; - // anything else (e.g. "Terminated:Wait") triggers termination detection. - std::string AutoscalingState; - - // Empty string → endpoint returns 404 (no spot interruption). - // Non-empty → returned as the response body, signalling a spot reclaim. - std::string SpotAction; - }; - - /** Azure IMDS response configuration. */ - struct AzureConfig - { - std::string VmId = "vm-12345678-1234-1234-1234-123456789abc"; - std::string Location = "eastus"; - std::string Priority = "Regular"; // "Spot" or "Regular" - - // Empty → instance is not in a VM Scale Set (no autoscaling). - std::string VmScaleSetName; - - // Empty → no scheduled events. Set to "Preempt", "Terminate", or - // "Reboot" to simulate a termination-class event. - std::string ScheduledEventType; - std::string ScheduledEventStatus = "Scheduled"; - }; - - /** GCP metadata response configuration. */ - struct GcpConfig - { - std::string InstanceId = "1234567890123456789"; - std::string Zone = "projects/123456/zones/us-central1-a"; - std::string Preemptible = "FALSE"; // "TRUE" or "FALSE" - std::string MaintenanceEvent = "NONE"; // "NONE" or event description - }; - - /** Which provider's endpoints respond successfully. - * Requests targeting other providers receive 404. - */ - CloudProvider ActiveProvider = CloudProvider::None; - - AwsConfig Aws; - AzureConfig Azure; - GcpConfig Gcp; - - const char* BaseUri() const override; - void HandleRequest(HttpServerRequest& Request) override; - -private: - void HandleAwsRequest(HttpServerRequest& Request); - void HandleAzureRequest(HttpServerRequest& Request); - void HandleGcpRequest(HttpServerRequest& Request); -}; - -} // namespace zen::compute - -#endif // ZEN_WITH_TESTS +#include <zenutil/cloud/mockimds.h> diff --git a/src/zencompute/testing/mockimds.cpp b/src/zencompute/testing/mockimds.cpp index dd09312df..5415f48f3 100644 --- a/src/zencompute/testing/mockimds.cpp +++ b/src/zencompute/testing/mockimds.cpp @@ -1,205 +1,2 @@ // Copyright Epic Games, Inc. All Rights Reserved. - -#include <zencompute/mockimds.h> - -#include <zencore/fmtutils.h> - -#if ZEN_WITH_TESTS - -namespace zen::compute { - -const char* -MockImdsService::BaseUri() const -{ - return "/"; -} - -void -MockImdsService::HandleRequest(HttpServerRequest& Request) -{ - std::string_view Uri = Request.RelativeUri(); - - // AWS endpoints live under /latest/ - if (Uri.starts_with("latest/")) - { - if (ActiveProvider == CloudProvider::AWS) - { - HandleAwsRequest(Request); - return; - } - Request.WriteResponse(HttpResponseCode::NotFound); - return; - } - - // Azure endpoints live under /metadata/ - if (Uri.starts_with("metadata/")) - { - if (ActiveProvider == CloudProvider::Azure) - { - HandleAzureRequest(Request); - return; - } - Request.WriteResponse(HttpResponseCode::NotFound); - return; - } - - // GCP endpoints live under /computeMetadata/ - if (Uri.starts_with("computeMetadata/")) - { - if (ActiveProvider == CloudProvider::GCP) - { - HandleGcpRequest(Request); - return; - } - Request.WriteResponse(HttpResponseCode::NotFound); - return; - } - - Request.WriteResponse(HttpResponseCode::NotFound); -} - -// --------------------------------------------------------------------------- -// AWS -// --------------------------------------------------------------------------- - -void -MockImdsService::HandleAwsRequest(HttpServerRequest& Request) -{ - std::string_view Uri = Request.RelativeUri(); - - // IMDSv2 token acquisition (PUT only) - if (Uri == "latest/api/token" && Request.RequestVerb() == HttpVerb::kPut) - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Aws.Token); - return; - } - - // Instance identity - if (Uri == "latest/meta-data/instance-id") - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Aws.InstanceId); - return; - } - - if (Uri == "latest/meta-data/placement/availability-zone") - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Aws.AvailabilityZone); - return; - } - - if (Uri == "latest/meta-data/instance-life-cycle") - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Aws.LifeCycle); - return; - } - - // Autoscaling lifecycle state — 404 when not in an ASG - if (Uri == "latest/meta-data/autoscaling/target-lifecycle-state") - { - if (Aws.AutoscalingState.empty()) - { - Request.WriteResponse(HttpResponseCode::NotFound); - return; - } - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Aws.AutoscalingState); - return; - } - - // Spot interruption notice — 404 when no interruption pending - if (Uri == "latest/meta-data/spot/instance-action") - { - if (Aws.SpotAction.empty()) - { - Request.WriteResponse(HttpResponseCode::NotFound); - return; - } - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Aws.SpotAction); - return; - } - - Request.WriteResponse(HttpResponseCode::NotFound); -} - -// --------------------------------------------------------------------------- -// Azure -// --------------------------------------------------------------------------- - -void -MockImdsService::HandleAzureRequest(HttpServerRequest& Request) -{ - std::string_view Uri = Request.RelativeUri(); - - // Instance metadata (single JSON document) - if (Uri == "metadata/instance") - { - std::string Json = fmt::format(R"({{"compute":{{"vmId":"{}","location":"{}","priority":"{}","vmScaleSetName":"{}"}}}})", - Azure.VmId, - Azure.Location, - Azure.Priority, - Azure.VmScaleSetName); - - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Json); - return; - } - - // Scheduled events for termination monitoring - if (Uri == "metadata/scheduledevents") - { - std::string Json; - if (Azure.ScheduledEventType.empty()) - { - Json = R"({"Events":[]})"; - } - else - { - Json = fmt::format(R"({{"Events":[{{"EventType":"{}","EventStatus":"{}"}}]}})", - Azure.ScheduledEventType, - Azure.ScheduledEventStatus); - } - - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Json); - return; - } - - Request.WriteResponse(HttpResponseCode::NotFound); -} - -// --------------------------------------------------------------------------- -// GCP -// --------------------------------------------------------------------------- - -void -MockImdsService::HandleGcpRequest(HttpServerRequest& Request) -{ - std::string_view Uri = Request.RelativeUri(); - - if (Uri == "computeMetadata/v1/instance/id") - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Gcp.InstanceId); - return; - } - - if (Uri == "computeMetadata/v1/instance/zone") - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Gcp.Zone); - return; - } - - if (Uri == "computeMetadata/v1/instance/scheduling/preemptible") - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Gcp.Preemptible); - return; - } - - if (Uri == "computeMetadata/v1/instance/maintenance-event") - { - Request.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, Gcp.MaintenanceEvent); - return; - } - - Request.WriteResponse(HttpResponseCode::NotFound); -} - -} // namespace zen::compute - -#endif // ZEN_WITH_TESTS +// Moved to zenutil/cloud/mockimds.cpp |