topo-provision 0.0.1
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 +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
|