Skip to content

Commit

Permalink
Merge pull request #870 from aws/s3/arn
Browse files Browse the repository at this point in the history
Adds support for access-point and outposts for s3 / s3control client
  • Loading branch information
skotambkar authored Nov 17, 2020
2 parents bb08101 + c0b6070 commit 59a6550
Show file tree
Hide file tree
Showing 153 changed files with 7,733 additions and 622 deletions.
18 changes: 15 additions & 3 deletions aws/middleware/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (s RegisterServiceMetadata) HandleInitialize(
ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler,
) (out middleware.InitializeOutput, metadata middleware.Metadata, err error) {
if len(s.ServiceID) > 0 {
ctx = setServiceID(ctx, s.ServiceID)
ctx = SetServiceID(ctx, s.ServiceID)
}
if len(s.SigningName) > 0 {
ctx = SetSigningName(ctx, s.SigningName)
Expand All @@ -46,6 +46,7 @@ type (
signingRegionKey struct{}
regionKey struct{}
operationNameKey struct{}
partitionIDKey struct{}
)

// GetServiceID retrieves the service id from the context.
Expand Down Expand Up @@ -78,6 +79,12 @@ func GetOperationName(ctx context.Context) (v string) {
return v
}

// GetPartitionID retrieves the endpoint partition id from the context.
func GetPartitionID(ctx context.Context) string {
v, _ := ctx.Value(partitionIDKey{}).(string)
return v
}

// SetSigningName set or modifies the signing name on the context.
func SetSigningName(ctx context.Context, value string) context.Context {
return context.WithValue(ctx, signingNameKey{}, value)
Expand All @@ -88,8 +95,8 @@ func SetSigningRegion(ctx context.Context, value string) context.Context {
return context.WithValue(ctx, signingRegionKey{}, value)
}

// setServiceID sets the service id on the context.
func setServiceID(ctx context.Context, value string) context.Context {
// SetServiceID sets the service id on the context.
func SetServiceID(ctx context.Context, value string) context.Context {
return context.WithValue(ctx, serviceIDKey{}, value)
}

Expand All @@ -102,3 +109,8 @@ func setRegion(ctx context.Context, value string) context.Context {
func setOperationName(ctx context.Context, value string) context.Context {
return context.WithValue(ctx, operationNameKey{}, value)
}

// SetPartitionID sets the partition id of a resolved region on the context
func SetPartitionID(ctx context.Context, value string) context.Context {
return context.WithValue(ctx, partitionIDKey{}, value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
* Writes out a file that resolves endpoints using endpoints.json, but the
* created resolver resolves endpoints for a single service.
*/
final class EndpointGenerator implements Runnable {
public class EndpointGenerator implements Runnable {
public static final String MIDDLEWARE_NAME = "ResolveEndpoint";
public static final String ADD_MIDDLEWARE_HELPER_NAME = String.format("add%sMiddleware", MIDDLEWARE_NAME);
public static final String RESOLVER_INTERFACE_NAME = "EndpointResolver";
Expand Down Expand Up @@ -74,18 +74,42 @@ final class EndpointGenerator implements Runnable {
private final ObjectNode endpointData;
private final String endpointPrefix;
private final Map<String, Partition> partitions = new TreeMap<>();
private final Boolean isInternalOnly;
private final String resolvedSdkID;

EndpointGenerator(
public EndpointGenerator(
GoSettings settings,
Model model,
TriConsumer<String, String, Consumer<GoWriter>> writerFactory
) {
this(
settings,
model,
writerFactory,
settings.getService(model).expectTrait(ServiceTrait.class)
.getSdkId(),
settings.getService(model).expectTrait(ServiceTrait.class)
.getArnNamespace(),
false
);
}

public EndpointGenerator(
GoSettings settings,
Model model,
TriConsumer<String, String, Consumer<GoWriter>> writerFactory,
String sdkID,
String arnNamespace,
Boolean internalOnly
) {
this.settings = settings;
this.model = model;
this.writerFactory = writerFactory;
serviceShape = settings.getService(model);
this.endpointPrefix = getEndpointPrefix(serviceShape);
this.endpointPrefix = getEndpointPrefix(sdkID, arnNamespace);
this.endpointData = Node.parse(IoUtils.readUtf8Resource(getClass(), "endpoints.json")).expectObjectNode();
this.isInternalOnly = internalOnly;
this.resolvedSdkID = sdkID;
validateVersion();
loadPartitions();
}
Expand All @@ -106,6 +130,12 @@ private String getEndpointPrefix(ServiceShape service) {
return endpointPrefixData.getStringMemberOrDefault(serviceTrait.getSdkId(), serviceTrait.getArnNamespace());
}

private String getEndpointPrefix(String sdkId, String arnNamespace) {
ObjectNode endpointPrefixData = Node.parse(IoUtils.readUtf8Resource(getClass(), "endpoint-prefix.json"))
.expectObjectNode();
return endpointPrefixData.getStringMemberOrDefault(sdkId, arnNamespace);
}

private void loadPartitions() {
List<ObjectNode> partitionObjects = endpointData
.expectArrayMember("partitions")
Expand All @@ -119,22 +149,31 @@ private void loadPartitions() {

@Override
public void run() {
writerFactory.accept("endpoints.go", settings.getModuleName(), writer -> {
generatePublicResolverTypes(writer);
generateMiddleware(writer);
generateAwsEndpointResolverWrapper(writer);
});
writerFactory.accept(INTERNAL_ENDPOINT_PACKAGE + "/endpoints.go", getInternalEndpointImportPath(), (writer) -> {
if (!this.isInternalOnly) {
writerFactory.accept("endpoints.go", settings.getModuleName(), writer -> {
generatePublicResolverTypes(writer);
generateMiddleware(writer);
generateAwsEndpointResolverWrapper(writer);
});
}

String pkgName = isInternalOnly ? INTERNAL_ENDPOINT_PACKAGE + "/" + this.endpointPrefix : INTERNAL_ENDPOINT_PACKAGE;
writerFactory.accept(pkgName + "/endpoints.go", getInternalEndpointImportPath(), (writer) -> {
generateInternalResolverImplementation(writer);
generateInternalEndpointsModel(writer);
});
writerFactory.accept(INTERNAL_ENDPOINT_PACKAGE + "/endpoints_test.go",
getInternalEndpointImportPath(), (writer) -> {
writer.addUseImports(SmithyGoDependency.TESTING);
writer.openBlock("func TestRegexCompile(t *testing.T) {", "}", () -> {
writer.write("_ = $T", getInternalEndpointsSymbol(INTERNAL_ENDPOINTS_DATA_NAME, false).build());

if (!this.isInternalOnly) {
writerFactory.accept(INTERNAL_ENDPOINT_PACKAGE + "/endpoints_test.go",
getInternalEndpointImportPath(), (writer) -> {
writer.addUseImports(SmithyGoDependency.TESTING);
writer.openBlock("func TestRegexCompile(t *testing.T) {", "}", () -> {
writer.write("_ = $T",
getInternalEndpointsSymbol(INTERNAL_ENDPOINTS_DATA_NAME, false).build());
});
});
});
}

}

private void generateAwsEndpointResolverWrapper(GoWriter writer) {
Expand Down Expand Up @@ -254,12 +293,13 @@ private void generateMiddlewareResolverBody(GoStackStepMiddlewareGenerator g, Go
});
w.write("ctx = awsmiddleware.SetSigningName(ctx, signingName)");
});
w.write("");

w.write("ctx = awsmiddleware.SetSigningRegion(ctx, endpoint.SigningRegion)");
w.write("ctx = smithyhttp.SetHostnameImmutable(ctx, endpoint.HostnameImmutable)");
w.write("");
// set signing region on context
w.write("ctx = awsmiddleware.SetSigningRegion(ctx, endpoint.SigningRegion)");
// set partition id on context
w.write("ctx = awsmiddleware.SetPartitionID(ctx, endpoint.PartitionID)");

w.insertTrailingNewline();
w.write("return next.HandleSerialize(ctx, in)");
}

Expand Down Expand Up @@ -389,8 +429,10 @@ private void generateInternalResolverImplementation(GoWriter writer) {

// Resolver
Symbol resolverImplSymbol = SymbolUtils.createPointableSymbolBuilder(INTERNAL_RESOLVER_NAME).build();


writer.writeDocs(String.format("%s %s endpoint resolver", resolverImplSymbol.getName(),
serviceShape.expectTrait(ServiceTrait.class).getSdkId()));
this.resolvedSdkID));
writer.openBlock("type $T struct {", "}", resolverImplSymbol, () -> {
writer.write("partitions $T", SymbolUtils.createValueSymbolBuilder("Partitions",
AwsGoDependency.AWS_ENDPOINTS).build());
Expand Down Expand Up @@ -505,11 +547,70 @@ private void writeEndpoint(GoWriter writer, ObjectNode node) {
});
}

private static class ResolveConfigField extends ConfigField {
private final boolean shared;

public ResolveConfigField(Builder builder) {
super(builder);
this.shared = builder.shared;
}

public static Builder builder() {
return new Builder();
}

public boolean isShared() {
return shared;
}

private static class Builder extends ConfigField.Builder {
private boolean shared;

public Builder() {
super();
}

/**
* Set the resolver config field to be shared common parameter
*
* @param shared whether the resolver config field is shared
* @return the builder
*/
public Builder shared(boolean shared) {
this.shared = shared;
return this;
}

@Override
public ResolveConfigField build() {
return new ResolveConfigField(this);
}

@Override
public Builder name(String name) {
super.name(name);
return this;
}

@Override
public Builder type(Symbol type) {
super.type(type);
return this;
}

@Override
public Builder documentation(String documentation) {
super.documentation(documentation);
return this;
}
}
}

private final class Partition {
private final String id;
private final ObjectNode defaults;
private String dnsSuffix;
private final ObjectNode config;
private final String dnsSuffix;

private Partition(ObjectNode config, String partition) {
id = partition;
Expand Down Expand Up @@ -563,63 +664,4 @@ public ObjectNode getConfig() {
return config;
}
}

private static class ResolveConfigField extends ConfigField {
private final boolean shared;

public ResolveConfigField(Builder builder) {
super(builder);
this.shared = builder.shared;
}

public boolean isShared() {
return shared;
}

public static Builder builder() {
return new Builder();
}

private static class Builder extends ConfigField.Builder {
private boolean shared;

public Builder() {
super();
}

/**
* Set the resolver config field to be shared common parameter
*
* @param shared whether the resolver config field is shared
* @return the builder
*/
public Builder shared(boolean shared) {
this.shared = shared;
return this;
}

@Override
public ResolveConfigField build() {
return new ResolveConfigField(this);
}

@Override
public Builder name(String name) {
super.name(name);
return this;
}

@Override
public Builder type(Symbol type) {
super.type(type);
return this;
}

@Override
public Builder documentation(String documentation) {
super.documentation(documentation);
return this;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package software.amazon.smithy.aws.go.codegen.customization;

import java.util.function.Consumer;
import software.amazon.smithy.aws.go.codegen.EndpointGenerator;
import software.amazon.smithy.aws.traits.ServiceTrait;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.go.codegen.GoSettings;
import software.amazon.smithy.go.codegen.GoWriter;
import software.amazon.smithy.go.codegen.TriConsumer;
import software.amazon.smithy.go.codegen.integration.GoIntegration;
import software.amazon.smithy.model.Model;

/**
* S3ControlEndpointResolverCustomizations adds an internal endpoint resolver
* for s3 service endpoints
*/
public class S3ControlEndpointResolver implements GoIntegration {

@Override
public void writeAdditionalFiles(
GoSettings settings,
Model model,
SymbolProvider symbolProvider,
TriConsumer<String, String, Consumer<GoWriter>> writerFactory
) {
if (!settings.getService(model).expectTrait(ServiceTrait.class).getSdkId().equalsIgnoreCase(
"S3 Control")){
return;
}

// Generate S3 internal endpoint resolver for S3 Control service
new EndpointGenerator(settings, model, writerFactory,"S3","s3", true).run();
}
}
Loading

0 comments on commit 59a6550

Please sign in to comment.