@@ -11,6 +11,8 @@ require 'tempfile'
1111require 'json'
1212require_relative './ext/common_helper'
1313require_relative './ext/zip_helper'
14+ require 'aws-sdk-s3'
15+ require 'aws-sdk-cloudformation'
1416require 'ciinabox-ecs' if Gem ::Specification ::find_all_by_name ( 'ciinabox-ecs' ) . any?
1517
1618namespace :ciinabox do
@@ -38,7 +40,7 @@ namespace :ciinabox do
3840 config = default_params
3941 end
4042
41- Dir [ "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/*.yml" ] . each { |config_file |
43+ Dir [ "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/*.yml" ] . each { |config_file |
4244 if not config_file . include? ( 'params.yml' )
4345 config = config . merge ( YAML . load ( File . read ( config_file ) ) )
4446 end
@@ -48,12 +50,12 @@ namespace :ciinabox do
4850
4951 # ciinabox binary version
5052 if Gem . loaded_specs [ 'ciinabox-ecs' ] . nil?
51- config [ 'ciinabox_binary_version' ] = `git rev-parse --short HEAD` . gsub ( "\n " , '' )
53+ config [ 'ciinabox_binary_version' ] = `git rev-parse --short HEAD` . gsub ( "\n " , '' )
5254 else
5355 config [ 'ciinabox_binary_version' ] = Gem . loaded_specs [ 'ciinabox-ecs' ] . version . to_s
5456 end
5557
56- File . write ( 'debug-ciinabox.config.yaml' , config . to_yaml ) if ENV [ 'DEBUG' ]
58+ File . write ( 'debug-ciinabox.config.yaml' , config . to_yaml ) if ENV [ 'DEBUG' ]
5759
5860 stack_name = config [ "stack_name" ] || "ciinabox"
5961
@@ -64,8 +66,8 @@ namespace :ciinabox do
6466 templates2 = Dir [ "#{ ciinaboxes_dir } /#{ ciinabox_name } /templates/**/*.rb" ]
6567
6668 ## we want to exclude overridden templates
67- templatesLocalFileNames = templates2 . collect { |templateFile | File . basename ( templateFile ) }
68- templates = templates . select { |templateFile | not templatesLocalFileNames . include? File . basename ( templateFile ) }
69+ templatesLocalFileNames = templates2 . collect { |templateFile | File . basename ( templateFile ) }
70+ templates = templates . select { |templateFile | not templatesLocalFileNames . include? File . basename ( templateFile ) }
6971 templates = templates + templates2
7072 end
7173
@@ -87,13 +89,13 @@ namespace :ciinabox do
8789 tmp_file = write_config_tmp_file ( config )
8890
8991 CfnDsl ::RakeTask . new do |t |
90- extras = [ [ :yaml , "#{ current_dir } /config/default_params.yml" ] ]
92+ extras = [ [ :yaml , "#{ current_dir } /config/default_params.yml" ] ]
9193 extras << [ :yaml , "#{ current_dir } /config/default_lambdas.yml" ]
9294 if File . exist? "#{ ciinaboxes_dir } /ciinabox_config.yml"
9395 extras << [ :yaml , "#{ ciinaboxes_dir } /ciinabox_config.yml" ]
9496 end
95- ( Dir [ "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/*.yml" ] . map { |f | [ :yaml , f ] } ) . each { |c | extras << c}
96- extras << [:ruby,"#{ current_dir } /ext/helper.rb"]
97+ ( Dir [ "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/*.yml" ] . map { |f | [ :yaml , f ] } ) . each { |c | extras << c }
98+ extras << [ :ruby , "#{ current_dir } /ext/helper.rb" ]
9799 extras << [ :yaml , tmp_file . path ]
98100 t . cfndsl_opts = {
99101 verbose : true ,
@@ -165,16 +167,16 @@ namespace :ciinabox do
165167 if File . exist? ( "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/params.yml" )
166168 config_output = user_params . merge ( input_hash ) #Merges input hash into user-provided template
167169 config_yaml = config_output . to_yaml #Convert output to YAML for writing
168- File.open("#{ ciinaboxes_dir } /#{ ciinabox_name } /config/params.yml", 'w') { |f| f.write(config_yaml) }
170+ File . open ( "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/params.yml" , 'w' ) { |f | f . write ( config_yaml ) }
169171 else
170- File.open("#{ ciinaboxes_dir } /#{ ciinabox_name } /config/params.yml", 'w') { |f| f.write(input_result) }
172+ File . open ( "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/params.yml" , 'w' ) { |f | f . write ( input_result ) }
171173 end
172174
173175 default_services = YAML . load ( File . read ( "#{ current_dir } /config/default_services.yml" ) )
174176
175177 class ::Hash
176178 def deep_merge ( second )
177- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
179+ merger = proc { |key , v1 , v2 | Hash === v1 && Hash === v2 ? v1 . merge ( v2 , &merger ) : Array === v1 && Array === v2 ? v1 | v2 : [ :undefined , nil , :nil ] . include? ( v2 ) ? v1 : v2 }
178180 self . merge ( second . to_h , &merger )
179181 end
180182 end
@@ -184,10 +186,10 @@ namespace :ciinabox do
184186 user_services = YAML . load ( File . read ( "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/services.yml" ) )
185187 combined_services = default_services . deep_merge ( user_services )
186188 yml_combined_services = combined_services . to_yaml
187- File.open("#{ ciinaboxes_dir } /#{ ciinabox_name } /config/services.yml", 'w') { |f| f.write(yml_combined_services) }
189+ File . open ( "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/services.yml" , 'w' ) { |f | f . write ( yml_combined_services ) }
188190 else
189191 yml_default_services = default_services . to_yaml
190- File.open("#{ ciinaboxes_dir } /#{ ciinabox_name } /config/services.yml", 'w') { |f| f.write(yml_default_services) }
192+ File . open ( "#{ ciinaboxes_dir } /#{ ciinabox_name } /config/services.yml" , 'w' ) { |f | f . write ( yml_default_services ) }
191193 end
192194
193195 display_active_ciinabox ciinaboxes_dir , ciinabox_name
@@ -251,7 +253,7 @@ namespace :ciinabox do
251253 check_active_ciinabox ( config )
252254 ciinabox_name = config [ 'ciinabox_name' ]
253255 cert_dir = "#{ ciinaboxes_dir } /#{ ciinabox_name } "
254- status, result = aws_execute( config, [
256+ status , result = aws_execute ( config , [
255257 'iam' , 'upload-server-certificate' ,
256258 '--server-certificate-name ciinabox' ,
257259 "--certificate-body file://#{ cert_dir } /ssl/ciinabox.crt" ,
@@ -387,6 +389,13 @@ namespace :ciinabox do
387389 desc ( 'Package Lambda Functions as ZipFiles' )
388390 task :package_lambdas do
389391 check_active_ciinabox ( config )
392+
393+ # custom lambda modification
394+ lambda_stack_required = config [ 'acm_auto_issue_validate' ]
395+ # in future any new conditions for lambda stack would be added here
396+ # lambda_stack_required ||= some_new_condition
397+ config [ 'lambdas' ] = nil unless lambda_stack_required
398+
390399 if !config [ 'lambdas' ] . nil? && !config [ 'lambdas' ] [ 'functions' ] . nil?
391400 log_header 'Package lambda functions'
392401
@@ -513,7 +522,7 @@ namespace :ciinabox do
513522 '--out json'
514523 ] )
515524 resp = JSON . parse ( result )
516- cert_output = resp['Stacks'][0]['Outputs'].find { |k| k['OutputKey'] == 'DefaultSSLCertificate' }
525+ cert_output = resp [ 'Stacks' ] [ 0 ] [ 'Outputs' ] . find { |k | k [ 'OutputKey' ] == 'DefaultSSLCertificate' }
517526 if cert_output . nil?
518527 STDERR . puts ( "ACM certificate is not present in stack outputs" )
519528 exit -1
@@ -525,6 +534,64 @@ namespace :ciinabox do
525534 puts "Set #{ cert_arn } as default_cert_arn"
526535 end
527536
537+
538+ desc ( 'validate cloudformation templates' )
539+ task :validate do
540+ cfn = Aws ::CloudFormation ::Client . new ( region : config [ 'source_region' ] )
541+ s3 = Aws ::S3 ::Client . new ( region : config [ 'source_region' ] )
542+ Dir . glob ( "output/**/*.json" ) do |file |
543+ template_content = IO . read ( file )
544+ # Skip if empty template generated
545+ next if ( template_content == "null\n " )
546+ template = File . open ( file , 'rb' )
547+ filename = File . basename file
548+ template_bytesize = template_content . bytesize
549+ file_size = File . size file
550+ local_validation = ( template_content . bytesize < 51200 )
551+ puts "INFO - #{ file } : Filesize: #{ file_size } , Bytesize: #{ template_bytesize } , local validation: #{ local_validation } "
552+ begin
553+ if not local_validation
554+ puts "INFO - Copy #{ file } -> s3://#{ config [ 'source_bucket' ] } /cloudformation/#{ project_name } /validate/#{ filename } "
555+ s3 . put_object ( {
556+ body : template ,
557+ bucket : "#{ config [ 'source_bucket' ] } " ,
558+ key : "cloudformation/#{ project_name } /validate/#{ filename } " ,
559+ } )
560+ template_url = "https://#{ config [ 'source_bucket' ] } .s3.amazonaws.com/cloudformation/#{ project_name } /validate/#{ filename } "
561+ puts "INFO - Copied #{ file } to s3://#{ config [ 'source_bucket' ] } /cloudformation/#{ project_name } /validate/#{ filename } "
562+ puts "INFO - Validating #{ template_url } "
563+ else
564+ puts "INFO - Validating #{ file } "
565+ end
566+ begin
567+ resp = cfn . validate_template ( { template_url : template_url } ) unless local_validation
568+ resp = cfn . validate_template ( { template_body : template_content } ) if local_validation
569+ puts "INFO - Template #{ filename } validated successfully"
570+ rescue => e
571+ puts "ERROR - Template #{ filename } failed to validate: #{ e } "
572+ exit 1
573+ end
574+
575+ rescue => e
576+ puts "ERROR - #{ e . class } , #{ e } "
577+ exit 1
578+ end
579+ end
580+ puts "INFO - #{ Dir [ "output/**/*.json" ] . count } templates validated successfully"
581+ end
582+
583+ desc ( 'vendor templates from ciinabox gem into ciinabox folder' )
584+ task :vendor do
585+ Dir [ "#{ current_dir } /templates/**/*.rb" ] . each do |template_path |
586+ relative_path = template_path . gsub ( "#{ current_dir } /" , '' )
587+ target_path = "#{ @ciinaboxes_dir } /#{ @ciinabox_name } /#{ relative_path } "
588+ target_dir = File . dirname ( target_path )
589+ FileUtils . mkdir_p target_dir
590+ puts "#{ relative_path } -> #{ target_path } "
591+ FileUtils . copy template_path , target_path
592+ end
593+ end
594+
528595 def add_ciinabox_config_setting ( element , value )
529596 file_name = "#{ @ciinaboxes_dir } /#{ @ciinabox_name } /config/params.yml"
530597 File . write ( file_name ,
@@ -534,7 +601,7 @@ namespace :ciinabox do
534601 )
535602 end
536603
537- def remove_update_ciinabox_config_setting(element, new_value= '')
604+ def remove_update_ciinabox_config_setting ( element , new_value = '' )
538605 f = File . new ( "#{ @ciinaboxes_dir } /#{ @ciinabox_name } /config/params.yml" , 'r+' )
539606 found = false
540607 f . each do |line |
@@ -550,7 +617,7 @@ namespace :ciinabox do
550617 end
551618 end
552619 f . close
553- add_ciinabox_config_setting(element, new_value) if((not found) and (not new_value.empty?))
620+ add_ciinabox_config_setting ( element , new_value ) if ( ( not found ) and ( not new_value . empty? ) )
554621 end
555622
556623 def check_active_ciinabox ( config )
@@ -608,12 +675,12 @@ namespace :ciinabox do
608675 question = ( "#{ question } (y/n)? [#{ default ? 'y' : 'n' } ]" )
609676 while true
610677 case get_input ( question )
611- when ''
612- return default
613- when 'Y', 'y', 'yes'
614- return true
615- when /\A [nN]o?\Z / #n or no
616- return false
678+ when ''
679+ return default
680+ when 'Y' , 'y' , 'yes'
681+ return true
682+ when /\A [nN]o?\Z / #n or no
683+ return false
617684 end
618685 end
619686 end
0 commit comments