protected void installSaaSBoost()

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);
    }