-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
aws/arn: Package for parsing and producing ARNs
- Loading branch information
1 parent
0fe2612
commit 0264554
Showing
2 changed files
with
176 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,86 @@ | ||
// Package arn provides a parser for interacting with Amazon Resource Names. | ||
package arn | ||
|
||
import ( | ||
"errors" | ||
"strings" | ||
) | ||
|
||
const ( | ||
arnDelimiter = ":" | ||
arnSections = 6 | ||
arnPrefix = "arn:" | ||
|
||
// zero-indexed | ||
sectionPartition = 1 | ||
sectionService = 2 | ||
sectionRegion = 3 | ||
sectionAccountID = 4 | ||
sectionResource = 5 | ||
|
||
// errors | ||
invalidPrefix = "arn: invalid prefix" | ||
invalidSections = "arn: not enough sections" | ||
) | ||
|
||
// ARN captures the individual fields of an Amazon Resource Name. | ||
// See http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html for more information. | ||
type ARN struct { | ||
// The partition that the resource is in. For standard AWS regions, the partition is "aws". If you have resources in | ||
// other partitions, the partition is "aws-partitionname". For example, the partition for resources in the China | ||
// (Beijing) region is "aws-cn". | ||
Partition string | ||
|
||
// The service namespace that identifies the AWS product (for example, Amazon S3, IAM, or Amazon RDS). For a list of | ||
// namespaces, see | ||
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces. | ||
Service string | ||
|
||
// The region the resource resides in. Note that the ARNs for some resources do not require a region, so this | ||
// component might be omitted. | ||
Region string | ||
|
||
// The ID of the AWS account that owns the resource, without the hyphens. For example, 123456789012. Note that the | ||
// ARNs for some resources don't require an account number, so this component might be omitted. | ||
AccountID string | ||
|
||
// The content of this part of the ARN varies by service. It often includes an indicator of the type of resource — | ||
// for example, an IAM user or Amazon RDS database - followed by a slash (/) or a colon (:), followed by the | ||
// resource name itself. Some services allows paths for resource names, as described in | ||
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-paths. | ||
Resource string | ||
} | ||
|
||
// Parse parses an ARN into its constituent parts. | ||
// | ||
// Some example ARNs: | ||
// arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment | ||
// arn:aws:iam::123456789012:user/David | ||
// arn:aws:rds:eu-west-1:123456789012:db:mysql-db | ||
// arn:aws:s3:::my_corporate_bucket/exampleobject.png | ||
func Parse(arn string) (ARN, error) { | ||
if !strings.HasPrefix(arn, arnPrefix) { | ||
return ARN{}, errors.New(invalidPrefix) | ||
} | ||
sections := strings.SplitN(arn, arnDelimiter, arnSections) | ||
if len(sections) != arnSections { | ||
return ARN{}, errors.New(invalidSections) | ||
} | ||
return ARN{ | ||
Partition: sections[sectionPartition], | ||
Service: sections[sectionService], | ||
Region: sections[sectionRegion], | ||
AccountID: sections[sectionAccountID], | ||
Resource: sections[sectionResource], | ||
}, nil | ||
} | ||
|
||
// String returns the canonical representation of the ARN | ||
func (arn ARN) String() string { | ||
return arnPrefix + | ||
arn.Partition + arnDelimiter + | ||
arn.Service + arnDelimiter + | ||
arn.Region + arnDelimiter + | ||
arn.AccountID + arnDelimiter + | ||
arn.Resource | ||
} |
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,90 @@ | ||
// +build go1.7 | ||
|
||
package arn | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
) | ||
|
||
func TestParseARN(t *testing.T) { | ||
cases := []struct { | ||
input string | ||
arn ARN | ||
err error | ||
}{ | ||
{ | ||
input: "invalid", | ||
err: errors.New(invalidPrefix), | ||
}, | ||
{ | ||
input: "arn:nope", | ||
err: errors.New(invalidSections), | ||
}, | ||
{ | ||
input: "arn:aws:ecr:us-west-2:123456789012:repository/foo/bar", | ||
arn: ARN{ | ||
Partition: "aws", | ||
Service: "ecr", | ||
Region: "us-west-2", | ||
AccountID: "123456789012", | ||
Resource: "repository/foo/bar", | ||
}, | ||
}, | ||
{ | ||
input: "arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment", | ||
arn: ARN{ | ||
Partition: "aws", | ||
Service: "elasticbeanstalk", | ||
Region: "us-east-1", | ||
AccountID: "123456789012", | ||
Resource: "environment/My App/MyEnvironment", | ||
}, | ||
}, | ||
{ | ||
input: "arn:aws:iam::123456789012:user/David", | ||
arn: ARN{ | ||
Partition: "aws", | ||
Service: "iam", | ||
Region: "", | ||
AccountID: "123456789012", | ||
Resource: "user/David", | ||
}, | ||
}, | ||
{ | ||
input: "arn:aws:rds:eu-west-1:123456789012:db:mysql-db", | ||
arn: ARN{ | ||
Partition: "aws", | ||
Service: "rds", | ||
Region: "eu-west-1", | ||
AccountID: "123456789012", | ||
Resource: "db:mysql-db", | ||
}, | ||
}, | ||
{ | ||
input: "arn:aws:s3:::my_corporate_bucket/exampleobject.png", | ||
arn: ARN{ | ||
Partition: "aws", | ||
Service: "s3", | ||
Region: "", | ||
AccountID: "", | ||
Resource: "my_corporate_bucket/exampleobject.png", | ||
}, | ||
}, | ||
} | ||
for _, tc := range cases { | ||
t.Run(tc.input, func(t *testing.T) { | ||
spec, err := Parse(tc.input) | ||
if tc.arn != spec { | ||
t.Errorf("Expected %q to parse as %v, but got %v", tc.input, tc.arn, spec) | ||
} | ||
if err == nil && tc.err != nil { | ||
t.Errorf("Expected err to be %v, but got nil", tc.err) | ||
} else if err != nil && tc.err == nil { | ||
t.Errorf("Expected err to be nil, but got %v", err) | ||
} else if err != nil && tc.err != nil && err.Error() != tc.err.Error() { | ||
t.Errorf("Expected err to be %v, but got %v", tc.err, err) | ||
} | ||
}) | ||
} | ||
} |