Skip to content
This repository has been archived by the owner on Sep 20, 2022. It is now read-only.

Commit

Permalink
added alexa skill kit service
Browse files Browse the repository at this point in the history
  • Loading branch information
ndpete committed Jul 20, 2017
1 parent 993225f commit 071e05d
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/index.rst
Expand Up @@ -31,6 +31,7 @@ Handel is a library that orchestrates your AWS deployments so you don't have to
:maxdepth: 1
:caption: Supported Services

supported-services/alexaskillkit
supported-services/apiaccess
supported-services/apigateway
supported-services/beanstalk
Expand Down
63 changes: 63 additions & 0 deletions docs/supported-services/alexaskillkit.rst
@@ -0,0 +1,63 @@
.. _alexaskillkit:

Alexa Skill Kit
=================
This document contains information about the Alexa Skill kit service supported in Handel. This Handel service provisions a Alexa Skill kit permission, which is used to integrate with Lambda to invoke them.

Parameters
----------

.. list-table::
:header-rows: 1

* - Parameter
- Type
- Required
- Default
- Description
* - type
- string
- Yes
-
- This must always be *alexaskillkit* for this service type.

Example Handel Files
--------------------

.. _alexaskillkit-lambda-example:

Example Lambda Config
~~~~~~~~~~~~~~~~~~~~~
This Handel file shows a Alexa Skill kit service being configured, producing to a Lambda:

.. code-block:: yaml
version: 1
name: my-alexaskill-lambda
environments:
dev:
function:
type: lambda
path_to_code: .
handler: app.handler
runtime: nodejs6.10
alexaskill:
type: alexaskillkit
event_consumers:
- service_name: function
Depending on this service
-------------------------
The Alexa Skill Kit service cannot be referenced as a dependency for another Handel service. This service is intended to be used as a producer of events for other services.

Events produced by this service
-------------------------------
The Alexa Skill Kit service currently produces events for the following service types:

* Lambda

Events consumed by this service
-------------------------------
The Alexa Skill Kit service does not consume events from other Handel services.
5 changes: 5 additions & 0 deletions lib/common/delete-phases-common.js
Expand Up @@ -93,4 +93,9 @@ exports.unPreDeployNotRequired = function (ownServiceContext, serviceName) {
exports.unBindNotRequired = function (ownServiceContext, serviceName) {
winston.info(`${serviceName} - UnBind is not required for this service`);
return Promise.resolve(new UnBindContext(ownServiceContext));
}

exports.unDeployNotRequired = function (ownServiceContext, serviceName) {
winston.info(`${serviceName} - UnDeploy is not required for this service`);
return Promise.resolve(new UnDeployContext(ownServiceContext));
}
6 changes: 6 additions & 0 deletions lib/common/deploy-phase-common.js
Expand Up @@ -22,6 +22,7 @@ const accountConfig = require('../common/account-config')().getAccountConfig();
const fs = require('fs');
const util = require('../common/util');
const os = require('os');
const DeployContext = require('../datatypes/deploy-context')

/**
* Given a ServiceContext and suffix, return the env var name used for environment variables naming
Expand Down Expand Up @@ -221,4 +222,9 @@ exports.getTags = function (serviceContext) {
}

return tags;
}

exports.deployNotRequired = function (ownServiceContext, serviceName) {
winston.info(`${serviceName} - Deploy is not required for this service, skipping it`);
return Promise.resolve(new DeployContext(ownServiceContext));
}
90 changes: 90 additions & 0 deletions lib/services/alexaskillkit/index.js
@@ -0,0 +1,90 @@
/*
* Copyright 2017 Brigham Young University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
const winston = require('winston');
const ProduceEventsContext = require('../../datatypes/produce-events-context');
const lambdaCalls = require('../../aws/lambda-calls');
const deployPhaseCommon = require('../../common/deploy-phase-common');
const preDeployPhaseCommon = require('../../common/pre-deploy-phase-common');
const bindPhaseCommon = require('../../common/bind-phase-common');
const deletePhasesCommon = require('../../common/delete-phases-common');
const yaml = require('js-yaml');
const accountConfig = require('../../common/account-config')().getAccountConfig();

const SERVICE_NAME = "Alexa Skill Kit";

/**
* Service Deployer Contract Methods
* See https://github.com/byu-oit-appdev/handel/wiki/Creating-a-New-Service-Deployer#service-deployer-contract
* for contract method documentation
*/

exports.check = function (serviceContext) {
let errors = [];

let serviceParams = serviceContext.params;
let valid_regions = ['us-east-1', 'eu-west-1']

//TODO check region
if (!(valid_regions.includes(accountConfig.region))) {
errors.push(`${SERVICE_NAME} - You must deploy to ${valid_regions.join(', ')} to use the Alexa Skill Kit`);
}

return errors;
}

exports.preDeploy = function (serviceContext) {
return preDeployPhaseCommon.preDeployNotRequired(SERVICE_NAME);
}

exports.bind = function (ownServiceContext, ownPreDeployContext, dependentOfServiceContext, dependentOfPreDeployContext) {
return bindPhaseCommon.bindNotRequired(ownServiceContext, dependentOfServiceContext, SERVICE_NAME);
}

exports.deploy = function (ownServiceContext, ownPreDeployContext) {
return deployPhaseCommon.deployNotRequired(ownServiceContext, SERVICE_NAME);
}

exports.consumeEvents = function (ownServiceContext, ownDeployContext, producerServiceContext, producerDeployContext) {
return Promise.reject(new Error(`The ${SERVICE_NAME} service doesn't consume events from other services`));
}

exports.produceEvents = function (ownServiceContext, ownDeployContext, consumerServiceContext, consumerDeployContext) {
return new Promise((resolve, reject) => {
winston.info(`${SERVICE_NAME} - Producing events from '${ownServiceContext.serviceName}' for consumer ${consumerServiceContext.serviceName}`);
});
}

exports.unPreDeploy = function (ownServiceContext) {
return deletePhasesCommon.unPreDeployNotRequired(ownServiceContext, SERVICE_NAME);
}

exports.unBind = function (ownServiceContext) {
return deletePhasesCommon.unBindNotRequired(ownServiceContext, SERVICE_NAME);
}

exports.unDeploy = function (ownServiceContext) {
// TODO
return deletePhasesCommon.unDeployNotRequired(ownServiceContext, SERVICE_NAME);
}

exports.producedEventsSupportedServices = [
'lambda'
];

exports.producedDeployOutputTypes = [];

exports.consumedDeployOutputTypes = [];
3 changes: 3 additions & 0 deletions lib/services/lambda/index.js
Expand Up @@ -162,6 +162,9 @@ exports.consumeEvents = function (ownServiceContext, ownDeployContext, producerS
principal = producerDeployContext.eventOutputs.principal;
sourceArn = producerDeployContext.eventOutputs.eventRuleArn;
}
else if (producerServiceType === 'alexaskillkit') {
principal = 'alexa-appkit.amazon.com';
}
else {
return reject(new Error(`${SERVICE_NAME} - Unsupported event producer type given: ${producerServiceType}`));
}
Expand Down
9 changes: 9 additions & 0 deletions test/common/delete-phases-common-test.js
Expand Up @@ -121,4 +121,13 @@ describe('Delete phases common module', function () {
});
});
});

describe('unDeployNotRequired', function() {
it('should return an emtpy UnDeployContext', function() {
return deletePhasesCommon.unDeployNotRequired({}, "FakeService")
.then(unDeployContext => {
expect(unDeployContext).to.be.instanceof(UnDeployContext);
});
});
});
});
66 changes: 66 additions & 0 deletions test/services/alexaskillkit/alexaskillkit-test.js
@@ -0,0 +1,66 @@
/*
* Copyright 2017 Brigham Young University
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
const accountConfig = require('../../../lib/common/account-config')(`${__dirname}/../../test-account-config.yml`).getAccountConfig();
const alexaSkillKit = require('../../../lib/services/alexaskillkit');
const deployPhaseCommon = require('../../../lib/common/deploy-phase-common');
const ServiceContext = require('../../../lib/datatypes/service-context');
const deletePhasesCommon = require('../../../lib/common/delete-phases-common');
const preDeployPhaseCommon = require('../../../lib/common/pre-deploy-phase-common');
const bindPhaseCommon = require('../../../lib/common/bind-phase-common');
const ProduceEventsContext = require('../../../lib/datatypes/produce-events-context');
const DeployContext = require('../../../lib/datatypes/deploy-context');
const UnDeployContext = require('../../../lib/datatypes/un-deploy-context');
const PreDeployContext = require('../../../lib/datatypes/pre-deploy-context');
const UnPreDeployContext = require('../../../lib/datatypes/un-pre-deploy-context');
const BindContext = require('../../../lib/datatypes/bind-context');
const UnBindContext = require('../../../lib/datatypes/un-bind-context');
const sinon = require('sinon');
const expect = require('chai').expect;

describe('alexaskillkit deployer', function () {
let sandbox;

beforeEach(function () {
sandbox = sinon.sandbox.create();
});

afterEach(function () {
sandbox.restore();
});

describe('check', function () {
it('should require the region to be us-east-1 or eu-west-1', function () {
let serviceContext = {
params: {}
}
let errors = alexaSkillKit.check(serviceContext);
expect(errors.length).to.equal(1);
expect(errors[0]).to.contain("You must deploy to");
});

it('should work when the region is us-east-1 or eu-west-1', function () {
let serviceContext = {
params: {}
}
old_region = accountConfig.region
accountConfig.region = 'us-east-1' //toggle region
let errors = alexaSkillKit.check(serviceContext);
accountConfig.region = old_region //reset the region
expect(errors.length).to.equal(0);
});
});
});
20 changes: 20 additions & 0 deletions test/services/lambda/lambda-test.js
Expand Up @@ -222,6 +222,26 @@ describe('lambda deployer', function () {
});
});

it('should add permissions for the alexaskillkit service type', function () {
let appName = "FakeApp";
let envName = "FakeEnv";
let deployVersion = "1";
let ownServiceContext = new ServiceContext(appName, envName, "consumerService", "lambda", deployVersion, {});
let ownDeployContext = new DeployContext(ownServiceContext);
ownDeployContext.eventOutputs.lambdaName = "FakeLambda";

let producerServiceContext = new ServiceContext(appName, envName, "producerService", "alexaskillkit", deployVersion, {});
let producerDeployContext = new DeployContext(producerServiceContext);

let addLambdaPermissionStub = sandbox.stub(lambdaCalls, 'addLambdaPermissionIfNotExists').returns(Promise.resolve({}));

return lambda.consumeEvents(ownServiceContext, ownDeployContext, producerServiceContext, producerDeployContext)
.then(consumeEventsContext => {
expect(consumeEventsContext).to.be.instanceof(ConsumeEventsContext);
expect(addLambdaPermissionStub.calledOnce).to.be.true;
});
});

it('should return an error for any other service type', function () {
let appName = "FakeApp";
let envName = "FakeEnv";
Expand Down

0 comments on commit 071e05d

Please sign in to comment.