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

new-param-to-use-existing-file-on-s3 #95

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ the version but not deploy it anywhere.
*It will prevent the action from (re)creating a bucket during deployment as well.*
Omit this parameter to have the action create the bucket. The latter requires the API key used to have the applicable permissions.

`existing_file_name` *(since v22)*: Use this flag to indicate an existing file name on s3 and to avoid upload your deployment package to.
This can be set to `true`. Default is `false`.
The file to create the new version will be:
```.bash
s3://<BUCKET_NAME>/<APPLICATION_NAME>/<VERSION>.zip
```

`s3folder` *(since v24)*: Use this to set the name of the folder where the deployment package is. Default value is "application_name".
The file to create the new version will be:
```.bash
s3://<BUCKET_NAME>/<s3folder>/<VERSION>.zip
```


### AWS Permissions

It should be enough for your AWS user to have the policies **AWSElasticBeanstalkWebTier** and **AWSElasticBeanstalkManagedUpdatesCustomerRolePolicy** attached
Expand All @@ -111,6 +125,12 @@ defined. Pass the rest of the parameters in on the command line, like so:
beanstalk-deploy.js MyApplicationName MyApplication-Environment 12345 us-west-2 deploy.zip
```

If the file already exists in the S3 bucket:
```.bash
beanstalk-deploy <MyApplicationName> <MyApplication-Environment> <VERSION> <AWS_REGION> <FILE> <BUCKET_NAME> true
```
`<FILE>`: is going to be ignored.

Just like in the GitHub action you can skip the final file parameter and the program will attempt to deploy an existing
version instead.

Expand Down
168 changes: 107 additions & 61 deletions beanstalk-deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,74 +138,113 @@ function expect(status, result, extraErrorMessage) {
}

//Uploads zip file, creates new version and deploys it
function deployNewVersion(application, environmentName, versionLabel, versionDescription, file, bucket, waitUntilDeploymentIsFinished, waitForRecoverySeconds) {
function deployNewVersion(application, environmentName, versionLabel, versionDescription, file, bucket, waitUntilDeploymentIsFinished, waitForRecoverySeconds, existingFileName, s3folder) {
//Lots of characters that will mess up an S3 filename, so only allow alphanumeric, - and _ in the actual file name.
//The version label can still contain all that other stuff though.
let s3filename = versionLabel.replace(/[^a-zA-Z0-9-_]/g, '-');
let s3filename = versionLabel.replace(/[^a-zA-Z0-9-_.]/g, '-');

let s3Key = `/${s3folder || application}/${s3filename}.jar`;

let s3Key = `/${application}/${s3filename}.zip`;
let deployStart, fileBuffer;

readFile(file).then(result => {
fileBuffer = result;
if (existingFileName) {
createBeanstalkVersion(application, bucket, s3Key, versionLabel, versionDescription)
.then(result => {
expect(200, result);
console.log(`Created new application version ${versionLabel} in Beanstalk.`);
if (!environmentName) {
console.log(`No environment name given, so exiting now without deploying the new version ${versionLabel} anywhere.`);
process.exit(0);
}
deployStart = new Date();
console.log(`Starting deployment of version ${versionLabel} to environment ${environmentName}`);
return deployBeanstalkVersion(application, environmentName, versionLabel, waitForRecoverySeconds);
}).then(result => {
expect(200, result);

if (bucket === null) {
console.log(`No existing bucket name given, creating/requesting storage location`);
return createStorageLocation();
}
}).then(result => {
if (bucket === null) {
expect(200, result, 'Failed to create storage location');
bucket = result.data.CreateStorageLocationResponse.CreateStorageLocationResult.S3Bucket;
}
if (waitUntilDeploymentIsFinished) {
console.log('Deployment started, "wait_for_deployment" was true...\n');
return waitForDeployment(application, environmentName, versionLabel, deployStart, waitForRecoverySeconds);
} else {
console.log('Deployment started, parameter "wait_for_deployment" was false, so action is finished.');
console.log('**** IMPORTANT: Please verify manually that the deployment succeeds!');
process.exit(0);
}

console.log(`Uploading file to bucket ${bucket}`);
}).then(envAfterDeployment => {
if (envAfterDeployment.Health === 'Green') {
console.log('Environment update successful!');
process.exit(0);
} else {
console.warn(`Environment update finished, but environment health is: ${envAfterDeployment.Health}, HealthStatus: ${envAfterDeployment.HealthStatus}`);
process.exit(1);
}
}).catch(err => {
console.error(`Deployment failed: ${err}`);
process.exit(2);
});
} else {
readFile(file).then(result => {
fileBuffer = result;

if (bucket === null) {
console.log(`No existing bucket name given, creating/requesting storage location`);
return createStorageLocation();
}
}).then(result => {
if (bucket === null) {
expect(200, result, 'Failed to create storage location');
bucket = result.data.CreateStorageLocationResponse.CreateStorageLocationResult.S3Bucket;
}

return checkIfFileExistsInS3(bucket, s3Key);
}).then(result => {
if (result.statusCode === 200) {
throw new Error(`Version ${versionLabel} already exists in S3!`);
}
expect(404, result);
return uploadFileToS3(bucket, s3Key, fileBuffer);
}).then(result => {
expect(200, result);
console.log(`New build successfully uploaded to S3, bucket=${bucket}, key=${s3Key}`);
return createBeanstalkVersion(application, bucket, s3Key, versionLabel, versionDescription);
}).then(result => {
expect(200, result);
console.log(`Created new application version ${versionLabel} in Beanstalk.`);
if (!environmentName) {
console.log(`No environment name given, so exiting now without deploying the new version ${versionLabel} anywhere.`);
process.exit(0);
}
deployStart = new Date();
console.log(`Starting deployment of version ${versionLabel} to environment ${environmentName}`);
return deployBeanstalkVersion(application, environmentName, versionLabel, waitForRecoverySeconds);
}).then(result => {
expect(200, result);
console.log(`Uploading file to bucket ${bucket}`);

if (waitUntilDeploymentIsFinished) {
console.log('Deployment started, "wait_for_deployment" was true...\n');
return waitForDeployment(application, environmentName, versionLabel, deployStart, waitForRecoverySeconds);
} else {
console.log('Deployment started, parameter "wait_for_deployment" was false, so action is finished.');
console.log('**** IMPORTANT: Please verify manually that the deployment succeeds!');
process.exit(0);
}
return checkIfFileExistsInS3(bucket, s3Key);
}).then(result => {
if (result.statusCode === 200) {
throw new Error(`Version ${versionLabel} already exists in S3!`);
}
expect(404, result);
return uploadFileToS3(bucket, s3Key, fileBuffer);
}).then(result => {
expect(200, result);
console.log(`New build successfully uploaded to S3, bucket=${bucket}, key=${s3Key}`);
return createBeanstalkVersion(application, bucket, s3Key, versionLabel, versionDescription);
}).then(result => {
expect(200, result);
console.log(`Created new application version ${versionLabel} in Beanstalk.`);
if (!environmentName) {
console.log(`No environment name given, so exiting now without deploying the new version ${versionLabel} anywhere.`);
process.exit(0);
}
deployStart = new Date();
console.log(`Starting deployment of version ${versionLabel} to environment ${environmentName}`);
return deployBeanstalkVersion(application, environmentName, versionLabel, waitForRecoverySeconds);
}).then(result => {
expect(200, result);

if (waitUntilDeploymentIsFinished) {
console.log('Deployment started, "wait_for_deployment" was true...\n');
return waitForDeployment(application, environmentName, versionLabel, deployStart, waitForRecoverySeconds);
} else {
console.log('Deployment started, parameter "wait_for_deployment" was false, so action is finished.');
console.log('**** IMPORTANT: Please verify manually that the deployment succeeds!');
process.exit(0);
}

}).then(envAfterDeployment => {
if (envAfterDeployment.Health === 'Green') {
console.log('Environment update successful!');
process.exit(0);
} else {
console.warn(`Environment update finished, but environment health is: ${envAfterDeployment.Health}, HealthStatus: ${envAfterDeployment.HealthStatus}`);
process.exit(1);
}
}).catch(err => {
console.error(`Deployment failed: ${err}`);
process.exit(2);
});
}).then(envAfterDeployment => {
if (envAfterDeployment.Health === 'Green') {
console.log('Environment update successful!');
process.exit(0);
} else {
console.warn(`Environment update finished, but environment health is: ${envAfterDeployment.Health}, HealthStatus: ${envAfterDeployment.HealthStatus}`);
process.exit(1);
}
}).catch(err => {
console.error(`Deployment failed: ${err}`);
process.exit(2);
});
}
}

//Deploys existing version in EB
Expand Down Expand Up @@ -256,7 +295,9 @@ function main() {
existingBucketName = null,
useExistingVersionIfAvailable,
waitForRecoverySeconds = 30,
waitUntilDeploymentIsFinished = true; //Whether or not to wait for the deployment to complete...
waitUntilDeploymentIsFinished = true, //Whether or not to wait for the deployment to complete...
existingFileName,
s3folder;

if (IS_GITHUB_ACTION) { //Running in GitHub Actions
application = strip(process.env.INPUT_APPLICATION_NAME);
Expand All @@ -282,6 +323,8 @@ function main() {
waitForRecoverySeconds = parseInt(process.env.INPUT_WAIT_FOR_ENVIRONMENT_RECOVERY);
}
useExistingVersionIfAvailable = process.env.INPUT_USE_EXISTING_VERSION_IF_AVAILABLE == 'true' || process.env.INPUT_USE_EXISTING_VERSION_IF_AVAILABLE == 'True';
existingFileName = (process.env.INPUT_EXISTING_FILE_NAME || '').toLowerCase() == 'true';
s3folder = process.env.INPUT_S3FOLDER;

} else { //Running as command line script
if (process.argv.length < 6) {
Expand All @@ -293,7 +336,8 @@ function main() {
process.exit(1);
}

[application, environmentName, versionLabel, region, file] = process.argv.slice(2);
[application, environmentName, versionLabel, region, file, existingBucketName, existingFileName, s3folder] = process.argv.slice(2);
existingFileName = (existingFileName || '').toLowerCase() == 'true';
versionDescription = ''; //Not available for this.
useExistingVersionIfAvailable = false; //This option is not available in the console version

Expand Down Expand Up @@ -336,6 +380,8 @@ function main() {
console.log(' AWS Secret Key: ' + awsApiRequest.secretKey.length + ' characters long, starts with ' + awsApiRequest.secretKey.charAt(0));
console.log(' Wait for deployment: ' + waitUntilDeploymentIsFinished);
console.log(' Recovery wait time: ' + waitForRecoverySeconds);
console.log(' Existing file Name: ' + existingFileName);
console.log(' s3 folder: ' + s3folder);
console.log('');

getApplicationVersion(application, versionLabel).then(result => {
Expand Down Expand Up @@ -368,7 +414,7 @@ function main() {
}
} else {
if (file) {
deployNewVersion(application, environmentName, versionLabel, versionDescription, file, existingBucketName, waitUntilDeploymentIsFinished, waitForRecoverySeconds);
deployNewVersion(application, environmentName, versionLabel, versionDescription, file, existingBucketName, waitUntilDeploymentIsFinished, waitForRecoverySeconds, existingFileName, s3folder);
} else {
console.error(`Deployment failed: No deployment package given but version ${versionLabel} doesn't exist, so nothing to deploy!`);
process.exit(2);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "beanstalk-deploy",
"version": "20.0.0",
"version": "23.0.0",
"description": "GitHub Action + command line tool to deploy to AWS Elastic Beanstalk.",
"main": "beanstalk-deploy.js",
"scripts": {
Expand Down