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

Reload configuration as code via curl instead of cli #145

Merged
merged 3 commits into from
Jun 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ OpenSearch Continuous Integration is an open source CI system for OpenSearch and

`npm run cdk deploy OpenSearch-CI-Config-Dev -- -c useSsl=false -c runWithOidc=false`

1. Locate the secret manager arns in the ci-config-stack outputs for `CASC_RELOAD_TOKEN` and update the secret value ([see docs](https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/put-secret-value.html)) with the password you want to use to reload jenkins configuration. _Do not enclose it in quotes_
```
$aws secretsmanager put-secret-value \
--secret-id MyCASCreloadTokenSecretARN \
--secret-string CascReloadToken
```
1. [Optional](#ssl-configuration) Configure the elements of the config stack for SSL configuration
1. [Optional](#setup-openid-connect-oidc-via-federate) Configure the elements setting up oidc via federate
1. Deploy the ci-stack, takes ~10 minutes to deploy (parameter values depend on step 2 and step 3)
Expand Down
10 changes: 10 additions & 0 deletions lib/ci-config-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export class CIConfigStack extends Stack {

static readonly OIDC_CONFIGURATION_VALUE_SECRET_EXPORT_VALUE: string = 'OIDCConfigValueSecret';

static readonly CASC_RELOAD_TOKEN_SECRET_EXPORT_VALUE: string = 'casc';

constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);

Expand All @@ -46,6 +48,9 @@ export class CIConfigStack extends Stack {
const OIDCConfigValuesSecret = new Secret(this, 'OIDCConfigValues', {
description: 'OIDC params in JSON format',
});
const CascReloadTokenValuesSecret = new Secret(this, 'CascReloadTokenValue', {
description: 'Reload token (password) required for configuration as code plugin',
});

new CfnOutput(this, 'certificateArnSecret', {
value: arnSecret.secretArn,
Expand Down Expand Up @@ -76,5 +81,10 @@ export class CIConfigStack extends Stack {
value: OIDCConfigValuesSecret.secretArn,
exportName: CIConfigStack.OIDC_CONFIGURATION_VALUE_SECRET_EXPORT_VALUE,
});

new CfnOutput(this, 'cascSecretValue', {
value: CascReloadTokenValuesSecret.secretArn,
exportName: CIConfigStack.CASC_RELOAD_TOKEN_SECRET_EXPORT_VALUE,
});
}
}
2 changes: 2 additions & 0 deletions lib/ci-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export class CIStack extends Stack {
const importedRedirectUrlSecretBucketValue = Fn.importValue(`${CIConfigStack.REDIRECT_URL_SECRET_EXPORT_VALUE}`);
const importedOidcConfigValuesSecretBucketValue = Fn.importValue(`${CIConfigStack.OIDC_CONFIGURATION_VALUE_SECRET_EXPORT_VALUE}`);
const certificateArn = Secret.fromSecretCompleteArn(this, 'certificateArn', importedArnSecretBucketValue.toString());
const importedReloadPasswordSecretsArn = Fn.importValue(`${CIConfigStack.CASC_RELOAD_TOKEN_SECRET_EXPORT_VALUE}`);
const listenerCertificate = ListenerCertificate.fromArn(certificateArn.secretValue.toString());
const agentNode = new AgentNodes(this);
const agentNodes: AgentNodeProps[] = [agentNode.AL2_X64, agentNode.AL2_X64_DOCKER_1, agentNode.AL2_ARM64, agentNode.AL2_ARM64_DOCKER_1,
Expand All @@ -109,6 +110,7 @@ export class CIStack extends Stack {
efsSG: securityGroups.efsSG,
dataRetention: props.dataRetention ?? false,
envVarsFilePath: props.envVarsFilePath ?? '',
reloadPasswordSecretsArn: importedReloadPasswordSecretsArn.toString(),
sslCertContentsArn: importedContentsSecretBucketValue.toString(),
sslCertChainArn: importedContentsChainBucketValue.toString(),
sslCertPrivateKeyContentsArn: importedCertSecretBucketValue.toString(),
Expand Down
21 changes: 12 additions & 9 deletions lib/compute/jenkins-main-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export interface JenkinsMainNodeProps extends HttpConfigProps, OidcFederateProps
readonly vpc: Vpc;
readonly sg: SecurityGroup;
readonly envVarsFilePath: string;
readonly reloadPasswordSecretsArn: string;
readonly failOnCloudInitError?: boolean;
}

Expand Down Expand Up @@ -144,6 +145,7 @@ export class JenkinsMainNode {
props,
props,
jenkinsyaml,
props.reloadPasswordSecretsArn,
this.EFS_ID,
)),
blockDevices: [{
Expand Down Expand Up @@ -222,7 +224,8 @@ export class JenkinsMainNode {
}

public static configElements(stackName: string, stackRegion: string, httpConfigProps: HttpConfigProps,
oidcFederateProps: OidcFederateProps, dataRetentionProps : DataRetentionProps, jenkinsyaml: string, efsId?: string): InitElement[] {
oidcFederateProps: OidcFederateProps, dataRetentionProps : DataRetentionProps, jenkinsyaml: string,
reloadPasswordSecretsArn: string, efsId?: string): InitElement[] {
return [
InitPackage.yum('wget'),
InitPackage.yum('openssl'),
Expand Down Expand Up @@ -365,15 +368,15 @@ export class JenkinsMainNode {
: 'echo Data rentention is disabled, not mounting efs'),

InitFile.fromFileInline('/docker-compose.yml', join(__dirname, '../../resources/docker-compose.yml')),
InitCommand.shellCommand('systemctl start docker && docker-compose up -d'),

InitCommand.shellCommand('systemctl start docker &&'
+ ` var=\`aws --region ${stackRegion} secretsmanager get-secret-value --secret-id ${reloadPasswordSecretsArn} --query SecretString --output text\` &&`
+ ' yq -i \'.services.jenkins.environment[1] = "CASC_RELOAD_TOKEN=\'$var\'"\' docker-compose.yml &&'
+ ' docker-compose up -d'),

// Commands are fired one after the other but it does not wait for the command to complete.
// Therefore, sleep 90 seconds to wait for jenkins to start
InitCommand.shellCommand('sleep 90'),

// Download jenkins-cli from the local machine
InitCommand.shellCommand('until $(curl --output /dev/null --silent --head --fail http://localhost:8080); do sleep 5; done &&'
+ ' wget -O "jenkins-cli.jar" http://localhost:8080/jnlpJars/jenkins-cli.jar'),
InitCommand.shellCommand('sleep 60'),

InitFile.fromFileInline('/initial_jenkins.yaml', jenkinsyaml),

Expand All @@ -390,8 +393,8 @@ export class JenkinsMainNode {

// Reload configuration via Jenkins.yaml
InitCommand.shellCommand('cp /initial_jenkins.yaml /var/lib/jenkins/jenkins.yaml &&'
+ ' java -jar /jenkins-cli.jar -s http://localhost:8080 reload-jcasc-configuration'),

+ ` var=\`aws --region ${stackRegion} secretsmanager get-secret-value --secret-id ${reloadPasswordSecretsArn} --query SecretString --output text\` &&`
+ ' curl -f -X POST "http://localhost:8080/reload-configuration-as-code/?casc-reload-token=$var"'),
];
}

Expand Down
3 changes: 2 additions & 1 deletion resources/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: '3.8'
services:
jenkins:
image: opensearchstaging/jenkins:2.332.3-lts-jdk8
restart: on-failure
restart: on-failure
privileged: true
tty: true
user: root
Expand All @@ -12,6 +12,7 @@ services:
container_name: jenkins
environment:
- JENKINS_JAVA_OPTS="-Xmx8g"
- CASC_RELOAD_TOKEN=reloadPasswordHere
volumes:
- /var/lib/jenkins:/var/jenkins_home
deploy:
Expand Down
5 changes: 3 additions & 2 deletions test/compute/jenkins-main-node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ describe('JenkinsMainNode Config Elements', () => {
runWithOidc: true,
}, {
dataRetention: true,
}, 'test/data/jenkins.yaml');
}, 'test/data/jenkins.yaml',
'ARN:ABC');

// THEN
test('Config elements expected counts', async () => {
expect(configElements.filter((e) => e.elementType === 'COMMAND')).toHaveLength(19);
expect(configElements.filter((e) => e.elementType === 'COMMAND')).toHaveLength(18);
expect(configElements.filter((e) => e.elementType === 'PACKAGE')).toHaveLength(10);
expect(configElements.filter((e) => e.elementType === 'FILE')).toHaveLength(4);
});
Expand Down