-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
datalakestore/paths: reintroducing the Resource ID Parser
- Loading branch information
hc-github-team-tf-azure
committed
Dec 14, 2023
1 parent
91b1b4a
commit fd7fe5d
Showing
4 changed files
with
498 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package paths | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
"strings" | ||
|
||
"github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" | ||
"github.com/tombuildsstuff/giovanni/storage/2020-08-04/blob/accounts" | ||
) | ||
|
||
// TODO: update this to implement `resourceids.ResourceId` once | ||
// https://github.com/hashicorp/go-azure-helpers/issues/187 is fixed | ||
var _ resourceids.Id = PathId{} | ||
|
||
type PathId struct { | ||
// AccountId specifies the ID of the Storage Account where this path exists. | ||
AccountId accounts.AccountId | ||
|
||
// FileSystemName specifies the name of the Data Lake FileSystem where this Path exists. | ||
FileSystemName string | ||
|
||
// Path specifies the path in question. | ||
Path string | ||
} | ||
|
||
func NewPathID(accountId accounts.AccountId, fileSystemName, path string) PathId { | ||
return PathId{ | ||
AccountId: accountId, | ||
FileSystemName: fileSystemName, | ||
Path: path, | ||
} | ||
} | ||
|
||
func (b PathId) ID() string { | ||
return fmt.Sprintf("%s/%s/%s", b.AccountId.ID(), b.FileSystemName, b.Path) | ||
} | ||
|
||
func (b PathId) String() string { | ||
components := []string{ | ||
fmt.Sprintf("File System %q", b.FileSystemName), | ||
fmt.Sprintf("Account %q", b.AccountId.String()), | ||
} | ||
return fmt.Sprintf("Path %q (%s)", b.Path, strings.Join(components, " / ")) | ||
} | ||
|
||
// ParsePathID parses `input` into a Path ID using a known `domainSuffix` | ||
func ParsePathID(input, domainSuffix string) (*PathId, error) { | ||
// example: https://foo.dfs.core.windows.net/Bar/some/path | ||
if input == "" { | ||
return nil, fmt.Errorf("`input` was empty") | ||
} | ||
|
||
account, err := accounts.ParseAccountID(input, domainSuffix) | ||
if err != nil { | ||
return nil, fmt.Errorf("parsing account %q: %+v", input, err) | ||
} | ||
|
||
if account.SubDomainType != accounts.DataLakeStoreSubDomainType { | ||
return nil, fmt.Errorf("expected the subdomain type to be %q but got %q", string(accounts.DataLakeStoreSubDomainType), string(account.SubDomainType)) | ||
} | ||
|
||
uri, err := url.Parse(input) | ||
if err != nil { | ||
return nil, fmt.Errorf("parsing %q as a uri: %+v", input, err) | ||
} | ||
|
||
uriPath := strings.TrimPrefix(uri.Path, "/") | ||
segments := strings.Split(uriPath, "/") | ||
if len(segments) < 2 { | ||
return nil, fmt.Errorf("expected the path to contain at least 2 segments but got %d", len(segments)) | ||
} | ||
fileSystemName := segments[0] | ||
path := strings.Join(segments[1:], "/") | ||
return &PathId{ | ||
AccountId: *account, | ||
FileSystemName: fileSystemName, | ||
Path: path, | ||
}, nil | ||
} |
169 changes: 169 additions & 0 deletions
169
storage/2020-08-04/datalakestore/paths/resource_id_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
package paths | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/go-azure-helpers/lang/pointer" | ||
"github.com/tombuildsstuff/giovanni/storage/2020-08-04/blob/accounts" | ||
) | ||
|
||
func TestParsePathIDStandard(t *testing.T) { | ||
input := "https://example1.dfs.core.windows.net/fileSystem1/some/path" | ||
expected := PathId{ | ||
AccountId: accounts.AccountId{ | ||
AccountName: "example1", | ||
SubDomainType: accounts.DataLakeStoreSubDomainType, | ||
DomainSuffix: "core.windows.net", | ||
}, | ||
FileSystemName: "fileSystem1", | ||
Path: "some/path", | ||
} | ||
actual, err := ParsePathID(input, "core.windows.net") | ||
if err != nil { | ||
t.Fatalf(err.Error()) | ||
} | ||
if actual.AccountId.AccountName != expected.AccountId.AccountName { | ||
t.Fatalf("expected AccountName to be %q but got %q", expected.AccountId.AccountName, actual.AccountId.AccountName) | ||
} | ||
if actual.AccountId.SubDomainType != expected.AccountId.SubDomainType { | ||
t.Fatalf("expected SubDomainType to be %q but got %q", expected.AccountId.SubDomainType, actual.AccountId.SubDomainType) | ||
} | ||
if actual.AccountId.DomainSuffix != expected.AccountId.DomainSuffix { | ||
t.Fatalf("expected DomainSuffix to be %q but got %q", expected.AccountId.DomainSuffix, actual.AccountId.DomainSuffix) | ||
} | ||
if actual.FileSystemName != expected.FileSystemName { | ||
t.Fatalf("expected FileSystemName to be %q but got %q", expected.FileSystemName, actual.FileSystemName) | ||
} | ||
if actual.Path != expected.Path { | ||
t.Fatalf("expected Path to be %q but got %q", expected.Path, actual.Path) | ||
} | ||
} | ||
|
||
func TestParsePathIDInADNSZone(t *testing.T) { | ||
input := "https://example1.zone1.dfs.storage.azure.net/fileSystem1/some/path" | ||
expected := PathId{ | ||
AccountId: accounts.AccountId{ | ||
AccountName: "example1", | ||
SubDomainType: accounts.DataLakeStoreSubDomainType, | ||
DomainSuffix: "storage.azure.net", | ||
ZoneName: pointer.To("zone1"), | ||
}, | ||
FileSystemName: "fileSystem1", | ||
Path: "some/path", | ||
} | ||
actual, err := ParsePathID(input, "storage.azure.net") | ||
if err != nil { | ||
t.Fatalf(err.Error()) | ||
} | ||
if actual.AccountId.AccountName != expected.AccountId.AccountName { | ||
t.Fatalf("expected AccountName to be %q but got %q", expected.AccountId.AccountName, actual.AccountId.AccountName) | ||
} | ||
if actual.AccountId.SubDomainType != expected.AccountId.SubDomainType { | ||
t.Fatalf("expected SubDomainType to be %q but got %q", expected.AccountId.SubDomainType, actual.AccountId.SubDomainType) | ||
} | ||
if actual.AccountId.DomainSuffix != expected.AccountId.DomainSuffix { | ||
t.Fatalf("expected DomainSuffix to be %q but got %q", expected.AccountId.DomainSuffix, actual.AccountId.DomainSuffix) | ||
} | ||
if pointer.From(actual.AccountId.ZoneName) != pointer.From(expected.AccountId.ZoneName) { | ||
t.Fatalf("expected ZoneName to be %q but got %q", pointer.From(expected.AccountId.ZoneName), pointer.From(actual.AccountId.ZoneName)) | ||
} | ||
if actual.FileSystemName != expected.FileSystemName { | ||
t.Fatalf("expected FileSystemName to be %q but got %q", expected.FileSystemName, actual.FileSystemName) | ||
} | ||
if actual.Path != expected.Path { | ||
t.Fatalf("expected Path to be %q but got %q", expected.Path, actual.Path) | ||
} | ||
} | ||
|
||
func TestParsePathIDInAnEdgeZone(t *testing.T) { | ||
input := "https://example1.dfs.zone1.edgestorage.azure.net/fileSystem1/some/path" | ||
expected := PathId{ | ||
AccountId: accounts.AccountId{ | ||
AccountName: "example1", | ||
SubDomainType: accounts.DataLakeStoreSubDomainType, | ||
DomainSuffix: "edgestorage.azure.net", | ||
ZoneName: pointer.To("zone1"), | ||
IsEdgeZone: true, | ||
}, | ||
FileSystemName: "fileSystem1", | ||
Path: "some/path", | ||
} | ||
actual, err := ParsePathID(input, "edgestorage.azure.net") | ||
if err != nil { | ||
t.Fatalf(err.Error()) | ||
} | ||
if actual.AccountId.AccountName != expected.AccountId.AccountName { | ||
t.Fatalf("expected AccountName to be %q but got %q", expected.AccountId.AccountName, actual.AccountId.AccountName) | ||
} | ||
if actual.AccountId.SubDomainType != expected.AccountId.SubDomainType { | ||
t.Fatalf("expected SubDomainType to be %q but got %q", expected.AccountId.SubDomainType, actual.AccountId.SubDomainType) | ||
} | ||
if actual.AccountId.DomainSuffix != expected.AccountId.DomainSuffix { | ||
t.Fatalf("expected DomainSuffix to be %q but got %q", expected.AccountId.DomainSuffix, actual.AccountId.DomainSuffix) | ||
} | ||
if pointer.From(actual.AccountId.ZoneName) != pointer.From(expected.AccountId.ZoneName) { | ||
t.Fatalf("expected ZoneName to be %q but got %q", pointer.From(expected.AccountId.ZoneName), pointer.From(actual.AccountId.ZoneName)) | ||
} | ||
if !actual.AccountId.IsEdgeZone { | ||
t.Fatalf("expected the Account to be in an Edge Zone but it wasn't") | ||
} | ||
if actual.FileSystemName != expected.FileSystemName { | ||
t.Fatalf("expected FileSystemName to be %q but got %q", expected.FileSystemName, actual.FileSystemName) | ||
} | ||
if actual.Path != expected.Path { | ||
t.Fatalf("expected Path to be %q but got %q", expected.Path, actual.Path) | ||
} | ||
} | ||
|
||
func TestFormatPathIDStandard(t *testing.T) { | ||
actual := PathId{ | ||
AccountId: accounts.AccountId{ | ||
AccountName: "example1", | ||
SubDomainType: accounts.DataLakeStoreSubDomainType, | ||
DomainSuffix: "core.windows.net", | ||
IsEdgeZone: false, | ||
}, | ||
FileSystemName: "fileSystem1", | ||
Path: "some/path", | ||
}.ID() | ||
expected := "https://example1.dfs.core.windows.net/fileSystem1/some/path" | ||
if actual != expected { | ||
t.Fatalf("expected %q but got %q", expected, actual) | ||
} | ||
} | ||
|
||
func TestFormatPathIDInDNSZone(t *testing.T) { | ||
actual := PathId{ | ||
AccountId: accounts.AccountId{ | ||
AccountName: "example1", | ||
ZoneName: pointer.To("zone2"), | ||
SubDomainType: accounts.DataLakeStoreSubDomainType, | ||
DomainSuffix: "storage.azure.net", | ||
IsEdgeZone: false, | ||
}, | ||
FileSystemName: "fileSystem1", | ||
Path: "some/path", | ||
}.ID() | ||
expected := "https://example1.zone2.dfs.storage.azure.net/fileSystem1/some/path" | ||
if actual != expected { | ||
t.Fatalf("expected %q but got %q", expected, actual) | ||
} | ||
} | ||
|
||
func TestFormatPathIDInEdgeZone(t *testing.T) { | ||
actual := PathId{ | ||
AccountId: accounts.AccountId{ | ||
AccountName: "example1", | ||
ZoneName: pointer.To("zone2"), | ||
SubDomainType: accounts.DataLakeStoreSubDomainType, | ||
DomainSuffix: "edgestorage.azure.net", | ||
IsEdgeZone: true, | ||
}, | ||
FileSystemName: "fileSystem1", | ||
Path: "some", | ||
}.ID() | ||
expected := "https://example1.dfs.zone2.edgestorage.azure.net/fileSystem1/some" | ||
if actual != expected { | ||
t.Fatalf("expected %q but got %q", expected, actual) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package paths | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
"strings" | ||
|
||
"github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" | ||
"github.com/tombuildsstuff/giovanni/storage/2023-11-03/blob/accounts" | ||
) | ||
|
||
// TODO: update this to implement `resourceids.ResourceId` once | ||
// https://github.com/hashicorp/go-azure-helpers/issues/187 is fixed | ||
var _ resourceids.Id = PathId{} | ||
|
||
type PathId struct { | ||
// AccountId specifies the ID of the Storage Account where this path exists. | ||
AccountId accounts.AccountId | ||
|
||
// FileSystemName specifies the name of the Data Lake FileSystem where this Path exists. | ||
FileSystemName string | ||
|
||
// Path specifies the path in question. | ||
Path string | ||
} | ||
|
||
func NewPathID(accountId accounts.AccountId, fileSystemName, path string) PathId { | ||
return PathId{ | ||
AccountId: accountId, | ||
FileSystemName: fileSystemName, | ||
Path: path, | ||
} | ||
} | ||
|
||
func (b PathId) ID() string { | ||
return fmt.Sprintf("%s/%s/%s", b.AccountId.ID(), b.FileSystemName, b.Path) | ||
} | ||
|
||
func (b PathId) String() string { | ||
components := []string{ | ||
fmt.Sprintf("File System %q", b.FileSystemName), | ||
fmt.Sprintf("Account %q", b.AccountId.String()), | ||
} | ||
return fmt.Sprintf("Path %q (%s)", b.Path, strings.Join(components, " / ")) | ||
} | ||
|
||
// ParsePathID parses `input` into a Path ID using a known `domainSuffix` | ||
func ParsePathID(input, domainSuffix string) (*PathId, error) { | ||
// example: https://foo.dfs.core.windows.net/Bar/some/path | ||
if input == "" { | ||
return nil, fmt.Errorf("`input` was empty") | ||
} | ||
|
||
account, err := accounts.ParseAccountID(input, domainSuffix) | ||
if err != nil { | ||
return nil, fmt.Errorf("parsing account %q: %+v", input, err) | ||
} | ||
|
||
if account.SubDomainType != accounts.DataLakeStoreSubDomainType { | ||
return nil, fmt.Errorf("expected the subdomain type to be %q but got %q", string(accounts.DataLakeStoreSubDomainType), string(account.SubDomainType)) | ||
} | ||
|
||
uri, err := url.Parse(input) | ||
if err != nil { | ||
return nil, fmt.Errorf("parsing %q as a uri: %+v", input, err) | ||
} | ||
|
||
uriPath := strings.TrimPrefix(uri.Path, "/") | ||
segments := strings.Split(uriPath, "/") | ||
if len(segments) < 2 { | ||
return nil, fmt.Errorf("expected the path to contain at least 2 segments but got %d", len(segments)) | ||
} | ||
fileSystemName := segments[0] | ||
path := strings.Join(segments[1:], "/") | ||
return &PathId{ | ||
AccountId: *account, | ||
FileSystemName: fileSystemName, | ||
Path: path, | ||
}, nil | ||
} |
Oops, something went wrong.