Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.sagebionetworks.template;

import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import software.amazon.awssdk.services.cloudformation.model.CloudFormationException;
Expand Down Expand Up @@ -65,19 +64,6 @@ public interface CloudFormationClientWrapper {
* @throws RuntimeException if the stack operation fails or times out
*/
Optional<Stack> waitForStackToComplete(String stackName) throws InterruptedException;

/**
* Waits for a stack operation to complete while handling CloudFormation wait conditions.
* Each wait condition handler in the provided set will be invoked when its corresponding
* wait condition is triggered during stack creation.
*
* @param stackName the name of the stack to wait for
* @param waitConditionHandlers a set of handlers for processing CloudFormation wait conditions
* @return an Optional containing the final Stack if it exists, or empty if it doesn't
* @throws InterruptedException if the waiting thread is interrupted
* @throws RuntimeException if the stack operation fails, a wait condition fails, or the operation times out
*/
Optional<Stack> waitForStackToComplete(String stackName, Set<WaitConditionHandler> waitConditionHandlers) throws InterruptedException;

/**
* Retrieves the value of a specific output from a CloudFormation stack.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,24 @@ public class CloudFormationClientWrapperImpl implements CloudFormationClientWrap

public static final int SLEEP_TIME = 10 * 1000;
public static final String NO_UPDATES_ARE_TO_BE_PERFORMED = "No updates are to be performed";
CloudFormationClient cloudFormationClient;
AmazonS3 s3Client;
Configuration configuration;
Logger logger;
ThreadProvider threadProvider;


private final CloudFormationClient cloudFormationClient;
private final AmazonS3 s3Client;
private final Configuration configuration;
private final Logger logger;
private final ThreadProvider threadProvider;
private final Map<String, WaitConditionHandler> waitConditionHandlerMap;

@Inject
public CloudFormationClientWrapperImpl(CloudFormationClient cloudFormationClient, AmazonS3 s3Client,
Configuration configuration, LoggerFactory loggerFactory, ThreadProvider threadProvider) {
Configuration configuration, LoggerFactory loggerFactory, ThreadProvider threadProvider, Set<WaitConditionHandler> waitConditionHandlers) {
super();
this.cloudFormationClient = cloudFormationClient;
this.s3Client = s3Client;
this.configuration = configuration;
this.logger = loggerFactory.getLogger(CloudFormationClientWrapperImpl.class);
this.threadProvider = threadProvider;
this.waitConditionHandlerMap = waitConditionHandlers.stream().collect(Collectors.toMap(WaitConditionHandler::getWaitConditionId, Function.identity()));
}

@Override
Expand Down Expand Up @@ -251,16 +254,8 @@ public boolean isStartedInUpdateRollbackComplete(String stackName) {

@Override
public Optional<Stack> waitForStackToComplete(String stackName) throws InterruptedException {
return waitForStackToComplete(stackName, Collections.emptySet());
}

@Override
public Optional<Stack> waitForStackToComplete(String stackName, Set<WaitConditionHandler> waitConditionHandlers) throws InterruptedException {
boolean startedInUpdateRollbackComplete = isStartedInUpdateRollbackComplete(stackName); // Initial state

Map<String, WaitConditionHandler> waitConditionHandlerMap = waitConditionHandlers.stream()
.collect(Collectors.toMap(WaitConditionHandler::getWaitConditionId, Function.identity()));

// To avoid re-processing the same wait condition multiple times we need to keep track of them
Set<String> processedWaitConditionSet = new HashSet<>();

Expand Down
1 change: 0 additions & 1 deletion src/main/java/org/sagebionetworks/template/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ public class Constants {
public static final String PROPERTY_KEY_VPC_ENDPOINTS_AZ = "org.sagebionetworks.vpc.endpoints.availability.zones";
public static final String PROPERTY_KEY_VPC_PEERING_ACCEPT_ROLE_ARN = "org.sagebionetworks.vpc.peering.accept.role.arn";
public static final String PROPERTY_KEY_OLD_VPC_CIDR = "org.sagebionetworks.vpc.old.vpc.cidr";
public static final String PROPERTY_KEY_OPS_VPC_EXPORT_PREFIX = "org.sagebionetworks.vpc.ops.export.prefix";
// repo
public static final String PROPERTY_KEY_STACK = "org.sagebionetworks.stack";
public static final String PROPERTY_KEY_INSTANCE = "org.sagebionetworks.instance";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
import org.sagebionetworks.template.docs.SynapseDocsBuilderImpl;
import org.sagebionetworks.template.global.GlobalResourcesBuilder;
import org.sagebionetworks.template.global.GlobalResourcesBuilderImpl;
import org.sagebionetworks.template.global.waitconditions.SynapseHelpCollectionIndexCreation;
import org.sagebionetworks.template.global.waitconditions.SynapseHelpKnowledgeBaseDataSourceSync;
import org.sagebionetworks.template.ip.address.IpAddressPoolBuilder;
import org.sagebionetworks.template.ip.address.IpAddressPoolBuilderImpl;
import org.sagebionetworks.template.jobs.AsynchAdminJobExecutor;
Expand Down Expand Up @@ -81,8 +83,6 @@
import org.sagebionetworks.template.repo.beanstalk.ssl.CertificateBuilderImpl;
import org.sagebionetworks.template.repo.beanstalk.ssl.ElasticBeanstalkExtentionBuilder;
import org.sagebionetworks.template.repo.beanstalk.ssl.ElasticBeanstalkExtentionBuilderImpl;
import org.sagebionetworks.template.repo.bedrock.SynapseHelpCollectionIndexCreation;
import org.sagebionetworks.template.repo.bedrock.SynapseHelpKnowledgeBaseDataSourceSync;
import org.sagebionetworks.template.repo.cloudwatchlogs.CloudwatchLogsConfig;
import org.sagebionetworks.template.repo.cloudwatchlogs.CloudwatchLogsConfigValidator;
import org.sagebionetworks.template.repo.cloudwatchlogs.CloudwatchLogsVelocityContextProvider;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,59 @@
package org.sagebionetworks.template.global;

import com.google.inject.Inject;
import org.apache.logging.log4j.Logger;
import static org.sagebionetworks.template.Constants.DELETION_POLICY;
import static org.sagebionetworks.template.Constants.GLOBAL_CFSTACK_OUTPUT_KEY_SES_BOUNCE_TOPIC;
import static org.sagebionetworks.template.Constants.GLOBAL_CFSTACK_OUTPUT_KEY_SES_COMPLAINT_TOPIC;
import static org.sagebionetworks.template.Constants.GLOBAL_RESOURCES_STACK_NAME_FORMAT;
import static org.sagebionetworks.template.Constants.IDENTITY_ARN;
import static org.sagebionetworks.template.Constants.JSON_INDENT;
import static org.sagebionetworks.template.Constants.OPS_VPC_EXPORT_PREFIX;
import static org.sagebionetworks.template.Constants.PROPERTY_KEY_STACK;
import static org.sagebionetworks.template.Constants.SES_SYNAPSE_DOMAIN;
import static org.sagebionetworks.template.Constants.STACK;
import static org.sagebionetworks.template.Constants.TEMPLATE_GLOBAL_RESOURCES;
import static org.sagebionetworks.template.Constants.VPC_EXPORT_PREFIX;

import java.io.StringWriter;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.json.JSONObject;
import org.sagebionetworks.template.CloudFormationClientWrapper;
import org.sagebionetworks.template.Constants;
import org.sagebionetworks.template.CreateOrUpdateStackRequest;
import org.sagebionetworks.template.LoggerFactory;
import org.sagebionetworks.template.SesClientWrapper;
import org.sagebionetworks.template.StackTagsProvider;
import org.sagebionetworks.template.config.Configuration;
import org.sagebionetworks.template.repo.DeletionPolicy;
import software.amazon.awssdk.services.cloudformation.model.Capability;

import java.io.StringWriter;
import com.google.inject.Inject;

import static org.sagebionetworks.template.Constants.DELETION_POLICY;
import static org.sagebionetworks.template.Constants.GLOBAL_RESOURCES_STACK_NAME_FORMAT;
import static org.sagebionetworks.template.Constants.JSON_INDENT;
import static org.sagebionetworks.template.Constants.PROPERTY_KEY_STACK;
import static org.sagebionetworks.template.Constants.SES_SYNAPSE_DOMAIN;
import static org.sagebionetworks.template.Constants.STACK;
import static org.sagebionetworks.template.Constants.TEMPLATE_GLOBAL_RESOURCES;
import static org.sagebionetworks.template.Constants.CAPABILITY_NAMED_IAM;
import static org.sagebionetworks.template.Constants.GLOBAL_CFSTACK_OUTPUT_KEY_SES_BOUNCE_TOPIC;
import static org.sagebionetworks.template.Constants.GLOBAL_CFSTACK_OUTPUT_KEY_SES_COMPLAINT_TOPIC;
import software.amazon.awssdk.services.cloudformation.model.Capability;
import software.amazon.awssdk.services.sts.StsClient;

public class GlobalResourcesBuilderImpl implements GlobalResourcesBuilder {

CloudFormationClientWrapper cloudFormationClientWrapper;
VelocityEngine velocityEngine;
Configuration config;
Logger logger;
StackTagsProvider stackTagsProvider;
SesClientWrapper sesClientWrapper;
private final CloudFormationClientWrapper cloudFormationClientWrapper;
private final VelocityEngine velocityEngine;
private final Configuration config;
private final StackTagsProvider stackTagsProvider;
private final SesClientWrapper sesClientWrapper;
private final StsClient stsClient;

@Inject
public GlobalResourcesBuilderImpl(CloudFormationClientWrapper cloudFormationClientWrapper,
VelocityEngine velocityEngine,
Configuration config,
LoggerFactory loggerFactory,
StackTagsProvider stackTagsProvider,
SesClientWrapper sesClientWrapper) {
SesClientWrapper sesClientWrapper,
StsClient stsClient) {
this.cloudFormationClientWrapper = cloudFormationClientWrapper;
this.velocityEngine = velocityEngine;
this.config = config;
this.logger = loggerFactory.getLogger(GlobalResourcesBuilderImpl.class);
this.stackTagsProvider = stackTagsProvider;
this.sesClientWrapper = sesClientWrapper;
this.stsClient = stsClient;
}

@Override
Expand Down Expand Up @@ -83,15 +86,23 @@ public String createStackName() {

public VelocityContext createContext() {
VelocityContext context = new VelocityContext();
context.put(STACK, config.getProperty(PROPERTY_KEY_STACK));
context.put(DELETION_POLICY,
Constants.isProd(config.getProperty(PROPERTY_KEY_STACK)) ? DeletionPolicy.Retain.name() : DeletionPolicy.Delete.name());

String stack = config.getProperty(PROPERTY_KEY_STACK);

context.put(STACK, stack);
context.put(DELETION_POLICY, Constants.isProd(config.getProperty(PROPERTY_KEY_STACK)) ? DeletionPolicy.Retain.name() : DeletionPolicy.Delete.name());

context.put(VPC_EXPORT_PREFIX, Constants.createVpcExportPrefix(stack));
context.put(OPS_VPC_EXPORT_PREFIX, "us-east-1-vpc");
context.put(IDENTITY_ARN, stsClient.getCallerIdentity().arn());

return context;
}

public void setupSesTopics(String stackName) {
String sesComplaintSnsTopic = this.cloudFormationClientWrapper.getOutput(stackName, GLOBAL_CFSTACK_OUTPUT_KEY_SES_COMPLAINT_TOPIC);
String sesBounceSnsTopic = this.cloudFormationClientWrapper.getOutput(stackName, GLOBAL_CFSTACK_OUTPUT_KEY_SES_BOUNCE_TOPIC);

sesClientWrapper.setComplaintNotificationTopic(SES_SYNAPSE_DOMAIN, sesComplaintSnsTopic);
sesClientWrapper.setBounceNotificationTopic(SES_SYNAPSE_DOMAIN, sesBounceSnsTopic);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package org.sagebionetworks.template.repo.bedrock;
package org.sagebionetworks.template.global.waitconditions;

import java.io.IOException;
import java.util.Optional;

import org.apache.logging.log4j.Logger;
import org.opensearch.client.opensearch._types.OpenSearchException;
import org.opensearch.client.opensearch._types.WaitForActiveShardOptions;
import org.opensearch.client.opensearch.indices.OpenSearchIndicesClient;
import org.sagebionetworks.template.Constants;
import org.sagebionetworks.template.LoggerFactory;
import org.sagebionetworks.template.OpenSearchClientFactory;
import org.sagebionetworks.template.WaitConditionHandler;
import org.sagebionetworks.template.config.RepoConfiguration;

import software.amazon.awssdk.services.cloudformation.model.StackEvent;
import com.google.inject.Inject;

import software.amazon.awssdk.services.cloudformation.model.StackEvent;
import software.amazon.awssdk.services.opensearchserverless.OpenSearchServerlessClient;
import software.amazon.awssdk.services.opensearchserverless.model.CollectionDetail;
import software.amazon.awssdk.services.opensearchserverless.model.CollectionStatus;
Expand Down Expand Up @@ -56,7 +57,7 @@ public String getWaitConditionId() {

@Override
public Optional<String> handle(StackEvent stackEvent) {
String collectionName = config.getProperty(Constants.PROPERTY_KEY_STACK) + "-" + config.getProperty(Constants.PROPERTY_KEY_INSTANCE) + "-synhelp";
String collectionName = config.getProperty(Constants.PROPERTY_KEY_STACK) + "-synhelp";

CollectionDetail collection = ossManagementClient.batchGetCollection(req -> req
.names(collectionName)
Expand All @@ -79,6 +80,7 @@ public Optional<String> handle(StackEvent stackEvent) {
logger.info("Index {} does not exist, creating...", IDX_NAME);

client.create(req -> req
.waitForActiveShards( opt -> opt.option(WaitForActiveShardOptions.All))
.index(IDX_NAME)
.settings(settings -> settings.knn(true).knnAlgoParamEfSearch(512))
.mappings(mappings -> mappings
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.sagebionetworks.template.repo.bedrock;
package org.sagebionetworks.template.global.waitconditions;

import java.util.Optional;

Expand Down Expand Up @@ -48,17 +48,17 @@ public String getWaitConditionId() {

@Override
public Optional<String> handle(StackEvent stackEvent) throws InterruptedException {
String stackPrefix = config.getProperty(Constants.PROPERTY_KEY_STACK) + "-" + config.getProperty(Constants.PROPERTY_KEY_INSTANCE);
String stack = config.getProperty(Constants.PROPERTY_KEY_STACK);

String knowledgeBaseName = stackPrefix + "-synhelp-knowledge-base";
String knowledgeBaseName = stack + "-synhelp-knowledge-base";
String knowledgeBaseId = bedrockAgentClient.listKnowledgeBasesPaginator(req -> {})
.knowledgeBaseSummaries().stream()
.filter(kb -> kb.name().equals(knowledgeBaseName))
.findFirst()
.map(KnowledgeBaseSummary::knowledgeBaseId)
.orElseThrow();

String dataSourceName = stackPrefix + "-synhelp-datasource";
String dataSourceName = stack + "-synhelp-datasource";
String dataSourceId = bedrockAgentClient.listDataSourcesPaginator(req -> req.knowledgeBaseId(knowledgeBaseId))
.dataSourceSummaries().stream()
.filter(dataSource -> dataSource.name().equals(dataSourceName))
Expand Down
Loading