Skip to content

Commit f87115a

Browse files
authored
Add the support for creating service with DNS namespace type (#48)
1 parent a6f457d commit f87115a

File tree

6 files changed

+392
-105
lines changed

6 files changed

+392
-105
lines changed

pkg/cloudmap/api.go

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ import (
1313
ctrl "sigs.k8s.io/controller-runtime"
1414
)
1515

16+
const (
17+
defaultServiceTTLInSeconds int64 = 60
18+
)
19+
1620
// ServiceDiscoveryApi handles the AWS Cloud Map API request and response processing logic, and converts results to
1721
// internal data structures. It manages all interactions with the AWS SDK.
1822
type ServiceDiscoveryApi interface {
1923
// ListNamespaces returns a list of all namespaces.
20-
ListNamespaces(ctx context.Context) (namespaces []*model.Resource, err error)
24+
ListNamespaces(ctx context.Context) (namespaces []*model.Namespace, err error)
2125

2226
// ListServices returns a list of services for a given namespace.
2327
ListServices(ctx context.Context, namespaceId string) (services []*model.Resource, err error)
@@ -35,7 +39,7 @@ type ServiceDiscoveryApi interface {
3539
CreateHttpNamespace(ctx context.Context, namespaceName string) (operationId string, err error)
3640

3741
// CreateService creates a named service in AWS Cloud Map under the given namespace.
38-
CreateService(ctx context.Context, namespaceId string, serviceName string) (serviceId string, err error)
42+
CreateService(ctx context.Context, namespace model.Namespace, serviceName string) (serviceId string, err error)
3943

4044
// RegisterInstance registers a service instance in AWS Cloud Map.
4145
RegisterInstance(ctx context.Context, serviceId string, instanceId string, instanceAttrs map[string]string) (operationId string, err error)
@@ -60,8 +64,8 @@ func NewServiceDiscoveryApiFromConfig(cfg *aws.Config) ServiceDiscoveryApi {
6064
}
6165
}
6266

63-
func (sdApi *serviceDiscoveryApi) ListNamespaces(ctx context.Context) ([]*model.Resource, error) {
64-
namespaces := make([]*model.Resource, 0)
67+
func (sdApi *serviceDiscoveryApi) ListNamespaces(ctx context.Context) ([]*model.Namespace, error) {
68+
namespaces := make([]*model.Namespace, 0)
6569
pages := sd.NewListNamespacesPaginator(sdApi.awsFacade, &sd.ListNamespacesInput{})
6670

6771
for pages.HasMorePages() {
@@ -71,10 +75,13 @@ func (sdApi *serviceDiscoveryApi) ListNamespaces(ctx context.Context) ([]*model.
7175
}
7276

7377
for _, ns := range output.Namespaces {
74-
namespaces = append(namespaces, &model.Resource{
75-
Id: aws.ToString(ns.Id),
76-
Name: aws.ToString(ns.Name),
77-
})
78+
if namespaceType := model.ConvertNamespaceType(ns.Type); !namespaceType.IsUnsupported() {
79+
namespaces = append(namespaces, &model.Namespace{
80+
Id: aws.ToString(ns.Id),
81+
Name: aws.ToString(ns.Name),
82+
Type: namespaceType,
83+
})
84+
}
7885
}
7986
}
8087

@@ -178,10 +185,19 @@ func (sdApi *serviceDiscoveryApi) CreateHttpNamespace(ctx context.Context, nsNam
178185
return aws.ToString(output.OperationId), nil
179186
}
180187

181-
func (sdApi *serviceDiscoveryApi) CreateService(ctx context.Context, nsId string, svcName string) (svcId string, err error) {
182-
output, err := sdApi.awsFacade.CreateService(ctx, &sd.CreateServiceInput{
183-
NamespaceId: &nsId,
184-
Name: &svcName})
188+
func (sdApi *serviceDiscoveryApi) CreateService(ctx context.Context, namespace model.Namespace, svcName string) (svcId string, err error) {
189+
var output *sd.CreateServiceOutput
190+
if namespace.Type == model.DnsPrivateNamespaceType {
191+
dnsConfig := sdApi.getDnsConfig()
192+
output, err = sdApi.awsFacade.CreateService(ctx, &sd.CreateServiceInput{
193+
NamespaceId: &namespace.Id,
194+
DnsConfig: &dnsConfig,
195+
Name: &svcName})
196+
} else {
197+
output, err = sdApi.awsFacade.CreateService(ctx, &sd.CreateServiceInput{
198+
NamespaceId: &namespace.Id,
199+
Name: &svcName})
200+
}
185201

186202
if err != nil {
187203
return "", err
@@ -192,6 +208,18 @@ func (sdApi *serviceDiscoveryApi) CreateService(ctx context.Context, nsId string
192208
return svcId, nil
193209
}
194210

211+
func (sdApi *serviceDiscoveryApi) getDnsConfig() types.DnsConfig {
212+
dnsConfig := types.DnsConfig{
213+
DnsRecords: []types.DnsRecord{
214+
{
215+
TTL: aws.Int64(defaultServiceTTLInSeconds),
216+
Type: "SRV",
217+
},
218+
},
219+
}
220+
return dnsConfig
221+
}
222+
195223
func (sdApi *serviceDiscoveryApi) RegisterInstance(ctx context.Context, svcId string, instId string, instAttrs map[string]string) (opId string, err error) {
196224
regResp, err := sdApi.awsFacade.RegisterInstance(ctx, &sd.RegisterInstanceInput{
197225
Attributes: instAttrs,

pkg/cloudmap/api_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package cloudmap
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/aws/aws-cloud-map-mcs-controller-for-k8s/mocks/pkg/cloudmap"
7+
"github.com/aws/aws-cloud-map-mcs-controller-for-k8s/test"
8+
"github.com/aws/aws-sdk-go-v2/aws"
9+
sd "github.com/aws/aws-sdk-go-v2/service/servicediscovery"
10+
"github.com/aws/aws-sdk-go-v2/service/servicediscovery/types"
11+
testingLogger "github.com/go-logr/logr/testing"
12+
"github.com/golang/mock/gomock"
13+
"github.com/stretchr/testify/assert"
14+
"testing"
15+
)
16+
17+
func TestNewServiceDiscoveryApi(t *testing.T) {
18+
sdc := NewServiceDiscoveryApiFromConfig(&aws.Config{})
19+
assert.NotNil(t, sdc)
20+
}
21+
22+
func TestServiceDiscoveryApi_ListNamespaces_HappyCase(t *testing.T) {
23+
mockController := gomock.NewController(t)
24+
defer mockController.Finish()
25+
26+
awsFacade := cloudmap.NewMockAwsFacade(mockController)
27+
sdApi := getServiceDiscoveryApi(t, awsFacade)
28+
29+
id, name := test.NsId, test.NsName
30+
ns := types.NamespaceSummary{
31+
Name: &name,
32+
Id: &id,
33+
Type: types.NamespaceTypeDnsPrivate,
34+
}
35+
awsFacade.EXPECT().ListNamespaces(context.TODO(), &sd.ListNamespacesInput{}).
36+
Return(&sd.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ns}}, nil)
37+
38+
namespaces, _ := sdApi.ListNamespaces(context.TODO())
39+
assert.True(t, len(namespaces) == 1)
40+
assert.Equal(t, test.GetTestDnsNamespace(), namespaces[0], "")
41+
}
42+
43+
func TestServiceDiscoveryApi_ListNamespaces_SkipPublicDNSNotSupported(t *testing.T) {
44+
mockController := gomock.NewController(t)
45+
defer mockController.Finish()
46+
47+
awsFacade := cloudmap.NewMockAwsFacade(mockController)
48+
sdApi := getServiceDiscoveryApi(t, awsFacade)
49+
50+
id, name := test.NsId, test.NsName
51+
ns := types.NamespaceSummary{
52+
Name: &name,
53+
Id: &id,
54+
Type: types.NamespaceTypeDnsPublic,
55+
}
56+
awsFacade.EXPECT().ListNamespaces(context.TODO(), &sd.ListNamespacesInput{}).
57+
Return(&sd.ListNamespacesOutput{Namespaces: []types.NamespaceSummary{ns}}, nil)
58+
59+
namespaces, _ := sdApi.ListNamespaces(context.TODO())
60+
assert.True(t, len(namespaces) == 0, "Successfully skipped DNS_PUBLIC from the output")
61+
}
62+
63+
func TestServiceDiscoveryApi_CreateService_CreateForHttpNamespace(t *testing.T) {
64+
mockController := gomock.NewController(t)
65+
defer mockController.Finish()
66+
67+
awsFacade := cloudmap.NewMockAwsFacade(mockController)
68+
sdApi := getServiceDiscoveryApi(t, awsFacade)
69+
70+
nsId, svcId, svcName := test.NsId, test.SvcId, test.SvcName
71+
awsFacade.EXPECT().CreateService(context.TODO(), &sd.CreateServiceInput{
72+
Name: &svcName,
73+
NamespaceId: &nsId,
74+
}).
75+
Return(&sd.CreateServiceOutput{
76+
Service: &types.Service{
77+
Id: &svcId,
78+
},
79+
}, nil)
80+
81+
retSvcId, _ := sdApi.CreateService(context.TODO(), *test.GetTestHttpNamespace(), svcName)
82+
assert.Equal(t, svcId, retSvcId, "Successfully created service")
83+
}
84+
85+
func TestServiceDiscoveryApi_CreateService_CreateForDnsNamespace(t *testing.T) {
86+
mockController := gomock.NewController(t)
87+
defer mockController.Finish()
88+
89+
awsFacade := cloudmap.NewMockAwsFacade(mockController)
90+
sdApi := getServiceDiscoveryApi(t, awsFacade)
91+
92+
nsId, svcId, svcName := test.NsId, test.SvcId, test.SvcName
93+
awsFacade.EXPECT().CreateService(context.TODO(), &sd.CreateServiceInput{
94+
Name: &svcName,
95+
NamespaceId: &nsId,
96+
DnsConfig: &types.DnsConfig{
97+
DnsRecords: []types.DnsRecord{{
98+
TTL: aws.Int64(60),
99+
Type: "SRV",
100+
}},
101+
},
102+
}).
103+
Return(&sd.CreateServiceOutput{
104+
Service: &types.Service{
105+
Id: &svcId,
106+
},
107+
}, nil)
108+
109+
retSvcId, _ := sdApi.CreateService(context.TODO(), *test.GetTestDnsNamespace(), svcName)
110+
assert.Equal(t, svcId, retSvcId, "Successfully created service")
111+
}
112+
113+
func TestServiceDiscoveryApi_CreateService_ThrowError(t *testing.T) {
114+
mockController := gomock.NewController(t)
115+
defer mockController.Finish()
116+
117+
awsFacade := cloudmap.NewMockAwsFacade(mockController)
118+
sdApi := getServiceDiscoveryApi(t, awsFacade)
119+
120+
nsId, svcName := test.NsId, test.SvcName
121+
awsFacade.EXPECT().CreateService(context.TODO(), &sd.CreateServiceInput{
122+
Name: &svcName,
123+
NamespaceId: &nsId,
124+
}).
125+
Return(nil, fmt.Errorf("dummy error"))
126+
127+
retSvcId, err := sdApi.CreateService(context.TODO(), *test.GetTestHttpNamespace(), svcName)
128+
assert.Empty(t, retSvcId)
129+
assert.Equal(t, "dummy error", fmt.Sprint(err), "Got error")
130+
}
131+
132+
func getServiceDiscoveryApi(t *testing.T, awsFacade *cloudmap.MockAwsFacade) serviceDiscoveryApi {
133+
return serviceDiscoveryApi{
134+
log: testingLogger.TestLogger{T: t},
135+
awsFacade: awsFacade,
136+
}
137+
}

0 commit comments

Comments
 (0)