Skip to content

Commit

Permalink
First spike
Browse files Browse the repository at this point in the history
  • Loading branch information
LevelbossMike committed Jul 15, 2017
1 parent a2a574b commit 2045ac2
Show file tree
Hide file tree
Showing 37 changed files with 980 additions and 1,732 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
/libpeerconnection.log
npm-debug.log*
testem.log
.env
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible Node.js debug attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "tests",
"program": "${workspaceRoot}/tests/runner.js",
"envFile": "${workspaceRoot}/.env"
}
]
}
175 changes: 161 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,173 @@
# ember-cli-deploy-fastboot-app-server-aws

This README outlines the details of collaborating on this Ember addon.
> An ember-cli-deploy plugin to deploy Ember FastBoot apps that are deployed via [fastboot-app-server](https://github.com/ember-fastboot/fastboot-app-server) to [AWS](https://aws.amazon.com) (S3)
## Installation
This plugin is not a standalone plugin. You will need to have a zipped fastboot-build available on the deployment context. This plugin works best in combination with [ember-cli-deploy-fastboot-app-server](https://github.com/LevelbossMike/ember-cli-deploy-fastboot-app-server).

* `git clone <repository-url>` this repository
* `cd ember-cli-deploy-fastboot-app-server-aws`
* `npm install`
## What is an ember-cli-deploy plugin?

## Running
A plugin is an addon that can be executed as a part of the ember-cli-deploy pipeline. A plugin will implement one or more of the ember-cli-deploy's pipeline hooks.

* `ember serve`
* Visit your app at [http://localhost:4200](http://localhost:4200).
For more information on what plugins are and how they work, please refer to the [Plugin Documentation][2].

## Quick Start
To get up and running quickly, do the following:

- Ensure [ember-cli-fastboot](https://github.com/ember-fastboot/ember-cli-fastboot) is installed.
- Ensure [ember-cli-deploy-build][4] is installed and configured.
- Ensure [ember-cli-deploy-revision-data][6] is installed and configured.
- Ensure [ember-cli-deploy-display-revisions](https://github.com/duizendnegen/ember-cli-deploy-display-revisions) is installed and configured.
- Ensure [ember-cli-deploy-fastboot-app-server](https://github.com/levelbossmike/ember-cli-deploy-fastboot-app-server) is installed and configured.

- Install this plugin

```bash
$ ember install ember-cli-deploy-fastboot-app-server-aws
```
- Run the pipeline

```bash
$ ember deploy production
```

## ember-cli-deploy Hooks Implemented

For detailed information on what plugin hooks are and how they work, please refer to the [Plugin Documentation][2].

- `configure`
- `upload`
- `fetchInitialRevisions`
- `fetchRevisions`
- `activate`

## Configuration Options

For detailed information on how configuration of plugins works, please refer to the [Plugin Documentation][2].

### accessKeyId

The AWS access key for the user that has the ability to upload to the `bucket`. If this is left undefined, the normal [AWS SDK credential resolution][7] will take place.

*Default:* `undefined`

### secretAccessKey

The AWS secret for the user that has the ability to upload to the `bucket`. This must be defined when `accessKeyId` is defined.

*Default:* `undefined`

### bucket (`required`)

The AWS bucket that the files will be uploaded to.

*Default:* `undefined`

### region (`required`)

The region your bucket is located in. (e.g. set this to `eu-west-1` if your bucket is located in the 'Ireland' region)

*Default:* `undefined`

### revisionKey

The unique revision number for the version of the app. By default this option will use either the `revision` passed in from the command line or the `revisionData.revisionKey` property from the deployment context.

*Default:* `context.commandOptions.revision || context.revisionData.revisionKey`

### archivePrefix

The prefix that will be used in combination with a revisionkey to build up the identifier for the revision you are deploying.

*Default:* `dist-`

### downloaderManifestContent

A function that gets added to the deploy context so that other plugins can update an app-manifest file that is used by [fastboot-app-server notifiers](https://github.com/ember-fastboot/fastboot-app-server#notifiers) and [-downloaders](https://github.com/ember-fastboot/fastboot-app-server#downloaders) to update the FastBoot-app served via `fastboot-app-server`.

*Default:* `context.downloaderManifestContent` (added by `ember-cli-deploy-fastboot-app-server`)

## TL;DR

### What does this plugin do exactly?
This plugin is meant to be used in combination with [ember-cli-deploy-fastboot-app-server](https://github.com/levelbossmike/ember-cli-deploy-fastboot-app-server). This plugin will upload the zipped fastboot-build to [S3](https://aws.amazon.com/de/s3/) and can be used to implement the [lightning-strategy](http://ember-cli-deploy.com/docs/v1.0.x/the-lightning-strategy/) that you are used to with `ember-cli-deploy` with FastBoot-applications.

This means you can list available revisions via `ember deploy:list` and switch around the revisions that are served to you users via the `ember deploy:activate`-command.

### How do I activate a revision?

A user can activate a revision by either:

- Passing a command line argument to the `deploy` command:

```bash
$ ember deploy --activate=true
```

- Running the `deploy:activate` command:

```bash
$ ember deploy:activate --revision <revision-key>
```

- Setting the `activateOnDeploy` flag in `deploy.js`

```javascript
ENV.pipeline = {
activateOnDeploy: true
}
```

### What does activation do?

When *ember-cli-deploy-fastboot-app-server* uploads a zipped FastBoot-build-file to S3, it uploads it under the key defined by a combination of the two config properties `archivePrefix` and `revisionKey`.

So, if the `archivePrefix` was configured to be `dist-` and there had been a few revisons deployed, then your bucket might look something like this:

```bash
$ aws s3 ls s3://<bucket>/
PRE assets/
2017-07-15 07:47:42 1207 fastboot-deploy-info.json
2017-07-15 07:25:51 1207 dist-a644ba43cdb987288d646c5a97b1c8a9.zip
2017-07-15 07:20:27 1207 dist-61cfff627b79058277e604686197bbbd.zip
2017-07-15 07:19:11 1207 dist-9dd26dbc8f3f9a8a342d067335315a63.zip
```

To activate a revision the plugin will update the contents of `fastboot-deploy-info.json` to point to the passed revision as the active revision. As soon as manifest-file has been updated an [fastboot-app-server-notifier](https://github.com/ember-fastboot/fastboot-app-server#notifiers) will notice the update and trigger an [fastboot-app-server-downloader](https://github.com/ember-fastboot/fastboot-app-server#downloaders) to update the version of your application served via a [fastboot-app-server](https://github.com/ember-fastboot/fastboot-app-server).

```bash
$ ember deploy:activate --revision a644ba43cdb987288d646c5a97b1c8a9
```

### When does activation occur?

Activation occurs during the `activate` hook of the pipeline. By default, activation is turned off and must be explicitly enabled by one of the 3 methods above.

## Prerequisites

The following properties are expected to be present on the deployment `context` object:

- `distDir` (provided by [ember-cli-deploy-build][4])
- `project.name()` (provided by [ember-cli-deploy][5])
- `revisionKey` (provided by [ember-cli-deploy-revision-data][6])
- `commandLineArgs.revisionKey` (provided by [ember-cli-deploy][5])
- `deployEnvironment` (provided by [ember-cli-deploy][5])

## Running Tests
You need to have a bucket on S3 setup for the test to complete. Tests expect
specific environment variables to be set so that tests are able to upload to
s3 automatically:

* `npm test` (Runs `ember try:each` to test your addon against multiple Ember versions)
* `ember test`
* `ember test --server`
* `AWS_ACCESS_KEY_ID` - to authenticate with AWS
* `AWS_SECRET_ACCESS_KEY` - to authenticate with AWS
* `TEST_BUCKET` - the name of the test bucket
* `TEST_REGION` - the region the test bucket is located in

## Building
To run tests:

* `ember build`
* `yarn test`

For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/).
[2]: http://ember-cli.github.io/ember-cli-deploy/plugins "Plugin Documentation"
[4]: https://github.com/ember-cli-deploy/ember-cli-deploy-build "ember-cli-deploy-build"
[5]: https://github.com/ember-cli/ember-cli-deploy "ember-cli-deploy"
[6]: https://github.com/ember-cli-deploy/ember-cli-deploy-revision-data "ember-cli-deploy-revision-data"
[7]: https://docs.aws.amazon.com/AWSJavaScriptSDK/guide/node-configuring.html#Setting_AWS_Credentials "Setting AWS Credentials"
Empty file removed addon/.gitkeep
Empty file.
Empty file removed app/.gitkeep
Empty file.
173 changes: 172 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,177 @@
/* eslint-env node */
'use strict';

const DeployPluginBase = require('ember-cli-deploy-plugin');

function _list(opts) {
let AWS = require('aws-sdk');
let RSVP = require('rsvp');

let accessKeyId = opts.accessKeyId;
let secretAccessKey = opts.secretAccessKey;
let archivePrefix = opts.archivePrefix;
let bucket = opts.bucket;
let region = opts.region;
let manifestKey = opts.manifestKey

let client = new AWS.S3({
accessKeyId,
secretAccessKey,
region
});

let listObjects = RSVP.denodeify(client.listObjects.bind(client));
let getObject = RSVP.denodeify(client.getObject.bind(client));

return RSVP.hash({
revisions: listObjects({ Bucket: bucket, Prefix: archivePrefix }),
current: getObject({ Bucket: bucket, Key: manifestKey })
})
.then((result) => {
let revisionsData = result.revisions;
let current = result.current;
let data = revisionsData.Contents;
let body = current.Body;

let manifestData = JSON.parse(body);

let revisions = data.sort(function(a, b) {
return new Date(b.LastModified) - new Date(a.LastModified);
})
.map((d) => {
let match = d.Key.match(/dist-([^.]*)\.zip/);
if (!match) {
return; // ignore files that are no zipped app builds
}

let revision = match[1];
return {
revision,
timestamp: d.LastModified,
active: d.Key === manifestData.key
}
}).filter((d) => d); // filter out empty values

return { revisions };
});
}

module.exports = {
name: 'ember-cli-deploy-fastboot-app-server-aws'
name: 'ember-cli-deploy-fastboot-app-server-aws',

createDeployPlugin: function(options) {
let DeployPlugin = DeployPluginBase.extend({
name: options.name,

defaultConfig: {
archivePrefix: 'dist-',

revisionKey: function(context) {
let revisionKey = context.revisionData && context.revisionData.revisionKey;
return context.commandOptions.revision || revisionKey;
},

downloaderManifestContent: function(context) {
// setup via ember-cli-deploy-fastboot-app-server plugin
return context.downloaderManifestContent;
},

manifestKey: 'fastboot-deploy-info.json'
},

requiredConfig: ['bucket', 'region'],

activate: function(/* context */) {
let revisionKey = this.readConfig('revisionKey');
let bucket = this.readConfig('bucket');
let archivePrefix = this.readConfig('archivePrefix');
// update manifest-file to point to passed revision
let downloaderManifestContent = this.readConfig('downloaderManifestContent');

let manifest = downloaderManifestContent(bucket, `${archivePrefix}${revisionKey}.zip`);
let AWS = require('aws-sdk');
let RSVP = require('rsvp');
let accessKeyId = this.readConfig('accessKeyId');
let secretAccessKey = this.readConfig('secretAccessKey');
let region = this.readConfig('region');
let manifestKey = this.readConfig('manifestKey');

let client = new AWS.S3({
accessKeyId,
secretAccessKey,
region
});
let putObject = RSVP.denodeify(client.putObject.bind(client));

return putObject({
Bucket: bucket,
Key: manifestKey,
Body: manifest,
ACL: 'public-read'
});
},

upload: function(context) {
let AWS = require('aws-sdk');
let RSVP = require('rsvp');
let fs = require('fs');

let accessKeyId = this.readConfig('accessKeyId');
let secretAccessKey = this.readConfig('secretAccessKey');
let bucket = this.readConfig('bucket');
let region = this.readConfig('region');

let client = new AWS.S3({
accessKeyId,
secretAccessKey,
region
});

let putObject = RSVP.denodeify(client.putObject.bind(client));

let data = fs.readFileSync(context.fastbootArchivePath);

return putObject({
Bucket: bucket,
Body: data,
Key: context.fastbootArchiveName
});
},

fetchRevisions: function() {
let accessKeyId = this.readConfig('accessKeyId');
let secretAccessKey = this.readConfig('secretAccessKey');
let archivePrefix = this.readConfig('archivePrefix');
let bucket = this.readConfig('bucket');
let region = this.readConfig('region');
let manifestKey = this.readConfig('manifestKey');

let opts = {
accessKeyId, secretAccessKey, archivePrefix, bucket, region, manifestKey
};

return _list(opts);
},

fetchInitialRevisions: function() {
let accessKeyId = this.readConfig('accessKeyId');
let secretAccessKey = this.readConfig('secretAccessKey');
let archivePrefix = this.readConfig('archivePrefix');
let bucket = this.readConfig('bucket');
let region = this.readConfig('region');
let manifestKey = this.readConfig('manifestKey');

let opts = {
accessKeyId, secretAccessKey, archivePrefix, bucket, region, manifestKey
};

return _list(opts)
.then((data) => {
return { initialRevisions: data.revisions };
});
}
});

return new DeployPlugin();
}
};
Loading

0 comments on commit 2045ac2

Please sign in to comment.