cfhighlander 0.8.2 → 0.9.0.alpha.1556659966
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +129 -1
- data/bin/cfhighlander.rb +3 -0
- data/cfndsl_ext/lambda_helper.rb +32 -16
- data/lib/cfhighlander.compiler.rb +43 -16
- data/lib/cfhighlander.version.rb +1 -1
- data/lib/util/zip.util.rb +1 -2
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 001df982a303f15386c95edefe223bb6d18e67adc357f0164b08f7b11b6735df
|
4
|
+
data.tar.gz: 287a98c600c8697d05b0439bfe44779022a32c48a48504d46d07f8fde61706ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 988727c8d0185cdd2f7b33c790156374e4e01aae50b5424bcb1072ae1f3f1bf53ff5b0c399c8daf4c610babe6fdd7872bd68ed48e93268b91e468b06dc33f0ab
|
7
|
+
data.tar.gz: 6f30346bb04ebdb05ddcd93ecdd618a00b959f72d35c5ced2aaddd39b937ccecc0e3462adffe749e04427f300ad3839c3ea9ce7b730a53460952cdd974e18870
|
data/README.md
CHANGED
@@ -653,12 +653,140 @@ so extension methods can be consumed within cfndsl template.
|
|
653
653
|
|
654
654
|
### LambdaFunctions
|
655
655
|
|
656
|
+
|
657
|
+
Cfhighlander supports following in terms of lambda source code management
|
658
|
+
|
659
|
+
- Package and deploy lambda that has source code published to s3 as zip archive
|
660
|
+
- Package and deploy lambda that has source code published to http(s) url
|
661
|
+
- Package and deploy lambda with absolute source code location, or relative to component
|
662
|
+
root directory
|
663
|
+
- When extending certain highlander component, of
|
664
|
+
- Execute arbitrary 'package command' before creating final archive. This allows for downloading
|
665
|
+
code dependencies
|
666
|
+
|
667
|
+
#### Configuration and rendering
|
668
|
+
|
669
|
+
Lambda functions are defined in cfhighlander templates using `LambdaFunctions` DSL statement:
|
670
|
+
|
671
|
+
```ruby
|
672
|
+
CfhighlanderTemplate do
|
673
|
+
Name 'my_app'
|
674
|
+
LambdaFunctions 'highlanderdocoexample'
|
675
|
+
end
|
676
|
+
```
|
677
|
+
|
678
|
+
In example above, `lambdas` - value passed to `LambdaFunctions` dsl statement is actually
|
679
|
+
cfhighlander component configuration key, under which lambda functions, and their respective
|
680
|
+
IAM roles are defined. Consider configuration below - all keys are commented with explanation
|
681
|
+
|
682
|
+
```yaml
|
683
|
+
highlanderdocoexample:
|
684
|
+
|
685
|
+
# custom policies can be referenced in roles
|
686
|
+
custom_policies:
|
687
|
+
cognito:
|
688
|
+
action:
|
689
|
+
- cognito-idp:*
|
690
|
+
resource: '*'
|
691
|
+
|
692
|
+
# at least one role must be defined
|
693
|
+
roles:
|
694
|
+
default:
|
695
|
+
# using one of the default policies, or custom policies defined above
|
696
|
+
# defined at https://github.com/theonestack/cfhighlander/blob/develop/cfndsl_ext/config/managed_policies.yaml
|
697
|
+
policies_inline:
|
698
|
+
- cloudwatch-logs
|
699
|
+
- cognito
|
700
|
+
|
701
|
+
# managed IAM policies are supported as well
|
702
|
+
policies_managed:
|
703
|
+
- arn:aws:iam::aws:policy/IAMReadOnlyAccess
|
704
|
+
- Fn::Sub: 'arn:aws:iam::${AWS::AccountId}:policy/my_app_policy'
|
705
|
+
|
706
|
+
# you can have multiple functions defined, each as key under 'functions'
|
707
|
+
functions:
|
708
|
+
myapp:
|
709
|
+
|
710
|
+
# link to a role key above defined - mandatory
|
711
|
+
role: default
|
712
|
+
|
713
|
+
# code location. Can be file, archive, s3://url or http(s)://url.
|
714
|
+
# mandatory configuration option
|
715
|
+
code: src/app.py
|
716
|
+
|
717
|
+
# lambda runtime
|
718
|
+
runtime: python3.6
|
719
|
+
|
720
|
+
# functions that are not named are having their name auto generated via cloudformation
|
721
|
+
# this key defaults to false if not given
|
722
|
+
named: true
|
723
|
+
|
724
|
+
# if function is named, either top level key (myapp) will be used, or explicit name
|
725
|
+
# this key is optional, and used only if named: is set to true
|
726
|
+
function_name:
|
727
|
+
Fn::Sub: '${EnvironmentName}-myapp-${EnvironmentVersion}'
|
728
|
+
|
729
|
+
# function timeout (defaults to 30)
|
730
|
+
timeout: 30
|
731
|
+
|
732
|
+
# lambda function entrypoint
|
733
|
+
handler: app.index
|
734
|
+
|
735
|
+
# command to install any dependencies (optional)
|
736
|
+
# if you don't want to get prompted for every command execution use -q (quiet) option
|
737
|
+
package_cmd: 'pip3 install -r requirements.txt -t .'
|
738
|
+
|
739
|
+
# (optional) allowed source. e.g. invocation using SNS
|
740
|
+
# for every allowed source, source_arn can be provided optionally
|
741
|
+
allowed_sources:
|
742
|
+
-
|
743
|
+
principal: sns.amazonaws.com
|
744
|
+
-
|
745
|
+
principal: sns.amazonaws.com
|
746
|
+
source_arn: arn:aws:sns:us-east-2:123456789012:my-topic
|
747
|
+
|
748
|
+
# (optional) invoke function on a schedule, with optional payload
|
749
|
+
schedules:
|
750
|
+
- cronExpression: 'rate(1 minute)'
|
751
|
+
payload: '{ "message": "ping" }'
|
752
|
+
```
|
753
|
+
|
754
|
+
|
656
755
|
#### Packaging and publishing
|
657
756
|
|
658
|
-
|
757
|
+
During cfhighlander compilation process, every defined lambda functio goes through process
|
758
|
+
of packaging:
|
759
|
+
|
760
|
+
- If s3 URI or http(s) uri is given as function code, it is being downloaded
|
761
|
+
- Temporary packaging directory is created
|
762
|
+
- If `package_cmd` key is given, this command is being executed in temporary directory
|
763
|
+
- Whole temporary directory is compressed and moved to `out/lambdas/$function.$timestamp.zip`
|
764
|
+
- Sha256 hash is calculated for given file and rendered into cloudformation as function
|
765
|
+
version
|
766
|
+
- Packaging information is rendered into `out/lambdas/$function.$timestamp.zip.info.yaml`
|
767
|
+
and added to final archive
|
768
|
+
|
769
|
+
Any archive with `*.zip` extension will be uploaded to s3 with `cfpublish` command
|
770
|
+
|
659
771
|
|
660
772
|
#### Referencing
|
661
773
|
|
774
|
+
As all of the lambda functions are rendered as cloudformation resources, they can be
|
775
|
+
referenced in other blocks. E.g. with example above, application component could have
|
776
|
+
following output defined in component's cfndsl file
|
777
|
+
|
778
|
+
```ruby
|
779
|
+
# myapp.cfndsl.rb
|
780
|
+
CloudFormation do
|
781
|
+
|
782
|
+
Output('MyAppFunctionName') do
|
783
|
+
Value(Ref('myapp'))
|
784
|
+
end
|
785
|
+
|
786
|
+
end
|
787
|
+
|
788
|
+
|
789
|
+
```
|
662
790
|
|
663
791
|
## Finding templates and creating components
|
664
792
|
|
data/bin/cfhighlander.rb
CHANGED
@@ -39,6 +39,7 @@ class HighlanderCli < Thor
|
|
39
39
|
|
40
40
|
# compile cfndsl template
|
41
41
|
component_compiler = Cfhighlander::Compiler::ComponentCompiler.new(component)
|
42
|
+
component_compiler.clear_out_dir
|
42
43
|
component_compiler.writeConfig(true)
|
43
44
|
end
|
44
45
|
|
@@ -59,6 +60,7 @@ class HighlanderCli < Thor
|
|
59
60
|
|
60
61
|
# compile cfndsl template
|
61
62
|
component_compiler = Cfhighlander::Compiler::ComponentCompiler.new(component)
|
63
|
+
component_compiler.clear_out_dir
|
62
64
|
component_compiler.silent_mode = options[:quiet]
|
63
65
|
out_format = options[:format]
|
64
66
|
component_compiler.compileCfnDsl out_format
|
@@ -102,6 +104,7 @@ class HighlanderCli < Thor
|
|
102
104
|
|
103
105
|
# compile cloud formation
|
104
106
|
component_compiler = Cfhighlander::Compiler::ComponentCompiler.new(component)
|
107
|
+
component_compiler.clear_out_dir
|
105
108
|
component_compiler.silent_mode = options[:quiet]
|
106
109
|
out_format = options[:format]
|
107
110
|
component_compiler.compileCloudFormation out_format
|
data/cfndsl_ext/lambda_helper.rb
CHANGED
@@ -43,7 +43,11 @@ def render_lambda_functions(cfndsl, lambdas, lambda_metadata, distribution)
|
|
43
43
|
end
|
44
44
|
|
45
45
|
if !lambda_config['named'].nil? && lambda_config['named']
|
46
|
-
|
46
|
+
if lambda_config['function_name'].nil?
|
47
|
+
FunctionName(name)
|
48
|
+
else
|
49
|
+
FunctionName(lambda_config['function_name'])
|
50
|
+
end
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
@@ -53,6 +57,33 @@ def render_lambda_functions(cfndsl, lambdas, lambda_metadata, distribution)
|
|
53
57
|
CodeSha256(lambda_metadata['sha256'][key])
|
54
58
|
end
|
55
59
|
|
60
|
+
# Scheduled triggering of lambda function
|
61
|
+
if lambda_config.key?('schedules')
|
62
|
+
lambda_config['schedules'].each_with_index do |schedule, index|
|
63
|
+
Events_Rule("Lambda#{name}Schedule#{index}") do
|
64
|
+
if schedule['cronExpression'].include?('rate')
|
65
|
+
then
|
66
|
+
expression = schedule['cronExpression']
|
67
|
+
else
|
68
|
+
expression = "cron(#{schedule['cronExpression']})"
|
69
|
+
end
|
70
|
+
ScheduleExpression(expression)
|
71
|
+
State('ENABLED')
|
72
|
+
target = {
|
73
|
+
'Arn' => FnGetAtt(name, 'Arn'), 'Id' => "lambda#{name}",
|
74
|
+
}
|
75
|
+
target['Input'] = schedule['payload'] if schedule.key?('payload')
|
76
|
+
Targets([target])
|
77
|
+
end
|
78
|
+
Lambda_Permission("Lambda#{name}Schedule#{index}Permission") do
|
79
|
+
FunctionName(Ref(name))
|
80
|
+
Action('lambda:InvokeFunction')
|
81
|
+
Principal('events.amazonaws.com')
|
82
|
+
SourceArn FnGetAtt("Lambda#{name}Schedule#{index}", 'Arn')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
56
87
|
# Generate lambda function Policy
|
57
88
|
unless lambda_config['allowed_sources'].nil?
|
58
89
|
i = 1
|
@@ -69,21 +100,6 @@ def render_lambda_functions(cfndsl, lambdas, lambda_metadata, distribution)
|
|
69
100
|
end
|
70
101
|
end
|
71
102
|
|
72
|
-
# Scheduled triggering of lambda function
|
73
|
-
if lambda_config.key?('schedules')
|
74
|
-
lambda_config['schedules'].each_with_index do |schedule, index|
|
75
|
-
Events_Rule("Lambda#{name}Schedule#{index}") do
|
76
|
-
ScheduleExpression("cron(#{schedule['cronExpression']})")
|
77
|
-
State('ENABLED')
|
78
|
-
target = {
|
79
|
-
'Arn' => FnGetAtt(name, 'Arn'), 'Id' => "lambda#{name}",
|
80
|
-
}
|
81
|
-
target['Input'] = schedule['payload'] if schedule.key?('payload')
|
82
|
-
Targets([target])
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
103
|
|
88
104
|
end
|
89
105
|
end
|
@@ -51,7 +51,7 @@ module Cfhighlander
|
|
51
51
|
|
52
52
|
if @@global_extensions_paths.empty?
|
53
53
|
global_extensions_folder = "#{File.dirname(__FILE__)}/../cfndsl_ext"
|
54
|
-
Dir["#{global_extensions_folder}/*.rb"].each {|f| @@global_extensions_paths << f}
|
54
|
+
Dir["#{global_extensions_folder}/*.rb"].each { |f| @@global_extensions_paths << f }
|
55
55
|
end
|
56
56
|
|
57
57
|
@component.highlander_dsl.subcomponents.each do |sub_component|
|
@@ -61,14 +61,19 @@ module Cfhighlander
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
def clear_out_dir
|
65
|
+
# Clear previous packages
|
66
|
+
FileUtils.rmtree "#{@workdir}/out/"
|
67
|
+
end
|
68
|
+
|
64
69
|
def process_lambdas=(value)
|
65
70
|
@process_lambdas = value
|
66
|
-
@sub_components.each {|scc| scc.process_lambdas = value}
|
71
|
+
@sub_components.each { |scc| scc.process_lambdas = value }
|
67
72
|
end
|
68
73
|
|
69
74
|
def silent_mode=(value)
|
70
75
|
@silent_mode = value
|
71
|
-
@sub_components.each {|scc| scc.silent_mode = value}
|
76
|
+
@sub_components.each { |scc| scc.silent_mode = value }
|
72
77
|
end
|
73
78
|
|
74
79
|
def compileCfnDsl(out_format)
|
@@ -77,7 +82,7 @@ module Cfhighlander
|
|
77
82
|
dsl = @component.highlander_dsl
|
78
83
|
component_cfndsl = @component.cfndsl_content
|
79
84
|
|
80
|
-
@component.highlander_dsl.subcomponents.each {|sc|
|
85
|
+
@component.highlander_dsl.subcomponents.each { |sc|
|
81
86
|
sc.distribution_format = out_format
|
82
87
|
}
|
83
88
|
|
@@ -91,7 +96,7 @@ module Cfhighlander
|
|
91
96
|
'component_cfndsl' => component_cfndsl,
|
92
97
|
'component_requires' => (@@global_extensions_paths + @component.cfndsl_ext_files),
|
93
98
|
'distribution_format' => out_format
|
94
|
-
}).instance_eval {binding})
|
99
|
+
}).instance_eval { binding })
|
95
100
|
|
96
101
|
# write to output file
|
97
102
|
output_dir = "#{@workdir}/out/cfndsl"
|
@@ -102,7 +107,7 @@ module Cfhighlander
|
|
102
107
|
puts "cfndsl template for #{dsl.name} written to #{output_path}"
|
103
108
|
@cfndsl_compiled_path = output_path
|
104
109
|
|
105
|
-
@sub_components.each {|subcomponent_compiler|
|
110
|
+
@sub_components.each { |subcomponent_compiler|
|
106
111
|
puts "Rendering sub-component cfndsl: #{subcomponent_compiler.component_name}"
|
107
112
|
subcomponent_compiler.compileCfnDsl out_format
|
108
113
|
}
|
@@ -230,9 +235,6 @@ module Cfhighlander
|
|
230
235
|
|
231
236
|
def generateSourceArchives
|
232
237
|
|
233
|
-
# Clear previous packages
|
234
|
-
FileUtils.rmtree "#{@workdir}/output/lambdas"
|
235
|
-
|
236
238
|
archive_paths = []
|
237
239
|
|
238
240
|
# Cached downloads map
|
@@ -299,13 +301,27 @@ module Cfhighlander
|
|
299
301
|
# zip local code
|
300
302
|
component = @component
|
301
303
|
component_dir = component.template.template_location
|
302
|
-
|
303
|
-
|
304
|
+
full_path_candidate_1 = "#{component_dir}/lambdas/#{lambda_config['code']}"
|
305
|
+
full_path_candidate_2 = "#{component_dir}/#{lambda_config['code']}"
|
306
|
+
full_path_candidate_3 = lambda_config['code']
|
307
|
+
full_path = full_path_candidate_1
|
308
|
+
full_path = full_path_candidate_2 if (File.exist? full_path_candidate_2 and (not File.exist? full_path))
|
309
|
+
full_path = full_path_candidate_3 if (File.exist? full_path_candidate_3 and (not File.exist? full_path))
|
310
|
+
|
311
|
+
# if component extends another component, both parent and child paths should be taken in
|
312
|
+
# consideration
|
304
313
|
until (File.exist? full_path or component_dir.nil?)
|
305
314
|
parent_exists = (not component.extended_component.nil?)
|
306
315
|
component = component.extended_component if parent_exists
|
307
316
|
component_dir = component.template.template_location if parent_exists
|
308
|
-
|
317
|
+
full_path_candidate_1 = "#{component_dir}/lambdas/#{lambda_config['code']}" if parent_exists
|
318
|
+
full_path_candidate_2 = "#{component_dir}/#{lambda_config['code']}" if parent_exists
|
319
|
+
full_path_candidate_3 = "#{lambda_config['code']}" if parent_exists
|
320
|
+
|
321
|
+
full_path = full_path_candidate_1
|
322
|
+
full_path = full_path_candidate_2 if (File.exist? full_path_candidate_2 and (not File.exist? full_path))
|
323
|
+
full_path = full_path_candidate_3 if (File.exist? full_path_candidate_3 and (not File.exist? full_path))
|
324
|
+
|
309
325
|
component_dir = nil unless parent_exists
|
310
326
|
end
|
311
327
|
if component_dir.nil?
|
@@ -343,9 +359,14 @@ module Cfhighlander
|
|
343
359
|
end
|
344
360
|
end
|
345
361
|
File.delete full_destination_path if File.exist? full_destination_path
|
346
|
-
zip_generator = Cfhighlander::Util::ZipFileGenerator.new(lambda_source_dir, full_destination_path)
|
347
|
-
zip_generator.write
|
348
362
|
|
363
|
+
# if source is already zip file, just add manifest to it
|
364
|
+
if full_path.end_with? '.zip'
|
365
|
+
FileUtils.copy full_path, full_destination_path
|
366
|
+
else
|
367
|
+
zip_generator = Cfhighlander::Util::ZipFileGenerator.new(lambda_source_dir, full_destination_path)
|
368
|
+
zip_generator.write
|
369
|
+
end
|
349
370
|
end
|
350
371
|
end
|
351
372
|
# add version information to avoid same package ever deployed 2 times
|
@@ -357,13 +378,19 @@ module Cfhighlander
|
|
357
378
|
puts "INFO | Lambda #{name} | Created zip package #{full_destination_path} with digest #{sha256}"
|
358
379
|
@metadata['sha256'][name] = sha256
|
359
380
|
@metadata['version'][name] = timestamp
|
360
|
-
end
|
381
|
+
end if ((not @lambda_config.nil?) and @lambda_config.key? 'functions')
|
361
382
|
|
362
383
|
return archive_paths
|
363
384
|
end
|
364
385
|
|
365
386
|
def mergeComponentConfig
|
366
|
-
@component.config
|
387
|
+
if @component.config.key? 'lambda_metadata'
|
388
|
+
@metadata.each do |mk,mh|
|
389
|
+
mh.each do |k,v| @component.config['lambda_metadata'][mk][k] = v end
|
390
|
+
end
|
391
|
+
else
|
392
|
+
@component.config['lambda_metadata'] = @metadata
|
393
|
+
end
|
367
394
|
end
|
368
395
|
|
369
396
|
end
|
data/lib/cfhighlander.version.rb
CHANGED
data/lib/util/zip.util.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'zip'
|
2
2
|
|
3
|
-
|
4
3
|
module Cfhighlander
|
5
4
|
module Util
|
6
5
|
###
|
@@ -18,7 +17,7 @@ module Cfhighlander
|
|
18
17
|
def write
|
19
18
|
entries = Dir.entries(@input_dir) - %w(. ..)
|
20
19
|
puts "DEBUG: Compressing #{@input_dir} to #{@output_file}"
|
21
|
-
|
20
|
+
Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile|
|
22
21
|
write_entries entries, '', zipfile
|
23
22
|
end
|
24
23
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cfhighlander
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0.alpha.1556659966
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nikola Tosic
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2019-
|
13
|
+
date: 2019-04-30 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: highline
|
@@ -297,11 +297,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
297
297
|
version: '0'
|
298
298
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
299
299
|
requirements:
|
300
|
-
- - "
|
300
|
+
- - ">"
|
301
301
|
- !ruby/object:Gem::Version
|
302
|
-
version:
|
302
|
+
version: 1.3.1
|
303
303
|
requirements: []
|
304
|
-
rubygems_version: 3.0.
|
304
|
+
rubygems_version: 3.0.3
|
305
305
|
signing_key:
|
306
306
|
specification_version: 4
|
307
307
|
summary: DSL on top of cfndsl. Manage libraries of cloudformation components
|