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

feat: support external role (breaking change) #39

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/aws/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ export default class Resource {

return this
}

public toJSON():any {
throw new Error('override this')
}
}
2 changes: 1 addition & 1 deletion src/aws/target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class Target extends Resource {
}

const nameTarget = this.name.target(this.read)
const nameRole = this.name.role()
const nameRole = this.options.role || this.name.role()
const nameDimension = this.name.dimension(this.read)

const DependsOn = [ this.options.table, nameRole ].concat(this.dependencies)
Expand Down
56 changes: 26 additions & 30 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import * as util from 'util'
import Policy from './aws/policy'
import Role from './aws/role'
import Target from './aws/target'
import Resource from './aws/resource'
import { coerceToArray, getFirstKey } from './utils'

const text = {
CLI_DONE: 'Added DynamoDB Auto Scaling to CloudFormation!',
CLI_RESOURCE: ' - Building configuration for resource "table/%s%s"',
CLI_SKIP: 'Skipping DynamoDB Auto Scaling: %s!',
CLI_START: 'Configure DynamoDB Auto Scaling …',
INVALID_CONFIGURATION: 'Invalid serverless configuration',
NO_AUTOSCALING_CONFIG: 'Not Auto Scaling configuration found',
NO_AUTOSCALING_CONFIG: 'No Auto Scaling configuration found',
ONLY_AWS_SUPPORT: 'Only supported for AWS provicer'
}

Expand All @@ -23,6 +25,7 @@ interface Defaults {

class AWSDBAutoScaling {
public hooks: {}
private options: AutoScalingOptions

/**
* Constructur
Expand Down Expand Up @@ -65,7 +68,7 @@ class AWSDBAutoScaling {
assert(this.serverless.service.provider.name === 'aws', text.ONLY_AWS_SUPPORT)

assert(this.serverless.service.custom, text.NO_AUTOSCALING_CONFIG)
assert(this.serverless.service.custom.capacities, text.NO_AUTOSCALING_CONFIG)
assert(this.options.capacities, text.NO_AUTOSCALING_CONFIG)
}

/**
Expand All @@ -89,15 +92,16 @@ class AWSDBAutoScaling {
/**
* Create CloudFormation resources for table (and optional index)
*/
private resources(table: string, index: string, config: Capacity): any[] {
private resources(table: string, index: string, config: Capacity): Resource[] {
const data = this.defaults(config)

const options: Options = {
index,
region: this.getRegion(),
service: this.getServiceName(),
stage: this.getStage(),
table
table,
role: this.options.role
}

// Start processing configuration
Expand All @@ -106,9 +110,10 @@ class AWSDBAutoScaling {
)

// Add role to manage Auto Scaling policies
const resources: any[] = [
new Role(options)
]
const resources: any[] = []
if (!this.options.role) {
resources.push(new Role(options))
}

// Only add Auto Scaling for read capacity if configuration set is available
if (!!config.read) {
Expand Down Expand Up @@ -137,60 +142,51 @@ class AWSDBAutoScaling {
* Generate CloudFormation resources for DynamoDB table and indexes
*/
private generate(table: string, config: Capacity) {
let resources: any[] = []
let lastRessources: any[] = []
let resources: Resource[] = []
let lastRessources: string[] = []

const indexes = this.normalize(config.index)
const indexes = coerceToArray(config.index)
if (!config.indexOnly) {
indexes.unshift('') // Horrible solution
}

indexes.forEach(
(index: string) => {
const current = this.resources(table, index, config).map(
(resource: any) => resource.setDependencies(lastRessources).toJSON()
resource => resource.setDependencies(lastRessources).toJSON()
)

resources = resources.concat(current)
lastRessources = current.map((item: any) => Object.keys(item).pop())
lastRessources = current.map(getFirstKey)
}
)

return resources
}

/**
* Check if parameter is defined and return as array if only a string is provided
*/
private normalize(data: string|string[]): string[] {
if (data && data.constructor !== Array) {
return [ data as string ]
}

return (data as string[] || []).slice(0)
}

/**
* Process the provided configuration
*/
private process() {
this.serverless.service.custom.capacities.filter(
const { capacities } = this.options
const allResources = this.serverless.service.provider.compiledCloudFormationTemplate.Resources
capacities.filter(
(config: Capacity) => !!config.read || !!config.write
).forEach(
(config: Capacity) => this.normalize(config.table).forEach(
(config: Capacity) => coerceToArray(config.table).forEach(
(table: string) => this.generate(table, config).forEach(
(resource: string) => _.merge(
this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
resource
)
(resources: any) => _.merge(allResources, resources)
)
)
)
}

private beforeDeployResources(): Promise<any> {
return Promise.resolve().then(
() => this.validate()
() => {
this.options = this.serverless.service.custom['dynamodb-autoscaling']
this.validate()
}
).then(
() => this.serverless.cli.log(util.format(text.CLI_START))
).then(
Expand Down
5 changes: 5 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const coerceToArray = <T>(data: T|T[]): T[] => {
return ([] as T[]).concat(data || [])
}

export const getFirstKey = (obj: any):string => Object.keys(obj).pop() as string
12 changes: 0 additions & 12 deletions test/plugin.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
import * as Plugin from '../src/plugin'

describe('Normalize', () => {
it('converts everything to an array', () => {
const test = new Plugin({ service: { provider: { stage: 'foo' } } })

expect(test.normalize('test')).toEqual(['test'])
expect(test.normalize(['test'])).toEqual(['test'])
expect(test.normalize(['test', 'foo'])).toEqual(['test', 'foo'])
expect(test.normalize([])).toEqual([])
expect(test.normalize()).toEqual([])
})
})

describe('Defaults', () => {
it('creates object with defaults', () => {
const config = {
Expand Down
11 changes: 11 additions & 0 deletions test/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { coerceToArray } from '../src/utils'

describe('Normalize', () => {
it('converts everything to an array', () => {
expect(coerceToArray('test')).toEqual(['test'])
expect(coerceToArray(['test'])).toEqual(['test'])
expect(coerceToArray(['test', 'foo'])).toEqual(['test', 'foo'])
expect(coerceToArray([])).toEqual([])
expect(coerceToArray()).toEqual([])
})
})
11 changes: 9 additions & 2 deletions vendor/main.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ declare interface Capacity {
indexOnly?: boolean
write?: CapacityConfiguration
read?: CapacityConfiguration
generateRoles?: boolean
}

declare interface CapacityConfiguration {
Expand All @@ -18,6 +19,12 @@ declare interface Options {
service: string
stage: string
table: string
role?: string
}

declare interface AutoScalingOptions {
role?: string // external role logical id
capacities: Capacity[]
}

/**
Expand All @@ -26,7 +33,7 @@ declare interface Options {
declare namespace Serverless {
namespace Service {
interface Custom {
capacities: Capacity[]
['dynamodb-autoscaling']: AutoScalingOptions
}
}
}
}