From 53e37bddd247d18bea7f41f9a0e9f78095a5832f Mon Sep 17 00:00:00 2001 From: Divya Madala Date: Thu, 5 Dec 2024 12:36:55 -0800 Subject: [PATCH 1/3] Configure agent nodes based on jenkins instane type Signed-off-by: Divya Madala --- lib/ci-stack.ts | 32 ++++++------------- lib/compute/agent-nodes.ts | 11 +++++++ test/ci-stack.test.ts | 43 ++++++++++++++++++++++++-- test/compute/agent-node-config.test.ts | 4 +-- 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/lib/ci-stack.ts b/lib/ci-stack.ts index 1772414..4705145 100644 --- a/lib/ci-stack.ts +++ b/lib/ci-stack.ts @@ -52,6 +52,8 @@ export interface CIStackProps extends StackProps { readonly enableViews?: boolean; /** Use Production Agents */ readonly useProdAgents?: boolean; + /** Specify jenkins instance type */ + readonly jenkinsType?: string; } function getServerAccess(serverAccessType: string, restrictServerAccessTo: string): IPeer { @@ -113,6 +115,11 @@ export class CIStack extends Stack { useProdAgents = 'false'; } + let jenkinsType = `${props?.jenkinsType ?? this.node.tryGetContext('jenkinsType')}`; + if (useProdAgents.toString() === 'true' && jenkinsType.toString() === 'undefined') { + jenkinsType = 'default'; + } + const serverAccessType = this.node.tryGetContext('serverAccessType'); const restrictServerAccessTo = this.node.tryGetContext('restrictServerAccessTo'); const serverAcess = props?.restrictServerAccessTo ?? getServerAccess(serverAccessType, restrictServerAccessTo); @@ -146,34 +153,15 @@ export class CIStack extends Stack { const listenerCertificate = ListenerCertificate.fromArn(certificateArn.secretValue.toString()); const agentNode = new AgentNodes(this); - if (useProdAgents.toString() === 'true') { - // eslint-disable-next-line no-console - console.warn('Please note that if you have decided to use the provided production jenkins agents then ' + // eslint-disable-next-line no-console + console.warn('Please note that if you have decided to use the provided production jenkins agents then ' + 'please make sure that you are deploying the stack in US-EAST-1 region as the AMIs used are only publicly ' + 'available in US-EAST-1 region. ' + 'If you want to deploy the stack in another region then please make sure you copy the public AMIs used ' + 'from us-east-1 region to your region of choice and update the ami-id in agent-nodes.ts file accordingly. ' + 'If you do not copy the AMI in required region and update the code then the jenkins agents will not spin up.'); - this.agentNodes = [ - agentNode.AL2023_X64, - agentNode.AL2_X64_DOCKER_HOST, - agentNode.AL2023_X64_DOCKER_HOST, - agentNode.AL2023_ARM64, - agentNode.AL2_ARM64_DOCKER_HOST, - agentNode.AL2023_ARM64_DOCKER_HOST, - agentNode.AL2023_X64_BENCHMARK_TEST, - agentNode.UBUNTU2004_X64_GRADLE_CHECK, - agentNode.UBUNTU2004_X64_DOCKER_BUILDER, - agentNode.MACOS13_X64_MULTI_HOST, - agentNode.MACOS13_ARM64_MULTI_HOST, - agentNode.WINDOWS2019_X64_DOCKER_HOST, - agentNode.WINDOWS2019_X64_DOCKER_BUILDER, - agentNode.WINDOWS2019_X64_GRADLE_CHECK, - ]; - } else { - this.agentNodes = [agentNode.AL2_X64_DEFAULT_AGENT, agentNode.AL2_ARM64_DEFAULT_AGENT]; - } + this.agentNodes = agentNode.getRequiredAgentNodes(jenkinsType.toString()); const mainJenkinsNode = new JenkinsMainNode(this, { vpc, diff --git a/lib/compute/agent-nodes.ts b/lib/compute/agent-nodes.ts index 2e037ce..a2d3057 100644 --- a/lib/compute/agent-nodes.ts +++ b/lib/compute/agent-nodes.ts @@ -281,4 +281,15 @@ export class AgentNodes { remoteFs: '/home/ec2-user', }; } + + public getRequiredAgentNodes(type: string): any[] { + return Object.keys(this) + .filter((key) => { + if (type === 'BTR') { + return !key.toLowerCase().includes('default'); + } + return key.toLowerCase().includes(type.toLowerCase()); + }) + .map((key) => (this as any)[key]); + } } diff --git a/test/ci-stack.test.ts b/test/ci-stack.test.ts index 171f81a..41431d1 100644 --- a/test/ci-stack.test.ts +++ b/test/ci-stack.test.ts @@ -10,11 +10,17 @@ import { App } from 'aws-cdk-lib'; import { Template } from 'aws-cdk-lib/assertions'; import { Peer } from 'aws-cdk-lib/aws-ec2'; import { CIStack } from '../lib/ci-stack'; +import { AgentNodes } from '../lib/compute/agent-nodes'; test('CI Stack Basic Resources', () => { const app = new App({ context: { - useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', additionalCommands: './test/data/hello-world.py', + useSsl: 'true', + runWithOidc: 'true', + serverAccessType: 'ipv4', + restrictServerAccessTo: '10.10.10.10/32', + additionalCommands: './test/data/hello-world.py', + jenkinsType: 'BTR', }, }); @@ -45,7 +51,7 @@ test('CI Stack Basic Resources', () => { test('External security group is open', () => { const app = new App({ context: { - useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: 'all', + useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: 'all', jenkinsType: 'BTR', }, }); @@ -364,6 +370,39 @@ test('LoadBalancer Access Logging', () => { }); }); +describe('AgentNodes', () => { + let agentNodes: AgentNodes; + const app = new App({ + context: { + useSsl: 'false', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', + }, + }); + + // WHEN + const stack = new CIStack(app, 'MyTestStack', { + env: { account: 'test-account', region: 'us-east-1' }, + }); + + beforeEach(() => { + agentNodes = new AgentNodes(stack); + }); + + it('should exclude "default" keys when type is "BTR"', () => { + const result = agentNodes.getRequiredAgentNodes('BTR'); + expect(result.length).toBe(14); + }); + + it('should return keys containing "benchmark" when type is "benchmark"', () => { + const result = agentNodes.getRequiredAgentNodes('benchmark'); + expect(result).toHaveLength(1); + }); + + it('should return keys containing "gradle" when type is "gradle"', () => { + const result = agentNodes.getRequiredAgentNodes('default'); + expect(result).toHaveLength(2); + }); +}); + test('WAF rules', () => { const app = new App({ context: { diff --git a/test/compute/agent-node-config.test.ts b/test/compute/agent-node-config.test.ts index 803ac7f..57e3bb5 100644 --- a/test/compute/agent-node-config.test.ts +++ b/test/compute/agent-node-config.test.ts @@ -15,7 +15,7 @@ import { CIStack } from '../../lib/ci-stack'; test('Agents Resource is present', () => { const app = new App({ context: { - useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', + useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', jenkinsType: 'BTR', }, }); const stack = new CIStack(app, 'TestStack', { @@ -83,7 +83,7 @@ test('Agents Resource is present', () => { test('Agents Node policy with assume role Resource is present', () => { const app = new App({ context: { - useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', + useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', jenkinsType: 'BTR', }, }); const stack = new CIStack(app, 'TestStack', { From 8d0f60aa6bdceec252f4069afa8c00ec7286396d Mon Sep 17 00:00:00 2001 From: Divya Madala Date: Mon, 6 Jan 2025 13:11:34 -0800 Subject: [PATCH 2/3] Add requested changes Signed-off-by: Divya Madala --- .eslintrc.js | 2 ++ bin/ci-stack.ts | 2 +- lib/ci-stack.ts | 21 ++++++++++---- lib/compute/agent-node-config.ts | 26 +++++++++--------- lib/compute/agent-nodes.ts | 38 ++++++++++++++------------ lib/compute/jenkins-main-node.ts | 6 ++-- test/ci-stack.test.ts | 13 ++++++--- test/compute/agent-node-config.test.ts | 4 +-- 8 files changed, 66 insertions(+), 46 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4f1dbdb..9df678e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,5 +30,7 @@ module.exports = { 'no-unused-vars': 'off', 'no-new': 'off', 'max-len': ['error', { 'code': 160, 'ignoreComments': true }], + 'no-shadow': 'off', + '@typescript-eslint/no-shadow': ['error'], }, }; diff --git a/bin/ci-stack.ts b/bin/ci-stack.ts index f6a67b7..fe6ee5f 100644 --- a/bin/ci-stack.ts +++ b/bin/ci-stack.ts @@ -13,7 +13,7 @@ import { CIStack } from '../lib/ci-stack'; const app = new App(); -const defaultEnv: string = 'Dev'; +const defaultEnv = 'Dev'; const ciConfigStack = new CIConfigStack(app, `OpenSearch-CI-Config-${defaultEnv}`, {}); diff --git a/lib/ci-stack.ts b/lib/ci-stack.ts index 4705145..a9b2af3 100644 --- a/lib/ci-stack.ts +++ b/lib/ci-stack.ts @@ -27,6 +27,13 @@ import { JenkinsExternalLoadBalancer } from './network/ci-external-load-balancer import { JenkinsSecurityGroups } from './security/ci-security-groups'; import { JenkinsWAF } from './security/waf'; +enum DeploymentType { + BTR='BTR', + GRADLE='gradle', + BENCHMARK='benchmark', + DEFAULT='default', +} + export interface CIStackProps extends StackProps { /** Should the Jenkins use https */ readonly useSsl?: boolean; @@ -53,7 +60,8 @@ export interface CIStackProps extends StackProps { /** Use Production Agents */ readonly useProdAgents?: boolean; /** Specify jenkins instance type */ - readonly jenkinsType?: string; + readonly jenkinsInstanceType?: string; + } function getServerAccess(serverAccessType: string, restrictServerAccessTo: string): IPeer { @@ -93,6 +101,7 @@ export class CIStack extends Stack { }, }, }); + const macAgentParameter = `${props?.macAgent ?? this.node.tryGetContext('macAgent')}`; const useSslParameter = `${props?.useSsl ?? this.node.tryGetContext('useSsl')}`; @@ -115,9 +124,11 @@ export class CIStack extends Stack { useProdAgents = 'false'; } - let jenkinsType = `${props?.jenkinsType ?? this.node.tryGetContext('jenkinsType')}`; - if (useProdAgents.toString() === 'true' && jenkinsType.toString() === 'undefined') { - jenkinsType = 'default'; + let jenkinsInstanceType = `${props?.jenkinsInstanceType ?? this.node.tryGetContext('jenkinsInstanceType')}`; + if (jenkinsInstanceType.toString() === 'undefined') { + jenkinsInstanceType = useProdAgents.toString() === 'true' ? 'BTR' : 'default'; + } else if (!Object.values(DeploymentType).includes(jenkinsInstanceType as DeploymentType)) { + throw new Error(`Invalid jenkinsInstanceType value: ${jenkinsInstanceType}`); } const serverAccessType = this.node.tryGetContext('serverAccessType'); @@ -161,7 +172,7 @@ export class CIStack extends Stack { + 'from us-east-1 region to your region of choice and update the ami-id in agent-nodes.ts file accordingly. ' + 'If you do not copy the AMI in required region and update the code then the jenkins agents will not spin up.'); - this.agentNodes = agentNode.getRequiredAgentNodes(jenkinsType.toString()); + this.agentNodes = agentNode.getRequiredAgentNodes(jenkinsInstanceType.toString()); const mainJenkinsNode = new JenkinsMainNode(this, { vpc, diff --git a/lib/compute/agent-node-config.ts b/lib/compute/agent-node-config.ts index cddddc4..7acfe69 100644 --- a/lib/compute/agent-node-config.ts +++ b/lib/compute/agent-node-config.ts @@ -23,7 +23,7 @@ export interface AgentNodeProps { amiId: string; instanceType: string; customDeviceMapping: string; - workerLabelString: string; + workerLabelString: string[]; remoteUser: string; maxTotalUses: number; minimumNumberOfSpareInstances: number; @@ -178,7 +178,7 @@ export class AgentNodeConfig { connectionStrategy: 'PRIVATE_IP', customDeviceMapping: config.customDeviceMapping, deleteRootOnTermination: true, - description: `jenkinsAgentNode-${config.workerLabelString}`, + description: `jenkinsAgentNode-${config.workerLabelString[0]}`, ebsEncryptRootVolume: 'ENCRYPTED', ebsOptimized: false, metadataTokensRequired: true, @@ -187,7 +187,7 @@ export class AgentNodeConfig { iamInstanceProfile: this.AgentNodeInstanceProfileArn, idleTerminationMinutes: '60', initScript: config.initScript, - labelString: config.workerLabelString, + labelString: config.workerLabelString[0], launchTimeoutStr: '300', maxTotalUses: config.maxTotalUses, minimumNumberOfInstances: 0, @@ -203,11 +203,11 @@ export class AgentNodeConfig { t2Unlimited: false, tags: [{ name: 'Name', - value: `${stack.stackName}/AgentNode/${config.workerLabelString}`, + value: `${stack.stackName}/AgentNode/${config.workerLabelString[0]}`, }, { name: 'type', - value: `jenkinsAgentNode-${config.workerLabelString}`, + value: `jenkinsAgentNode-${config.workerLabelString[0]}`, }, ], tenancy: 'Default', @@ -270,7 +270,7 @@ export class AgentNodeConfig { connectionStrategy: 'PRIVATE_IP', customDeviceMapping: config.customDeviceMapping, deleteRootOnTermination: true, - description: `jenkinsAgentNode-${config.workerLabelString}`, + description: `jenkinsAgentNode-${config.workerLabelString[0]}`, ebsEncryptRootVolume: 'ENCRYPTED', ebsOptimized: true, metadataTokensRequired: true, @@ -278,7 +278,7 @@ export class AgentNodeConfig { hostKeyVerificationStrategy: 'OFF', iamInstanceProfile: this.AgentNodeInstanceProfileArn, idleTerminationMinutes: '720', - labelString: config.workerLabelString, + labelString: config.workerLabelString[0], launchTimeoutStr: '1000', initScript: config.initScript, maxTotalUses: config.maxTotalUses, @@ -296,11 +296,11 @@ export class AgentNodeConfig { tags: [ { name: 'Name', - value: `${stack.stackName}/AgentNode/${config.workerLabelString}`, + value: `${stack.stackName}/AgentNode/${config.workerLabelString[0]}`, }, { name: 'type', - value: `jenkinsAgentNode-${config.workerLabelString}`, + value: `jenkinsAgentNode-${config.workerLabelString[0]}`, }, ], tenancy: 'Host', @@ -335,7 +335,7 @@ export class AgentNodeConfig { connectionStrategy: 'PRIVATE_IP', customDeviceMapping: config.customDeviceMapping, deleteRootOnTermination: true, - description: `jenkinsAgentNode-${config.workerLabelString}`, + description: `jenkinsAgentNode-${config.workerLabelString[0]}`, ebsEncryptRootVolume: 'ENCRYPTED', ebsOptimized: true, metadataTokensRequired: true, @@ -344,7 +344,7 @@ export class AgentNodeConfig { iamInstanceProfile: this.AgentNodeInstanceProfileArn, idleTerminationMinutes: '120', initScript: config.initScript, - labelString: config.workerLabelString, + labelString: config.workerLabelString[0], launchTimeoutStr: '1200', maxTotalUses: config.maxTotalUses, minimumNumberOfInstances: 0, @@ -360,11 +360,11 @@ export class AgentNodeConfig { t2Unlimited: false, tags: [{ name: 'Name', - value: `${stack.stackName}/AgentNode/${config.workerLabelString}`, + value: `${stack.stackName}/AgentNode/${config.workerLabelString[0]}`, }, { name: 'type', - value: `jenkinsAgentNode-${config.workerLabelString}`, + value: `jenkinsAgentNode-${config.workerLabelString[0]}`, }, ], tenancy: 'Default', diff --git a/lib/compute/agent-nodes.ts b/lib/compute/agent-nodes.ts index a2d3057..83af021 100644 --- a/lib/compute/agent-nodes.ts +++ b/lib/compute/agent-nodes.ts @@ -48,7 +48,7 @@ export class AgentNodes { this.AL2023_X64 = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-AL2023-X64-C54xlarge-Single-Host', + workerLabelString: ['Jenkins-Agent-AL2023-X64-C54xlarge-Single-Host', 'BTR'], instanceType: 'C54xlarge', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -62,7 +62,7 @@ export class AgentNodes { this.AL2_X64_DOCKER_HOST = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-AL2-X64-C54xlarge-Docker-Host', + workerLabelString: ['Jenkins-Agent-AL2-X64-C54xlarge-Docker-Host', 'BTR'], instanceType: 'C54xlarge', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -76,7 +76,7 @@ export class AgentNodes { this.AL2023_X64_DOCKER_HOST = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:600:true:::encrypted', - workerLabelString: 'Jenkins-Agent-AL2023-X64-M54xlarge-Docker-Host', + workerLabelString: ['Jenkins-Agent-AL2023-X64-M54xlarge-Docker-Host', 'BTR'], instanceType: 'M54xlarge', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -90,7 +90,7 @@ export class AgentNodes { this.AL2023_ARM64 = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-AL2023-Arm64-C6g4xlarge-Single-Host', + workerLabelString: ['Jenkins-Agent-AL2023-Arm64-C6g4xlarge-Single-Host', 'BTR'], instanceType: 'C6g4xlarge', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -104,7 +104,7 @@ export class AgentNodes { this.AL2_ARM64_DOCKER_HOST = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-AL2-Arm64-C6g4xlarge-Docker-Host', + workerLabelString: ['Jenkins-Agent-AL2-Arm64-C6g4xlarge-Docker-Host', 'BTR'], instanceType: 'C6g4xlarge', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -118,7 +118,7 @@ export class AgentNodes { this.AL2023_ARM64_DOCKER_HOST = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:600:true:::encrypted', - workerLabelString: 'Jenkins-Agent-AL2023-Arm64-M6g4xlarge-Docker-Host', + workerLabelString: ['Jenkins-Agent-AL2023-Arm64-M6g4xlarge-Docker-Host', 'BTR'], instanceType: 'M6g4xlarge', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -132,7 +132,7 @@ export class AgentNodes { this.AL2023_X64_BENCHMARK_TEST = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-AL2023-X64-M52xlarge-Benchmark-Test', + workerLabelString: ['Jenkins-Agent-AL2023-X64-M52xlarge-Benchmark-Test', 'benchmark'], instanceType: 'M52xlarge', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -146,7 +146,7 @@ export class AgentNodes { this.UBUNTU2004_X64_GRADLE_CHECK = { agentType: 'unix', customDeviceMapping: '/dev/sda1=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-Ubuntu2004-X64-M58xlarge-Single-Host', + workerLabelString: ['Jenkins-Agent-Ubuntu2004-X64-M58xlarge-Single-Host', 'gradle'], instanceType: 'M58xlarge', remoteUser: 'ubuntu', maxTotalUses: 1, @@ -161,7 +161,7 @@ export class AgentNodes { this.UBUNTU2004_X64_DOCKER_BUILDER = { agentType: 'unix', customDeviceMapping: '/dev/sda1=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-Ubuntu2004-X64-M52xlarge-Docker-Builder', + workerLabelString: ['Jenkins-Agent-Ubuntu2004-X64-M52xlarge-Docker-Builder', 'BTR'], instanceType: 'M52xlarge', remoteUser: 'ubuntu', maxTotalUses: 10, @@ -176,7 +176,7 @@ export class AgentNodes { this.MACOS13_X64_MULTI_HOST = { agentType: 'mac', customDeviceMapping: '/dev/sda1=:300:true:gp3::encrypted', - workerLabelString: 'Jenkins-Agent-MacOS13-X64-Mac1Metal-Multi-Host', + workerLabelString: ['Jenkins-Agent-MacOS13-X64-Mac1Metal-Multi-Host', 'BTR'], instanceType: 'Mac1Metal', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -189,7 +189,7 @@ export class AgentNodes { this.MACOS13_ARM64_MULTI_HOST = { agentType: 'mac', customDeviceMapping: '/dev/sda1=:300:true:gp3::encrypted', - workerLabelString: 'Jenkins-Agent-MacOS13-ARM64-Mac2M2proMetal-Multi-Host', + workerLabelString: ['Jenkins-Agent-MacOS13-ARM64-Mac2M2proMetal-Multi-Host', 'BTR'], instanceType: 'Mac2M2proMetal', remoteUser: 'ec2-user', maxTotalUses: 10, @@ -202,7 +202,7 @@ export class AgentNodes { this.WINDOWS2019_X64_DOCKER_HOST = { agentType: 'windows', customDeviceMapping: '/dev/sda1=:600:true:::encrypted', - workerLabelString: 'Jenkins-Agent-Windows2019-X64-M54xlarge-Docker-Host', + workerLabelString: ['Jenkins-Agent-Windows2019-X64-M54xlarge-Docker-Host', 'BTR'], instanceType: 'M54xlarge', remoteUser: 'Administrator', maxTotalUses: 10, @@ -219,7 +219,7 @@ export class AgentNodes { this.WINDOWS2019_X64_DOCKER_BUILDER = { agentType: 'windows', customDeviceMapping: '/dev/sda1=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-Windows2019-X64-M54xlarge-Docker-Builder', + workerLabelString: ['Jenkins-Agent-Windows2019-X64-M54xlarge-Docker-Builder', 'BTR'], instanceType: 'M54xlarge', remoteUser: 'Administrator', maxTotalUses: 10, @@ -236,7 +236,7 @@ export class AgentNodes { this.WINDOWS2019_X64_GRADLE_CHECK = { agentType: 'windows', customDeviceMapping: '/dev/sda1=:300:true:::encrypted', - workerLabelString: 'Jenkins-Agent-Windows2019-X64-C524xlarge-Single-Host', + workerLabelString: ['Jenkins-Agent-Windows2019-X64-C524xlarge-Single-Host', 'gradle'], instanceType: 'C524xlarge', remoteUser: 'Administrator', maxTotalUses: 1, @@ -249,7 +249,7 @@ export class AgentNodes { this.AL2_X64_DEFAULT_AGENT = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:300:true:::encrypted', - workerLabelString: 'Jenkins-Default-Agent-X64-C5xlarge-Single-Host', + workerLabelString: ['Jenkins-Default-Agent-X64-C5xlarge-Single-Host', 'default'], instanceType: 'C54xlarge', remoteUser: 'ec2-user', maxTotalUses: -1, @@ -266,7 +266,7 @@ export class AgentNodes { this.AL2_ARM64_DEFAULT_AGENT = { agentType: 'unix', customDeviceMapping: '/dev/xvda=:300:true:::encrypted', - workerLabelString: 'Jenkins-Default-Agent-ARM64-C5xlarge-Single-Host', + workerLabelString: ['Jenkins-Default-Agent-ARM64-C5xlarge-Single-Host', 'default'], instanceType: 'C6g4xlarge', remoteUser: 'ec2-user', maxTotalUses: -1, @@ -285,10 +285,12 @@ export class AgentNodes { public getRequiredAgentNodes(type: string): any[] { return Object.keys(this) .filter((key) => { + const agent = (this as any)[key]; + // If condition will be omitted once we maintain individual jenkins for BTR , Benchmark, Gradle if (type === 'BTR') { - return !key.toLowerCase().includes('default'); + return !agent?.workerLabelString?.some((label: string) => label.toLowerCase() === 'default'); } - return key.toLowerCase().includes(type.toLowerCase()); + return agent?.workerLabelString?.some((label: string) => label.includes(type)); }) .map((key) => (this as any)[key]); } diff --git a/lib/compute/jenkins-main-node.ts b/lib/compute/jenkins-main-node.ts index 505b967..b83a9f6 100644 --- a/lib/compute/jenkins-main-node.ts +++ b/lib/compute/jenkins-main-node.ts @@ -72,11 +72,11 @@ export class JenkinsMainNode { static readonly NEW_JENKINS_YAML_PATH: string = join(__dirname, '../../resources/jenkins.yaml'); - static readonly CERTIFICATE_FILE_PATH: String = '/etc/ssl/certs/test-jenkins.opensearch.org.crt'; + static readonly CERTIFICATE_FILE_PATH: string = '/etc/ssl/certs/test-jenkins.opensearch.org.crt'; - static readonly CERTIFICATE_CHAIN_FILE_PATH: String = '/etc/ssl/certs/test-jenkins.opensearch.org.pem'; + static readonly CERTIFICATE_CHAIN_FILE_PATH: string = '/etc/ssl/certs/test-jenkins.opensearch.org.pem'; - static readonly PRIVATE_KEY_PATH: String = '/etc/ssl/private/test-jenkins.opensearch.org.key'; + static readonly PRIVATE_KEY_PATH: string = '/etc/ssl/private/test-jenkins.opensearch.org.key'; private readonly EFS_ID: string; diff --git a/test/ci-stack.test.ts b/test/ci-stack.test.ts index 41431d1..b30ba85 100644 --- a/test/ci-stack.test.ts +++ b/test/ci-stack.test.ts @@ -20,7 +20,7 @@ test('CI Stack Basic Resources', () => { serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', additionalCommands: './test/data/hello-world.py', - jenkinsType: 'BTR', + jenkinsInstanceType: 'BTR', }, }); @@ -51,7 +51,7 @@ test('CI Stack Basic Resources', () => { test('External security group is open', () => { const app = new App({ context: { - useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: 'all', jenkinsType: 'BTR', + useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: 'all', jenkinsInstanceType: 'BTR', }, }); @@ -95,7 +95,7 @@ test('External security group is open', () => { test('External security group is restricted', () => { const app = new App({ context: { - useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.0.0.0/24', + useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.0.0.0/24', useProdAgents: 'true', }, }); @@ -374,7 +374,7 @@ describe('AgentNodes', () => { let agentNodes: AgentNodes; const app = new App({ context: { - useSsl: 'false', runWithOidc: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', + useSsl: 'false', run: 'false', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', }, }); @@ -398,6 +398,11 @@ describe('AgentNodes', () => { }); it('should return keys containing "gradle" when type is "gradle"', () => { + const result = agentNodes.getRequiredAgentNodes('gradle'); + expect(result).toHaveLength(2); + }); + + it('should return keys containing "default" when type is "default"', () => { const result = agentNodes.getRequiredAgentNodes('default'); expect(result).toHaveLength(2); }); diff --git a/test/compute/agent-node-config.test.ts b/test/compute/agent-node-config.test.ts index 57e3bb5..79d8b38 100644 --- a/test/compute/agent-node-config.test.ts +++ b/test/compute/agent-node-config.test.ts @@ -15,7 +15,7 @@ import { CIStack } from '../../lib/ci-stack'; test('Agents Resource is present', () => { const app = new App({ context: { - useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', jenkinsType: 'BTR', + useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', jenkinsInstanceType: 'BTR', }, }); const stack = new CIStack(app, 'TestStack', { @@ -83,7 +83,7 @@ test('Agents Resource is present', () => { test('Agents Node policy with assume role Resource is present', () => { const app = new App({ context: { - useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', jenkinsType: 'BTR', + useSsl: 'true', runWithOidc: 'true', serverAccessType: 'ipv4', restrictServerAccessTo: '10.10.10.10/32', jenkinsInstanceType: 'BTR', }, }); const stack = new CIStack(app, 'TestStack', { From 6c3d912852c072a1936d600c2963eb5efb1d472e Mon Sep 17 00:00:00 2001 From: Divya Madala Date: Wed, 8 Jan 2025 17:23:12 -0800 Subject: [PATCH 3/3] Add variable type changes Signed-off-by: Divya Madala --- lib/ci-stack.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/ci-stack.ts b/lib/ci-stack.ts index b2fda87..3388d8e 100644 --- a/lib/ci-stack.ts +++ b/lib/ci-stack.ts @@ -29,7 +29,7 @@ import { JenkinsWAF } from './security/waf'; import { FineGrainedAccessSpecs } from './compute/auth-config'; enum DeploymentType { - BTR='BTR', + BTR='BTR', // Build Test Release GRADLE='gradle', BENCHMARK='benchmark', DEFAULT='default', @@ -61,7 +61,7 @@ export interface CIStackProps extends StackProps { /** Use Production Agents */ readonly useProdAgents?: boolean; /** Specify jenkins instance type */ - readonly jenkinsInstanceType?: string; + readonly jenkinsInstanceType?: string | DeploymentType; /** Fine grain access control specifications */ readonly fineGrainedAccessSpecs?: FineGrainedAccessSpecs[]; } @@ -126,9 +126,9 @@ export class CIStack extends Stack { useProdAgents = 'false'; } - let jenkinsInstanceType = `${props?.jenkinsInstanceType ?? this.node.tryGetContext('jenkinsInstanceType')}`; + let jenkinsInstanceType: string | DeploymentType = `${props?.jenkinsInstanceType ?? this.node.tryGetContext('jenkinsInstanceType')}`; if (jenkinsInstanceType.toString() === 'undefined') { - jenkinsInstanceType = useProdAgents.toString() === 'true' ? 'BTR' : 'default'; + jenkinsInstanceType = useProdAgents.toString() === 'true' ? DeploymentType.BTR : DeploymentType.DEFAULT; } else if (!Object.values(DeploymentType).includes(jenkinsInstanceType as DeploymentType)) { throw new Error(`Invalid jenkinsInstanceType value: ${jenkinsInstanceType}`); } @@ -166,13 +166,15 @@ export class CIStack extends Stack { const listenerCertificate = ListenerCertificate.fromArn(certificateArn.secretValue.toString()); const agentNode = new AgentNodes(this); - // eslint-disable-next-line no-console - console.warn('Please note that if you have decided to use the provided production jenkins agents then ' + if (useProdAgents.toString() === 'true') { + // eslint-disable-next-line no-console + console.warn('Please note that if you have decided to use the provided production jenkins agents then ' + 'please make sure that you are deploying the stack in US-EAST-1 region as the AMIs used are only publicly ' + 'available in US-EAST-1 region. ' + 'If you want to deploy the stack in another region then please make sure you copy the public AMIs used ' + 'from us-east-1 region to your region of choice and update the ami-id in agent-nodes.ts file accordingly. ' + 'If you do not copy the AMI in required region and update the code then the jenkins agents will not spin up.'); + } this.agentNodes = agentNode.getRequiredAgentNodes(jenkinsInstanceType.toString());