Skip to content

Commit

Permalink
Implement aws.IsVirtualHostableS3Bucket function. (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
alextwoods authored Sep 15, 2022
1 parent 53b0e80 commit 77b09ad
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.smithy.rulesengine.customize;

import software.amazon.smithy.rulesengine.language.EndpointRuleset;
import software.amazon.smithy.rulesengine.traits.EndpointTestsTrait;

/**
* Customize generated EndpointRulesets and EndpointTests.
* <p>
* To customize the Endpoint rules for a service, implement this interface
* and update the `rule-set-synthesis-configuration.json` to add the
* fully qualified classname of your implementation as `customization` on the service definition.
*/
public interface EndpointRulesetCustomization {

/**
* Customize the base, generated EndpointRuleset (the ruleset generated from endpoints.json).
* <p>
* Most Customizations will need to add additional rules and parameters. The generated rules
* contains a single, top level TreeRule which you can use to insert additional rules into:
* <pre>{@code
* public EndpointRuleset customizeRuleset(EndpointRuleset ruleset) {
* assert ruleset.getRules().size() == 1;
* TreeRule rootRule = (TreeRule) ruleset.getRules().get(0);
*
* List<Rule> subRules = new ArrayList<>();
* // Add our new custom rules first
* subRules.add(myNewCustomRules());
* // ensure the base/generated rule are added
* subRules.addAll(ruleset.getRules());
*
* // create a new root rule from the old rule (with our new subRules)
* Rule newRootRule = TreeRule.builder()
* .conditions(rootRule.getConditions())
* .treeRule(subRules);
*
* // add a new custom parameter
* Parameters newParameters = ruleset.getParameters().toBuilder()
* .addParameter(myNewParameter()).build();
*
* // use the Rulset builder with our modified parameters and rules
* return EndpointRuleset.builder()
* .parameters(newParameters)
* .addRule(newRootRule)
* .build();
* }
* }</pre>
*
* @param ruleset the base generated ruleset
* @return ruleset customized for the service
*/
default EndpointRuleset customizeRuleset(EndpointRuleset ruleset) {
return ruleset;
}

/**
* Customize the base, generated Test Suite (generated from endpoints.json).
* <p>
* Most customizations will simply need to add additional test cases:
* <pre>{@code
* public EndpointTestsTrait customizeTestSuite(EndpointTestsTrait testSuite) {
* List<EndpointTestCase> testCases = new ArrayList<>();
* testCases.addAll(testSuite.getTestCases());
* testCases.add(myCustomTestCase());
* return ((EndpointTestsTrait.Builder)testSuite.toBuilder()).testCases(testCases).build();
* }
* }</pre>
*
* @param testSuite the base generated test suite
* @return test suite customized for the service
*/
default EndpointTestsTrait customizeTestSuite(EndpointTestsTrait testSuite) {
return testSuite;
}

/**
* If a service has private/internal/development only features, return true.
* The {@link #developmentRuleset(EndpointRuleset)} developmentRuleset} and
* {@link #developmentTestSuite(EndpointTestsTrait)} methods will be called
* and the resulting rules/tests will be saved in a separate output folder.
*
* @return true if the service has development (internal only) endpoint rules
*/
default boolean hasDevelopmentFeatures() {
return false;
}

/**
* Called when hasDevelopmentFeatures is true to produce rules with internal/development
* features enabled.
* See {@link #customizeRuleset(EndpointRuleset)}
*
* @param ruleset the base generated ruleset
* @return ruleset customized for the service including development (internal) features
*/
default EndpointRuleset developmentRuleset(EndpointRuleset ruleset) {
return ruleset;
}

/**
* Called when hasDevelopmentFeatures is true to produce test cases with internal/development
* features enabled.
* See {@link #customizeTestSuite(EndpointTestsTrait)}
*
* @param testSuite the base generated test suite
* @return test suite customized for the service including development (internal) features
*/
default EndpointTestsTrait developmentTestSuite(EndpointTestsTrait testSuite) {
return testSuite;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.smithy.rulesengine.language.stdlib;

import java.util.Arrays;
import java.util.List;
import software.amazon.smithy.rulesengine.language.eval.Type;
import software.amazon.smithy.rulesengine.language.eval.Value;
import software.amazon.smithy.rulesengine.language.syntax.fn.FunctionDefinition;
import software.amazon.smithy.utils.SmithyUnstableApi;

@SmithyUnstableApi
public class IsVirtualHostableS3Bucket extends FunctionDefinition {
public static final String ID = "aws.isVirtualHostableS3Bucket";

@Override
public String id() {
return ID;
}

@Override
public List<Type> arguments() {
return Arrays.asList(Type.str(), Type.bool());
}

@Override
public Type returnType() {
return Type.bool();
}

@Override
public Value eval(List<Value> arguments) {
String hostLabel = arguments.get(0).expectString();
boolean allowDots = arguments.get(1).expectBool();
if (allowDots) {
return Value.bool(hostLabel.matches("[a-z\\d][a-z\\d\\-.]{1,61}[a-z\\d]"));
} else {
return Value.bool(hostLabel.matches("[a-z\\d][a-z\\d\\-]{1,61}[a-z\\d]"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.HashMap;
import java.util.Optional;
import software.amazon.smithy.rulesengine.language.stdlib.IsValidHostLabel;
import software.amazon.smithy.rulesengine.language.stdlib.IsVirtualHostableS3Bucket;
import software.amazon.smithy.rulesengine.language.stdlib.ParseArn;
import software.amazon.smithy.rulesengine.language.stdlib.ParseUrl;
import software.amazon.smithy.rulesengine.language.stdlib.PartitionFn;
Expand All @@ -26,6 +27,7 @@
import software.amazon.smithy.rulesengine.language.util.LazyValue;
import software.amazon.smithy.utils.SmithyUnstableApi;


/**
* Collection of registered functions.
*/
Expand All @@ -40,6 +42,7 @@ public final class FunctionRegistry {
registry.registerFunction(new ParseUrl());
registry.registerFunction(new Substring());
registry.registerFunction(new UriEncode());
registry.registerFunction(new IsVirtualHostableS3Bucket());
return registry;
}).build();

Expand All @@ -48,6 +51,10 @@ public final class FunctionRegistry {
private FunctionRegistry() {
}

static FunctionRegistry getGlobalRegistry() {
return GLOBAL_REGISTRY.value();
}

public void registerFunction(FunctionDefinition definition) {
registry.put(definition.id(), definition);
}
Expand All @@ -59,8 +66,4 @@ public Optional<LibraryFunction> forNode(FnNode node) {
return Optional.empty();
}
}

static FunctionRegistry getGlobalRegistry() {
return GLOBAL_REGISTRY.value();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{
"version": "1.0",
"testCases": [
{
"documentation": "bucket-name: isVirtualHostable",
"params": {
"BucketName": "bucket-name"
},
"expect": {
"endpoint": {
"url": "https://bucket-name.s3.amazonaws.com"
}
}
},
{
"documentation": "bucket-with-number-1: isVirtualHostable",
"params": {
"BucketName": "bucket-with-number-1"
},
"expect": {
"endpoint": {
"url": "https://bucket-with-number-1.s3.amazonaws.com"
}
}
},
{
"documentation": "BucketName: not isVirtualHostable (uppercase characters)",
"params": {
"BucketName": "BucketName"
},
"expect": {
"error": "not isVirtualHostableS3Bucket"
}
},
{
"documentation": "bucket_name: not isVirtualHostable (underscore)",
"params": {
"BucketName": "bucket_name"
},
"expect": {
"error": "not isVirtualHostableS3Bucket"
}
},
{
"documentation": "bucket.name: isVirtualHostable (http only)",
"params": {
"BucketName": "bucket.name"
},
"expect": {
"endpoint": {
"url": "http://bucket.name.s3.amazonaws.com"
}
}
},
{
"documentation": "bucket.name.multiple.dots1: isVirtualHostable (http only)",
"params": {
"BucketName": "bucket.name.multiple.dots1"
},
"expect": {
"endpoint": {
"url": "http://bucket.name.multiple.dots1.s3.amazonaws.com"
}
}
},
{
"documentation": "-bucket-name: not isVirtualHostable (leading dash)",
"params": {
"BucketName": "-bucket-name"
},
"expect": {
"error": "not isVirtualHostableS3Bucket"
}
},
{
"documentation": "bucket-name-: not isVirtualHostable (trailing dash)",
"params": {
"BucketName": "bucket-name-"
},
"expect": {
"error": "not isVirtualHostableS3Bucket"
}
},
{
"documentation": "aa: not isVirtualHostable (< 3 characters)",
"params": {
"BucketName": "aa"
},
"expect": {
"error": "not isVirtualHostableS3Bucket"
}
},
{
"documentation": "'a'*64: not isVirtualHostable (> 63 characters)",
"params": {
"BucketName": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
},
"expect": {
"error": "not isVirtualHostableS3Bucket"
}
},
{
"documentation": ".bucket-name: not isVirtualHostable (leading dot)",
"params": {
"BucketName": ".bucket-name"
},
"expect": {
"error": "not isVirtualHostableS3Bucket"
}
},
{
"documentation": "bucket-name.: not isVirtualHostable (trailing dot)",
"params": {
"BucketName": "bucket-name."
},
"expect": {
"error": "not isVirtualHostableS3Bucket"
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ valid-hostlabel.json
substring.json
uri-encode.json
fns.json
partition-fn.json
partition-fn.json
is-virtual-hostable-s3-bucket.json
Loading

0 comments on commit 77b09ad

Please sign in to comment.