cumuliform 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: abff1bdeb60a617a79f889e191789cc21dee2335
4
- data.tar.gz: 8320b16dd011e3155aaeef164a4dce008634e46d
3
+ metadata.gz: 2078446f4607d50e1623eab3072e964341ab06b2
4
+ data.tar.gz: 96c0569cfaeb8f991b878364b27defdf210753ef
5
5
  SHA512:
6
- metadata.gz: 49b1742f90f29be0daacbd3c452cdda449100bc452ec831466661639c8fc28402e2cbdf833a04c5d4cecf1eeee97e4ccd03bf4717943032a4eb2813c407df54c
7
- data.tar.gz: 20147ec9d4c9790d2ac5fc5fb78c5f3126582e2ed7c86c698be3bf25b6b7cf49bc625759e7a2e07d93309510fc1dba25f714ca1a2dc573e53eb514cce13f26f4
6
+ metadata.gz: a0bed284a17feef9d26083b3967579d9d78714229b9992905210bcc626142f864358dd6aeab3b49676f72558c977c4712b13ef56c1e6d5662426201245b8936c
7
+ data.tar.gz: e67caccb78bc3d10dad37d96e50db5e4d1e88713e863468af79f3c1151e727e1d6c35e159356c50fdf7eea455d271b218f6b7c616bd5cd2b3d130dc94ccc256c
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.2
1
+ 2.3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
+ ## Unreleased
6
+ ### Changed
7
+ - Internal refactor of code / file structure to more clearly separate DSL and
8
+ domain objects
9
+
5
10
  ## [0.5.1] - 2015-12-03
6
11
  ### Changed
7
12
  - Make some fragment-related functions private
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Cumuliform
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/cumuliform.svg)](http://badge.fury.io/rb/cumuliform) [![Build Status](https://travis-ci.org/tape-tv/cumuliform.svg?branch=master)](https://travis-ci.org/tape-tv/cumuliform) [![Code Climate](https://codeclimate.com/github/tape-tv/cumuliform/badges/gpa.svg)](https://codeclimate.com/github/tape-tv/cumuliform) [![Test Coverage](https://codeclimate.com/github/tape-tv/cumuliform/badges/coverage.svg)](https://codeclimate.com/github/tape-tv/cumuliform/coverage)
3
+ [![Gem Version](https://badge.fury.io/rb/cumuliform.svg)](http://badge.fury.io/rb/cumuliform) [![Build Status](https://travis-ci.org/tape-tv/cumuliform.svg?branch=master)](https://travis-ci.org/tape-tv/cumuliform) [![Code Climate](https://codeclimate.com/github/tape-tv/cumuliform/badges/gpa.svg)](https://codeclimate.com/github/tape-tv/cumuliform) [![Test Coverage](https://codeclimate.com/github/tape-tv/cumuliform/badges/coverage.svg)](https://codeclimate.com/github/tape-tv/cumuliform/coverage) [![Documentation](https://inch-ci.org/github/tape-tv/cumuliform.svg?branch=master)]
4
4
 
5
5
  Amazon’s [CloudFormation AWS service][cf] provides a way to describe
6
6
  infrastructure stacks using a JSON template. We love CloudFormation, and use it
@@ -772,11 +772,376 @@ And the output:
772
772
  ```
773
773
 
774
774
  ## Importing other templates
775
- _TODO_
775
+ If you want to share complete resources, or fragments, between different
776
+ templates then you can import one template into another. All the imported
777
+ template's resources will be available to you, and you can override template
778
+ parts (i.e. a parameter) or even fragments simply be defining them again in the
779
+ importing template.
780
+
781
+ To import a template, you simply `require` it as you would any other ruby file,
782
+ and then use Cumuliform's `import` method to import it.
783
+
784
+ This is easier to explain with an example. Take this very simple example,
785
+ defining a single `AWS::EC2::Instance` in a `resource`, and a `parameter` that
786
+ controls the AMI it uses:
787
+
788
+ ```ruby
789
+ BaseTemplate = Cumuliform.template do
790
+ parameter 'AMI' do
791
+ {
792
+ Description: 'The AMI id for our template (defaults to the stock Ubuntu 14.04 image in eu-central-1)',
793
+ Type: 'String',
794
+ Default: 'ami-accff2b1'
795
+ }
796
+ end
797
+
798
+ resource 'MyInstance' do
799
+ {
800
+ Type: 'AWS::EC2::Instance',
801
+ Properties: {
802
+ ImageId: ref('AMI'),
803
+ InstanceType: 'm3.medium'
804
+ }
805
+ }
806
+ end
807
+ end
808
+ ```
809
+
810
+ It generates the following JSON (as expected):
811
+
812
+ ```
813
+ {
814
+ "Parameters": {
815
+ "AMI": {
816
+ "Description": "The AMI id for our template (defaults to the stock Ubuntu 14.04 image in eu-central-1)",
817
+ "Type": "String",
818
+ "Default": "ami-accff2b1"
819
+ }
820
+ },
821
+ "Resources": {
822
+ "MyInstance": {
823
+ "Type": "AWS::EC2::Instance",
824
+ "Properties": {
825
+ "ImageId": {
826
+ "Ref": "AMI"
827
+ },
828
+ "InstanceType": "m3.medium"
829
+ }
830
+ }
831
+ }
832
+ }
833
+ ```
834
+
835
+ Say we to change the default AMI parameter but reuse everything else. We can
836
+ import that template and redefine the `parameter`:
837
+
838
+ ```ruby
839
+ require_relative './import-base.rb'
840
+
841
+ Cumuliform.template do
842
+ import BaseTemplate
843
+
844
+ parameter 'AMI' do
845
+ {
846
+ Description: 'A different AMI',
847
+ Type: 'String',
848
+ Default: 'ami-DIFFERENT'
849
+ }
850
+ end
851
+ end
852
+ ```
853
+
854
+ That produces the following JSON:
855
+
856
+ ```
857
+ {
858
+ "Parameters": {
859
+ "AMI": {
860
+ "Description": "A different AMI",
861
+ "Type": "String",
862
+ "Default": "ami-DIFFERENT"
863
+ }
864
+ },
865
+ "Resources": {
866
+ "MyInstance": {
867
+ "Type": "AWS::EC2::Instance",
868
+ "Properties": {
869
+ "ImageId": {
870
+ "Ref": "AMI"
871
+ },
872
+ "InstanceType": "m3.medium"
873
+ }
874
+ }
875
+ }
876
+ }
877
+ ```
878
+
879
+ There are a couple of very important points to note: First, we have to
880
+ `require` the base template (exactly as you require any ruby file). Second, we
881
+ have to assign the result of calling `Cumuliform.template` to a constant so
882
+ that it is available once we've required the file.
883
+
884
+ In the importing template, once we have `require`d the base template, we pass
885
+ the constant containing the base template to the `import` DSL method.
886
+
887
+ ## Importing fragments
888
+ Fragments defined in a template are also available when imported. You can
889
+ override fragments in the importing template as you would override a resource.
890
+
891
+ Here's a base template that defines several fragments (shown with the JSON it
892
+ generates).
893
+
894
+ ```ruby
895
+ FragmentBaseTemplate = Cumuliform.template do
896
+ def_fragment(:ami_param) do |opts|
897
+ parameter 'AMI' do
898
+ {
899
+ Description: 'AMI id',
900
+ Type: 'String',
901
+ Default: opts[:ami_id]
902
+ }
903
+ end
904
+ end
905
+
906
+ def_fragment(:instance_type) do |opts|
907
+ parameter 'InstanceType' do
908
+ {
909
+ Description: 'InstanceType',
910
+ Type: 'String',
911
+ Default: opts[:type],
912
+ AllowedValues: ['t2.small', 't2.medium', 't2.large']
913
+ }
914
+ end
915
+ end
916
+
917
+ def_fragment(:instance) do |opts|
918
+ resource 'MyInstance' do
919
+ {
920
+ Type: 'AWS::EC2::Instance',
921
+ Properties: {
922
+ ImageId: ref('AMI'),
923
+ InstanceType: ref('InstanceType')
924
+ }
925
+ }
926
+ end
927
+ end
928
+
929
+ fragment(:ami_param, ami_id: 'ami-accff2b1')
930
+ fragment(:instance_type, type: 't2.medium')
931
+ fragment(:instance)
932
+ end
933
+ ```
934
+
935
+ ```
936
+ {
937
+ "Parameters": {
938
+ "AMI": {
939
+ "Description": "AMI id",
940
+ "Type": "String",
941
+ "Default": "ami-accff2b1"
942
+ },
943
+ "InstanceType": {
944
+ "Description": "InstanceType",
945
+ "Type": "String",
946
+ "Default": "m4.medium",
947
+ "AllowedValues": [
948
+ "t2.small",
949
+ "t2.medium",
950
+ "t2.large"
951
+ ]
952
+ }
953
+ },
954
+ "Resources": {
955
+ "MyInstance": {
956
+ "Type": "AWS::EC2::Instance",
957
+ "Properties": {
958
+ "ImageId": {
959
+ "Ref": "AMI"
960
+ },
961
+ "InstanceType": {
962
+ "Ref": "InstanceType"
963
+ }
964
+ }
965
+ }
966
+ }
967
+ }
968
+ ```
969
+
970
+ An importing template can use, or override, the fragments exactly as with any
971
+ other resource:
972
+
973
+ ```ruby
974
+ require_relative './import-fragments-base.rb'
975
+
976
+ Cumuliform.template do
977
+ import FragmentBaseTemplate
978
+
979
+ def_fragment(:instance_type) do |opts|
980
+ parameter 'InstanceType' do
981
+ {
982
+ Description: 'InstanceType',
983
+ Type: 'String',
984
+ Default: opts[:type],
985
+ AllowedValues: ['m3.medium', 'm4.large', 'm4.xlarge']
986
+ }
987
+ end
988
+ end
989
+
990
+ fragment(:instance_type, type: 'm3.medium')
991
+ end
992
+ ```
993
+
994
+ ```
995
+ {
996
+ "Parameters": {
997
+ "AMI": {
998
+ "Description": "AMI id",
999
+ "Type": "String",
1000
+ "Default": "ami-accff2b1"
1001
+ },
1002
+ "InstanceType": {
1003
+ "Description": "InstanceType",
1004
+ "Type": "String",
1005
+ "Default": "m3.medium",
1006
+ "AllowedValues": [
1007
+ "m3.medium",
1008
+ "m4.large",
1009
+ "m4.xlarge"
1010
+ ]
1011
+ }
1012
+ },
1013
+ "Resources": {
1014
+ "MyInstance": {
1015
+ "Type": "AWS::EC2::Instance",
1016
+ "Properties": {
1017
+ "ImageId": {
1018
+ "Ref": "AMI"
1019
+ },
1020
+ "InstanceType": {
1021
+ "Ref": "InstanceType"
1022
+ }
1023
+ }
1024
+ }
1025
+ }
1026
+ }
1027
+ ```
1028
+
1029
+ We redefined the fragment so the allowed values for instance type allowed the
1030
+ instance type we wanted to use. (Using the fragments in the base template is a
1031
+ bit weird, and not really recommended - it's included here to warn you...)
1032
+
1033
+
1034
+ ## Assigning templates to constants, namespaces, and processing
1035
+ The `Cumuliform.template` method returns a template object directly. So, to
1036
+ make a template that can be imported into another template you need to assign
1037
+ it to a variable or constant.
1038
+
1039
+ If you want to be able to directly process your base templates (instead of only
1040
+ using them by importing them into another template), then you also need to make
1041
+ sure your file returns the template when it's run. The runner works by
1042
+ `class_eval`ing your template file as a string and expecting that the result of
1043
+ that call will be an instance of `Cumuliform::Template`. If you use namespaces
1044
+ for your template objects (as you might if you have several base templates)
1045
+ then you need to be careful of that: the last line in your template must be
1046
+ something that returns the template. If you're nesting within modules, then the
1047
+ call to `module` will return `nil`, not the template. Instead, return the
1048
+ template as the last line:
1049
+
1050
+ ```
1051
+ module Stacks
1052
+ Base = Cumuliform.template do
1053
+ ...
1054
+ end
1055
+ end
1056
+
1057
+ Stacks::Base
1058
+ ```
776
1059
 
777
1060
  ## Helpers
778
- _TODO_
1061
+ Because templates are actually instances, not classes or modules, you can't
1062
+ simply `include` a mixin module. Cumuliform provides a `helpers` DSL method
1063
+ that allows you pass in modules, or block containing helper methods, that will
1064
+ be made available to the template:
1065
+
1066
+ ```ruby
1067
+ Cumuliform.template do
1068
+ helpers do
1069
+ def ami
1070
+ 'ami-accff2b1'
1071
+ end
1072
+ end
1073
+
1074
+ resource 'MyInstance' do
1075
+ {
1076
+ Type: 'AWS::EC2::Instance',
1077
+ Properties: {
1078
+ ImageId: ami,
1079
+ InstanceType: 'm3.medium'
1080
+ }
1081
+ }
1082
+ end
1083
+ end
1084
+ ```
1085
+
1086
+ Which evaluates to:
1087
+
1088
+ ```
1089
+ {
1090
+ "Resources": {
1091
+ "MyInstance": {
1092
+ "Type": "AWS::EC2::Instance",
1093
+ "Properties": {
1094
+ "ImageId": "ami-accff2b1",
1095
+ "InstanceType": "m3.medium"
1096
+ }
1097
+ }
1098
+ }
1099
+ }
1100
+ ```
1101
+
1102
+ Or using a module:
1103
+
1104
+ ```ruby
1105
+ module AmiHelper
1106
+ def ami
1107
+ 'ami-accff2b1'
1108
+ end
1109
+ end
1110
+
1111
+ Cumuliform.template do
1112
+ helpers AmiHelper
1113
+
1114
+ resource 'MyInstance' do
1115
+ {
1116
+ Type: 'AWS::EC2::Instance',
1117
+ Properties: {
1118
+ ImageId: ami,
1119
+ InstanceType: 'm3.medium'
1120
+ }
1121
+ }
1122
+ end
1123
+ end
1124
+ ```
1125
+
1126
+ Which also evaluates to:
1127
+
1128
+ ```
1129
+ {
1130
+ "Resources": {
1131
+ "MyInstance": {
1132
+ "Type": "AWS::EC2::Instance",
1133
+ "Properties": {
1134
+ "ImageId": "ami-accff2b1",
1135
+ "InstanceType": "m3.medium"
1136
+ }
1137
+ }
1138
+ }
1139
+ }
1140
+ ```
779
1141
 
1142
+ Helper methods are not able to access any methods on the template (like
1143
+ `resource`), they're really for wrapping complex external calls (for example, a
1144
+ class that fetches an API token you need to use in your template).
780
1145
 
781
1146
  # Development
782
1147
 
@@ -0,0 +1,17 @@
1
+ Cumuliform.template do
2
+ helpers do
3
+ def ami
4
+ 'ami-accff2b1'
5
+ end
6
+ end
7
+
8
+ resource 'MyInstance' do
9
+ {
10
+ Type: 'AWS::EC2::Instance',
11
+ Properties: {
12
+ ImageId: ami,
13
+ InstanceType: 'm3.medium'
14
+ }
15
+ }
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ BaseTemplate = Cumuliform.template do
2
+ parameter 'AMI' do
3
+ {
4
+ Description: 'The AMI id for our template (defaults to the stock Ubuntu 14.04 image in eu-central-1)',
5
+ Type: 'String',
6
+ Default: 'ami-accff2b1'
7
+ }
8
+ end
9
+
10
+ resource 'MyInstance' do
11
+ {
12
+ Type: 'AWS::EC2::Instance',
13
+ Properties: {
14
+ ImageId: ref('AMI'),
15
+ InstanceType: 'm3.medium'
16
+ }
17
+ }
18
+ end
19
+ end