topo-provision 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/README.md +100 -0
- data/bin/topo-provision +23 -0
- data/lib/topo/converter.rb +80 -0
- data/lib/topo/converter/cloudformation/converter.rb +219 -0
- data/lib/topo/exporter.rb +15 -0
- data/lib/topo/loader.rb +31 -0
- data/lib/topo/provision.rb +3 -0
- data/lib/topo/provision/aws/generator.rb +55 -0
- data/lib/topo/provision/aws/generators/aws_auto_scaling_group.rb +61 -0
- data/lib/topo/provision/aws/generators/aws_launch_configuration.rb +65 -0
- data/lib/topo/provision/aws/generators/context.rb +33 -0
- data/lib/topo/provision/aws/generators/load_balancer.rb +47 -0
- data/lib/topo/provision/aws/generators/machine.rb +36 -0
- data/lib/topo/provision/aws/generators/machine_image.rb +38 -0
- data/lib/topo/provision/aws/generators/node_group.rb +64 -0
- data/lib/topo/provision/cli.rb +95 -0
- data/lib/topo/provision/generator.rb +185 -0
- data/lib/topo/provision/generators/chef_node.rb +35 -0
- data/lib/topo/provision/generators/context.rb +70 -0
- data/lib/topo/provision/generators/load_balancer.rb +40 -0
- data/lib/topo/provision/generators/machine.rb +50 -0
- data/lib/topo/provision/generators/machine_image.rb +43 -0
- data/lib/topo/provision/generators/node_group.rb +74 -0
- data/lib/topo/provision/generators/resource.rb +91 -0
- data/lib/topo/provision/generators/templates/context.erb +8 -0
- data/lib/topo/provision/generators/templates/machine_deploy.erb +11 -0
- data/lib/topo/provision/generators/templates/machine_stop.erb +5 -0
- data/lib/topo/provision/generators/templates/node_group_action.erb +6 -0
- data/lib/topo/provision/generators/templates/node_group_deploy.erb +5 -0
- data/lib/topo/provision/generators/templates/resource_deploy.erb +5 -0
- data/lib/topo/provision/generators/templates/resource_undeploy.erb +5 -0
- data/lib/topo/provision/topology_generator.rb +84 -0
- data/lib/topo/provision/vagrant/generator.rb +33 -0
- data/lib/topo/provision/version.rb +5 -0
- data/lib/topo/topology.rb +61 -0
- data/lib/topo/utils/output.rb +31 -0
- data/lib/topo/utils/parsegen.rb +101 -0
- 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
|