first commit

This commit is contained in:
Arwid Thornström
2022-01-19 07:28:09 +01:00
commit f55052d5b3
40 changed files with 6193 additions and 0 deletions
@@ -0,0 +1,221 @@
import { GluegunMenuToolbox } from '@lenne.tech/gluegun-menu'
const chalk = require('chalk');
const { AutoComplete, Input, Confirm } = require('enquirer');
import { Octokit } from "@octokit/core";
import { GluegunPrint } from 'gluegun';
const os = require("os");
const STACK_DEFAULTS = {
STACK_ENVIRONMENT_NAME_TAG: 'test',
CPU_SIZE: 512,
MEMORY_SIZE: '1GB',
HOSTED_ZONE_WITHOUT_TLD: 'photowall-test',
PRIMARY_CERTIFICATE_ARN:
'arn:aws:acm:eu-west-1:954747537408:certificate/12e33b74-da14-430d-a7ed-f62fa7113112',
STATIC_CDN_CERTIFICATE_ARN:
'arn:aws:acm:us-east-1:954747537408:certificate/223550cf-e404-4ff1-85bb-703b936c9347',
DB_SECURITY_GROUP_ID: 'sg-001b3667edf19e1ce',
STATIC_CDN_HOSTNAME: `''`,
MAX_CONTAINERS: 1,
MIN_CONTAINERS: 1,
AWS_KEY_ENVIRONMENT: 'staging'
}
type Stack = {
name: string
status: string
drift_status: string
branch: string
updated: string
}
const getDownloadFileFromRepoCommand = (token: string, org: string, repo: string, path: string) => {
const file = path.split('/').pop();
return `curl -o /tmp/${file} -H 'Authorization: token ${token} ' -H 'Accept: application/vnd.github.v3.raw' -O -L https://api.github.com/repos/${org}/${repo}/contents/${path}`;
}
const getLifeCyclePolicyCommand = (stackName: string, policyFile: string) => {
return `aws ecr put-lifecycle-policy --repository-name ${stackName} --lifecycle-policy-text "${policyFile}"`;
}
const getUpdateStackCommand = (stackName: string, branch: string, templateFile: string) => {
const cmd = [
`aws cloudformation update-stack --stack-name ${stackName}`,
`--template-body ${templateFile}`,
`--capabilities CAPABILITY_NAMED_IAM`,
`--tags Key=EnvironmentName,Value=test`,
`--parameters`,
`ParameterKey=EnvironmentName,UsePreviousValue=true`,
`ParameterKey=Image,UsePreviousValue=true`,
`ParameterKey=HostedZoneNameWithOutTLD,UsePreviousValue=true`,
`ParameterKey=DomainNameWithoutTld,UsePreviousValue=true`,
`ParameterKey=PrimaryCertificateArn,UsePreviousValue=true`,
`ParameterKey=GitHubRepo,UsePreviousValue=true`,
`ParameterKey=GitHubUser,UsePreviousValue=true`,
`ParameterKey=GitHubBranch,ParameterValue=${branch}`,
`ParameterKey=GitHubToken,UsePreviousValue=true`,
`ParameterKey=ComposerAuth,UsePreviousValue=true`,
`ParameterKey=CpuSize,ParameterValue=${STACK_DEFAULTS.CPU_SIZE}`,
`ParameterKey=MemorySize,ParameterValue=${STACK_DEFAULTS.MEMORY_SIZE}`,
`ParameterKey=MinContainers,ParameterValue=${STACK_DEFAULTS.MIN_CONTAINERS}`,
`ParameterKey=MaxContainers,ParameterValue=${STACK_DEFAULTS.MAX_CONTAINERS}`,
`ParameterKey=StaticCdnHostName,ParameterValue=${STACK_DEFAULTS.STATIC_CDN_HOSTNAME}`,
`ParameterKey=StaticCdnCertificateArn,ParameterValue=${STACK_DEFAULTS.STATIC_CDN_CERTIFICATE_ARN}`,
`ParameterKey=AwsAccessKeyParamNameEnvironment,ParameterValue=${STACK_DEFAULTS.AWS_KEY_ENVIRONMENT}`,
`ParameterKey=DatabaseSecurityGroup,ParameterValue=${STACK_DEFAULTS.DB_SECURITY_GROUP_ID}`
];
return cmd.join(' ');
}
const getBranchName = async (print: GluegunPrint, token: string) => {
const input = new Input({
type: 'input',
name: 'branch',
message: 'What github branch should be deployed?'
});
const responseBranch = await input.run();
// First ask what branch should be deployed
const octokit = new Octokit({ auth: token });
try {
const response = await octokit.request("GET /repos/{owner}/{repo}/branches/{branch}", {
owner: "photowall",
repo: "photowall",
branch: responseBranch
});
if (response.status === 200) {
return responseBranch;
}
} catch (e) {
print.error('Not a valid branch on photowall repo');
return null;
}
};
const getConfirmation = async (branchName: string, stackName: string) => {
const confirm = new Confirm({
name: 'confirm',
message: `The branch ${chalk.green(branchName)} will deploy to ${chalk.yellow(stackName)}`
});
try {
return confirm.run();
} catch (e) {
console.error(e);
return false;
}
}
/**
* Subsection1 menu
*/
module.exports = {
name: 'update',
alias: ['u'],
description: 'Update stack with different branch (u)',
hidden: true,
run: async (toolbox: GluegunMenuToolbox) => {
const { system, strings, print, filesystem } = toolbox;
// Load settings
const config = await filesystem.readAsync(`${os.homedir()}/.pwcli_settings`, "json");
if (!config) {
print.error(`
No config found, please run [ ${chalk.cyan('pwcli s')} ] or setup from the menu.
`);
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu()
} else {
return;
}
}
let branchName = null;
while (!branchName) {
branchName = await getBranchName(print, config.gh_token);
}
const stacks = JSON.parse(
strings.trim(await system.run(`aws cloudformation list-stacks`))
)
const teststacks: Stack[] = await Promise.all(
stacks.StackSummaries.map(async item => {
if (
item.StackName.indexOf('photowall-test-') > -1 &&
[
'CREATE_COMPLETE',
'UPDATE_COMPLETE',
'UPDATE_IN_PROGRESS',
'UPDATE_FAILED',
'CREATE_FAILED',
'CREATE_IN_PROGRESS'
].includes(item.StackStatus)
) {
const pipeline = JSON.parse(
strings.trim(
await system.run(
`aws codepipeline get-pipeline --name ${item.StackName}Pipeline`
)
)
)
const branch = pipeline.pipeline.stages.filter(stage => {
return stage.name === 'Source'
})[0].actions[0].configuration.Branch
const lastUpdated = pipeline.metadata.updated
return {
name: item.StackName,
status: item.StackStatus,
drift_status: item.DriftInformation.StackDriftStatus,
branch: branch,
updated: lastUpdated
}
}
return Promise.resolve(null)
})
)
const curratedStacks: Stack[] = teststacks.filter(Boolean)
const options = curratedStacks.map(item => {
return item.name;
});
const prompt = new AutoComplete({
name: 'testserver',
message: 'Choose a server',
limit: options.length - 1,
initial: options.length - 1,
choices: options
});
try {
// Download files to /tmp
await system.run(getDownloadFileFromRepoCommand(config.gh_token, 'Photowall', 'photowall', 'cloudformation/ecr-lifecycle-policy.json'));
await system.run(getDownloadFileFromRepoCommand(config.gh_token, 'Photowall', 'photowall', 'cloudformation/ecs-service.yaml'));
const stackName = await prompt.run();
const lifeCycleCommand = getLifeCyclePolicyCommand(stackName, `file://ecr-lifecycle-policy.json`);
const updateStackCommand = getUpdateStackCommand(stackName, branchName, `file://ecs-service.yaml`);
const shouldRun = await getConfirmation(branchName, stackName);
if (shouldRun) {
let output = await system.run(lifeCycleCommand, {cwd: '/tmp/', trim: true});
print.fancy(output);
output = await system.run(updateStackCommand, {cwd: '/tmp/', trim: true});
print.fancy(output);
}
} catch (e) {
console.log(`e`, e)
}
if (toolbox.fromMenu()) {
await toolbox.menu.showMenu('deployment testservers')
}
}
}