0.3.12 • Published 8 years ago

amityjs v0.3.12

Weekly downloads
3
License
Apache-2.0
Repository
github
Last release
8 years ago

_**Amity.js**_ framework

https://gitter.im/aletheia/amity Build Status dependencies

NPM

DISCLAIMER: Amity.js is still in ALPHA release, so something could need to be fixed. This means Amity.js is not intended to be ready for production projects, until release 1.0 is out.

Amity.js aims to be a fast and straightforward tool to create AWS functions and resources. Written completely in Node.js it relies only on aws sdk for NodeJS, thus exposing allthe functionalities of the project manager tool to be invoked at runtime.

Getting started

Amity.js can be installed as Node.js global module using NPM

NPM

Architecture and usage

Amity.js can be used either as library from Node source file or with an handy Command Line Interface (CLI). Amity.js adopts a paradigm that is indepdendent from machine-specific configurations, thus main Amity.js library is instantiated withoud any reference to variables that are not project-specific. All of them are required to be specified (at least as their default values) whenever an execution occurs and are wrapped inside an ExecutionContext object.

####Amity.js Execution Context ExecutionContexts are runtime-specific configurations (such as AWS account or deployment regions) that must be provided to Amity.js before executing any command. An ExecutionContext is defined as follows:

/**
 * @typedef     {object}    AmityExecutionContext
 * @property    currentFolder   {string}
 * @property    accountId       {string}
 * @property    region          {string}
 * @property    credentials     {AWS.Credentials}
 * @property    options         {object}
 */

where

Propertyrequireddefault valueMeaning
currentFolderYES__dirnameSets the execution current folder. Every command will affect data starting from this folder
accountIdYESnoneIts the id of the current AWS account. It is a required property for some legacy operations. Unfortunately AWS does not provide an API call to retrieve an user account Id. Currently we're moving this requirement out from amity, thus relying only over APIs that does not require it. It's scheduled to be removed in a future release.
regionYESus-east-1It's the region where Amity.js resources must be deployed. It is not part of the project (unlike Serverless) 'cause our deploy should be made region-independent
credentialsNOsystem default AWS credentialsAWS credentials to be used by amity to perform remote operations. If not provided they are defaulted to system configured credentials, using standard AWS failback Credentials Provider Chain.

###Lyfecycle model Amity.JS deployment model is made of sequenced phases:

resource creation ---> resource deploy ---> resource undeploy ---> resource delete

Resources have to be created locally. Amity.JS considers remote cloud environment as an active mirror of the existing local project, thus Amity.JS is a project-driven framework, where resources are a local representation of cloud services. Lifecycle model heavily relies on Javascript Promises following the Promises A+ model. Since Amity.JS is an ES5 project promises are achieved through Bluebird.

####Resources, Templates, Managers Amity.js execution model is composed of three main objects:resources, templates and managers. These represent virtually any (of the supported) resources in an amity project.

#####Resources##### Resources are the local JSON representation of a configuration for a given AWS service. Resources are serialized to JSON data and can be created starting from any JSON-serialized representation (by injecting it as constructor parameter).

Currently available resources are:

  • S3 buckets
  • DynamoDB tables
  • IAM role
  • Amazon Lambda functions
  • SNS topic
  • APIGateway endpoint

These resources are exposed through amity.resources.<resource name>. property. Any resource name is a string that can be retrieved as a static property on its corrensponding Resource exported module by property Name.

Exmple
var Amity = require("amityjs");
var amity = new Amity({currentFolder: ".", region: "us-east-1"});
var dynamoTable = amity.resources.dynamodb.Table.defaultTableForName(dynamoTableName);

#####Templates Resource template are an easy way to instantiare resources starting from Templates. Amity.JS model maps as a thin layer over AWS configuration files, but in some cases many defaults options can be leveraged to improve ease of use. Templates comes to the rescue, 'cause they represent a set of default configurations for any given resource and can be also built by developers to increase reusability. Templates are currently not exposed by amity, but an inner feature of any resource, thus in order to provide new sets of templates, a new AWS resource must be created. Templates use Handlebars as templating language, which is a project required dependency.

#####Managers Managers should be considered the effective worker on Amity.JS, because are the components that manage the resource lifecycle. Each manager is bound to a specific resource and extends a generic AbstractManager that provides four main methods:

  1. createResource(resource,executionContext,awsClient): creates locally a new resource of a given type.
  2. deployResource(resource,executionContext,awsClient)
  3. undeployResource(resource,executionContext,awsClient)
  4. deleteResource(resource,executionContext,awsClient)

Managers are exposed through amity.managers.<manager name> property and need to be instantiated. They receive an AmityExecutionContext and an AWS client as optional parameters injected into constructor. Each method however can be invoked with three parameters:

  • A Resource. Required. Is the object being manipulated through current manager
  • An ExecutionContext. Optional. It is the context of current execution, if undefined existing context is used.
  • An AWS client. Optional. It is the AWS SDK client object that is used to perform cloud operations. If undefined a standard AWS client is instantiated. This param can be used to inject a custom client, when required.
Example
var Amity = require("amityjs");
var amity = new Amity({currentFolder: ".", region: "us-east-1"});
var dynamoManager = new amity.managers.dynamodb(amity.executionContext);
dynamoManager.createResource(dynamoTable, amity.executionContext)
    .then(function() {
        // do something whenever a resource is created.
    });
    
dynamoManager.deployResource(dynamoTable, amity.executionContext);
    .then(function() {
        // do something whenever a resource is deployed to cloud.
    })

dynamoManager.undeployResource(dynamoTable, amity.executionContext);
    .then(function() {
        // do something whenever a resource is undeployed.
    });

dynamoManager.undeployResource(dynamoTable, amity.executionContext);
    .then(function() {
        // do something whenever a resource is deleted.
    });

Complete Example (create a DynamoDB table)

"use strict";
var _ = require("lodash");
var winston = require("winston");
var logger = new (winston.Logger)({
    transports: [
        new (winston.transports.Console)({timestamp: true, colorize: true})
    ]
});
var path = require("path");
var mkdirp = require("mkdirp");
var del = require("del");

var Promise = require("bluebird");
var Amity = require("amityjs");

// config variables
var dynamoConfigPath = path.join(".", "dynamo");

// instantiating Amity, with an ExecutionContext object
var amity = new Amity({currentFolder: dynamoConfigPath, region: "us-east-1"});


// Start execution
var dynamoTableName = "MyTestTable";
mkdirp(dynamoConfigPath);

var dynamoTable = amity.resources.dynamodb.Table.defaultTableForName(dynamoTableName);

var dynamoManager = new amity.managers.dynamodb(amity.executionContext);

// Creating function locally
logger.info("CREATE RESOURCE");
dynamoManager.createResource(dynamoTable, amity.executionContext)
    .then(function() {
        logger.info("Function template created");
    })
    .then(function() {
        logger.info("PREPARE RESOURCE");
        return dynamoManager.deployResource(dynamoTable, amity.executionContext);
    })
    .then(function() {
        return new Promise(function(resolve, reject) {
            setTimeout(function(){
            	// do something
                resolve();
            },5000);
        });
    })
    .then(function() {
        return dynamoManager.undeployResource(dynamoTable, amity.executionContext);
    })
    .then(function() {
    });

Amity.js Command Line Interface (CLI)

Amity Command Line Interface is the preferred way of usage with Amity.JS. It offers a set of shotcuts to speed resource creation and deployment. Since Amity.JS mantains operations strictly synched to amity.project.json project file, every time Amity.JS is invoked in a folder contanining a project file, it is updated with Amity.JS command results.

Any Amity command is built using the following structure

amity [create|deploy|undeploy|delete] <service name>:<resource type> <resource id in project> [-paramName:paramValue]

Each manager command is mapped to corresponding CLI command, while resource type should be provided with a custom format combining AWS service name and resource type with a semicolon notation. When amity command line is invoked with no extra parameters, then project file is read or created. If CLI is invoked only specifying command option, then resource type project is assumed as default. If only service name is provided i.e. amity create iam something then the Resource default type is used.

Interaction workflow:

amity create
amity create iam:role MyIAMRole
amity create lambda:function MyLambdaFunction
amity deploy

Amity.js folder structure

Amity.js relies on standardized project structure, to better organize files and folder. This structure is flexible and can be customized through amity.project.json file.

<project root>
	├─── cloud
	├─── code
	│       ├─── lambda
	│       └─── app
	├─── gulpfile.js
	├─── .jshintrc
	├─── amity.project.json
	├─── package.json
	├─── test
	└─── dist
  • cloud: contains all the cloud configurations that have to be considered project-wide.
  • code - lambda: contains all the functions that belong to this project, one in each folder. Cross-function resources can be configured here.
  • code - app: contains all the static code for any client app for this project. It will be deployed in an S3 bucket.
  • gulpfile.js: contains standard gulp tasks required to manage amity build and deployments through GulpJS
  • test: contains all the tests for this project, run through jasmine command.
  • dist: output folder, containing all the generated files.

What is Amity.js development status?

As stated before, Amity.js is a currently active work in progress. Visit the Amity.js Trello board to stay tuned on what's going on. Wanna contribute with some great idea? Join us to Amity.js Gitter chat and start discussing the feature you miss most.

Upcoming Amity.js releases

  • 0.3.0: Lambda functions creation and management
  • 0.4.0: Cloud resources creation from scratch
  • 0.5.0: Test coverage, CLI improvements, Cloud resources upgrade and delete production ready release
  • 0.6.0: Support for CloudSearch domains creation

Why Amity.js and not X?

X = Serverless (aka JAWS))

Amity.js took great inspiration from JAWS people and their idea of a cloud project manager made us dream of a better world. Unfortunately JAWS is really a complex project and has a big development cycle. Some basic assumptions (like using CloudFormation as a common middle layer) found our understanding, but not our approval: we were looking for a tool that can be used interactively within our projects and in the near future also as standalone Lambda function deployed on AWS (maybe exposing its capabilities through a set of REST APIs). Sounds cool, eh? Unfortunately Serverless approach cuts off this possibility both in the near and far future. This is not what we love and the way (in our very humble opinion) serverless projects will be managed. So, this meant we've to start over with a new project that could (hopefully) merge into JAWS/Serverless in the near future, adding Amity.js capabilities to every Serverless powered project.

Basically Amity.js differs from Serverless for a couple of capabilities:

  • provides JS Objects modeling AWS Resources
  • can be used in interactive mode (add/remove a single resource or function)
  • does not rely on CloudFormation Syntax (which can be cumbersome and does not allow for AWS services such as APIGateway and Cloudsearch)

Amity.js can be thought as Serverless little flexible brother: where Serverless aim to manage extremely big projects, with hundreds of functions, Amity.js holds a smaller approcah thus providing capabilities focused on mobile backend-less development, thus focusing on enabling support for features such as AWS SNS, IoT and CloudSearch that are often key points in a mobile project. Serverless aims to support these capabilities with a polyfill approach: fake Cloudformation-like configurations are created from resource configuration JSON, then they are translated to classes using AWS SDK to implement this capability.

We hope in the near future, as soon as Amity.js and Serverless both becomes mature that the projects could merge. Due to this reason we choose to keep Amity.js project structure as cloose as possible to Serverless configuration files, in order to ease the process.

Now and in the future, our gratitude goes to Austen (@ac360) and the Serverless team for having deeply inspired us with his work.

X = just plain Javascript with AWS SDK for NodeJS

AWS SDK is great to be used as a library in your Node projects. Amity.js aims being something different and more structured, allowing developers to manage Projects directly from a single place. Using directly the SDK so remains a goog option, but is definitely too difficult to manage projects from it, enforcing some standard and best practices.

X = just plain GulpJS or LambdaAWS

GulpJS is a great tool for buld automation and could be easily adapted to manage Lambda funcitons packagind and deployment. Using it as a tool to create a cloud infrastructure, provision access policies (many of them coming from template evaluation) and keep the complete project under the same project is very hard to achieve. Moreover, it does not have an easy method to support functions plugging in and multi-region deployment. We started using just gulpJS, but quickly realized that the effort needed to make it work for other than build automation was more than starting a new project from scratch and using many gulp plugin in it. So we did amity. LambdaAWS was an interesting effort towards many of the feature we love in Amity, but was abandoned as soon as Lambda come out of 1.0.

X = Backbeam

Backbeam is an interesting tool, to manage infrastructure as code but has a strong vendor lock-in and it is not free. We aim providing Amity.js as an helpful tool any developer can use and evolve for her needs, thus making the overall system better at each iteration.

##FAQ##

###Why ES5?## Since one of the mayor goal of Amity.JS is being deployed as a serverless cloud manager iteself through Amazon Lambda, we needed to stick to the supported NodeJS version of Lambda which is 0.10.36 (note: recently Amazon announced support for Node 4.3.2 LTS, so this requirement is not manadatory anymore. Migration to ES6 is scheduled, in a future release).

###Why not using Babel to write in ES6?## We believe Babel.JS is a great tool to handle browser cross-compatibility. But we believe also that using it to retro-fit Node app inside Lambda functions is pretty much overkilling. We prefer staying plain and leverage ES5 as soon as it does not compromise any functionality. (note: since ES6 support has recently been added by AWS, we do not require Babel anyway).

Contributing Amity

Since today Amity.js is backed only by Neosperience and all the development effort is due to Neosperience team (manu thanks to them) and to Luca Bianchi overnight effort, we're looking for contributors willing to join us into this fantastic project. Fork the project and start sending your pull requests!!

Join us into Amity contributors

Amity.js sponsors

Amity.js is mantained and developed by