Skip to content

Commit dbaa1fc

Browse files
authored
Add integration test for service export (#69)
1 parent 58191bf commit dbaa1fc

22 files changed

+369
-34
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
vendor/
22
bin/
33
testbin/
4+
testlog/
45
cover.out
56

67
# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ test: manifests generate generate-mocks fmt vet ## Run tests.
6060
test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.7.2/hack/setup-envtest.sh
6161
source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out -covermode=atomic
6262

63+
integration-setup: ## Setup the integration test using kind clusters
64+
@./integration/scripts/setup-kind.sh
65+
66+
integration-run: ## Run the integration test controller
67+
@./integration/scripts/run-tests.sh
68+
69+
integration-cleanup: ## Cleanup integration test resources in Cloud Map and local kind cluster
70+
@./integration/scripts/cleanup-cloudmap.sh
71+
@./integration/scripts/cleanup-kind.sh
72+
6373
##@ Build
6474

6575
build: manifests generate generate-mocks fmt vet ## Build manager binary.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
namespace: aws-cloud-map-mcs-e2e
5+
name: coredns-deployment
6+
labels:
7+
app: coredns
8+
spec:
9+
replicas: 5
10+
selector:
11+
matchLabels:
12+
app: coredns
13+
template:
14+
metadata:
15+
labels:
16+
app: coredns
17+
spec:
18+
containers:
19+
- name: coredns
20+
image: k8s.gcr.io/coredns:1.7.0
21+
ports:
22+
- containerPort: 80

integration/configs/e2e-export.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: ServiceExport
2+
apiVersion: multicluster.x-k8s.io/v1alpha1
3+
metadata:
4+
namespace: aws-cloud-map-mcs-e2e
5+
name: e2e-service

integration/configs/e2e-service.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
kind: Service
2+
apiVersion: v1
3+
metadata:
4+
namespace: aws-cloud-map-mcs-e2e
5+
name: e2e-service
6+
spec:
7+
selector:
8+
app: coredns
9+
ports:
10+
- port: 8080
11+
targetPort: 80

integration/janitor/janitor.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ type cloudMapJanitor struct {
2222

2323
// NewDefaultJanitor returns a new janitor object.
2424
func NewDefaultJanitor() CloudMapJanitor {
25-
awsCfg, err := config.LoadDefaultConfig(context.TODO(),
26-
config.WithRegion(os.Getenv("AWS_REGION")),
27-
)
25+
awsCfg, err := config.LoadDefaultConfig(context.TODO())
2826

2927
if err != nil {
3028
fmt.Printf("unable to configure AWS session: %s", err.Error())

integration/janitor/runner/main.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ package main
22

33
import (
44
"context"
5+
"fmt"
56
"github.com/aws/aws-cloud-map-mcs-controller-for-k8s/integration/janitor"
6-
)
7-
8-
const (
9-
e2eNs = "aws-cloud-map-mcs-e2e"
7+
"os"
108
)
119

1210
func main() {
11+
if len(os.Args) != 2 {
12+
fmt.Println("Expected single namespace name argument")
13+
os.Exit(1)
14+
}
15+
1316
j := janitor.NewDefaultJanitor()
14-
j.Cleanup(context.TODO(), e2eNs)
17+
nsName := os.Args[1]
18+
j.Cleanup(context.TODO(), nsName)
1519
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package scenarios
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/aws/aws-cloud-map-mcs-controller-for-k8s/pkg/cloudmap"
7+
"github.com/aws/aws-cloud-map-mcs-controller-for-k8s/pkg/controllers"
8+
"github.com/aws/aws-cloud-map-mcs-controller-for-k8s/pkg/model"
9+
"github.com/aws/aws-sdk-go-v2/aws"
10+
"k8s.io/apimachinery/pkg/util/wait"
11+
"strconv"
12+
"strings"
13+
"time"
14+
)
15+
16+
const (
17+
defaultScenarioPollInterval = 10 * time.Second
18+
defaultScenarioPollTimeout = 2 * time.Minute
19+
)
20+
21+
// ExportServiceScenario defines an integration test against a service export to check creation of namespace, service,
22+
// and endpoint export.
23+
type ExportServiceScenario interface {
24+
// Run executes the service export integration test scenario, returning any error.
25+
Run() error
26+
}
27+
28+
type exportServiceScenario struct {
29+
sdClient cloudmap.ServiceDiscoveryClient
30+
expectedSvc model.Service
31+
}
32+
33+
func NewExportServiceScenario(cfg *aws.Config, nsName string, svcName string, portStr string, ips string) (ExportServiceScenario, error) {
34+
endpts := make([]*model.Endpoint, 0)
35+
36+
port, parseError := strconv.ParseUint(portStr, 10, 16)
37+
if parseError != nil {
38+
return nil, parseError
39+
}
40+
41+
for _, ip := range strings.Split(ips, ",") {
42+
endpts = append(endpts, &model.Endpoint{
43+
Id: model.EndpointIdFromIPAddress(ip),
44+
IP: ip,
45+
Port: int32(port),
46+
Attributes: make(map[string]string, 0),
47+
})
48+
}
49+
50+
return &exportServiceScenario{
51+
sdClient: cloudmap.NewServiceDiscoveryClientWithCustomCache(cfg,
52+
&cloudmap.SdCacheConfig{
53+
NsTTL: time.Second,
54+
SvcTTL: time.Second,
55+
EndptTTL: time.Second,
56+
}),
57+
expectedSvc: model.Service{
58+
Namespace: nsName,
59+
Name: svcName,
60+
Endpoints: endpts,
61+
},
62+
}, nil
63+
}
64+
65+
func (e *exportServiceScenario) Run() error {
66+
fmt.Printf("Seeking expected service: %v\n", e.expectedSvc)
67+
68+
return wait.Poll(defaultScenarioPollInterval, defaultScenarioPollTimeout, func() (done bool, err error) {
69+
fmt.Println("Polling service...")
70+
cmSvc, err := e.sdClient.GetService(context.TODO(), e.expectedSvc.Namespace, e.expectedSvc.Name)
71+
if err != nil {
72+
return true, err
73+
}
74+
75+
if cmSvc == nil {
76+
fmt.Println("Service not found.")
77+
return false, nil
78+
}
79+
80+
fmt.Printf("Found service: %v\n", cmSvc)
81+
return e.compareEndpoints(cmSvc.Endpoints), nil
82+
})
83+
}
84+
85+
func (e *exportServiceScenario) compareEndpoints(cmEndpoints []*model.Endpoint) bool {
86+
if len(e.expectedSvc.Endpoints) != len(cmEndpoints) {
87+
fmt.Println("Endpoints do not match.")
88+
return false
89+
}
90+
91+
for _, expected := range e.expectedSvc.Endpoints {
92+
match := false
93+
for _, actual := range cmEndpoints {
94+
// Ignore K8S instance attribute for the purpose of this test.
95+
delete(actual.Attributes, controllers.K8sVersionAttr)
96+
if expected.Equals(actual) {
97+
match = true
98+
break
99+
}
100+
}
101+
if !match {
102+
fmt.Println("Endpoints do not match.")
103+
return false
104+
}
105+
}
106+
107+
fmt.Println("Endpoints match.")
108+
return true
109+
}

integration/scenarios/runner/main.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/aws/aws-cloud-map-mcs-controller-for-k8s/integration/scenarios"
7+
"github.com/aws/aws-sdk-go-v2/aws"
8+
"github.com/aws/aws-sdk-go-v2/config"
9+
"os"
10+
)
11+
12+
func main() {
13+
if len(os.Args) != 5 {
14+
fmt.Println("Expected namespace, service, endpoint port, and endpoint IP list arguments")
15+
os.Exit(1)
16+
}
17+
18+
nsName := os.Args[1]
19+
svcName := os.Args[2]
20+
port := os.Args[3]
21+
ips := os.Args[4]
22+
23+
testServiceExport(nsName, svcName, port, ips)
24+
}
25+
26+
func testServiceExport(nsName string, svcName string, port string, ips string) {
27+
fmt.Printf("Testing service export integration for namespace %s and service %s\n", nsName, svcName)
28+
29+
export, err := scenarios.NewExportServiceScenario(getAwsConfig(), nsName, svcName, port, ips)
30+
if err != nil {
31+
fmt.Printf("Failed to setup service export integration test scenario: %s", err.Error())
32+
os.Exit(1)
33+
}
34+
35+
if err := export.Run(); err != nil {
36+
fmt.Printf("Service export integration test scenario failed: %s", err.Error())
37+
os.Exit(1)
38+
}
39+
}
40+
41+
func getAwsConfig() *aws.Config {
42+
awsCfg, err := config.LoadDefaultConfig(context.TODO())
43+
44+
if err != nil {
45+
fmt.Printf("unable to configure AWS session: %s", err.Error())
46+
os.Exit(1)
47+
}
48+
49+
return &awsCfg
50+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
3+
# Deletes all AWS Cloud Map resources used for integration test.
4+
5+
set -eo pipefail
6+
source ./integration/scripts/common.sh
7+
8+
go run ./integration/janitor/runner/main.go "$NAMESPACE"

0 commit comments

Comments
 (0)