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

Deploy Jenkins Instance #26

Merged
merged 3 commits into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
],
rules: {
hasTrailingComma: 'off',
indent: ['error', 2],
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/no-extraneous-dependencies': 'off',
Expand Down
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
<img src="https://opensearch.org/assets/brand/SVG/Logo/opensearch_logo_default.svg" height="64px"/>

- [OpenSearch Continous Integration](#opensearch-continous-integration)
- [Getting Started](#getting-started)
- [Deployment](#deployment)
- [Troubleshooting](#troubleshooting)
- [Main Node](#main-node)
- [Useful commands](#useful-commands)
- [Architecture Overview](#architecture-overview)
- [Contributing](#contributing)
- [Getting Help](#getting-help)
- [Code of Conduct](#code-of-conduct)
Expand All @@ -17,7 +23,24 @@ OpenSearch Continous Integration is an open source CI system for OpenSearch and
- Requires [NPM](https://docs.npmjs.com/cli/v7/configuring-npm/install) to be installed
- Install project dependencies using `npm install` from this project directory
- Configure [aws credentials](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_prerequisites)
- Deploy with `npm run cdk deploy`
- Deploy stacks with `npm run cdk deploy`

## Deployment
1. Setup your local machine to credentials to deploy to the AWS Account
2. Deploy the ci config stack, `npm run cdk deploy CI-Config-Dev`, takes ~1 minute to deploy
3. [Optional] Configure the elements of the config stack for SSL configuration
4. Deploy the ci stack, without ssl, `npm run cdk deploy CI-Dev -- --parameters useSsl=false`, takes ~10 minutes to deploy
5. Log onto the AWS Console of the account, navigate to [cloud watch](https://console.aws.amazon.com/cloudwatch/home), open log groups, looking for `JenkinsMainNode/var/log/jenkins/jenkins.log`
6. Search the logs for `Jenkins initial setup is required. An admin user has been created and a password generated.` After that entry the password for the jenkins instance will be in the cloudwatch logs.
7. Go to the `CI-Dev.JenkinsExternalLoadBalancerDns` url returned by CDK output to access the jenkins host.

### Troubleshooting
#### Main Node
Useful links
- Log are found in [Cloud Watch Logs](https://console.aws.amazon.com/cloudwatch/home)
- Need to access the host, ssh via Session Manager in [EC2 Console](https://console.aws.amazon.com/ec2/v2/home)
- Instance instance isn't coming up, get the system log in [EC2 Console](https://console.aws.amazon.com/ec2/v2/home)


### Useful commands

Expand Down
6 changes: 4 additions & 2 deletions bin/ci-stack.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#!/usr/bin/env node

/**
* SPDX-License-Identifier: Apache-2.0
*
Expand All @@ -11,6 +9,10 @@
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { CIStack } from '../lib/ci-stack';
import { CIConfigStack } from '../lib/ci-config-stack';

const app = new cdk.App();

new CIConfigStack(app, 'CI-Config-Dev', {});
abhinavGupta16 marked this conversation as resolved.
Show resolved Hide resolved

new CIStack(app, 'CI-Dev', { });
52 changes: 52 additions & 0 deletions lib/ci-config-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

import {
CfnOutput, Construct, Stack, StackProps,
} from '@aws-cdk/core';

import { Secret } from '@aws-cdk/aws-secretsmanager';

export class CIConfigStack extends Stack {
static readonly CERTIFICATE_ARN_SECRET_EXPORT_VALUE: string = 'certificateArnSecret';

static readonly CERTIFICATE_CONTENTS_SECRET_EXPORT_VALUE: string = 'certContentsSecret';

static readonly PRIVATE_KEY_SECRET_EXPORT_VALUE: string = 'privateKeySecret';

static readonly REDIRECT_URL_SECRET_EXPORT_VALUE: string = 'redirectUrlSecret';

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

const arnSecret = new Secret(this, 'certificateArn', {});
const certContentsSecret = new Secret(this, 'certContents', {});
const privateKeySecret = new Secret(this, 'privateKey', {});
const redirectUrlSecret = new Secret(this, 'redirectUrl', {});

new CfnOutput(this, 'certificateArnSecret', {
value: arnSecret.secretArn,
exportName: CIConfigStack.CERTIFICATE_ARN_SECRET_EXPORT_VALUE,
});

new CfnOutput(this, 'certContentsSecret', {
value: certContentsSecret.secretArn,
exportName: CIConfigStack.CERTIFICATE_CONTENTS_SECRET_EXPORT_VALUE,
});

new CfnOutput(this, 'privateKeySecret', {
value: privateKeySecret.secretArn,
exportName: CIConfigStack.PRIVATE_KEY_SECRET_EXPORT_VALUE,
});

new CfnOutput(this, 'redirectUrlSecret', {
value: redirectUrlSecret.secretArn,
exportName: CIConfigStack.REDIRECT_URL_SECRET_EXPORT_VALUE,
});
}
}
49 changes: 43 additions & 6 deletions lib/ci-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,58 @@
* compatible open source license.
*/

import { Construct, Stack, StackProps } from '@aws-cdk/core';
import { Vpc } from '@aws-cdk/aws-ec2';
import { Secret } from '@aws-cdk/aws-secretsmanager';
import {
CfnParameter,
Construct, Fn, Stack, StackProps,
} from '@aws-cdk/core';
import { ListenerCertificate } from '@aws-cdk/aws-elasticloadbalancingv2';
import { CIConfigStack } from './ci-config-stack';
import { JenkinsMainNode } from './compute/jenkins-main-node';
import { JenkinsMonitoring } from './monitoring/ci-alarms';
import { JenkinsExternalLoadBalancer } from './network/ci-external-load-balancer';
import { JenkinsSecurityGroups } from './security/ci-security-groups';

export class CIStack extends Stack {
// eslint-disable-next-line no-useless-constructor
Copy link
Contributor

Choose a reason for hiding this comment

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

This constructor is no longer useless. We can get rid of this

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

// Network / VPC
const vpc = new Vpc(this, 'JenkinsVPC');

// Security Groups
const useSslParameter = new CfnParameter(this, 'useSsl', {
description: 'If the jenkins instance should be access via SSL',
allowedValues: ['true', 'false'],
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use y or n instead? It would be lesser syllables to type.

Copy link
Member Author

@peternied peternied Oct 14, 2021

Choose a reason for hiding this comment

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

It looks like npm run cdk deploy CI-Dev -- --parameters useSsl=false in practice which I think is more readable than using y/n

Copy link
Contributor

Choose a reason for hiding this comment

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

Would it not ask as a y/n question when deploying, something like -
Are you sure you want to delete: JenkinsStack (y/n)? y?

Copy link
Member

Choose a reason for hiding this comment

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

Nope we can skip that saying --require-approval-never
When deploying using CIs we do not want to have interactive terminals

Copy link
Member

@dblock dblock Oct 14, 2021

Choose a reason for hiding this comment

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

--approve :)

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a little bit of a quagmire at this point, I have limited options as we are using the CDK to do the deployment

npm run cdk deploy CI-Dev -- --parameters useSsl=false
 -- Only part I have control over         ^^^^^^^^^^^^

As far as adding flags to avoid interactive dialogs during deployment, we will do that, but the guide and primary use case is for developers to get started, I would much rather they see the CDK diff when they make changes.

I know this is an unfulfilling response, if there is an issue we would like to address feel free to ask or open one, but I think that is out of scope for this PR

});
const useSsl = useSslParameter.valueAsString === 'true';

// Compute
const securityGroups = new JenkinsSecurityGroups(this, vpc, useSsl);

// Load Balancers
const importedContentsSecretBucketValue = Fn.importValue(`${CIConfigStack.CERTIFICATE_CONTENTS_SECRET_EXPORT_VALUE}`);
const importedCertSecretBucketValue = Fn.importValue(`${CIConfigStack.PRIVATE_KEY_SECRET_EXPORT_VALUE}`);
const importedArnSecretBucketValue = Fn.importValue(`${CIConfigStack.CERTIFICATE_ARN_SECRET_EXPORT_VALUE}`);
const importedRedirectUrlSecretBucketValue = Fn.importValue(`${CIConfigStack.REDIRECT_URL_SECRET_EXPORT_VALUE}`);
const certificateArn = Secret.fromSecretCompleteArn(this, 'certificateArn', importedArnSecretBucketValue.toString());
const listenerCertificate = ListenerCertificate.fromArn(certificateArn.secretValue.toString());

// Monitoring
const mainJenkinsNode = new JenkinsMainNode(this, {
vpc,
sg: securityGroups.mainNodeSG,
sslCertContentsArn: importedContentsSecretBucketValue.toString(),
sslCertPrivateKeyContentsArn: importedCertSecretBucketValue.toString(),
redirectUrlArn: importedRedirectUrlSecretBucketValue.toString(),
useSsl,
});

const externalLoadBalancer = new JenkinsExternalLoadBalancer(this, {
vpc,
sg: securityGroups.externalAccessSG,
targetInstance: mainJenkinsNode.ec2Instance,
listenerCertificate,
useSsl,
});

const monitoring = new JenkinsMonitoring(this, externalLoadBalancer, mainJenkinsNode);
}
}
Loading