Skip to content

Commit dd8dc69

Browse files
feat(host): add v3 format for dynamic dns names (#178)
* feat(host): add v3 format for dynamic dns names
1 parent 088ae14 commit dd8dc69

File tree

2 files changed

+110
-6
lines changed

2 files changed

+110
-6
lines changed

host/host.go

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type Name struct {
1515
Machine string
1616
Site string
1717
Project string
18+
Org string
1819
Domain string
1920
Suffix string
2021
Version string
@@ -27,6 +28,15 @@ func Parse(name string) (Name, error) {
2728

2829
reV1 := regexp.MustCompile(`(?:[a-z-.]+)?(mlab[1-4]d?)[-.]([a-z]{3}[0-9tc]{2})\.(measurement-lab.org)$`)
2930
reV2 := regexp.MustCompile(`([a-z0-9]+)?-?(mlab[1-4]d?)-([a-z]{3}[0-9tc]{2})\.(.*?)\.(measurement-lab.org)(-[a-z0-9]{4})?$`)
31+
// The v3 naming convention is defined in:
32+
// * https://docs.google.com/document/d/1XHgpX7Tbjy_c71TKsFUxb1_ax2624PB4SE9R15OoD_o/edit?#heading=h.s5vpfclyu15x
33+
// The structure follows the pattern:
34+
// * <service>-<IATA><ASN>-<machine>.<organization>.<project>.measurement-lab.org
35+
// * the same rules apply for service, iata, and project names as earlier versions.
36+
// * most ASNs are 16bit numbers, but since 2007 they can be 32bit numbers, allowing up to 10 decimal digits.
37+
// * machine names are 6 byte base64 encoded IPv4 addresses.
38+
// * site name precedes machine name for readability.
39+
reV3 := regexp.MustCompile(`^(?:([a-z0-9]+)-)?([a-z]{3}[0-9]{1,10})-([a-zA-Z0-9]{6})\.(.*?)\.(.*?)\.(measurement-lab.org)$`)
3040

3141
// Example hostnames with field counts when split by '.':
3242
// v1
@@ -39,6 +49,10 @@ func Parse(name string) (Name, error) {
3949
// ndt-mlab1-lga01.mlab-oti.measurement-lab.org-d9h6 - 4 (A MIG instance with a service and random suffix)
4050
// ndt-iupui-mlab1-lga01.mlab-oti.measurement-lab.org - 4
4151
// ndt-mlab1-lga01.mlab-oti.measurement-lab.org - 4
52+
// v3
53+
// lga3356-BA6fSw.rnp.autojoin.measurement-lab.org - 5
54+
// ndt-lga3356-BA6fSw.rnp.autojoin.measurement-lab.org - 5
55+
// ndt-lga3356-BA6fSw.mlab.sandbox.measurement-lab.org - 5
4256

4357
if name == "third-party" {
4458
// Unconditionally return a Name for third-party origins.
@@ -54,9 +68,26 @@ func Parse(name string) (Name, error) {
5468
return parts, fmt.Errorf("invalid hostname: %s", name)
5569
}
5670

57-
// v2 names always have four fields. And the first field will always
58-
// be longer than a machine name e.g. "mlab1".
59-
if len(fields) == 4 && len(fields[0]) > 6 {
71+
// v3 names always have 5 fields.
72+
// v2 names always have 4 fields. And, the first field will always
73+
// be longer than a machine name e.g. "mlab1", which distinguishes
74+
// it from v1 name with four fields.
75+
switch {
76+
case len(fields) == 5:
77+
mV3 := reV3.FindAllStringSubmatch(name, -1)
78+
if len(mV3) != 1 || len(mV3[0]) != 7 {
79+
return parts, fmt.Errorf("invalid v3 hostname: %s", name)
80+
}
81+
parts = Name{
82+
Service: mV3[0][1],
83+
Site: mV3[0][2],
84+
Machine: mV3[0][3],
85+
Org: mV3[0][4],
86+
Project: mV3[0][5],
87+
Domain: mV3[0][6],
88+
Version: "v3",
89+
}
90+
case len(fields) == 4 && len(fields[0]) > 6:
6091
mV2 := reV2.FindAllStringSubmatch(name, -1)
6192
if len(mV2) != 1 || len(mV2[0]) != 7 {
6293
return parts, fmt.Errorf("invalid v2 hostname: %s", name)
@@ -70,7 +101,7 @@ func Parse(name string) (Name, error) {
70101
Suffix: mV2[0][6],
71102
Version: "v2",
72103
}
73-
} else {
104+
default:
74105
mV1 := reV1.FindAllStringSubmatch(name, -1)
75106
if len(mV1) != 1 || len(mV1[0]) != 4 {
76107
return parts, fmt.Errorf("invalid v1 hostname: %s", name)
@@ -91,6 +122,8 @@ func Parse(name string) (Name, error) {
91122
// Example: mlab2-abc01.mlab-sandbox.measurement-lab.org
92123
func (n Name) String() string {
93124
switch n.Version {
125+
case "v3":
126+
return fmt.Sprintf("%s-%s.%s.%s.%s", n.Site, n.Machine, n.Org, n.Project, n.Domain)
94127
case "v2":
95128
return fmt.Sprintf("%s-%s.%s.%s", n.Machine, n.Site, n.Project, n.Domain)
96129
default:
@@ -102,7 +135,7 @@ func (n Name) String() string {
102135
// Example: ndt-mlab1-abc01.mlab-sandbox.measurement-lab.org
103136
func (n Name) StringWithService() string {
104137
if n.Service != "" {
105-
return fmt.Sprintf("%s-%s-%s.%s.%s", n.Service, n.Machine, n.Site, n.Project, n.Domain)
138+
return fmt.Sprintf("%s-%s", n.Service, n.String())
106139
} else {
107140
return n.String()
108141
}
@@ -111,7 +144,7 @@ func (n Name) StringWithService() string {
111144
// Returns an M-lab hostname with any suffix preserved
112145
// Example: mlab1-abc01.mlab-sandbox.measurement-lab.org-gz77
113146
func (n Name) StringWithSuffix() string {
114-
return fmt.Sprintf("%s-%s.%s.%s%s", n.Machine, n.Site, n.Project, n.Domain, n.Suffix)
147+
return fmt.Sprintf("%s%s", n.String(), n.Suffix)
115148
}
116149

117150
// Returns an M-lab hostname with any service and suffix preserved

host/host_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,61 @@ func TestName(t *testing.T) {
165165
want: Name{},
166166
wantErr: true,
167167
},
168+
{
169+
name: "valid-v3-machine",
170+
hostname: "lol12345-abcdef.mlab.sandbox.measurement-lab.org",
171+
want: Name{
172+
Machine: "abcdef",
173+
Site: "lol12345",
174+
Org: "mlab",
175+
Project: "sandbox",
176+
Domain: "measurement-lab.org",
177+
Version: "v3",
178+
},
179+
},
180+
{
181+
name: "valid-v3-service",
182+
hostname: "ndt-lol12345-abcdef.mlab.sandbox.measurement-lab.org",
183+
want: Name{
184+
Service: "ndt",
185+
Machine: "abcdef",
186+
Site: "lol12345",
187+
Org: "mlab",
188+
Project: "sandbox",
189+
Domain: "measurement-lab.org",
190+
Version: "v3",
191+
},
192+
},
193+
{
194+
name: "invalid-v3-too-long-asn-machine",
195+
hostname: "lol12345678901-abcdef.mlab.sandbox.measurement-lab.org",
196+
want: Name{},
197+
wantErr: true,
198+
},
199+
{
200+
name: "invalid-v3-too-long-asn-service",
201+
hostname: "ndt-lol12345678901-abcdef.mlab.sandbox.measurement-lab.org",
202+
want: Name{},
203+
wantErr: true,
204+
},
205+
{
206+
name: "invalid-v3-site-too-long",
207+
hostname: "abcd12345-abcdef.mlab.sandbox.measurement-lab.org",
208+
want: Name{},
209+
wantErr: true,
210+
},
211+
{
212+
name: "invalid-v3-missing-service",
213+
hostname: "-abc12345-abcdef.mlab.sandbox.measurement-lab.org",
214+
want: Name{},
215+
wantErr: true,
216+
},
217+
{
218+
name: "invalid-v3-machine-too-long",
219+
hostname: "abc12345-abcdef8.mlab.sandbox.measurement-lab.org",
220+
want: Name{},
221+
wantErr: true,
222+
},
168223
}
169224

170225
for _, test := range tests {
@@ -205,6 +260,10 @@ func TestName_String(t *testing.T) {
205260
name: "ndt-mlab1-foo01.mlab-sandbox.measurement-lab.org-qf8y",
206261
want: "mlab1-foo01.mlab-sandbox.measurement-lab.org",
207262
},
263+
{
264+
name: "ndt-lol12345-abcdef.mlab.sandbox.measurement-lab.org",
265+
want: "lol12345-abcdef.mlab.sandbox.measurement-lab.org",
266+
},
208267
}
209268
for _, tt := range tests {
210269
t.Run(tt.name, func(t *testing.T) {
@@ -238,6 +297,10 @@ func TestName_StringWithService(t *testing.T) {
238297
name: "ndt-mlab1-foo01.mlab-sandbox.measurement-lab.org-qf8y",
239298
want: "ndt-mlab1-foo01.mlab-sandbox.measurement-lab.org",
240299
},
300+
{
301+
name: "ndt-lol12345-abcdef.mlab.sandbox.measurement-lab.org",
302+
want: "ndt-lol12345-abcdef.mlab.sandbox.measurement-lab.org",
303+
},
241304
}
242305
for _, tt := range tests {
243306
t.Run(tt.name, func(t *testing.T) {
@@ -271,6 +334,10 @@ func TestName_StringWithSuffix(t *testing.T) {
271334
name: "ndt-mlab1-foo01.mlab-sandbox.measurement-lab.org-qf8y",
272335
want: "mlab1-foo01.mlab-sandbox.measurement-lab.org-qf8y",
273336
},
337+
{
338+
name: "ndt-lol12345-abcdef.mlab.sandbox.measurement-lab.org",
339+
want: "lol12345-abcdef.mlab.sandbox.measurement-lab.org",
340+
},
274341
}
275342
for _, tt := range tests {
276343
t.Run(tt.name, func(t *testing.T) {
@@ -304,6 +371,10 @@ func TestName_StringAll(t *testing.T) {
304371
name: "ndt-mlab1-foo01.mlab-sandbox.measurement-lab.org-qf8y",
305372
want: "ndt-mlab1-foo01.mlab-sandbox.measurement-lab.org-qf8y",
306373
},
374+
{
375+
name: "ndt-lol12345-abcdef.mlab.sandbox.measurement-lab.org",
376+
want: "ndt-lol12345-abcdef.mlab.sandbox.measurement-lab.org",
377+
},
307378
}
308379
for _, tt := range tests {
309380
t.Run(tt.name, func(t *testing.T) {

0 commit comments

Comments
 (0)