Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Jenkins] Add Solutions CFN Create VPC Test #1159

Merged
merged 10 commits into from
Nov 23, 2024
15 changes: 10 additions & 5 deletions deployment/migration-assistant-solution/bin/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { App, DefaultStackSynthesizer } from 'aws-cdk-lib';
import { SolutionsInfrastructureStack } from '../lib/solutions-stack';

const getProps = () => {
const { CODE_BUCKET, SOLUTION_NAME, CODE_VERSION } = process.env;
const { CODE_BUCKET, SOLUTION_NAME, CODE_VERSION, STACK_NAME_SUFFIX } = process.env;
if (typeof CODE_BUCKET !== 'string' || CODE_BUCKET.trim() === '') {
console.warn(`Missing environment variable CODE_BUCKET, using a default value`);
}
Expand All @@ -19,27 +19,32 @@ const getProps = () => {
const codeBucket = CODE_BUCKET ?? "Unknown";
const solutionVersion = CODE_VERSION ?? "Unknown";
const solutionName = SOLUTION_NAME ?? "MigrationAssistant";
const stackNameSuffix = STACK_NAME_SUFFIX ?? undefined;
const solutionId = 'SO0290';
const description = `(${solutionId}) - The AWS CloudFormation template for deployment of the ${solutionName}. Version ${solutionVersion}`;
return {
codeBucket,
solutionVersion,
solutionId,
solutionName,
description
description,
stackNameSuffix
};
};

const app = new App();
const infraProps = getProps()

new SolutionsInfrastructureStack(app, 'Migration-Assistant-Infra-Import-VPC', {
const baseImportVPCStackName = "Migration-Assistant-Infra-Import-VPC"
const baseCreateVPCStackName = "Migration-Assistant-Infra-Create-VPC"
new SolutionsInfrastructureStack(app, baseImportVPCStackName, {
synthesizer: new DefaultStackSynthesizer(),
createVPC: false,
stackName: infraProps.stackNameSuffix ? `${baseImportVPCStackName}-${infraProps.stackNameSuffix}` : baseImportVPCStackName,
lewijacn marked this conversation as resolved.
Show resolved Hide resolved
...infraProps
});
new SolutionsInfrastructureStack(app, 'Migration-Assistant-Infra-Create-VPC', {
new SolutionsInfrastructureStack(app, baseCreateVPCStackName, {
synthesizer: new DefaultStackSynthesizer(),
createVPC: true,
stackName: infraProps.stackNameSuffix ? `${baseCreateVPCStackName}-${infraProps.stackNameSuffix}` : baseCreateVPCStackName,
...infraProps
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
def gitBranch = params.GIT_BRANCH ?: 'sol-pipeline'
def gitUrl = params.GIT_REPO_URL ?: 'https://github.com/lewijacn/opensearch-migrations.git'
lewijacn marked this conversation as resolved.
Show resolved Hide resolved

library identifier: "migrations-lib@${gitBranch}", retriever: modernSCM(
[$class: 'GitSCMSource',
remote: "${gitUrl}"])

// Shared library function (location from root: vars/solutionsCFNTest.groovy)
solutionsCFNTest()
108 changes: 108 additions & 0 deletions test/awsRunInitBootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/bin/bash
lewijacn marked this conversation as resolved.
Show resolved Hide resolved

usage() {
echo ""
echo "Script to run initBootstrap.sh on Migration Assistant bootstrap box"
echo ""
echo "Usage: "
echo " ./awsRunInitBootstrap.sh [--stage] [--workflow]--"
echo ""
echo "Options:"
echo " --stage Deployment stage name, e.g. sol-integ"
echo " --workflow Workflow to execute, options include ALL(default)|INIT_BOOTSTRAP|VERIFY_INIT_BOOTSTRAP"
echo ""
exit 1
}

STAGE="aws-integ"
WORKFLOW="ALL"
REGION="us-east-1"
while [[ $# -gt 0 ]]; do
case $1 in
--stage)
STAGE="$2"
shift # past argument
shift # past value
;;
--workflow)
WORKFLOW="$2"
shift # past argument
shift # past value
;;
-h|--help)
usage
;;
-*)
echo "Unknown option $1"
usage
;;
*)
shift # past argument
;;
esac
done

execute_command_and_wait_for_result() {
local command="$1"
local instance_id="$2"
echo "Executing command: [$command] on node: $instance_id"
sleep 5
command_id=$(aws ssm send-command --instance-ids "$instance_id" --document-name "AWS-RunShellScript" --parameters commands="$command" --output text --query 'Command.CommandId')
if [[ -z "$command_id" ]]; then
echo "Error: Unable to retrieve command id from triggered SSM command"
exit 1
fi
sleep 5
command_status=$(aws ssm get-command-invocation --command-id "$command_id" --instance-id "$instance_id" --output text --query 'Status')
max_attempts=25
attempt_count=0
while [ "$command_status" != "Success" ] && [ "$command_status" != "Failed" ] && [ "$command_status" != "TimedOut" ]
do
((attempt_count++))
if [[ $attempt_count -ge $max_attempts ]]; then
echo "Error: Command did not complete within the maximum retry limit."
exit 1
fi
echo "Waiting for command to complete, current status is $command_status"
sleep 60
command_status=$(aws ssm get-command-invocation --command-id "$command_id" --instance-id "$instance_id" --output text --query 'Status')
done
echo "Command has completed with status: $command_status, appending output"
echo "Standard Output:"
aws ssm get-command-invocation --command-id "$command_id" --instance-id "$instance_id" --output text --query 'StandardOutputContent'
echo "Standard Error:"
aws ssm get-command-invocation --command-id "$command_id" --instance-id "$instance_id" --output text --query 'StandardErrorContent'

if [[ "$command_status" != "Success" ]]; then
echo "Error: Command [$command] was not successful, see logs above"
exit 1
fi
}

get_instance_id() {
# Retrieve the instance ID
instance_id=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=bootstrap-instance-${STAGE}-${REGION}" "Name=instance-state-name,Values=running" \
--query "Reservations[0].Instances[0].InstanceId" \
--output text)

if [[ -z "$instance_id" || "$instance_id" == "None" ]]; then
echo "Error: Running bootstrap EC2 instance not found"
exit 1
fi
echo "$instance_id"
}

instance_id=$(get_instance_id)
init_command="cd /opensearch-migrations && ./initBootstrap.sh"
verify_command="cdk --version && docker --version && java --version && python3 --version"
if [ "$WORKFLOW" = "ALL" ]; then
execute_command_and_wait_for_result "$init_command" "$instance_id"
execute_command_and_wait_for_result "$verify_command" "$instance_id"
elif [ "$WORKFLOW" = "INIT_BOOTSTRAP" ]; then
execute_command_and_wait_for_result "$init_command" "$instance_id"
elif [ "$WORKFLOW" = "VERIFY_INIT_BOOTSTRAP" ]; then
execute_command_and_wait_for_result "$verify_command" "$instance_id"
lewijacn marked this conversation as resolved.
Show resolved Hide resolved
else
echo "Error: Unknown workflow: ${WORKFLOW} specified"
fi
94 changes: 94 additions & 0 deletions vars/solutionsCFNTest.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
def call(Map config = [:]) {

pipeline {
agent { label config.workerAgent ?: 'Jenkins-Default-Agent-X64-C5xlarge-Single-Host' }

parameters {
string(name: 'GIT_REPO_URL', defaultValue: 'https://github.com/lewijacn/opensearch-migrations.git', description: 'Git repository url')
string(name: 'GIT_BRANCH', defaultValue: 'sol-pipeline', description: 'Git branch to use for repository')
string(name: 'STAGE', defaultValue: "sol-integ", description: 'Stage name for deployment environment')
}

options {
// Acquire lock on a given deployment stage
lock(label: params.STAGE, quantity: 1, variable: 'stage')
timeout(time: 1, unit: 'HOURS')
buildDiscarder(logRotator(daysToKeepStr: '30'))
}

stages {
stage('Checkout') {
steps {
script {
git branch: "${params.GIT_BRANCH}", url: "${params.GIT_REPO_URL}"
}
}
}

stage('Deployment') {
steps {
timeout(time: 15, unit: 'MINUTES') {
dir('deployment/migration-assistant-solution') {
script {
env.STACK_NAME_SUFFIX = "${stage}-us-east-1"
sh "sudo npm install"
withCredentials([string(credentialsId: 'migrations-test-account-id', variable: 'MIGRATIONS_TEST_ACCOUNT_ID')]) {
withAWS(role: 'JenkinsDeploymentRole', roleAccount: "${MIGRATIONS_TEST_ACCOUNT_ID}", region: "us-east-1", duration: 3600, roleSessionName: 'jenkins-session') {
sh "sudo --preserve-env cdk deploy 'Migration-Assistant-Infra-Create-VPC' --parameters Stage=${stage} --require-approval never --concurrency 3"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use npm deploy to reduce extra parameters like --require-approval and CDK doesn't need to be installed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only saves me not having to provide the --require-approval flag I believe and CDK CLI will already be on the box. My preference is to keep the same, but open if others want to change it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd really prefer we didn't have to run npm install -g cdk as part of the env setup, by using npm run it ensures everything is correctly version locked. 🧂

}
}
}
}
}
}
}

stage('Init Bootstrap') {
steps {
timeout(time: 30, unit: 'MINUTES') {
dir('test') {
script {
withCredentials([string(credentialsId: 'migrations-test-account-id', variable: 'MIGRATIONS_TEST_ACCOUNT_ID')]) {
withAWS(role: 'JenkinsDeploymentRole', roleAccount: "${MIGRATIONS_TEST_ACCOUNT_ID}", region: "us-east-1", duration: 3600, roleSessionName: 'jenkins-session') {
sh "sudo --preserve-env ./awsRunInitBootstrap.sh --stage ${stage} --workflow INIT_BOOTSTRAP"
}
}
}
}
}
}
}

stage('Verify Bootstrap Instance') {
steps {
timeout(time: 5, unit: 'MINUTES') {
dir('test') {
script {
withCredentials([string(credentialsId: 'migrations-test-account-id', variable: 'MIGRATIONS_TEST_ACCOUNT_ID')]) {
withAWS(role: 'JenkinsDeploymentRole', roleAccount: "${MIGRATIONS_TEST_ACCOUNT_ID}", region: "us-east-1", duration: 3600, roleSessionName: 'jenkins-session') {
sh "sudo --preserve-env ./awsRunInitBootstrap.sh --stage ${stage} --workflow VERIFY_INIT_BOOTSTRAP"
}
}
}
}
}
}
}
}
post {
always {
timeout(time: 30, unit: 'MINUTES') {
dir('deployment/migration-assistant-solution') {
script {
withCredentials([string(credentialsId: 'migrations-test-account-id', variable: 'MIGRATIONS_TEST_ACCOUNT_ID')]) {
withAWS(role: 'JenkinsDeploymentRole', roleAccount: "${MIGRATIONS_TEST_ACCOUNT_ID}", region: "us-east-1", duration: 3600, roleSessionName: 'jenkins-session') {
sh "sudo --preserve-env cdk destroy 'Migration-Assistant-Infra-Create-VPC' --force"
}
}
}
}
}
}
}
}
}