topo-provision 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +100 -0
  4. data/bin/topo-provision +23 -0
  5. data/lib/topo/converter.rb +80 -0
  6. data/lib/topo/converter/cloudformation/converter.rb +219 -0
  7. data/lib/topo/exporter.rb +15 -0
  8. data/lib/topo/loader.rb +31 -0
  9. data/lib/topo/provision.rb +3 -0
  10. data/lib/topo/provision/aws/generator.rb +55 -0
  11. data/lib/topo/provision/aws/generators/aws_auto_scaling_group.rb +61 -0
  12. data/lib/topo/provision/aws/generators/aws_launch_configuration.rb +65 -0
  13. data/lib/topo/provision/aws/generators/context.rb +33 -0
  14. data/lib/topo/provision/aws/generators/load_balancer.rb +47 -0
  15. data/lib/topo/provision/aws/generators/machine.rb +36 -0
  16. data/lib/topo/provision/aws/generators/machine_image.rb +38 -0
  17. data/lib/topo/provision/aws/generators/node_group.rb +64 -0
  18. data/lib/topo/provision/cli.rb +95 -0
  19. data/lib/topo/provision/generator.rb +185 -0
  20. data/lib/topo/provision/generators/chef_node.rb +35 -0
  21. data/lib/topo/provision/generators/context.rb +70 -0
  22. data/lib/topo/provision/generators/load_balancer.rb +40 -0
  23. data/lib/topo/provision/generators/machine.rb +50 -0
  24. data/lib/topo/provision/generators/machine_image.rb +43 -0
  25. data/lib/topo/provision/generators/node_group.rb +74 -0
  26. data/lib/topo/provision/generators/resource.rb +91 -0
  27. data/lib/topo/provision/generators/templates/context.erb +8 -0
  28. data/lib/topo/provision/generators/templates/machine_deploy.erb +11 -0
  29. data/lib/topo/provision/generators/templates/machine_stop.erb +5 -0
  30. data/lib/topo/provision/generators/templates/node_group_action.erb +6 -0
  31. data/lib/topo/provision/generators/templates/node_group_deploy.erb +5 -0
  32. data/lib/topo/provision/generators/templates/resource_deploy.erb +5 -0
  33. data/lib/topo/provision/generators/templates/resource_undeploy.erb +5 -0
  34. data/lib/topo/provision/topology_generator.rb +84 -0
  35. data/lib/topo/provision/vagrant/generator.rb +33 -0
  36. data/lib/topo/provision/version.rb +5 -0
  37. data/lib/topo/topology.rb +61 -0
  38. data/lib/topo/utils/output.rb +31 -0
  39. data/lib/topo/utils/parsegen.rb +101 -0
  40. metadata +126 -0
@@ -0,0 +1,95 @@
1
+ #
2
+ # Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
3
+ # Copyright:: Copyright (c) 2015 ThirdWave Insights LLC
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'mixlib/cli'
20
+ require 'topo/provision'
21
+
22
+ module Topo
23
+ module Provision
24
+ class CLI
25
+ include Mixlib::CLI
26
+
27
+ banner('Usage: topo-provision topofile [option]')
28
+
29
+ option :format,
30
+ long: '--format topo|cloudformation',
31
+ description: 'Specifies format of the input topology file'
32
+
33
+ option :output_topo,
34
+ long: '--output-topo filename',
35
+ description: 'Specifies file to output topology JSON'
36
+
37
+ option :output,
38
+ long: '--output filename',
39
+ description: 'Specifies file to output generated recipe to'
40
+
41
+ option :action,
42
+ long: '--action deploy|undeploy|stop',
43
+ description: 'Specifies action to generate - defaults to deploy',
44
+ default: "deploy"
45
+
46
+ attr_accessor :topology
47
+
48
+ def initialize(argv=[])
49
+ super()
50
+ parse_and_validate_args
51
+ end
52
+
53
+ def parse_and_validate_args
54
+ begin
55
+ parse_options
56
+ @input_file = cli_arguments()[0]
57
+ rescue OptionParser::InvalidOption => e
58
+ STDERR.puts e.message
59
+ puts opt_parser
60
+ exit(-1)
61
+ end
62
+
63
+ if !@input_file
64
+ STDERR.puts opt_parser
65
+ exit(-1)
66
+ end
67
+ end
68
+
69
+ def redirect_stdout(file)
70
+ begin
71
+ $stdout.reopen(file, "w")
72
+ rescue => e
73
+ STDERR.puts "ERROR: Cannot open provisioning output file #{file} - #{e.message}"
74
+ end
75
+ end
76
+
77
+ def run
78
+ @topology = Topo::Loader.from_file(@input_file, @config[:format] || "default")
79
+
80
+ # output topo file
81
+ @topology.to_file(@config[:output_topo]) if(@config[:output_topo])
82
+
83
+ # redirect generated recipe to file
84
+ redirect_stdout(@config[:output]) if(@config[:output])
85
+
86
+ # run generator
87
+ @generator = Topo::Provision::Generator.new(@topology)
88
+ action = @config[:action].to_sym
89
+ @generator.generate_provisioning_recipe(action)
90
+
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,185 @@
1
+ #
2
+ # Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
3
+ # Copyright:: Copyright (c) 2015 ThirdWave Insights LLC
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'topo/utils/parsegen'
20
+ require 'topo/provision/topology_generator'
21
+
22
+ # load the resource generators
23
+ %w[context machine machine_image chef_node load_balancer node_group].each do |gen|
24
+ require_relative 'generators/' + gen
25
+ end
26
+
27
+ #require 'topo/provision/generators/machine_image'
28
+
29
+ #
30
+ # The Generator class invokes driver-specific or base generators to generate
31
+ # elements of the provisioning recipe.
32
+ #
33
+
34
+ module Topo
35
+ module Provision
36
+ class Generator
37
+
38
+ include Topo::ParseGen
39
+
40
+ attr_accessor :topology
41
+
42
+ # Generators for each driver (root driver)
43
+ @@generator_classes = {}
44
+ @driver_name = "default"
45
+
46
+ def self.register_generator(driver, class_name)
47
+ @@generator_classes[driver] = class_name
48
+ end
49
+
50
+ self.register_generator(@driver_name, self.name)
51
+
52
+ def initialize(topo=nil)
53
+ @topology = topo
54
+ @generators = { @driver_name => self }
55
+ end
56
+
57
+ # Get the right generator for the driver in place (e.g. vagrant, fog)
58
+ def generator(driver)
59
+ unless @generators.key?(driver)
60
+
61
+ generator_class = @@generator_classes[driver]
62
+
63
+ unless generator_class
64
+ begin
65
+ require "topo/provision/#{driver}/generator"
66
+ generator_class = @@generator_classes[driver]
67
+ rescue LoadError => e
68
+ STDERR.puts e.message
69
+ STDERR.puts("#{driver} driver cannot be loaded - using default generator instead")
70
+ generator_class = @@generator_classes["default"]
71
+ end
72
+ end
73
+
74
+ @generators[driver] = Object::const_get(generator_class).new(@topology)
75
+ end
76
+
77
+ @generators[driver]
78
+ end
79
+
80
+ # Add resources & their generators to the topology generator, then
81
+ # call them in dependency order to generate the overall recipe
82
+ # TODO: Driver-specific generation of dependencies other than through topo refs, e.g. autoscaling depend on loadbalancer
83
+ def generate_provisioning_recipe(action=:deploy)
84
+
85
+ topology_generator = Topo::Provision::TopologyGenerator.new()
86
+ generator(@topology.driver).generate_context(action)
87
+
88
+ @topology.services.each do |service|
89
+ depends_on = topo_refs(service).to_a
90
+ process_lazy_attrs(service) if depends_on.length > 0
91
+ topology_generator.add(service, depends_on,
92
+ { :resource_generator => resource_generator(service['type'], service) })
93
+ end
94
+
95
+ @topology.nodes.each do |node|
96
+ depends_on = topo_refs(node).to_a
97
+ process_lazy_attrs(node) if depends_on.length > 0
98
+ topology_generator.add(node, depends_on,
99
+ { :resource_generator => resource_generator("node", node) })
100
+ end
101
+
102
+ if [:undeploy, :stop].include?(action)
103
+ topology_generator.reverse_generate(action)
104
+ else
105
+ topology_generator.generate(action)
106
+ end
107
+
108
+ end
109
+
110
+
111
+
112
+ def driver(resource)
113
+ if resource['provisioning'] && resource['provisioning']['driver']
114
+ resource_driver = resource['provisioning']['driver'].split(":",2)[0]
115
+ else
116
+ resource_driver = @topology.driver
117
+ end
118
+ resource_driver
119
+ end
120
+
121
+ # Convert attributes with references to lazy attributes, and return array of resource names
122
+ # that this resource depends on
123
+ def process_lazy_attrs(resource)
124
+ depends_on = Set.new
125
+ if resource['attributes']
126
+ resource['attributes'].each do |key, value|
127
+ deps = topo_refs(value)
128
+ if deps.size > 0
129
+ depends_on.merge(deps)
130
+ resource['lazy_attributes'][key] = lazy_attribute_to_s(value)
131
+ resource['attributes'].delete(key)
132
+ end
133
+ end
134
+ end
135
+ depends_on.to_a
136
+ end
137
+
138
+ # BASE DRIVER GENERATORS
139
+
140
+
141
+ def generate_context(action)
142
+ cxt_gen = context
143
+ if (cxt_gen.respond_to? action)
144
+ cxt_gen.send(action)
145
+ else
146
+ cxt_gen.send("default_action", action)
147
+ end
148
+ end
149
+
150
+ def resource_generator(resource_type, data)
151
+ generator = nil
152
+ driver_generator = generator(driver(data))
153
+ if driver_generator.respond_to?(resource_type)
154
+ generator = driver_generator.send(resource_type, data)
155
+ else
156
+ STDERR.puts "Driver #{@topology.driver} does not support resource type #{resource_type}"
157
+ end
158
+ generator
159
+ end
160
+
161
+ # Functions to return the resource generators
162
+
163
+ def node(data)
164
+ if (data['provisioning'])
165
+ if(data['provisioning']['node_group'] && data['provisioning']['node_group']['size'])
166
+ Topo::Provision::NodeGroupGenerator.new(data)
167
+ else
168
+ Topo::Provision::MachineGenerator.new(data)
169
+ end
170
+ else
171
+ Topo::Provision::ChefNodeGenerator.new(data)
172
+ end
173
+ end
174
+
175
+ def load_balancer(data)
176
+ Topo::Provision::LoadBalancerGenerator.new(data)
177
+ end
178
+
179
+ def context()
180
+ @context ||= Topo::Provision::ContextGenerator.new(@topology.provisioning, @topology.driver)
181
+ end
182
+
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,35 @@
1
+ #
2
+ # Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
3
+ # Copyright:: Copyright (c) 2015 ThirdWave Insights LLC
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require_relative 'resource'
20
+
21
+ module Topo
22
+ module Provision
23
+ class ChefNodeGenerator < Topo::Provision::ResourceGenerator
24
+
25
+ def initialize(data)
26
+ @resource_type ||= "chef_node"
27
+ super
28
+ %w[run_list chef_environment tags attributes].each do |key|
29
+ @resource_attributes[key] = data[key] if data.key? key
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,70 @@
1
+ #
2
+ # Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
3
+ # Copyright:: Copyright (c) 2015 ThirdWave Insights LLC
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'erb'
20
+ require 'topo/utils/parsegen'
21
+
22
+ #
23
+ # The ContextGenerator class generates the recipe context
24
+ #
25
+
26
+ module Topo
27
+ module Provision
28
+
29
+ class ContextGenerator
30
+ include Topo::ParseGen
31
+
32
+ @@driver_files = {
33
+ 'default' =>'chef/provisioning',
34
+ 'aws' =>'chef/provisioning/aws_driver',
35
+ # 'fog' => 'chef/provisoning/fog_driver/driver', - not currently supported
36
+ 'vagrant' => 'chef/provisioning/vagrant_driver/driver'
37
+ }
38
+ @@template = nil
39
+
40
+
41
+ def initialize(data, default_driver)
42
+ @driver = data['driver'].split(':', 2).first if data['driver']
43
+ @driver ||= default_driver
44
+ @require_driver = @@driver_files['default']
45
+ if @driver && @@driver_files.key?(@driver)
46
+ @require_driver = @@driver_files[@driver]
47
+ end
48
+ @machine_options = convert_keys_to_sym(data['machine_options']) if data['machine_options']
49
+ @driver = data['driver']
50
+ end
51
+
52
+ def deploy()
53
+ puts(template.result(binding))
54
+ end
55
+
56
+ def default_action(action)
57
+ puts(template.result(binding))
58
+ end
59
+
60
+ def template()
61
+ unless @@template
62
+ path = File.expand_path("../templates/context.erb", __FILE__)
63
+ @@template = ERB.new(File.new(path).read, nil, '>')
64
+ end
65
+ @@template
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,40 @@
1
+ #
2
+ # Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
3
+ # Copyright:: Copyright (c) 2015 ThirdWave Insights LLC
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'topo/provision/generators/resource'
20
+
21
+ module Topo
22
+ module Provision
23
+
24
+ class LoadBalancerGenerator < Topo::Provision::ResourceGenerator
25
+ include Topo::ParseGen
26
+
27
+ def initialize(data)
28
+ @resource_type ||= "load_balancer"
29
+ super
30
+ @undeploy_action = "destroy"
31
+ %w[machines load_balancer_options].each do |key|
32
+ @resource_attributes[key] = data['provisioning'][key] if data['provisioning'].key? key
33
+ end
34
+
35
+ # Note: driver-specific classes may need to convert load_balancer_options into symbols
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,50 @@
1
+ #
2
+ # Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
3
+ # Copyright:: Copyright (c) 2015 ThirdWave Insights LLC
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'topo/provision/generators/resource'
20
+
21
+ #
22
+ # The ResourceGenerator class generates the recipe resources
23
+ #
24
+
25
+ module Topo
26
+ module Provision
27
+ class MachineGenerator < Topo::Provision::ResourceGenerator
28
+
29
+ attr_reader :machine_options, :normal_attributes, :lazy_attributes
30
+
31
+ def initialize(data)
32
+ @resource_type ||= "machine"
33
+ super
34
+ @undeploy_action = "destroy"
35
+ @normal_attributes = data['attributes']||{}
36
+ @lazy_attributes = data['lazy_attributes']||{}
37
+ %w[run_list chef_environment tags ].each do |key|
38
+ @resource_attributes[key] = data[key] if data.key? key
39
+ end
40
+ opts = data['provisioning']['machine_options']
41
+ @machine_options = convert_keys_to_sym(opts) if opts
42
+ end
43
+
44
+ def stop()
45
+ puts(template("stop").result(binding))
46
+ end
47
+
48
+ end
49
+ end
50
+ end