/**
* Created by arming on 6/15/16.
*/
'use strict'
const RequiredPropertyException = require('./exceptions').RequiredPropertyException
const ConditionNotMetException = require('./exceptions').ConditionNotMetException
const TypeException = require('./exceptions').TypeException
const Policy = require('./policy').Policy
/** @module Core */
/**
* A CloudFormation Resource, mapping to those defined at http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html.
* @memberof module:Core
* @property {String} WKName
*/
class WKResource {
/** @constructs WKResource */
constructor (name, resourceType, properties, propertiesObject, conditional) {
this.WKName = name
this.WKResourceType = resourceType
this.properties = properties
this.conditional = conditional
for (let prop in this.properties) {
Object.defineProperty(this, prop, {
set: (value) => {
this.properties[prop].set(value)
},
get: () => {
return this.properties[prop]
}
})
}
if (propertiesObject) {
for (let prop in propertiesObject) {
if(this.properties[prop]) {
let property = propertiesObject[prop]
if(typeof property === 'string') {
property = new String(property)
} else if(typeof property === 'boolean') {
property = new Boolean(property)
} else if(typeof property === 'number') {
property = new Number(property)
}
if(this.properties[prop].Type) {
if(property instanceof this.properties[prop].Type) {
} else {
try {
property = new this.properties[prop].Type(property)
} catch(e) {
}
}
try {
this.properties[prop].set(propertiesObject[prop])
} catch (e) {
}
}
}
}
}
}
/**
* Adds a DependsOn dependency for another Resource
* @param resource
*/
dependsOn (resource) {
this.dependsOn = resource
}
/**
* Adds a Config block to the Metadata AWS::CloudFormation::Init block of an Instance
* @param config
*/
addConfig (config) {
if(this instanceof require('./resources/ec2').Instance) {
if(!this.Metadata) {
this.Metadata = {
}
}
if(!this.Metadata['AWS::CloudFormation::Init']) {
this.Metadata['AWS::CloudFormation::Init'] = {
configSets: {}
}
}
this.Metadata['AWS::CloudFormation::Init'][config.WKName] = config
} else {
throw new TypeException('Not allowed to add ' + config + 'to ' + this.WKName + ' because it is not an Instance or LaunchConfiguration')
}
}
/**
* Adds a ConfigSet block to the Metadata AWS::CloudFormation::Init block of an Instance
* @param configSet
*/
addConfigSet (configSet) {
if(this instanceof require('./resources/ec2').Instance) {
if(!this.Metadata) {
this.Metadata = {
}
}
if(!this.Metadata['AWS::CloudFormation::Init']) {
this.Metadata['AWS::CloudFormation::Init'] = {
configSets: {}
}
}
this.Metadata['AWS::CloudFormation::Init'].configSets[configSet.WKName] = configSet.configs
} else {
throw new TypeException('Not allowed to add ' + configSet + 'to ' + this.WKName + ' because it is not an Instance or LaunchConfiguration')
}
}
/**
* Adds a CreationPolicy, UpdatePolicy, or DeletePolic
* @param policy
*/
addPolicy (policy) {
if(!this.policies) {
this.policies = {}
}
if(policy instanceof Policy) {
this.policies[policy.WKName] = policy
} else {
throw new TypeException(policy + ' must be of type Policy')
}
}
/**
* Performs validation and returns a pretty-printed JSON object.
* @returns {String}
*/
toJson () {
let newProperties = JSON.parse(JSON.stringify(this.properties))
for (let prop in newProperties) {
try {
newProperties[prop] = this.properties[prop].toJson()
} catch (e) {
if (e instanceof RequiredPropertyException) {
throw new RequiredPropertyException(this.WKName + '.' + prop + ' or a subproperty is required but not defined: ' + e.message)
}
}
}
if(this.conditional) {
try {
this.conditional(this.properties)
} catch (e) {
if (e instanceof ConditionNotMetException) {
throw new ConditionNotMetException(this.WKName + ' has a condition that was not met: ' + e.message)
}
}
}
let newMetadata = {}
if(this.Metadata) {
if(this.Metadata['AWS::CloudFormation::Init']) {
newMetadata['AWS::CloudFormation::Init'] = {}
for (let config in this.Metadata['AWS::CloudFormation::Init']) {
if(config === 'configSets') {
newMetadata['AWS::CloudFormation::Init'][config] = this.Metadata['AWS::CloudFormation::Init'][config]
} else {
newMetadata['AWS::CloudFormation::Init'][config] = this.Metadata['AWS::CloudFormation::Init'][config].toJson()
}
}
}
}
let returnObject = {
Type: this.WKResourceType,
Properties: newProperties,
}
if(this.Metadata) {
returnObject.Metadata = newMetadata
}
if(this.policies) {
for(let policy in this.policies) {
returnObject[policy] = this.policies[policy].toJson()
}
}
if (this.dependsOn) {
returnObject.DependsOn = this.dependsOn.WKName
}
return returnObject
}
}
/**
* A CloudFormation ResourceProperty, mapped to those listed at http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-product-property-reference.html
* @memberof module:Core
*/
class ResourceProperty {
constructor (name, properties, propertiesObject, conditional) {
this.WKName = name
this.properties = properties
this.conditional = conditional
for (let prop in this.properties) {
Object.defineProperty(this, prop, {
set: (value) => {
this.properties[prop].set(value)
},
get: () => {
return this.properties[prop]
}
})
}
if (propertiesObject) {
for (let prop in propertiesObject) {
this.properties[prop] = propertiesObject[prop]
}
}
}
/**
* Performs validation and returns a pretty-printed JSON object.
* @returns {String}
*/
toJson() {
let newProperties = JSON.parse(JSON.stringify(this.properties))
for (let prop in newProperties) {
try {
newProperties[prop] = this.properties[prop].toJson()
} catch (e) {
if (e instanceof RequiredPropertyException) {
throw new RequiredPropertyException(this.WKName + '.' + prop + ' is required but not defined: ' + e.message)
}
}
}
if(this.conditional) {
try {
this.conditional(this.properties)
} catch (e) {
if (e instanceof ConditionNotMetException) {
throw new ConditionNotMetException(this.WKName + ' has a condition that was not met: ' + e.message)
}
}
}
return newProperties
}
}
module.exports = {
WKResource: WKResource,
ResourceProperty: ResourceProperty
}