Skip to content

Commit

Permalink
Installer update enhancements (#288)
Browse files Browse the repository at this point in the history
* Rename and fix all update scripts.

* Add caching to AwsClientBuilderFactory

* Fix build script indexing bug for sample app

* Update enhancements: intelligent updating, improved architecture, more tests.

* Address PR comments

Co-authored-by: PoeppingT <[email protected]>
  • Loading branch information
PoeppingT and PoeppingT authored Sep 15, 2022
1 parent b5f3f0c commit ebe713c
Show file tree
Hide file tree
Showing 44 changed files with 1,848 additions and 454 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion installer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ limitations under the License.
</licenses>

<properties>
<checkstyle.maxAllowedViolations>102</checkstyle.maxAllowedViolations>
<checkstyle.maxAllowedViolations>82</checkstyle.maxAllowedViolations>
</properties>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.amazon.aws.partners.saasfactory.saasboost;

import software.amazon.awssdk.core.SdkSystemSetting;
import software.amazon.awssdk.regions.Region;

public final class Constants {
public static final Region AWS_REGION = Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()));
public static final String OS = System.getProperty("os.name").toLowerCase();
public static final String VERSION = Utils.version(Constants.class);
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ public class AwsClientBuilderFactory {
private final Region awsRegion;
private final AwsCredentialsProvider credentialsProvider;

private ApiGatewayClientBuilder cachedApiGatewayBuilder;
private CloudFormationClientBuilder cachedCloudFormationBuilder;
private EcrClientBuilder cachedEcrBuilder;
private IamClientBuilder cachedIamBuilder;
private LambdaClientBuilder cachedLambdaBuilder;
private QuickSightClientBuilder cachedQuickSightBuilder;
private S3ClientBuilder cachedS3Builder;
private SsmClientBuilder cachedSsmBuilder;
private StsClientBuilder cachedStsBuilder;
private SecretsManagerClientBuilder cachedSecretsManagerClientBuilder;

AwsClientBuilderFactory() {
// for testing
this.awsRegion = null;
this.credentialsProvider = null;
}

private AwsClientBuilderFactory(Builder builder) {
// passing no region or a null region to any of the AWS Client Builders
// leads to the default region from the configured profile being used
Expand All @@ -71,54 +88,85 @@ <C extends SdkClient, B extends AwsClientBuilder<B, C>> B decorateBuilderWithDef
}

public ApiGatewayClientBuilder apiGatewayBuilder() {
// override throttling policy to wait 5 seconds if we're throttled on CreateDeployment
// https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html
return decorateBuilderWithDefaults(ApiGatewayClient.builder())
if (cachedApiGatewayBuilder == null) {
// override throttling policy to wait 5 seconds if we're throttled on CreateDeployment
// https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html
cachedApiGatewayBuilder = decorateBuilderWithDefaults(ApiGatewayClient.builder())
.overrideConfiguration(config -> config.retryPolicy(AwsRetryPolicy.addRetryConditions(
RetryPolicy.builder().throttlingBackoffStrategy(retryPolicyContext -> {
if (retryPolicyContext.originalRequest() instanceof CreateDeploymentRequest) {
return Duration.ofSeconds(5);
}
return null;
}).build())));
RetryPolicy.builder().throttlingBackoffStrategy(retryPolicyContext -> {
if (retryPolicyContext.originalRequest() instanceof CreateDeploymentRequest) {
return Duration.ofSeconds(5);
}
return null;
}).build())));
}

return cachedApiGatewayBuilder;
}

public CloudFormationClientBuilder cloudFormationBuilder() {
return decorateBuilderWithDefaults(CloudFormationClient.builder());
if (cachedCloudFormationBuilder == null) {
cachedCloudFormationBuilder = decorateBuilderWithDefaults(CloudFormationClient.builder());
}
return cachedCloudFormationBuilder;
}

public EcrClientBuilder ecrBuilder() {
return decorateBuilderWithDefaults(EcrClient.builder());
if (cachedEcrBuilder == null) {
cachedEcrBuilder = decorateBuilderWithDefaults(EcrClient.builder());
}
return cachedEcrBuilder;
}

public IamClientBuilder iamBuilder() {
// IAM is not regionalized: all endpoints except us-gov and aws-cn use the AWS_GLOBAL region
// ref: https://docs.aws.amazon.com/general/latest/gr/iam-service.html
return decorateBuilderWithDefaults(IamClient.builder()).region(Region.AWS_GLOBAL);
if (cachedIamBuilder == null) {
// IAM is not regionalized: all endpoints except us-gov and aws-cn use the AWS_GLOBAL region
// ref: https://docs.aws.amazon.com/general/latest/gr/iam-service.html
cachedIamBuilder = decorateBuilderWithDefaults(IamClient.builder()).region(Region.AWS_GLOBAL);
}
return cachedIamBuilder;
}

public LambdaClientBuilder lambdaBuilder() {
return decorateBuilderWithDefaults(LambdaClient.builder());
if (cachedLambdaBuilder == null) {
cachedLambdaBuilder = decorateBuilderWithDefaults(LambdaClient.builder());
}
return cachedLambdaBuilder;
}

public QuickSightClientBuilder quickSightBuilder() {
return decorateBuilderWithDefaults(QuickSightClient.builder());
if (cachedQuickSightBuilder == null) {
cachedQuickSightBuilder = decorateBuilderWithDefaults(QuickSightClient.builder());
}
return cachedQuickSightBuilder;
}

public S3ClientBuilder s3Builder() {
return decorateBuilderWithDefaults(S3Client.builder());
if (cachedS3Builder == null) {
cachedS3Builder = decorateBuilderWithDefaults(S3Client.builder());
}
return cachedS3Builder;
}

public SsmClientBuilder ssmBuilder() {
return decorateBuilderWithDefaults(SsmClient.builder());
if (cachedSsmBuilder == null) {
cachedSsmBuilder = decorateBuilderWithDefaults(SsmClient.builder());
}
return cachedSsmBuilder;
}

public StsClientBuilder stsBuilder() {
return decorateBuilderWithDefaults(StsClient.builder());
if (cachedStsBuilder == null) {
cachedStsBuilder = decorateBuilderWithDefaults(StsClient.builder());
}
return cachedStsBuilder;
}

public SecretsManagerClientBuilder secretsManagerBuilder() {
return decorateBuilderWithDefaults(SecretsManagerClient.builder());
if (cachedSecretsManagerClientBuilder == null) {
cachedSecretsManagerClientBuilder = decorateBuilderWithDefaults(SecretsManagerClient.builder());
}
return cachedSecretsManagerClientBuilder;
}

public static Builder builder() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/*
* Copyright 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.amazon.aws.partners.saasfactory.saasboost.model;

import com.amazon.aws.partners.saasfactory.saasboost.SaaSBoostArtifactsBucket;

import java.util.Map;

/**
* The <code>Environment</code> class represents all gathered information about a SaaS Boost environment.
*
* Objects for existing environments should be created using {@link ExistingEnvironmentFactory#create}.
*
* New Environments can be created using {@link Environment.Builder#build}. Instances of {@link Environment.Builder}
* can be instantiated via the {@link Environment#builder()} static function.
*/
public final class Environment {
private String name;
private String accountId;
private SaaSBoostArtifactsBucket artifactsBucket;
private String lambdasFolderName;
private String baseCloudFormationStackName;
private Map<String, String> baseCloudFormationStackInfo;
private boolean metricsAnalyticsDeployed;

private Environment(Builder b) {
this.name = b.name;
this.accountId = b.accountId;
this.artifactsBucket = b.artifactsBucket;
this.lambdasFolderName = b.lambdasFolderName;
this.baseCloudFormationStackName = b.baseCloudFormationStackName;
this.baseCloudFormationStackInfo = b.baseCloudFormationStackInfo;
this.metricsAnalyticsDeployed = b.metricsAnalyticsDeployed;
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public String getAccountId() {
return this.accountId;
}

public void setAccountId(String accountId) {
this.accountId = accountId;
}

public SaaSBoostArtifactsBucket getArtifactsBucket() {
return this.artifactsBucket;
}

public void setArtifactsBucket(SaaSBoostArtifactsBucket artifactsBucket) {
this.artifactsBucket = artifactsBucket;
}

public String getLambdasFolderName() {
return this.lambdasFolderName;
}

public void setLambdasFolderName(String lambdasFolderName) {
this.lambdasFolderName = lambdasFolderName;
}

public String getBaseCloudFormationStackName() {
return this.baseCloudFormationStackName;
}

public void setBaseCloudFormationStackName(String baseCloudFormationStackName) {
this.baseCloudFormationStackName = baseCloudFormationStackName;
}

public Map<String, String> getBaseCloudFormationStackInfo() {
return this.baseCloudFormationStackInfo;
}

public void setBaseCloudFormationStackInfo(Map<String, String> baseCloudFormationStackInfo) {
this.baseCloudFormationStackInfo = baseCloudFormationStackInfo;
}

public boolean isMetricsAnalyticsDeployed() {
return this.metricsAnalyticsDeployed;
}

public void setMetricsAnalyticsDeployed(boolean metricsAnalyticsDeployed) {
this.metricsAnalyticsDeployed = metricsAnalyticsDeployed;
}

/**
* Retrieves a new empty instance of the {@link Environment.Builder}.
*
* @return an empty {@link Environment.Builder}.
*/
public static Builder builder() {
return new Builder();
}

/**
* Constructs a {@link Environment.Builder} using the provided {@link Environment} as a baseline.
*
* It will always be true that calling <code>build</code> on the {@link Environment.Builder} returned
* by this function will create an {@link Environment} equal to the provided {@link Environment}. In other words:
* <code>
* myEnvironment.equals(Environment.builder(myEnvironment).build()) // <== always true
* </code>
*
* @param baseEnvironment the {@link Environment} to base this {@link Environment.Builder} on.
* @return the prebuilt {@link Environment.Builder}
*/
public static Builder builder(Environment baseEnvironment) {
return new Builder();
}

/**
* A convenient `Builder` class for {@link Environment}.
*/
public static final class Builder {

private String name;
private String accountId;
private SaaSBoostArtifactsBucket artifactsBucket;
private String lambdasFolderName;
private String baseCloudFormationStackName;
private Map<String, String> baseCloudFormationStackInfo;
private boolean metricsAnalyticsDeployed;

private Builder() {

}

public Builder name(String name) {
this.name = name;
return this;
}

public Builder accountId(String accountId) {
this.accountId = accountId;
return this;
}

public Builder artifactsBucket(SaaSBoostArtifactsBucket artifactsBucket) {
this.artifactsBucket = artifactsBucket;
return this;
}

public Builder lambdasFolderName(String lambdasFolderName) {
this.lambdasFolderName = lambdasFolderName;
return this;
}

public Builder baseCloudFormationStackName(String baseCloudFormationStackName) {
this.baseCloudFormationStackName = baseCloudFormationStackName;
return this;
}

public Builder baseCloudFormationStackInfo(Map<String, String> baseCloudFormationStackInfo) {
this.baseCloudFormationStackInfo = baseCloudFormationStackInfo;
return this;
}

public Builder metricsAnalyticsDeployed(boolean metricsAnalyticsDeployed) {
this.metricsAnalyticsDeployed = metricsAnalyticsDeployed;
return this;
}

public Environment build() {
return new Environment(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.amazon.aws.partners.saasfactory.saasboost.model;

/**
* A {@link RuntimeException} indicating that the specified {@link Environment} was unable
* to be loaded.
*/
public final class EnvironmentLoadException extends RuntimeException {
public EnvironmentLoadException(String message) {
super(message);
}
}
Loading

0 comments on commit ebe713c

Please sign in to comment.