Note: Any code blocks preceeded by a Implementation is actual code and not code examples.
Implementation
Q = require 'q'
_ = require 'lodash'
colors = require 'colors'
S = require 'string'
path = require 'path'
moment = require 'moment'
module.exports = (grunt, niteoaws) ->
In order to test the interaction with the niteoaws.cloudFormationProvider
, we need to be abstract the object. Therefore we need to allow that abstraction to be passed into the module.
Implementation
if not niteoaws?
niteoaws = require 'niteoaws'
We clear up namespaces here.
Implementation
if not grunt.niteo?
grunt.niteo = { }
if not grunt.niteo.aws?
grunt.niteo.aws = { }
if not grunt.niteo.aws.cloudFormation?
grunt.niteo.aws.cloudFormation = { }
Implementation
grunt.niteo.aws.cloudFormation.createJSONStringArray = (content) ->
result = [ ]
for item in S(content).strip('\r').split('\n')
result.push item
result.push '\\n'
JSON.stringify result, null, 4
This method processes a template with path in this.data.src
and stores the result into grunt.option(this.data.key)
.
- src (Required) The path of the template file.
- key (Required) The key used with
grunt.option
to store the result for future use.
Example
grunt.initConfig({
processTemplate: {
src: '/Some/file/path.json'
key: 'someFilePathJsonKey'
data: {
SomeDataNeededWithinTheTemplate: "Hello There!"
}
}
});
The above example configures grunt to process the template file located at /Some/file/path.json
with the data object
{
"data": {
"SomeDataNeededWithinTheTemplate": "Hello There!"
}
}
Grunt then places the result into grunt.option('someFilepathJsonKey')
for future use within the grunt run.
Implementation
grunt.niteo.aws.cloudFormation.processTemplate = ->
if not @data.src?
grunt.warn "You must define a source template file."
return
if not @data.key?
grunt.warn "You must define a key so that this task can place the template somewhere for future use."
return
templateContent = grunt.template.process(grunt.file.read(@data.src, {encoding: "utf8" }), {data:(@data.data ? { })})
if @data.convertToArray ? false
templateContent = grunt.niteo.aws.cloudFormation.createJSONStringArray templateContent
grunt.option(@data.key, templateContent)
grunt.verbose.writeln "#{@data.key}:"['gray']
grunt.verbose.writeln grunt.option(@data.key)['gray']
grunt.log.ok "Created template from #{@data.src} and placed it in grunt.option(\"#{@data.key}\")"
This task handles creating a stack within AWS Cloud Formation.
- region (Required) The region to create the stack in.
- name (Required) The name of the stack
- templateKey (Required) A string that is used with
grunt.option
in order to find the text used for the template. TheprocessTemplate
method shows us how to get the contents of a template intogrunt.option
. - outputKey (Required) A string representing where in
grunt.option
to place the JSON metadata of the created stack. You can use this metadata within other tasks.
Example
grunt.initConfig({
processTemplate: {
src: '/Some/file/path.json',
key: 'someFilePathJsonKey',
data: {
SomeDataNeededWithinTheTemplate: "Hello There!"
}
},
createStack: {
region: "us-east-1",
name: "MyStack",
templateKey: "someFilePathJsonKey",
outputKey: "MyStackMetadata"
}
});
grunt.registerTask('default', [ 'processTemplate', 'createStack' ])
This example uses the output from the processTemplate
to feed the createStack
task which creates a new stack within the us-east-1
region called MyStack. It then stores the metadata of that stack within grunt.option('MyStackMetadata')
Implementation
grunt.niteo.aws.cloudFormation.createStack = ->
done = @async()
if not @data.region?
grunt.fail.fatal "You need to define a region in order to create a stack."
done()
return
if not @data.name?
grunt.fail.fatal "You need to define a stack name in order to create a stack."
done()
return
if not @data.templateKey?
grunt.fail.fatal "You need to define a template key in order to create a stack."
done()
return
if not @data.outputKey?
grunt.fail.fatal "You need to define a key in order to store the stack metadata once it's created."
done()
return
niteoawsCF = niteoaws.cloudFormationProvider.factory @data.region
content = grunt.option(@data.templateKey)
if not content?
grunt.fail.fatal "The template retreived was invalid."
done()
return
niteoawsCF.doesStackExist(@data.name)
.then (result) =>
if not result
grunt.log.ok "Stack #{@data.name} does not exist."
niteoawsCF.validateTemplate(content)
.then =>
grunt.log.ok "Template Validated."
niteoawsCF.createStack(@data.name, content, @data.parameters, @data.capabilities)
.then =>
grunt.log.ok "Successfully created stack #{@data.name}"
.then =>
niteoawsCF.getStackId(@data.name)
.then (result)=>
grunt.log.ok "Successfully retreived the stack id #{result}"
niteoawsCF.getResource(result)
.done (result) =>
grunt.verbose.writeln JSON.stringify(result, null, 4)['gray']
grunt.option(@data.outputKey, result)
grunt.log.ok "Successfully retreived the stack metadata and placed it into grunt.option(#{@data.outputKey})"
done()
, (err) ->
grunt.fail.fatal err
done()
, (progress) ->
grunt.log.writeln "#{moment().format()}: #{progress}"['gray']
This task handles updating a stack within AWS Cloud Formation.
- region (Required) The region to update the stack in.
- name (Required) The name of the stack
- templateKey (Required) A string that is used with
grunt.option
in order to find the text used for the template. TheprocessTemplate
method shows us how to get the contents of a template intogrunt.option
. - outputKey (Required) A string representing where in
grunt.option
to place the JSON metadata of the updated stack. You can use this metadata within other tasks.
Example
grunt.initConfig({
processTemplate: {
src: '/Some/file/path.json',
key: 'someFilePathJsonKey',
data: {
SomeDataNeededWithinTheTemplate: "Hello There!"
}
},
updateStack: {
region: "us-east-1",
name: "MyStack",
templateKey: "someFilePathJsonKey",
outputKey: "MyStackMetadata"
}
});
grunt.registerTask('default', [ 'processTemplate', 'updateStack' ])
This example uses the output from the processTemplate
to feed the updateStack
task which updates an existing stack within the us-east-1
region called MyStack. It then stores the metadata of that stack within grunt.option('MyStackMetadata')
Implementation
grunt.niteo.aws.cloudFormation.updateStack = ->
done = @async()
if not @data.region?
grunt.fail.fatal "You need to define a region in order to create a stack."
done()
return
if not @data.name?
grunt.fail.fatal "You need to define a stack name in order to create a stack."
done()
return
if not @data.templateKey?
grunt.fail.fatal "You need to define a template key in order to create a stack."
done()
return
if not @data.outputKey?
grunt.fail.fatal "You need to define a key in order to store the stack metadata once it's updated."
done()
return
niteoawsCF = niteoaws.cloudFormationProvider.factory @data.region
content = grunt.option(@data.templateKey)
if not content?
grunt.fail.fatal "The template retreived was invalid."
done()
return
niteoawsCF.doesStackExist(@data.name)
.then (result) =>
if result
grunt.log.ok "Stack #{@data.name} does not exist."
niteoawsCF.validateTemplate(content)
.then =>
grunt.log.ok "Template Validated."
deferred = Q.defer()
niteoawsCF.updateStack(@data.name, content, @data.parameters, @data.capabilities)
.done((success) ->
deferred.resolve()
,(err) ->
if(err.message == "No updates are to be performed.")
grunt.log.ok "There were no updates to be performed."
deferred.resolve();
else
deferred.reject(err);
, (progress) ->
deferred.notify(progress)
)
deferred.promise
else
grunt.fail.fatal "The stack #{@data.name} does not exist."
.then =>
niteoawsCF.getStackId(@data.name)
.then (result)=>
grunt.log.ok "Successfully retreived the stack id #{result}"
niteoawsCF.getResource(result)
.done (result) =>
grunt.verbose.writeln JSON.stringify(result, null, 4)['gray']
grunt.option(@data.outputKey, result)
grunt.log.ok "Successfully retreived the stack metadata and placed it into grunt.option(#{@data.outputKey})"
done()
, (err) ->
grunt.fail.fatal err
done()
, (progress) ->
grunt.log.writeln "#{moment().format()}: #{progress}"['gray']
This task handles deleting a stack from within AWS Cloud Formation.
- region (Required) The region to create the stack in.
- name (Required) The name of the stack
Example
grunt.initConfig({
processTemplate: {
src: '/Some/file/path.json',
key: 'someFilePathJsonKey',
data: {
SomeDataNeededWithinTheTemplate: "Hello There!"
}
},
createStack: {
region: "us-east-1",
name: "MyStack",
templateKey: "someFilePathJsonKey",
outputKey: "MyStackMetadata"
},
deleteStack: {
region: "us-east-1",
name: "MyStack"
}
});
grunt.registerTask('default', [ 'processTemplate', 'createStack', 'deleteStack' ]);
This example uses the output from the processTemplate
to feed the createStack
task which creates a new stack within the us-east-1
region called MyStack. It then stores the metadata of that stack within grunt.option('MyStackMetadata')
. Finally, the stack is deleted.
Implementation
grunt.niteo.aws.cloudFormation.deleteStack = ->
done = @async()
if not @data.region?
grunt.fail.fatal "You need to define a region in order to create a stack."
if not @data.name?
grunt.fail.fatal "You need to define a stack name in order to create a stack."
niteoawsCF = new niteoaws.cloudFormationProvider.factory @data.region
niteoawsCF.deleteStack(@data.name)
.done (result) ->
grunt.verbose.writeln JSON.stringify(result, null, 4)['gray']
grunt.log.ok "Success"
done()
, (err) ->
grunt.fail.fatal err
done()
, (progress) ->
grunt.log.writeln "#{moment().format()}: #{progress}"['gray']
Implementations
grunt.registerMultiTask 'processTemplate', grunt.niteo.aws.cloudFormation.processTemplate
grunt.registerMultiTask 'createStack', grunt.niteo.aws.cloudFormation.createStack
grunt.registerMultiTask 'updateStack', grunt.niteo.aws.cloudFormation.updateStack
grunt.registerMultiTask 'deleteStack', grunt.niteo.aws.cloudFormation.deleteStack