Skip to content

Commit eeeaf3f

Browse files
committed
Added functionality to find public and private namespaces by name
1 parent 8f81940 commit eeeaf3f

File tree

3 files changed

+481
-0
lines changed

3 files changed

+481
-0
lines changed
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
// Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
// Package servicediscovery contains functions for working with the route53 APIs
15+
// that back ECS Service Discovery
16+
package route53
17+
18+
import (
19+
"testing"
20+
21+
"github.com/aws/aws-sdk-go/aws"
22+
"github.com/aws/aws-sdk-go/service/route53"
23+
"github.com/aws/aws-sdk-go/service/servicediscovery"
24+
"github.com/stretchr/testify/assert"
25+
)
26+
27+
func TestFindPrivateNamespace(t *testing.T) {
28+
mockSD := setupNamespaceMocks(t, false)
29+
mockR53 := setupHostedZoneMocks(t)
30+
31+
var testCases = []struct {
32+
testName string
33+
name string
34+
vpc string
35+
region string
36+
expectedID *string
37+
}{
38+
{
39+
testName: "Find namespace1",
40+
name: "corp",
41+
vpc: "vpc-8BAADF00D",
42+
region: "us-east-1",
43+
expectedID: aws.String("namespace1"),
44+
},
45+
{
46+
testName: "Find namespace2",
47+
name: "prod",
48+
vpc: "vpc-1CEB00DA",
49+
region: "us-east-1",
50+
expectedID: aws.String("namespace2"),
51+
},
52+
{
53+
testName: "Find namespace4",
54+
name: "corp",
55+
vpc: "vpc-C00010FF",
56+
region: "sa-east-1",
57+
expectedID: aws.String("namespace4"),
58+
},
59+
{
60+
testName: "Namespace Does Not Exist",
61+
name: "corp",
62+
vpc: "vpc-C00010FF",
63+
region: "us-east-1",
64+
expectedID: nil,
65+
},
66+
{
67+
testName: "Namspace with multiple VPCs",
68+
name: "bridge",
69+
vpc: "vpc-D15EA5E",
70+
region: "ap-south-1",
71+
expectedID: aws.String("namespace3"),
72+
},
73+
}
74+
75+
for _, testCase := range testCases {
76+
t.Run(testCase.testName, func(t *testing.T) {
77+
namespaceID, err := findPrivateNamespace(testCase.name, testCase.vpc, testCase.region, mockR53, mockSD)
78+
assert.Equal(t, testCase.expectedID, namespaceID, "Expected namespace ID to match")
79+
assert.NoError(t, err, "Unexpected error from FindPrivateNamespace")
80+
})
81+
}
82+
}
83+
84+
func TestFindPublicNamespace(t *testing.T) {
85+
mockSD := setupNamespaceMocks(t, true)
86+
87+
var testCases = []struct {
88+
testName string
89+
name string
90+
expectedID *string
91+
}{
92+
{
93+
testName: "Find namespace1",
94+
name: "corp",
95+
expectedID: aws.String("namespace1"),
96+
},
97+
{
98+
testName: "Find namespace2",
99+
name: "prod",
100+
expectedID: aws.String("namespace2"),
101+
},
102+
{
103+
testName: "Find namespace3",
104+
name: "bridge",
105+
expectedID: aws.String("namespace3"),
106+
},
107+
{
108+
testName: "Namespace Does Not Exist",
109+
name: "cat",
110+
expectedID: nil,
111+
},
112+
}
113+
114+
for _, testCase := range testCases {
115+
t.Run(testCase.testName, func(t *testing.T) {
116+
namespaceID, err := findPublicNamespace(testCase.name, mockSD)
117+
assert.Equal(t, testCase.expectedID, namespaceID, "Expected namespace ID to match")
118+
assert.NoError(t, err, "Unexpected error from FindPrivateNamespace")
119+
})
120+
}
121+
}
122+
123+
// Implements serviceDiscoveryClient interface
124+
type mockSDClient struct {
125+
usingFilter bool
126+
publicNamespaces bool
127+
namespaceData map[string]servicediscovery.Namespace
128+
t *testing.T
129+
}
130+
131+
func (mock *mockSDClient) ListNamespacesPages(input *servicediscovery.ListNamespacesInput, fn func(*servicediscovery.ListNamespacesOutput, bool) bool) error {
132+
if mock.usingFilter {
133+
filter := aws.StringValue(input.Filters[0].Values[0])
134+
if mock.publicNamespaces {
135+
assert.Equal(mock.t, servicediscovery.NamespaceTypeDnsPublic, filter)
136+
} else {
137+
assert.Equal(mock.t, servicediscovery.NamespaceTypeDnsPrivate, filter)
138+
}
139+
}
140+
141+
var namespaces []*servicediscovery.NamespaceSummary
142+
for _, namespace := range mock.namespaceData {
143+
namespaceSummary := servicediscovery.NamespaceSummary{
144+
Id: namespace.Id,
145+
Name: namespace.Name,
146+
}
147+
namespaces = append(namespaces, &namespaceSummary)
148+
}
149+
apiOutput := &servicediscovery.ListNamespacesOutput{
150+
Namespaces: namespaces,
151+
}
152+
153+
fn(apiOutput, true)
154+
return nil
155+
}
156+
157+
func (mock *mockSDClient) GetNamespace(input *servicediscovery.GetNamespaceInput) (*servicediscovery.GetNamespaceOutput, error) {
158+
namespace := mock.namespaceData[aws.StringValue(input.Id)]
159+
return &servicediscovery.GetNamespaceOutput{
160+
Namespace: &namespace,
161+
}, nil
162+
}
163+
164+
// Implements route53Client interface
165+
type mockRoute53Client struct {
166+
hostedZoneData map[string]route53.GetHostedZoneOutput
167+
}
168+
169+
func (mock *mockRoute53Client) GetHostedZone(input *route53.GetHostedZoneInput) (*route53.GetHostedZoneOutput, error) {
170+
zone := mock.hostedZoneData[aws.StringValue(input.Id)]
171+
return &zone, nil
172+
}
173+
174+
func setupHostedZoneMocks(t *testing.T) route53Client {
175+
// Mock Data
176+
var hostedZoneData = map[string]route53.GetHostedZoneOutput{
177+
"zone1": route53.GetHostedZoneOutput{
178+
VPCs: []*route53.VPC{
179+
&route53.VPC{
180+
VPCId: aws.String("vpc-8BAADF00D"),
181+
VPCRegion: aws.String("us-east-1"),
182+
},
183+
},
184+
},
185+
"zone2": route53.GetHostedZoneOutput{
186+
VPCs: []*route53.VPC{
187+
&route53.VPC{
188+
VPCId: aws.String("vpc-1CEB00DA"),
189+
VPCRegion: aws.String("us-east-1"),
190+
},
191+
},
192+
},
193+
"zone3": route53.GetHostedZoneOutput{
194+
VPCs: []*route53.VPC{
195+
&route53.VPC{
196+
VPCId: aws.String("vpc-C00010FF"),
197+
VPCRegion: aws.String("ap-south-1"),
198+
},
199+
&route53.VPC{
200+
VPCId: aws.String("vpc-D15EA5E"),
201+
VPCRegion: aws.String("ap-south-1"),
202+
},
203+
},
204+
},
205+
"zone4": route53.GetHostedZoneOutput{
206+
VPCs: []*route53.VPC{
207+
&route53.VPC{
208+
VPCId: aws.String("vpc-C00010FF"),
209+
VPCRegion: aws.String("sa-east-1"),
210+
},
211+
},
212+
},
213+
"zone5": route53.GetHostedZoneOutput{
214+
VPCs: []*route53.VPC{
215+
&route53.VPC{
216+
VPCId: aws.String("vpc-DEADBAAD"),
217+
VPCRegion: aws.String("ap-south-1"),
218+
},
219+
&route53.VPC{
220+
VPCId: aws.String("vpc-1CEB00DA"),
221+
VPCRegion: aws.String("ap-south-1"),
222+
},
223+
},
224+
},
225+
}
226+
227+
return &mockRoute53Client{
228+
hostedZoneData: hostedZoneData,
229+
}
230+
}
231+
232+
func setupNamespaceMocks(t *testing.T, publicNamespaces bool) serviceDiscoveryClient {
233+
// Mock Data
234+
namespaceType := servicediscovery.NamespaceTypeDnsPrivate
235+
if publicNamespaces {
236+
namespaceType = servicediscovery.NamespaceTypeDnsPublic
237+
}
238+
var namespaceData = map[string]servicediscovery.Namespace{
239+
"namespace1": servicediscovery.Namespace{
240+
Id: aws.String("namespace1"),
241+
Name: aws.String("corp"),
242+
Properties: &servicediscovery.NamespaceProperties{
243+
DnsProperties: &servicediscovery.DnsProperties{
244+
HostedZoneId: aws.String("zone1"),
245+
},
246+
},
247+
Type: aws.String(namespaceType),
248+
},
249+
"namespace2": servicediscovery.Namespace{
250+
Id: aws.String("namespace2"),
251+
Name: aws.String("prod"),
252+
Properties: &servicediscovery.NamespaceProperties{
253+
DnsProperties: &servicediscovery.DnsProperties{
254+
HostedZoneId: aws.String("zone2"),
255+
},
256+
},
257+
Type: aws.String(namespaceType),
258+
},
259+
"namespace3": servicediscovery.Namespace{
260+
Id: aws.String("namespace3"),
261+
Name: aws.String("bridge"),
262+
Properties: &servicediscovery.NamespaceProperties{
263+
DnsProperties: &servicediscovery.DnsProperties{
264+
HostedZoneId: aws.String("zone3"),
265+
},
266+
},
267+
Type: aws.String(namespaceType),
268+
},
269+
}
270+
271+
if !publicNamespaces {
272+
// Add in extra namespaces with the same name, since this is possible with private namespaces
273+
namespaceData["namespace4"] = servicediscovery.Namespace{
274+
Id: aws.String("namespace4"),
275+
Name: aws.String("corp"),
276+
Properties: &servicediscovery.NamespaceProperties{
277+
DnsProperties: &servicediscovery.DnsProperties{
278+
HostedZoneId: aws.String("zone4"),
279+
},
280+
},
281+
Type: aws.String(namespaceType),
282+
}
283+
namespaceData["namespace5"] = servicediscovery.Namespace{
284+
Id: aws.String("namespace5"),
285+
Name: aws.String("bridge"),
286+
Properties: &servicediscovery.NamespaceProperties{
287+
DnsProperties: &servicediscovery.DnsProperties{
288+
HostedZoneId: aws.String("zone5"),
289+
},
290+
},
291+
Type: aws.String(namespaceType),
292+
}
293+
294+
}
295+
return &mockSDClient{
296+
usingFilter: true,
297+
publicNamespaces: publicNamespaces,
298+
namespaceData: namespaceData,
299+
t: t,
300+
}
301+
302+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
// Package route53 contains functions for working with the route53 APIs
15+
// that back ECS Service Discovery
16+
package route53
17+
18+
import (
19+
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/clients"
20+
"github.com/aws/amazon-ecs-cli/ecs-cli/modules/config"
21+
"github.com/aws/aws-sdk-go/service/route53"
22+
)
23+
24+
// Private Route53 Client that can be mocked in unit tests
25+
// The SDK's route53 client implements this interface
26+
type route53Client interface {
27+
GetHostedZone(input *route53.GetHostedZoneInput) (*route53.GetHostedZoneOutput, error)
28+
}
29+
30+
// factory function to create clients
31+
func newRoute53Client(config *config.CommandConfig) route53Client {
32+
r53Client := route53.New(config.Session)
33+
r53Client.Handlers.Build.PushBackNamed(clients.CustomUserAgentHandler())
34+
return r53Client
35+
}

0 commit comments

Comments
 (0)