From 6210f474f6caab05b4bfd24b30c51261a1f97f98 Mon Sep 17 00:00:00 2001 From: Matt Keeler Date: Fri, 19 May 2023 13:40:04 -0400 Subject: [PATCH] Implement a Catalog Controllers Integration Test This also fixes a bug where multiple service ports with a 0 value virtual port could not be set. A 0 virtual port means unset and so we should allow duplicates of these. --- .../v1alpha1/api-service.json | 37 + .../v1alpha1/api-workload-1-health.json | 33 + .../v1alpha1/api-workload-1.json | 46 ++ .../v1alpha1/api-workload-10-health.json | 33 + .../v1alpha1/api-workload-10.json | 46 ++ .../v1alpha1/api-workload-11-health.json | 33 + .../v1alpha1/api-workload-11.json | 46 ++ .../v1alpha1/api-workload-12-health.json | 33 + .../v1alpha1/api-workload-12.json | 46 ++ .../v1alpha1/api-workload-13-health.json | 33 + .../v1alpha1/api-workload-13.json | 46 ++ .../v1alpha1/api-workload-14-health.json | 33 + .../v1alpha1/api-workload-14.json | 46 ++ .../v1alpha1/api-workload-15-health.json | 33 + .../v1alpha1/api-workload-15.json | 46 ++ .../v1alpha1/api-workload-16-health.json | 33 + .../v1alpha1/api-workload-16.json | 46 ++ .../v1alpha1/api-workload-17-health.json | 33 + .../v1alpha1/api-workload-17.json | 45 ++ .../v1alpha1/api-workload-18-health.json | 33 + .../v1alpha1/api-workload-18.json | 45 ++ .../v1alpha1/api-workload-19-health.json | 33 + .../v1alpha1/api-workload-19.json | 45 ++ .../v1alpha1/api-workload-2-health.json | 33 + .../v1alpha1/api-workload-2.json | 46 ++ .../v1alpha1/api-workload-20-health.json | 33 + .../v1alpha1/api-workload-20.json | 45 ++ .../v1alpha1/api-workload-3-health.json | 33 + .../v1alpha1/api-workload-3.json | 46 ++ .../v1alpha1/api-workload-4-health.json | 33 + .../v1alpha1/api-workload-4.json | 46 ++ .../v1alpha1/api-workload-5-health.json | 33 + .../v1alpha1/api-workload-5.json | 46 ++ .../v1alpha1/api-workload-6-health.json | 33 + .../v1alpha1/api-workload-6.json | 46 ++ .../v1alpha1/api-workload-7-health.json | 33 + .../v1alpha1/api-workload-7.json | 46 ++ .../v1alpha1/api-workload-8-health.json | 33 + .../v1alpha1/api-workload-8.json | 46 ++ .../v1alpha1/api-workload-9-health.json | 33 + .../v1alpha1/api-workload-9.json | 46 ++ .../v1alpha1/foo-service-endpoints.json | 47 ++ .../v1alpha1/foo-service.json | 24 + .../v1alpha1/grpc-api-service.json | 42 ++ .../v1alpha1/http-api-service.json | 29 + .../v1alpha1/node-1-health.json | 33 + .../v1alpha1/node-1.json | 27 + .../v1alpha1/node-2-health.json | 33 + .../v1alpha1/node-2.json | 27 + .../v1alpha1/node-3-health.json | 33 + .../v1alpha1/node-3.json | 27 + .../v1alpha1/node-4-health.json | 33 + .../v1alpha1/node-4.json | 27 + internal/catalog/catalogtest/run_test.go | 39 + .../catalogtest/test_integration_v1alpha1.go | 707 ++++++++++++++++++ .../controllers/nodehealth/controller.go | 14 +- .../internal/controllers/nodehealth/status.go | 42 ++ .../controllers/workloadhealth/controller.go | 24 +- .../controllers/workloadhealth/status.go | 125 ++++ internal/catalog/internal/types/service.go | 2 +- .../catalog/internal/types/service_test.go | 12 + internal/resource/resourcetest/fs.go | 40 + 62 files changed, 2965 insertions(+), 35 deletions(-) create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-service.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-1-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-1.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-10-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-10.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-11-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-11.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-12-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-12.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-13-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-13.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-14-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-14.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-15-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-15.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-16-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-16.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-17-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-17.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-18-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-18.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-19-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-19.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-2-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-2.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-20-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-20.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-3-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-3.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-4-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-4.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-5-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-5.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-6-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-6.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-7-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-7.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-8-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-8.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-9-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-9.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/foo-service-endpoints.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/foo-service.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/grpc-api-service.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/http-api-service.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/node-1-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/node-1.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/node-2-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/node-2.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/node-3-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/node-3.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/node-4-health.json create mode 100644 internal/catalog/catalogtest/integration_test_data/v1alpha1/node-4.json create mode 100644 internal/catalog/catalogtest/run_test.go create mode 100644 internal/catalog/catalogtest/test_integration_v1alpha1.go create mode 100644 internal/resource/resourcetest/fs.go diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-service.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-service.json new file mode 100644 index 0000000000000..866c384b1d97a --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-service.json @@ -0,0 +1,37 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Service" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Service", + "workloads": { + "prefixes": [ + "api-" + ] + }, + "ports": [ + { + "target_port": "http", + "protocol": "PROTOCOL_HTTP" + }, + { + "target_port": "grpc", + "protocol": "PROTOCOL_GRPC" + }, + { + "target_port": "mesh", + "protocol": "PROTOCOL_MESH" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-1-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-1-health.json new file mode 100644 index 0000000000000..a1dd1609f297b --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-1-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-1-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-1" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_PASSING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-1.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-1.json new file mode 100644 index 0000000000000..1935a767a19fb --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-1.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-1" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.1" + }, + { + "host": "198.18.2.1", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-1" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-10-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-10-health.json new file mode 100644 index 0000000000000..9c60ce7b09135 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-10-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-10-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-10" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_WARNING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-10.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-10.json new file mode 100644 index 0000000000000..362baa4099ec0 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-10.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-10" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.10" + }, + { + "host": "198.18.2.10", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-3" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-11-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-11-health.json new file mode 100644 index 0000000000000..2f8025258075f --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-11-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-11-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-11" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_CRITICAL" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-11.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-11.json new file mode 100644 index 0000000000000..be9c1898835ea --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-11.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-11" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.11" + }, + { + "host": "198.18.2.11", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-3" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-12-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-12-health.json new file mode 100644 index 0000000000000..dd1026eed11ae --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-12-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-12-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-12" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_MAINTENANCE" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-12.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-12.json new file mode 100644 index 0000000000000..34f34d534239f --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-12.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-12" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.12" + }, + { + "host": "198.18.2.12", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-3" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-13-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-13-health.json new file mode 100644 index 0000000000000..2a5084afa14ce --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-13-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-13-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-13" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_PASSING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-13.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-13.json new file mode 100644 index 0000000000000..3d896e0365900 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-13.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-13" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.13" + }, + { + "host": "198.18.2.13", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-4" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-14-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-14-health.json new file mode 100644 index 0000000000000..991b66ee526d0 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-14-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-14-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-14" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_WARNING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-14.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-14.json new file mode 100644 index 0000000000000..e8712a6c6520b --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-14.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-14" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.14" + }, + { + "host": "198.18.2.14", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-4" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-15-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-15-health.json new file mode 100644 index 0000000000000..22b2ff83340d7 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-15-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-15-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-15" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_CRITICAL" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-15.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-15.json new file mode 100644 index 0000000000000..dbe0f0a44af7a --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-15.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-15" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.15" + }, + { + "host": "198.18.2.15", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-4" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-16-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-16-health.json new file mode 100644 index 0000000000000..06e36994387e7 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-16-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-16-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-16" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_MAINTENANCE" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-16.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-16.json new file mode 100644 index 0000000000000..3db40493b1d34 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-16.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-16" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.16" + }, + { + "host": "198.18.2.16", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-4" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-17-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-17-health.json new file mode 100644 index 0000000000000..3b4614cd6f704 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-17-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-17-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-17" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_PASSING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-17.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-17.json new file mode 100644 index 0000000000000..79d26a2b33814 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-17.json @@ -0,0 +1,45 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-17" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.17" + }, + { + "host": "198.18.2.17", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-18-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-18-health.json new file mode 100644 index 0000000000000..7764016a98594 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-18-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-18-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-18" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_WARNING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-18.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-18.json new file mode 100644 index 0000000000000..04df2611c8679 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-18.json @@ -0,0 +1,45 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-18" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.18" + }, + { + "host": "198.18.2.18", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-19-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-19-health.json new file mode 100644 index 0000000000000..468cddfbcbab8 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-19-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-19-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-19" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_CRITICAL" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-19.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-19.json new file mode 100644 index 0000000000000..bf9c8fe25a7ff --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-19.json @@ -0,0 +1,45 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-19" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.19" + }, + { + "host": "198.18.2.19", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-2-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-2-health.json new file mode 100644 index 0000000000000..d9bf96b62b52e --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-2-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-2-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-2" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_WARNING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-2.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-2.json new file mode 100644 index 0000000000000..b80c0ccb85327 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-2.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-2" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.2" + }, + { + "host": "198.18.2.2", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-1" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-20-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-20-health.json new file mode 100644 index 0000000000000..98af32bd00fd7 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-20-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-20-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-20" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_MAINTENANCE" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-20.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-20.json new file mode 100644 index 0000000000000..89723f54fe004 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-20.json @@ -0,0 +1,45 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-20" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.20" + }, + { + "host": "198.18.2.20", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-3-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-3-health.json new file mode 100644 index 0000000000000..28670cc33728c --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-3-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-3-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-3" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_CRITICAL" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-3.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-3.json new file mode 100644 index 0000000000000..c5ea7d82a5df9 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-3.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-3" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.3" + }, + { + "host": "198.18.2.3", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-1" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-4-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-4-health.json new file mode 100644 index 0000000000000..041d6eed5afd8 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-4-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-4-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-4" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_MAINTENANCE" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-4.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-4.json new file mode 100644 index 0000000000000..53934b9d5eea1 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-4.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-4" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.4" + }, + { + "host": "198.18.2.4", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-1" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-5-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-5-health.json new file mode 100644 index 0000000000000..1773cb44ca84d --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-5-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-5-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-5" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_PASSING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-5.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-5.json new file mode 100644 index 0000000000000..cbed9843adb5b --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-5.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-5" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.5" + }, + { + "host": "198.18.2.5", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-2" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-6-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-6-health.json new file mode 100644 index 0000000000000..3cf2104ef4fce --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-6-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-6-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-6" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_WARNING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-6.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-6.json new file mode 100644 index 0000000000000..1646e7c0291c0 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-6.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-6" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.6" + }, + { + "host": "198.18.2.6", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-2" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-7-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-7-health.json new file mode 100644 index 0000000000000..d1dbc895fd3ad --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-7-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-7-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-7" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_CRITICAL" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-7.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-7.json new file mode 100644 index 0000000000000..240f1e29a6932 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-7.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-7" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.7" + }, + { + "host": "198.18.2.7", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-2" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-8-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-8-health.json new file mode 100644 index 0000000000000..cdbb062703752 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-8-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-8-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-8" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_MAINTENANCE" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-8.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-8.json new file mode 100644 index 0000000000000..16e686c4b4092 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-8.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-8" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.8" + }, + { + "host": "198.18.2.8", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-2" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-9-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-9-health.json new file mode 100644 index 0000000000000..6d221b07bd965 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-9-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-9-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-9" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_PASSING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-9.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-9.json new file mode 100644 index 0000000000000..9081ff2e9cad9 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/api-workload-9.json @@ -0,0 +1,46 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Workload" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "api-9" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Workload", + "addresses": [ + { + "host": "172.16.1.9" + }, + { + "host": "198.18.2.9", + "external": true, + "ports": [ + "mesh" + ] + } + ], + "ports": { + "http": { + "port": 8080, + "protocol": "PROTOCOL_HTTP" + }, + "grpc": { + "port": 9090, + "protocol": "PROTOCOL_GRPC" + }, + "mesh": { + "port": 10000, + "protocol": "PROTOCOL_MESH" + } + }, + "identity": "api", + "node_name": "node-3" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/foo-service-endpoints.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/foo-service-endpoints.json new file mode 100644 index 0000000000000..b96f8805b1510 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/foo-service-endpoints.json @@ -0,0 +1,47 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "ServiceEndpoints" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "foo" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Service" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "foo" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.ServiceEndpoints", + "endpoints": [ + { + "addresses": [ + { + "host": "198.18.0.1" + } + ], + "ports": { + "external-service-port": { + "port": 9876, + "protocol": "PROTOCOL_HTTP2" + } + }, + "health_status": "HEALTH_PASSING" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/foo-service.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/foo-service.json new file mode 100644 index 0000000000000..a79cdb2331661 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/foo-service.json @@ -0,0 +1,24 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Service" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "foo" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Service", + "ports": [ + { + "target_port": "external-service-port", + "protocol": "PROTOCOL_HTTP2" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/grpc-api-service.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/grpc-api-service.json new file mode 100644 index 0000000000000..6aa39628bf0f7 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/grpc-api-service.json @@ -0,0 +1,42 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Service" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "grpc-api" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Service", + "workloads": { + "names": [ + "api-1", + "api-2", + "api-3", + "api-4", + "api-5", + "api-6", + "api-7", + "api-8", + "api-9", + "api-20" + ] + }, + "ports": [ + { + "target_port": "grpc", + "protocol": "PROTOCOL_GRPC" + }, + { + "target_port": "mesh", + "protocol": "PROTOCOL_MESH" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/http-api-service.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/http-api-service.json new file mode 100644 index 0000000000000..989851e725647 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/http-api-service.json @@ -0,0 +1,29 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Service" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "http-api" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Service", + "workloads": { + "prefixes": [ + "api-1" + ] + }, + "ports": [ + { + "target_port": "http", + "protocol": "PROTOCOL_HTTP" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-1-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-1-health.json new file mode 100644 index 0000000000000..5f58cda6ae887 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-1-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-1-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Node" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-1" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_PASSING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-1.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-1.json new file mode 100644 index 0000000000000..c0f618279dcb4 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-1.json @@ -0,0 +1,27 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Node" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-1" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Node", + "addresses": [ + { + "host": "198.18.1.1", + "external": true + }, + { + "host": "172.16.0.1" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-2-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-2-health.json new file mode 100644 index 0000000000000..6c67a1c1d1fce --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-2-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-2-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Node" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-2" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_WARNING" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-2.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-2.json new file mode 100644 index 0000000000000..f68fd86ded71c --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-2.json @@ -0,0 +1,27 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Node" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-2" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Node", + "addresses": [ + { + "host": "198.18.1.2", + "external": true + }, + { + "host": "172.16.0.2" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-3-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-3-health.json new file mode 100644 index 0000000000000..2efa143afa2c2 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-3-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-3-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Node" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-3" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_CRITICAL" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-3.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-3.json new file mode 100644 index 0000000000000..b8d9a4e1651be --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-3.json @@ -0,0 +1,27 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Node" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-3" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Node", + "addresses": [ + { + "host": "198.18.1.3", + "external": true + }, + { + "host": "172.16.0.3" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-4-health.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-4-health.json new file mode 100644 index 0000000000000..a4f425e3cdc36 --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-4-health.json @@ -0,0 +1,33 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "HealthStatus" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-4-health" + }, + "owner": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Node" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-4" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.HealthStatus", + "type": "synthetic", + "status": "HEALTH_MAINTENANCE" + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-4.json b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-4.json new file mode 100644 index 0000000000000..17c98cd98dd1b --- /dev/null +++ b/internal/catalog/catalogtest/integration_test_data/v1alpha1/node-4.json @@ -0,0 +1,27 @@ +{ + "id": { + "type": { + "group": "catalog", + "group_version": "v1alpha1", + "kind": "Node" + }, + "tenancy": { + "partition": "default", + "namespace": "default", + "peer_name": "local" + }, + "name": "node-4" + }, + "data": { + "@type": "hashicorp.consul.catalog.v1alpha1.Node", + "addresses": [ + { + "host": "198.18.1.4", + "external": true + }, + { + "host": "172.16.0.4" + } + ] + } +} \ No newline at end of file diff --git a/internal/catalog/catalogtest/run_test.go b/internal/catalog/catalogtest/run_test.go new file mode 100644 index 0000000000000..7c17052d8246d --- /dev/null +++ b/internal/catalog/catalogtest/run_test.go @@ -0,0 +1,39 @@ +package catalogtest + +import ( + "testing" + + svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" + "github.com/hashicorp/consul/internal/catalog" + "github.com/hashicorp/consul/internal/catalog/internal/controllers" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/resource/reaper" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/sdk/testutil" +) + +func runInMemResourceServiceAndControllers(t *testing.T, deps controllers.Dependencies) pbresource.ResourceServiceClient { + t.Helper() + + ctx := testutil.TestContext(t) + + // Create the in-mem resource service + client := svctest.RunResourceService(t, catalog.RegisterTypes) + + // Setup/Run the controller manager + mgr := controller.NewManager(client, testutil.Logger(t)) + catalog.RegisterControllers(mgr, deps) + + // We also depend on the reaper to take care of cleaning up owned health statuses and + // service endpoints so we must enable that controller as well + reaper.RegisterControllers(mgr) + mgr.SetRaftLeader(true) + go mgr.Run(ctx) + + return client +} + +func TestControllers_Integration(t *testing.T) { + client := runInMemResourceServiceAndControllers(t, catalog.DefaultControllerDependencies()) + RunCatalogV1Alpha1IntegrationTest(t, client) +} diff --git a/internal/catalog/catalogtest/test_integration_v1alpha1.go b/internal/catalog/catalogtest/test_integration_v1alpha1.go new file mode 100644 index 0000000000000..8a7f4cd9a2488 --- /dev/null +++ b/internal/catalog/catalogtest/test_integration_v1alpha1.go @@ -0,0 +1,707 @@ +package catalogtest + +import ( + "embed" + "fmt" + "testing" + + "github.com/hashicorp/consul/internal/catalog" + "github.com/hashicorp/consul/internal/catalog/internal/controllers/endpoints" + "github.com/hashicorp/consul/internal/catalog/internal/controllers/nodehealth" + "github.com/hashicorp/consul/internal/catalog/internal/controllers/workloadhealth" + "github.com/hashicorp/consul/internal/catalog/internal/types" + rtest "github.com/hashicorp/consul/internal/resource/resourcetest" + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v1alpha1" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/proto/private/prototest" + "github.com/hashicorp/consul/sdk/testutil" + "github.com/stretchr/testify/require" +) + +var ( + //go:embed integration_test_data + testData embed.FS +) + +// RunCatalogV1Alpha1IntegrationTest will push up a bunch of catalog related data and then +// verify that all the expected reconciliations happened correctly. This test is +// intended to exercise a large swathe of behavior of the overall catalog package. +// Besides just controller reconciliation behavior, the intent is also to verify +// that integrations with the resource service are also working (i.e. the various +// validation, mutation and ACL hooks get invoked and are working properly) +// +// This test specifically is not doing any sort of lifecycle related tests to ensure +// that modification to values results in re-reconciliation as expected. Instead there +// is another RunCatalogIntegrationTestLifeCycle function that can be used for those +// purposes. The two are distinct so that the data being published and the assertions +// made against the system can be reused in upgrade tests. +func RunCatalogV1Alpha1IntegrationTest(t *testing.T, client pbresource.ResourceServiceClient) { + t.Helper() + + PublishCatalogV1Alpha1IntegrationTestData(t, client) + VerifyCatalogV1Alpha1IntegrationTestResults(t, client) +} + +// PublishCatalogV1Alpha1IntegrationTestData will perform a whole bunch of resource writes +// for Service, ServiceEndpoints, Workload, Node and HealthStatus objects +func PublishCatalogV1Alpha1IntegrationTestData(t *testing.T, client pbresource.ResourceServiceClient) { + t.Helper() + + c := rtest.NewClient(client) + + resources := rtest.ParseResourcesFromFilesystem(t, testData, "integration_test_data/v1alpha1") + c.PublishResources(t, resources) +} + +func VerifyCatalogV1Alpha1IntegrationTestResults(t *testing.T, client pbresource.ResourceServiceClient) { + t.Helper() + + c := rtest.NewClient(client) + + testutil.RunStep(t, "resources-exist", func(t *testing.T) { + c.RequireResourceExists(t, rtest.Resource(catalog.ServiceV1Alpha1Type, "api").ID()) + c.RequireResourceExists(t, rtest.Resource(catalog.ServiceV1Alpha1Type, "http-api").ID()) + c.RequireResourceExists(t, rtest.Resource(catalog.ServiceV1Alpha1Type, "grpc-api").ID()) + c.RequireResourceExists(t, rtest.Resource(catalog.ServiceV1Alpha1Type, "foo").ID()) + + for i := 1; i < 5; i++ { + nodeId := rtest.Resource(catalog.NodeV1Alpha1Type, fmt.Sprintf("node-%d", i)).ID() + c.RequireResourceExists(t, nodeId) + + res := c.RequireResourceExists(t, rtest.Resource(catalog.HealthStatusV1Alpha1Type, fmt.Sprintf("node-%d-health", i)).ID()) + rtest.RequireOwner(t, res, nodeId, true) + } + + for i := 1; i < 21; i++ { + workloadId := rtest.Resource(catalog.WorkloadV1Alpha1Type, fmt.Sprintf("api-%d", i)).ID() + c.RequireResourceExists(t, workloadId) + + res := c.RequireResourceExists(t, rtest.Resource(catalog.HealthStatusV1Alpha1Type, fmt.Sprintf("api-%d-health", i)).ID()) + rtest.RequireOwner(t, res, workloadId, true) + } + }) + + testutil.RunStep(t, "node-health-reconciliation", func(t *testing.T) { + c.WaitForStatusCondition(t, rtest.Resource(catalog.NodeV1Alpha1Type, "node-1").ID(), nodehealth.StatusKey, nodehealth.ConditionPassing) + c.WaitForStatusCondition(t, rtest.Resource(catalog.NodeV1Alpha1Type, "node-2").ID(), nodehealth.StatusKey, nodehealth.ConditionWarning) + c.WaitForStatusCondition(t, rtest.Resource(catalog.NodeV1Alpha1Type, "node-3").ID(), nodehealth.StatusKey, nodehealth.ConditionCritical) + c.WaitForStatusCondition(t, rtest.Resource(catalog.NodeV1Alpha1Type, "node-4").ID(), nodehealth.StatusKey, nodehealth.ConditionMaintenance) + }) + + testutil.RunStep(t, "workload-health-reconciliation", func(t *testing.T) { + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-1").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadPassing) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-2").ID(), workloadhealth.StatusKey, workloadhealth.ConditionWorkloadWarning) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-3").ID(), workloadhealth.StatusKey, workloadhealth.ConditionWorkloadCritical) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-4").ID(), workloadhealth.StatusKey, workloadhealth.ConditionWorkloadMaintenance) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-5").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeWarning) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-6").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadWarning) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-7").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadCritical) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-8").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadMaintenance) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-9").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeCritical) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-10").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadCritical) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-11").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadCritical) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-12").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadMaintenance) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-13").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeMaintenance) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-14").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadMaintenance) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-15").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadMaintenance) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-16").ID(), workloadhealth.StatusKey, workloadhealth.ConditionNodeAndWorkloadMaintenance) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-17").ID(), workloadhealth.StatusKey, workloadhealth.ConditionWorkloadPassing) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-18").ID(), workloadhealth.StatusKey, workloadhealth.ConditionWorkloadWarning) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-19").ID(), workloadhealth.StatusKey, workloadhealth.ConditionWorkloadCritical) + c.WaitForStatusCondition(t, rtest.Resource(catalog.WorkloadV1Alpha1Type, "api-20").ID(), workloadhealth.StatusKey, workloadhealth.ConditionWorkloadMaintenance) + }) + + testutil.RunStep(t, "service-reconciliation", func(t *testing.T) { + c.WaitForStatusCondition(t, rtest.Resource(catalog.ServiceV1Alpha1Type, "foo").ID(), endpoints.StatusKey, endpoints.ConditionUnmanaged) + c.WaitForStatusCondition(t, rtest.Resource(catalog.ServiceV1Alpha1Type, "api").ID(), endpoints.StatusKey, endpoints.ConditionManaged) + c.WaitForStatusCondition(t, rtest.Resource(catalog.ServiceV1Alpha1Type, "http-api").ID(), endpoints.StatusKey, endpoints.ConditionManaged) + c.WaitForStatusCondition(t, rtest.Resource(catalog.ServiceV1Alpha1Type, "grpc-api").ID(), endpoints.StatusKey, endpoints.ConditionManaged) + }) + + testutil.RunStep(t, "service-endpoints-generation", func(t *testing.T) { + verifyServiceEndpoints(t, c, rtest.Resource(catalog.ServiceEndpointsV1Alpha1Type, "foo").ID(), expectedFooServiceEndpoints()) + verifyServiceEndpoints(t, c, rtest.Resource(catalog.ServiceEndpointsV1Alpha1Type, "api").ID(), expectedApiServiceEndpoints(t, c)) + verifyServiceEndpoints(t, c, rtest.Resource(catalog.ServiceEndpointsV1Alpha1Type, "http-api").ID(), expectedHTTPApiServiceEndpoints(t, c)) + verifyServiceEndpoints(t, c, rtest.Resource(catalog.ServiceEndpointsV1Alpha1Type, "grpc-api").ID(), expectedGRPCApiServiceEndpoints(t, c)) + }) +} + +func expectedFooServiceEndpoints() *pbcatalog.ServiceEndpoints { + return &pbcatalog.ServiceEndpoints{ + Endpoints: []*pbcatalog.Endpoint{ + { + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "198.18.0.1"}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "external-service-port": { + Port: 9876, + Protocol: pbcatalog.Protocol_PROTOCOL_HTTP2, + }, + }, + HealthStatus: pbcatalog.Health_HEALTH_PASSING, + }, + }, + } +} + +func expectedApiServiceEndpoints(t *testing.T, c *rtest.Client) *pbcatalog.ServiceEndpoints { + return &pbcatalog.ServiceEndpoints{ + Endpoints: []*pbcatalog.Endpoint{ + // api-1 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-1").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.1", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.1", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_PASSING, + }, + // api-2 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-2").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.2", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.2", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_WARNING, + }, + // api-3 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-3").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.3", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.3", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-4 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-4").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.4", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.4", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-5 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-5").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.5", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.5", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_WARNING, + }, + // api-6 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-6").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.6", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.6", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_WARNING, + }, + // api-7 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-7").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.7", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.7", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-8 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-8").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.8", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.8", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-9 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-9").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.9", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.9", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-10 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-10").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.10", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.10", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-11 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-11").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.11", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.11", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-12 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-12").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.12", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.12", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-13 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-13").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.13", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.13", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-14 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-14").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.14", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.14", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-15 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-15").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.15", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.15", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-16 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-16").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.16", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.16", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-17 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-17").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.17", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.17", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_PASSING, + }, + // api-18 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-18").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.18", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.18", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_WARNING, + }, + // api-19 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-19").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.19", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.19", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-20 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-20").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.20", Ports: []string{"grpc", "http", "mesh"}}, + {Host: "198.18.2.20", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + }, + } +} + +func expectedHTTPApiServiceEndpoints(t *testing.T, c *rtest.Client) *pbcatalog.ServiceEndpoints { + return &pbcatalog.ServiceEndpoints{ + Endpoints: []*pbcatalog.Endpoint{ + // api-1 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-1").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.1", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_PASSING, + }, + // api-10 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-10").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.10", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-11 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-11").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.11", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-12 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-12").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.12", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-13 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-13").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.13", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-14 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-14").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.14", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-15 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-15").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.15", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-16 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-16").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.16", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-17 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-17").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.17", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_PASSING, + }, + // api-18 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-18").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.18", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_WARNING, + }, + // api-19 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-19").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.19", Ports: []string{"http"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + }, + } +} + +func expectedGRPCApiServiceEndpoints(t *testing.T, c *rtest.Client) *pbcatalog.ServiceEndpoints { + return &pbcatalog.ServiceEndpoints{ + Endpoints: []*pbcatalog.Endpoint{ + // api-1 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-1").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.1", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.1", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_PASSING, + }, + // api-2 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-2").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.2", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.2", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_WARNING, + }, + // api-3 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-3").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.3", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.3", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-4 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-4").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.4", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.4", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-5 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-5").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.5", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.5", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_WARNING, + }, + // api-6 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-6").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.6", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.6", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_WARNING, + }, + // api-7 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-7").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.7", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.7", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-8 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-8").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.8", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.8", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + // api-9 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-9").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.9", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.9", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_CRITICAL, + }, + // api-20 + { + TargetRef: c.ResolveResourceID(t, rtest.Resource(types.WorkloadV1Alpha1Type, "api-20").ID()), + Addresses: []*pbcatalog.WorkloadAddress{ + {Host: "172.16.1.20", Ports: []string{"grpc", "mesh"}}, + {Host: "198.18.2.20", External: true, Ports: []string{"mesh"}}, + }, + Ports: map[string]*pbcatalog.WorkloadPort{ + "grpc": {Port: 9090, Protocol: pbcatalog.Protocol_PROTOCOL_GRPC}, + "mesh": {Port: 10000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, + HealthStatus: pbcatalog.Health_HEALTH_MAINTENANCE, + }, + }, + } +} + +func verifyServiceEndpoints(t *testing.T, c *rtest.Client, id *pbresource.ID, expected *pbcatalog.ServiceEndpoints) { + c.WaitForResourceState(t, id, func(t rtest.T, res *pbresource.Resource) { + var actual pbcatalog.ServiceEndpoints + err := res.Data.UnmarshalTo(&actual) + require.NoError(t, err) + prototest.AssertElementsMatch(t, expected.Endpoints, actual.Endpoints) + }) +} diff --git a/internal/catalog/internal/controllers/nodehealth/controller.go b/internal/catalog/internal/controllers/nodehealth/controller.go index d7586f6121cbe..4e3aff9993ba1 100644 --- a/internal/catalog/internal/controllers/nodehealth/controller.go +++ b/internal/catalog/internal/controllers/nodehealth/controller.go @@ -50,22 +50,10 @@ func (r *nodeHealthReconciler) Reconcile(ctx context.Context, rt controller.Runt return err } - message := NodeHealthyMessage - statusState := pbresource.Condition_STATE_TRUE - if health != pbcatalog.Health_HEALTH_PASSING { - statusState = pbresource.Condition_STATE_FALSE - message = NodeUnhealthyMessage - } - newStatus := &pbresource.Status{ ObservedGeneration: res.Generation, Conditions: []*pbresource.Condition{ - { - Type: StatusConditionHealthy, - State: statusState, - Reason: health.String(), - Message: message, - }, + Conditions[health], }, } diff --git a/internal/catalog/internal/controllers/nodehealth/status.go b/internal/catalog/internal/controllers/nodehealth/status.go index 8cb989101dad6..14a3151484b59 100644 --- a/internal/catalog/internal/controllers/nodehealth/status.go +++ b/internal/catalog/internal/controllers/nodehealth/status.go @@ -3,6 +3,11 @@ package nodehealth +import ( + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v1alpha1" + "github.com/hashicorp/consul/proto-public/pbresource" +) + const ( StatusKey = "consul.io/node-health" StatusConditionHealthy = "healthy" @@ -10,3 +15,40 @@ const ( NodeHealthyMessage = "All node health checks are passing" NodeUnhealthyMessage = "One or more node health checks are not passing" ) + +var ( + ConditionPassing = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_TRUE, + Reason: pbcatalog.Health_HEALTH_PASSING.String(), + Message: NodeHealthyMessage, + } + + ConditionWarning = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_WARNING.String(), + Message: NodeUnhealthyMessage, + } + + ConditionCritical = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_CRITICAL.String(), + Message: NodeUnhealthyMessage, + } + + ConditionMaintenance = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_MAINTENANCE.String(), + Message: NodeUnhealthyMessage, + } + + Conditions = map[pbcatalog.Health]*pbresource.Condition{ + pbcatalog.Health_HEALTH_PASSING: ConditionPassing, + pbcatalog.Health_HEALTH_WARNING: ConditionWarning, + pbcatalog.Health_HEALTH_CRITICAL: ConditionCritical, + pbcatalog.Health_HEALTH_MAINTENANCE: ConditionMaintenance, + } +) diff --git a/internal/catalog/internal/controllers/workloadhealth/controller.go b/internal/catalog/internal/controllers/workloadhealth/controller.go index 05fccf631f71a..77009697bcd7e 100644 --- a/internal/catalog/internal/controllers/workloadhealth/controller.go +++ b/internal/catalog/internal/controllers/workloadhealth/controller.go @@ -120,33 +120,15 @@ func (r *workloadHealthReconciler) Reconcile(ctx context.Context, rt controller. health = workloadHealth } - statusState := pbresource.Condition_STATE_TRUE - if health != pbcatalog.Health_HEALTH_PASSING { - statusState = pbresource.Condition_STATE_FALSE - } - - message := WorkloadHealthyMessage + condition := WorkloadConditions[workloadHealth] if workload.NodeName != "" { - message = NodeAndWorkloadHealthyMessage - } - switch { - case workloadHealth != pbcatalog.Health_HEALTH_PASSING && nodeHealth != pbcatalog.Health_HEALTH_PASSING: - message = NodeAndWorkloadUnhealthyMessage - case workloadHealth != pbcatalog.Health_HEALTH_PASSING: - message = WorkloadUnhealthyMessage - case nodeHealth != pbcatalog.Health_HEALTH_PASSING: - message = nodehealth.NodeUnhealthyMessage + condition = NodeAndWorkloadConditions[workloadHealth][nodeHealth] } newStatus := &pbresource.Status{ ObservedGeneration: res.Generation, Conditions: []*pbresource.Condition{ - { - Type: StatusConditionHealthy, - State: statusState, - Reason: health.String(), - Message: message, - }, + condition, }, } diff --git a/internal/catalog/internal/controllers/workloadhealth/status.go b/internal/catalog/internal/controllers/workloadhealth/status.go index a7da3fad6b3ca..05cc989ddd934 100644 --- a/internal/catalog/internal/controllers/workloadhealth/status.go +++ b/internal/catalog/internal/controllers/workloadhealth/status.go @@ -1,5 +1,11 @@ package workloadhealth +import ( + "github.com/hashicorp/consul/internal/catalog/internal/controllers/nodehealth" + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v1alpha1" + "github.com/hashicorp/consul/proto-public/pbresource" +) + const ( StatusKey = "consul.io/workload-health" StatusConditionHealthy = "healthy" @@ -9,3 +15,122 @@ const ( NodeAndWorkloadUnhealthyMessage = "One or more workload and node health checks are not passing" WorkloadUnhealthyMessage = "One or more workload health checks are not passing" ) + +var ( + ConditionWorkloadPassing = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_TRUE, + Reason: pbcatalog.Health_HEALTH_PASSING.String(), + Message: WorkloadHealthyMessage, + } + + ConditionWorkloadWarning = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_WARNING.String(), + Message: WorkloadUnhealthyMessage, + } + + ConditionWorkloadCritical = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_CRITICAL.String(), + Message: WorkloadUnhealthyMessage, + } + + ConditionWorkloadMaintenance = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_MAINTENANCE.String(), + Message: WorkloadUnhealthyMessage, + } + + ConditionNodeAndWorkloadPassing = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_TRUE, + Reason: pbcatalog.Health_HEALTH_PASSING.String(), + Message: NodeAndWorkloadHealthyMessage, + } + + ConditionNodeAndWorkloadWarning = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_WARNING.String(), + Message: NodeAndWorkloadUnhealthyMessage, + } + + ConditionNodeAndWorkloadCritical = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_CRITICAL.String(), + Message: NodeAndWorkloadUnhealthyMessage, + } + + ConditionNodeAndWorkloadMaintenance = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_MAINTENANCE.String(), + Message: NodeAndWorkloadUnhealthyMessage, + } + + ConditionNodeWarning = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_WARNING.String(), + Message: nodehealth.NodeUnhealthyMessage, + } + + ConditionNodeCritical = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_CRITICAL.String(), + Message: nodehealth.NodeUnhealthyMessage, + } + + ConditionNodeMaintenance = &pbresource.Condition{ + Type: StatusConditionHealthy, + State: pbresource.Condition_STATE_FALSE, + Reason: pbcatalog.Health_HEALTH_MAINTENANCE.String(), + Message: nodehealth.NodeUnhealthyMessage, + } + + // WorkloadConditions is a map of the workloadhealth to the status condition + // used to represent that health. + WorkloadConditions = map[pbcatalog.Health]*pbresource.Condition{ + pbcatalog.Health_HEALTH_PASSING: ConditionWorkloadPassing, + pbcatalog.Health_HEALTH_WARNING: ConditionWorkloadWarning, + pbcatalog.Health_HEALTH_CRITICAL: ConditionWorkloadCritical, + pbcatalog.Health_HEALTH_MAINTENANCE: ConditionWorkloadMaintenance, + } + + // NodeAndWorkloadConditions is a map whose ultimate values are the status conditions + // used to represent the combined health of a workload and its associated node. + // The outer map's keys are the workloads health and the inner maps keys are the nodes + // health + NodeAndWorkloadConditions = map[pbcatalog.Health]map[pbcatalog.Health]*pbresource.Condition{ + pbcatalog.Health_HEALTH_PASSING: { + pbcatalog.Health_HEALTH_PASSING: ConditionNodeAndWorkloadPassing, + pbcatalog.Health_HEALTH_WARNING: ConditionNodeWarning, + pbcatalog.Health_HEALTH_CRITICAL: ConditionNodeCritical, + pbcatalog.Health_HEALTH_MAINTENANCE: ConditionNodeMaintenance, + }, + pbcatalog.Health_HEALTH_WARNING: { + pbcatalog.Health_HEALTH_PASSING: ConditionWorkloadWarning, + pbcatalog.Health_HEALTH_WARNING: ConditionNodeAndWorkloadWarning, + pbcatalog.Health_HEALTH_CRITICAL: ConditionNodeAndWorkloadCritical, + pbcatalog.Health_HEALTH_MAINTENANCE: ConditionNodeAndWorkloadMaintenance, + }, + pbcatalog.Health_HEALTH_CRITICAL: { + pbcatalog.Health_HEALTH_PASSING: ConditionWorkloadCritical, + pbcatalog.Health_HEALTH_WARNING: ConditionNodeAndWorkloadCritical, + pbcatalog.Health_HEALTH_CRITICAL: ConditionNodeAndWorkloadCritical, + pbcatalog.Health_HEALTH_MAINTENANCE: ConditionNodeAndWorkloadMaintenance, + }, + pbcatalog.Health_HEALTH_MAINTENANCE: { + pbcatalog.Health_HEALTH_PASSING: ConditionWorkloadMaintenance, + pbcatalog.Health_HEALTH_WARNING: ConditionNodeAndWorkloadMaintenance, + pbcatalog.Health_HEALTH_CRITICAL: ConditionNodeAndWorkloadMaintenance, + pbcatalog.Health_HEALTH_MAINTENANCE: ConditionNodeAndWorkloadMaintenance, + }, + } +) diff --git a/internal/catalog/internal/types/service.go b/internal/catalog/internal/types/service.go index f4da3cd8e4b6e..27e13530e5f3f 100644 --- a/internal/catalog/internal/types/service.go +++ b/internal/catalog/internal/types/service.go @@ -71,7 +71,7 @@ func ValidateService(res *pbresource.Resource) error { }, }, }) - } else { + } else if port.VirtualPort != 0 { usedVirtualPorts[port.VirtualPort] = idx } diff --git a/internal/catalog/internal/types/service_test.go b/internal/catalog/internal/types/service_test.go index 241a49939dee8..1a0a035d91613 100644 --- a/internal/catalog/internal/types/service_test.go +++ b/internal/catalog/internal/types/service_test.go @@ -45,6 +45,18 @@ func TestValidateService_Ok(t *testing.T) { VirtualPort: 42, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP, }, + { + TargetPort: "other", + // leaving VirtualPort unset to verify that seeing + // a zero virtual port multiple times is fine. + Protocol: pbcatalog.Protocol_PROTOCOL_HTTP2, + }, + { + TargetPort: "other2", + // leaving VirtualPort unset to verify that seeing + // a zero virtual port multiple times is fine. + Protocol: pbcatalog.Protocol_PROTOCOL_GRPC, + }, }, VirtualIps: []string{"198.18.0.1"}, } diff --git a/internal/resource/resourcetest/fs.go b/internal/resource/resourcetest/fs.go new file mode 100644 index 0000000000000..4763d63a44228 --- /dev/null +++ b/internal/resource/resourcetest/fs.go @@ -0,0 +1,40 @@ +package resourcetest + +import ( + "fmt" + "io/fs" + + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" +) + +// ParseResourcesFromFilesystem will walk the filesystem at the given path +// and parse all files as protobuf/JSON resources. +func ParseResourcesFromFilesystem(t T, files fs.FS, path string) []*pbresource.Resource { + t.Helper() + + var resources []*pbresource.Resource + err := fs.WalkDir(files, path, func(fpath string, dent fs.DirEntry, err error) error { + if dent.IsDir() { + return nil + } + + data, err := fs.ReadFile(files, fpath) + if err != nil { + return err + } + + var res pbresource.Resource + err = protojson.Unmarshal(data, &res) + if err != nil { + return fmt.Errorf("error decoding data from %s: %w", fpath, err) + } + + resources = append(resources, &res) + return nil + }) + + require.NoError(t, err) + return resources +}