in installer/src/main/java/com/amazon/aws/partners/saasfactory/saasboost/SaaSBoostInstall.java [229:374]
protected void installSaaSBoost() {
LOGGER.info("Performing new installation of AWS SaaS Boost");
// Check if yarn.lock exists in the client/web folder
// If it doesn't, exit and ask them to run yarn which will download the NPM dependencies
// TODO We're doing this because downloading Node modules for the first time takes a while... is this necessary?
Path webClientDir = workingDir.resolve("client").resolve("web");
Path yarnLockFile = webClientDir.resolve("yarn.lock");
if (!Files.exists(yarnLockFile)) {
outputMessage("Please run 'yarn' command from " + webClientDir.toString() + " before running this installer.");
System.exit(2);
}
while (true) {
System.out.print("Enter name of the AWS SaaS Boost environment to deploy (Ex. dev, test, uat, prod, etc.): ");
this.envName = Keyboard.readString();
if (validateEnvironmentName(this.envName)) {
break;
} else {
outputMessage("Entered value is incorrect, maximum of 10 alphanumeric characters, please try again.");
}
}
String emailAddress;
while (true) {
System.out.print("Enter the email address for your AWS SaaS Boost administrator: ");
emailAddress = Keyboard.readString();
if (validateEmail(emailAddress)) {
System.out.print("Enter the email address address again to confirm: ");
String emailAddress2 = Keyboard.readString();
if (emailAddress.equals(emailAddress2)) {
break;
} else {
outputMessage("Entered value for email address does not match " + emailAddress);
}
} else {
outputMessage("Entered value for email address is incorrect or wrong format, please try again.");
}
}
System.out.print("Would you like to install the metrics and analytics module of AWS SaaS Boost (y or n)? ");
this.useAnalyticsModule = Keyboard.readBoolean();
// If installing the analytics module, ask about QuickSight.
if (useAnalyticsModule) {
System.out.print("Would you like to setup Amazon Quicksight for the Analytics module? You must have already registered for Quicksight in your account (y or n)? ");
this.useQuickSight = Keyboard.readBoolean();
}
if (this.useQuickSight) {
getQuickSightUsername();
}
System.out.println("If your application runs on Windows and uses a shared file system, Active Directory is required.");
System.out.print("Would you like to provision AWS Directory Service to use with FSx for Windows File Server (y or n)? ");
boolean setupActiveDirectory = Keyboard.readBoolean();
System.out.println();
outputMessage("===========================================================");
outputMessage("");
outputMessage("Would you like to continue the installation with the following options?");
outputMessage("AWS Account: " + this.accountId);
outputMessage("AWS Region: " + AWS_REGION.toString());
outputMessage("AWS SaaS Boost Environment Name: " + this.envName);
outputMessage("Admin Email Address: " + emailAddress);
outputMessage("Install optional Analytics Module: " + this.useAnalyticsModule);
if (this.useAnalyticsModule && isNotBlank(this.quickSightUsername)) {
outputMessage("Amazon QuickSight user for Analytics Module: " + this.quickSightUsername);
} else {
outputMessage("Amazon QuickSight user for Analytics Module: N/A");
}
outputMessage("Setup AWS Directory Service for FSx for Windows File Server: " + setupActiveDirectory);
System.out.println();
System.out.print("Continue (y or n)? ");
boolean continueInstall = Keyboard.readBoolean();
if (!continueInstall) {
cancel();
}
System.out.println();
outputMessage("===========================================================");
outputMessage("Installing AWS SaaS Boost");
outputMessage("===========================================================");
// Check for the AWS managed service roles:
outputMessage("Checking for necessary AWS service linked roles");
setupAwsServiceRoles();
// Create the S3 artifacts bucket
outputMessage("Creating S3 artifacts bucket");
saasBoostArtifactsBucket = SaaSBoostArtifactsBucket.createS3ArtifactBucket(s3, envName, AWS_REGION);
outputMessage("Created S3 artifacts bucket: " + saasBoostArtifactsBucket);
// Copy the CloudFormation templates
outputMessage("Uploading CloudFormation templates to S3 artifacts bucket");
copyTemplateFilesToS3();
// Compile all the source code
outputMessage("Compiling Lambda functions and uploading to S3 artifacts bucket. This will take some time...");
processLambdas();
final String activeDirectoryPasswordParameterName = "/saas-boost/" + envName + "/ACTIVE_DIRECTORY_PASSWORD";
if (setupActiveDirectory) {
String activeDirectoryPassword = generatePassword(16);
LOGGER.info("Add SSM param ACTIVE_DIRECTORY_PASSWORD with password");
try {
ssm.putParameter(PutParameterRequest.builder()
.name(activeDirectoryPasswordParameterName)
.type(ParameterType.SECURE_STRING)
.value(activeDirectoryPassword)
.overwrite(true)
.build()
);
} catch (SdkServiceException ssmError) {
LOGGER.error("ssm:PutParameter error", ssmError);
LOGGER.error(getFullStackTrace(ssmError));
throw ssmError;
}
outputMessage("Active Directory admin user password stored in secure SSM Parameter: " + activeDirectoryPasswordParameterName);
}
// Run CloudFormation create stack
outputMessage("Running CloudFormation");
this.stackName = "sb-" + envName;
createSaaSBoostStack(stackName, emailAddress, setupActiveDirectory, activeDirectoryPasswordParameterName);
// TODO if we capture the create complete event for the web bucket from the main SaaS Boost stack
// we could pop a message in a queue that we could listen to here and trigger the website build
// while the rest of the CloudFormation is finishing. Or, we could move this to a simple CodeBuild
// project and have CloudFormation own building/copying the web files to S3.
// Wait for completion and then build web app
outputMessage("Build website and upload to S3");
String webUrl = buildAndCopyWebApp();
if (useAnalyticsModule) {
LOGGER.info("Install metrics and analytics module");
// The analytics module stack reads baseStackDetails for its CloudFormation template parameters
// because we're not yet creating the analytics resources as a nested child stack of the main stack
this.baseStackDetails = getExistingSaaSBoostStackDetails();
installAnalyticsModule();
}
outputMessage("Check the admin email box for the temporary password.");
outputMessage("AWS SaaS Boost Artifacts Bucket: " + saasBoostArtifactsBucket);
outputMessage("AWS SaaS Boost Console URL is: " + webUrl);
}