From d13773fa0d7a9b778a4c38bfaeeb0f1f745bc92e Mon Sep 17 00:00:00 2001 From: Rishabh Singh Date: Wed, 25 Oct 2023 11:07:16 -0700 Subject: [PATCH] add respository-s3 plugin install and support to pass custom iam role for instance Signed-off-by: Rishabh Singh --- lib/infra/infra-stack.ts | 49 +++++++++++++++++++----------------- lib/os-cluster-entrypoint.ts | 3 +++ test/os-cluster.test.ts | 33 ++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/lib/infra/infra-stack.ts b/lib/infra/infra-stack.ts index b33e112d710..0976e2f56b1 100644 --- a/lib/infra/infra-stack.ts +++ b/lib/infra/infra-stack.ts @@ -29,7 +29,9 @@ import { } from 'aws-cdk-lib/aws-ec2'; import { NetworkListener, NetworkLoadBalancer, Protocol } from 'aws-cdk-lib/aws-elasticloadbalancingv2'; import { InstanceTarget } from 'aws-cdk-lib/aws-elasticloadbalancingv2-targets'; -import { ManagedPolicy, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'; +import { + ManagedPolicy, Role, IRole, ServicePrincipal, +} from 'aws-cdk-lib/aws-iam'; import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs'; import { readFileSync } from 'fs'; import { dump, load } from 'js-yaml'; @@ -38,7 +40,7 @@ import { CloudwatchAgent } from '../cloudwatch/cloudwatch-agent'; import { nodeConfig } from '../opensearch-config/node-config'; import { RemoteStoreResources } from './remote-store-resources'; -export interface infraProps extends StackProps{ +export interface infraProps extends StackProps { readonly vpc: IVpc, readonly securityGroup: ISecurityGroup, readonly opensearchVersion: string, @@ -63,7 +65,8 @@ export interface infraProps extends StackProps{ readonly use50PercentHeap: boolean, readonly isInternal: boolean, readonly enableRemoteStore: boolean, - readonly storageVolumeType: EbsDeviceVolumeType + readonly storageVolumeType: EbsDeviceVolumeType, + readonly customRoleArn: string } export class InfraStack extends Stack { @@ -86,12 +89,16 @@ export class InfraStack extends Stack { removalPolicy: RemovalPolicy.DESTROY, }); - this.instanceRole = new Role(this, 'instanceRole', { - managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ReadOnlyAccess'), - ManagedPolicy.fromAwsManagedPolicyName('CloudWatchAgentServerPolicy'), - ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore')], - assumedBy: new ServicePrincipal('ec2.amazonaws.com'), - }); + if (props.customRoleArn === 'undefined') { + this.instanceRole = new Role(this, 'instanceRole', { + managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName('AmazonEC2ReadOnlyAccess'), + ManagedPolicy.fromAwsManagedPolicyName('CloudWatchAgentServerPolicy'), + ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore')], + assumedBy: new ServicePrincipal('ec2.amazonaws.com'), + }); + } else { + this.instanceRole = Role.fromRoleArn(this, 'custom-role-arn', `${props.customRoleArn}`); + } if (props.enableRemoteStore) { // Remote Store needs an S3 bucket to be registered as snapshot repo @@ -475,6 +482,10 @@ export class InfraStack extends Stack { cwd: '/home/ec2-user', ignoreErrors: false, })); + cfnInitConfig.push(InitCommand.shellCommand('set -ex;cd opensearch;sudo -u ec2-user bin/opensearch-plugin install repository-s3 --batch', { + cwd: '/home/ec2-user', + ignoreErrors: false, + })); } else { cfnInitConfig.push(InitCommand.shellCommand('set -ex;cd opensearch;sudo -u ec2-user bin/opensearch-plugin install ' + `https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/${props.opensearchVersion}/latest/linux/${props.cpuArch}` @@ -482,23 +493,15 @@ export class InfraStack extends Stack { cwd: '/home/ec2-user', ignoreErrors: false, })); + cfnInitConfig.push(InitCommand.shellCommand('set -ex;cd opensearch;sudo -u ec2-user bin/opensearch-plugin install ' + + `https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/${props.opensearchVersion}/latest/linux/${props.cpuArch}` + + `/tar/builds/opensearch/core-plugins/repository-s3-${props.opensearchVersion}.zip --batch`, { + cwd: '/home/ec2-user', + ignoreErrors: false, + })); } if (props.enableRemoteStore) { - if (props.distributionUrl.includes('artifacts.opensearch.org') && !props.minDistribution) { - cfnInitConfig.push(InitCommand.shellCommand('set -ex;cd opensearch;sudo -u ec2-user bin/opensearch-plugin install repository-s3 --batch', { - cwd: '/home/ec2-user', - ignoreErrors: false, - })); - } else { - cfnInitConfig.push(InitCommand.shellCommand('set -ex;cd opensearch;sudo -u ec2-user bin/opensearch-plugin install ' - + `https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/${props.opensearchVersion}/latest/linux/${props.cpuArch}` - + `/tar/builds/opensearch/core-plugins/repository-s3-${props.opensearchVersion}.zip --batch`, { - cwd: '/home/ec2-user', - ignoreErrors: false, - })); - } - // eslint-disable-next-line max-len cfnInitConfig.push(InitCommand.shellCommand(`set -ex;cd opensearch; echo "node.attr.remote_store.segment.repository: ${scope.stackName}-repo" >> config/opensearch.yml`, { cwd: '/home/ec2-user', diff --git a/lib/os-cluster-entrypoint.ts b/lib/os-cluster-entrypoint.ts index dc622cd37f3..752696b9bfa 100644 --- a/lib/os-cluster-entrypoint.ts +++ b/lib/os-cluster-entrypoint.ts @@ -199,6 +199,8 @@ export class OsClusterEntrypoint { const remoteStore = `${scope.node.tryGetContext('enableRemoteStore')}`; const enableRemoteStore = remoteStore === 'true'; + const customRoleArn = `${scope.node.tryGetContext('customRoleArn')}`; + const network = new NetworkStack(scope, 'opensearch-network-stack', { cidrBlock: cidrRange, maxAzs: 3, @@ -249,6 +251,7 @@ export class OsClusterEntrypoint { isInternal, enableRemoteStore, storageVolumeType: volumeType, + customRoleArn, ...props, }); diff --git a/test/os-cluster.test.ts b/test/os-cluster.test.ts index d1313bed2f1..bf07428a824 100644 --- a/test/os-cluster.test.ts +++ b/test/os-cluster.test.ts @@ -447,3 +447,36 @@ test('Throw error on unsupported ebs volume type', () => { expect(error.message).toEqual('Invalid volume type provided, please provide any one of the following: standard, gp2, gp3'); } }); + +test('Test multi-node cluster with custom IAM Role', () => { + const app = new App({ + context: { + securityDisabled: true, + minDistribution: false, + distributionUrl: 'www.example.com', + cpuArch: 'x64', + singleNodeCluster: false, + dashboardsUrl: 'www.example.com', + distVersion: '1.0.0', + serverAccessType: 'ipv4', + restrictServerAccessTo: 'all', + managerNodeCount: 0, + dataNodeCount: 3, + dataNodeStorage: 200, + customRoleArn: 'arn:aws:iam::12345678:role/customRoleName', + }, + }); + + // WHEN + const testStack = new OsClusterEntrypoint(app, { + env: { account: 'test-account', region: 'us-east-1' }, + }); + expect(testStack.stacks).toHaveLength(2); + + const infraStack = testStack.stacks.filter((s) => s.stackName === 'opensearch-infra-stack')[0]; + const infraTemplate = Template.fromStack(infraStack); + infraTemplate.resourceCountIs('AWS::IAM::Role', 0); + infraTemplate.hasResourceProperties('AWS::IAM::InstanceProfile', { + Roles: ['customRoleName'], + }); +});