@@ -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
92123func (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
103136func (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
113146func (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
0 commit comments