knife-topo 0.0.3
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.
- data/LICENSE +201 -0
- data/README.md +308 -0
- data/knife-topo.gemspec +21 -0
- data/lib/chef/knife/topo/version.rb +5 -0
- data/lib/chef/knife/topo_bootstrap.rb +114 -0
- data/lib/chef/knife/topo_cookbook_create.rb +178 -0
- data/lib/chef/knife/topo_cookbook_upload.rb +84 -0
- data/lib/chef/knife/topo_create.rb +110 -0
- data/lib/chef/knife/topo_export.rb +137 -0
- data/lib/chef/knife/topo_import.rb +100 -0
- data/lib/chef/knife/topo_update.rb +110 -0
- data/lib/chef/knife/topology_helper.rb +280 -0
- data/test-repo/.chef/dummy.pem +27 -0
- data/test-repo/.chef/knife.rb +13 -0
- data/test-repo/Berksfile +4 -0
- data/test-repo/Instructions.txt +48 -0
- data/test-repo/Vagrantfile +67 -0
- data/test-repo/cookbooks/README.md +54 -0
- data/test-repo/cookbooks/testapp/CHANGELOG.md +10 -0
- data/test-repo/cookbooks/testapp/README.md +26 -0
- data/test-repo/cookbooks/testapp/files/default/index.html +13 -0
- data/test-repo/cookbooks/testapp/files/default/package.json +14 -0
- data/test-repo/cookbooks/testapp/files/default/server.js +42 -0
- data/test-repo/cookbooks/testapp/metadata.rb +9 -0
- data/test-repo/cookbooks/testapp/recipes/appserver.rb +8 -0
- data/test-repo/cookbooks/testapp/recipes/db.rb +9 -0
- data/test-repo/cookbooks/testapp/recipes/default.rb +11 -0
- data/test-repo/cookbooks/testapp/recipes/deploy.rb +50 -0
- data/test-repo/cookbooks/testapp/templates/default/nodejs.upstart.conf.erb +9 -0
- data/test-repo/multipletopology.json +117 -0
- data/test-repo/topology.json +99 -0
- metadata +78 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 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 'topology_helper'
|
20
|
+
require 'chef/knife/cookbook_create'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Knife
|
24
|
+
class TopoCookbookCreate < Chef::Knife
|
25
|
+
|
26
|
+
deps do
|
27
|
+
Chef::Knife::CookbookCreate.load_deps
|
28
|
+
end
|
29
|
+
|
30
|
+
banner "knife topo cookbook create TOPOLOGY [ TOPOLOGY_FILE ] (options)"
|
31
|
+
|
32
|
+
option :data_bag,
|
33
|
+
:short => '-D DATA_BAG',
|
34
|
+
:long => "--data-bag DATA_BAG",
|
35
|
+
:description => "The data bag the topologies are stored in"
|
36
|
+
|
37
|
+
# Make the base cookbook create options available on topo cookbook
|
38
|
+
self.options = (Chef::Knife::CookbookCreate.options).merge(self.options)
|
39
|
+
|
40
|
+
def initialize (args)
|
41
|
+
super
|
42
|
+
@cookbook_create_args = initialize_cmd_args(args, [ 'cookbook', 'create' ])
|
43
|
+
|
44
|
+
# All called commands need to accept union of options
|
45
|
+
Chef::Knife::CookbookCreate.options = options
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def run
|
50
|
+
if !@name_args[0]
|
51
|
+
show_usage
|
52
|
+
ui.fatal("You must specify the name of a topology")
|
53
|
+
exit 1
|
54
|
+
end
|
55
|
+
|
56
|
+
@bag_name = topo_bag_name(config[:data_bag])
|
57
|
+
@topo_name = @name_args[0]
|
58
|
+
@topo_file = @name_args[1]
|
59
|
+
|
60
|
+
# Get the topology data from either the file or the server
|
61
|
+
if @topo_file
|
62
|
+
topologies = load_topologies(@topo_file)
|
63
|
+
index = topologies.find_index{ |t| t['name'] == @topo_name}
|
64
|
+
unless index
|
65
|
+
ui.fatal("Topology #{@topo_name} was not found in topology file #{@topo_file}")
|
66
|
+
exit(1)
|
67
|
+
end
|
68
|
+
topo = topologies[index]
|
69
|
+
else
|
70
|
+
unless topo = load_from_server(@bag_name, @topo_name )
|
71
|
+
ui.fatal("Topology #{@bag_name}/#{@topo_name} does not exist on the server - use 'knife topo create' first")
|
72
|
+
exit(1)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# create the topology cookbooks
|
77
|
+
attribute_cookbooks = topo['cookbook_attributes']
|
78
|
+
@failed = []
|
79
|
+
succeeded = 0
|
80
|
+
if attribute_cookbooks && attribute_cookbooks.length > 0
|
81
|
+
attribute_cookbooks.each do |cookbook_spec|
|
82
|
+
run_create_cookbook(cookbook_spec['cookbook'])
|
83
|
+
create_attr_file(@cookbook_path, cookbook_spec['cookbook'],
|
84
|
+
cookbook_spec['filename'] + ".rb", cookbook_spec)
|
85
|
+
succeeded += 1
|
86
|
+
end
|
87
|
+
else
|
88
|
+
ui.info "No cookbook attributes found for topology #{@topo_name}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
include Chef::Knife::TopologyHelper
|
95
|
+
|
96
|
+
def run_create_cookbook(cookbook_name)
|
97
|
+
@cookbook_create_args[2] = cookbook_name
|
98
|
+
begin
|
99
|
+
command = run_cmd(Chef::Knife::CookbookCreate, @cookbook_create_args)
|
100
|
+
rescue Exception => e
|
101
|
+
raise if Chef::Config[:verbosity] == 2
|
102
|
+
@failed << cookbook_name
|
103
|
+
ui.warn "create of cookbook #{cookbook_name} exited with error"
|
104
|
+
humanize_exception(e)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Store the cookbook path for use later
|
108
|
+
@cookbook_path = File.expand_path(Array(command.config[:cookbook_path]).first)
|
109
|
+
@copyright = command.config[:cookbook_copyright] || "YOUR_COMPANY_NAME"
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_attr_file(dir, cookbook_name, filename, attrs)
|
114
|
+
|
115
|
+
ui.info("** Creating attribute file #{filename}")
|
116
|
+
|
117
|
+
open(File.join(dir, cookbook_name, "attributes", filename), "w") do |file|
|
118
|
+
file.puts <<-EOH
|
119
|
+
#
|
120
|
+
# THIS FILE IS GENERATED BY THE KNIFE TOPO PLUGIN - MANUAL CHANGES WILL BE OVERWRITTEN
|
121
|
+
#
|
122
|
+
# Cookbook Name:: #{cookbook_name}
|
123
|
+
# Attribute File:: #{filename}
|
124
|
+
#
|
125
|
+
# Copyright #{Time.now.year}, #{@copyright}
|
126
|
+
#
|
127
|
+
EOH
|
128
|
+
|
129
|
+
# Print out attribute line
|
130
|
+
def print_attr(file, lhs, value1)
|
131
|
+
if value1.is_a?(Hash)
|
132
|
+
value1.each do |key, value2|
|
133
|
+
print_attr(file, "#{lhs}['#{key}']", value2)
|
134
|
+
end
|
135
|
+
else
|
136
|
+
file.write "#{lhs} = \"#{value1}\"\n"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Print out attributes hashed by priority
|
141
|
+
def print_priority_attrs(file, attrs, indent=0)
|
142
|
+
%w(default force_default normal override force_override).each do |priority|
|
143
|
+
if attrs[priority]
|
144
|
+
lhs = ""
|
145
|
+
indent.times { |i| lhs += " " }
|
146
|
+
lhs += priority
|
147
|
+
print_attr(file, lhs, attrs[priority])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Print out qualified attributes
|
153
|
+
def print_qualified_attr(file, qualifier, qualifier_hash)
|
154
|
+
qualifier_hash.each do |qualifier_value, qualified_attrs|
|
155
|
+
file.puts "if node['topo']['#{qualifier}'] == \"#{qualifier_value}\""
|
156
|
+
print_priority_attrs(file, qualified_attrs, 2)
|
157
|
+
file.puts "end"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Process the attributes not needing qualification
|
162
|
+
print_priority_attrs(file, attrs)
|
163
|
+
file.puts
|
164
|
+
|
165
|
+
# Process attributes that need to be qualified (must appear after the above in cookbook)
|
166
|
+
%w(node_type).each do |qualifier|
|
167
|
+
if attrs[qualifier]
|
168
|
+
file.puts "# Attributes for specific #{qualifier}"
|
169
|
+
print_qualified_attr(file, qualifier, attrs[qualifier])
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 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 'chef/knife'
|
20
|
+
require_relative 'topology_helper'
|
21
|
+
|
22
|
+
## only require if not already defined (to prevent warning about already initialized constants)
|
23
|
+
require 'chef/knife/cookbook_upload' if !defined? Chef::Knife::CookbookUpload
|
24
|
+
|
25
|
+
class Chef
|
26
|
+
class Knife
|
27
|
+
class TopoCookbookUpload < Chef::Knife
|
28
|
+
|
29
|
+
deps do
|
30
|
+
Chef::Knife::CookbookUpload.load_deps
|
31
|
+
end
|
32
|
+
|
33
|
+
banner "knife topo cookbook upload [ TOPOLOGY ] (options)"
|
34
|
+
|
35
|
+
option :data_bag,
|
36
|
+
:short => '-D DATA_BAG',
|
37
|
+
:long => "--data-bag DATA_BAG",
|
38
|
+
:description => "The data bag the topologies are stored in"
|
39
|
+
|
40
|
+
# Make called command options available
|
41
|
+
self.options = (Chef::Knife::CookbookUpload.options).merge(self.options)
|
42
|
+
|
43
|
+
def initialize (args)
|
44
|
+
super
|
45
|
+
@topo_upload_args = initialize_cmd_args(args, [ 'cookbook', 'upload' ])
|
46
|
+
|
47
|
+
# All called commands need to accept union of options
|
48
|
+
Chef::Knife::CookbookUpload.options = options
|
49
|
+
end
|
50
|
+
|
51
|
+
def run
|
52
|
+
if !@name_args[0]
|
53
|
+
show_usage
|
54
|
+
ui.fatal("You must specify the name of a topology")
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
|
58
|
+
bag_name = topo_bag_name(config[:data_bag])
|
59
|
+
topo_name = @name_args[0]
|
60
|
+
|
61
|
+
# Load the topology data
|
62
|
+
unless topo = load_from_file(bag_name, topo_name )
|
63
|
+
ui.fatal("Topology file #{topologies_path}/#{bag_name}/#{topo_name}.json not found - use 'knife topo import' first")
|
64
|
+
exit(1)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Run cookbook upload command on the topology cookbooks
|
68
|
+
if topo['cookbook_attributes'].length > 0
|
69
|
+
argPos = 2
|
70
|
+
topo['cookbook_attributes'].each do |entry|
|
71
|
+
@topo_upload_args[argPos] = entry['cookbook']
|
72
|
+
argPos += 1
|
73
|
+
end
|
74
|
+
run_cmd(Chef::Knife::CookbookUpload, @topo_upload_args)
|
75
|
+
else
|
76
|
+
ui.info("No cookbooks found for topology #{topo_name}.")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
include Chef::Knife::TopologyHelper
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 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 'chef/knife'
|
20
|
+
require_relative 'topology_helper'
|
21
|
+
require_relative 'topo_bootstrap'
|
22
|
+
require_relative 'topo_cookbook_upload'
|
23
|
+
|
24
|
+
class Chef
|
25
|
+
class Knife
|
26
|
+
class TopoCreate < Chef::Knife
|
27
|
+
|
28
|
+
deps do
|
29
|
+
Chef::Knife::TopoCookbookUpload.load_deps
|
30
|
+
Chef::Knife::TopoBootstrap.load_deps
|
31
|
+
end
|
32
|
+
|
33
|
+
banner "knife topo create TOPOLOGY (options)"
|
34
|
+
|
35
|
+
option :data_bag,
|
36
|
+
:short => '-D DATA_BAG',
|
37
|
+
:long => "--data-bag DATA_BAG",
|
38
|
+
:description => "The data bag the topologies are stored in"
|
39
|
+
|
40
|
+
option :bootstrap,
|
41
|
+
:long => "--bootstrap",
|
42
|
+
:description => "Whether to bootstrap newly created nodes",
|
43
|
+
:boolean => false
|
44
|
+
|
45
|
+
option :no_upload,
|
46
|
+
:long => "--no-upload",
|
47
|
+
:description => "Do not upload cookbooks",
|
48
|
+
:boolean => false
|
49
|
+
|
50
|
+
# Make called command options available
|
51
|
+
opts = self.options
|
52
|
+
self.options = (Chef::Knife::TopoBootstrap.options).merge(Chef::Knife::TopoCookbookUpload.options)
|
53
|
+
self.options.merge!(opts)
|
54
|
+
|
55
|
+
def initialize (args)
|
56
|
+
super
|
57
|
+
@topo_bootstrap_args = initialize_cmd_args(args, [ 'topo', 'bootstrap', @name_args[0] ])
|
58
|
+
@topo_upload_args = initialize_cmd_args(args, [ 'topo', 'cookbook', 'upload', @name_args[0] ])
|
59
|
+
|
60
|
+
# All called commands need to accept union of options
|
61
|
+
Chef::Knife::TopoBootstrap.options = options
|
62
|
+
Chef::Knife::TopoCookbookUpload.options = options
|
63
|
+
end
|
64
|
+
|
65
|
+
def run
|
66
|
+
if !@name_args[0]
|
67
|
+
show_usage
|
68
|
+
ui.fatal("You must specify the name of a topology")
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
bag_name = topo_bag_name(config[:data_bag])
|
73
|
+
topo_name = @name_args[0]
|
74
|
+
|
75
|
+
# Load the topology data & create the topology bag
|
76
|
+
unless topo = load_from_file(bag_name, topo_name )
|
77
|
+
ui.fatal("Topology file #{topologies_path}/#{bag_name}/#{topo_name}.json not found - use 'knife topo import' first")
|
78
|
+
exit(1)
|
79
|
+
end
|
80
|
+
@data_bag = create_bag(bag_name)
|
81
|
+
|
82
|
+
# Add topology item to the data bag on the server
|
83
|
+
begin
|
84
|
+
topo.create
|
85
|
+
rescue Net::HTTPServerException => e
|
86
|
+
raise unless e.to_s =~ /^409/
|
87
|
+
ui.confirm("Topology already exists - do you want to re-create it", true, false)
|
88
|
+
end
|
89
|
+
|
90
|
+
# make sure env and cookbooks are in place
|
91
|
+
check_chef_env(topo['chef_environment']) if topo['chef_environment']
|
92
|
+
upload_cookbooks(@topo_upload_args) if (!config[:no_upload])
|
93
|
+
|
94
|
+
# setup the actual nodes on the server
|
95
|
+
create_or_update_nodes(topo)
|
96
|
+
ui.info("Topology created")
|
97
|
+
|
98
|
+
# if bootstrap is specified, run the bootstrap command
|
99
|
+
run_cmd(Chef::Knife::TopoBootstrap, @topo_bootstrap_args) if config[:bootstrap]
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
include Chef::Knife::TopologyHelper
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 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 'chef/knife'
|
20
|
+
|
21
|
+
require_relative 'topology_helper'
|
22
|
+
|
23
|
+
# NOTE: This command exports to stdout - do not add ui messages (other than fatal) to this command
|
24
|
+
|
25
|
+
class Chef
|
26
|
+
class Knife
|
27
|
+
class TopoExport < Chef::Knife
|
28
|
+
|
29
|
+
deps do
|
30
|
+
end
|
31
|
+
|
32
|
+
banner "knife topo export [ TOPOLOGY [ NODE ... ]] (options)"
|
33
|
+
|
34
|
+
option :data_bag,
|
35
|
+
:short => '-D DATA_BAG',
|
36
|
+
:long => "--data-bag DATA_BAG",
|
37
|
+
:description => "The data bag the topologies are stored in"
|
38
|
+
|
39
|
+
def run
|
40
|
+
|
41
|
+
@bag_name = topo_bag_name(config[:data_bag])
|
42
|
+
|
43
|
+
@topo_name = @name_args[0]
|
44
|
+
@node_names = @name_args[1..-1]
|
45
|
+
|
46
|
+
if @topo_name
|
47
|
+
if topo = load_from_server(@bag_name, @topo_name)
|
48
|
+
export = topo.raw_data
|
49
|
+
else
|
50
|
+
export = empty_topology
|
51
|
+
end
|
52
|
+
|
53
|
+
# merge in data for nodes that user explicitly specified
|
54
|
+
@node_names.each do |node_name|
|
55
|
+
merge_node_properties!(export['nodes'], node_name)
|
56
|
+
end
|
57
|
+
|
58
|
+
else
|
59
|
+
# export all topologies
|
60
|
+
export = []
|
61
|
+
if dbag = load_from_server(@bag_name)
|
62
|
+
dbag.keys.each do |topo_name|
|
63
|
+
if topo = load_from_server(@bag_name, topo_name)
|
64
|
+
export << topo.raw_data
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
output(Chef::JSONCompat.to_json_pretty(export))
|
71
|
+
end
|
72
|
+
|
73
|
+
# give user a template to get started
|
74
|
+
def empty_topology
|
75
|
+
{
|
76
|
+
"id" => @topo_name || "topo1",
|
77
|
+
"name" => @topo_name || "topo1",
|
78
|
+
"chef_environment" => "_default",
|
79
|
+
"tags" => [ ],
|
80
|
+
"normal" => { },
|
81
|
+
"nodes" => [
|
82
|
+
"node1" => empty_node("node1")
|
83
|
+
],
|
84
|
+
"cookbook_attributes" => [{
|
85
|
+
"cookbook" => @topo_name || "topo1",
|
86
|
+
"filename" => "topology"
|
87
|
+
}]
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def empty_node(name)
|
92
|
+
{
|
93
|
+
"name" => name,
|
94
|
+
"run_list" => [],
|
95
|
+
"ssh_host" => name,
|
96
|
+
"ssh_port" => "22",
|
97
|
+
"normal" => {},
|
98
|
+
"tags" => []
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
# get actual node properties for export
|
103
|
+
def node_export (node_name)
|
104
|
+
begin
|
105
|
+
node = Chef::Node.load(node_name).to_hash
|
106
|
+
rescue Net::HTTPServerException => e
|
107
|
+
raise unless e.to_s =~ /^404/
|
108
|
+
node = empty_node(node_name)
|
109
|
+
end
|
110
|
+
props = %w{name chef_environment normal run_list recipes}
|
111
|
+
node_data = {}
|
112
|
+
|
113
|
+
props.each do |prop|
|
114
|
+
node_data[prop] = node[prop] if node.has_key?(prop)
|
115
|
+
end
|
116
|
+
|
117
|
+
node_data[tags] = node_data[normal][tags]
|
118
|
+
|
119
|
+
node_data
|
120
|
+
end
|
121
|
+
|
122
|
+
# merge hash properties with the actual node properties
|
123
|
+
def merge_node_properties!(nodes, node_name)
|
124
|
+
# find out if the node is already in the array
|
125
|
+
node = nodes.find{|n| n["name"] == node_name }
|
126
|
+
if node
|
127
|
+
node.merge!(node_export(node_name))
|
128
|
+
else
|
129
|
+
nodes.push(node_export(node_name))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
include Chef::Knife::TopologyHelper
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Christine Draper (<christine_draper@thirdwaveinsights.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 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 'chef/knife'
|
20
|
+
|
21
|
+
require_relative 'topology_helper'
|
22
|
+
require_relative 'topo_cookbook_create'
|
23
|
+
|
24
|
+
class Chef
|
25
|
+
class Knife
|
26
|
+
class TopoImport < Chef::Knife
|
27
|
+
|
28
|
+
deps do
|
29
|
+
Chef::Knife::TopoCookbookCreate.load_deps
|
30
|
+
end
|
31
|
+
|
32
|
+
banner "knife topo import [ TOPOLOGY_FILE [ TOPOLOGY ... ]] (options)"
|
33
|
+
|
34
|
+
option :data_bag,
|
35
|
+
:short => '-D DATA_BAG',
|
36
|
+
:long => "--data-bag DATA_BAG",
|
37
|
+
:description => "The data bag to store the topologies in"
|
38
|
+
|
39
|
+
# Make called command options available
|
40
|
+
self.options = Chef::Knife::TopoCookbookCreate.options.merge(self.options)
|
41
|
+
|
42
|
+
def initialize (args)
|
43
|
+
super
|
44
|
+
@topo_cookbook_args = initialize_cmd_args(args, [ 'topo', 'cookbook', '', '' ])
|
45
|
+
|
46
|
+
# All called commands need to accept union of options
|
47
|
+
Chef::Knife::TopoCookbookCreate.options = options
|
48
|
+
end
|
49
|
+
|
50
|
+
def run
|
51
|
+
|
52
|
+
# load data from the topologies file
|
53
|
+
topo_file = @name_args[0] || 'topology.json'
|
54
|
+
topologies = load_topologies(topo_file)
|
55
|
+
bag_name = topo_bag_name(config[:data_bag])
|
56
|
+
topo_names = @name_args[1..-1] if @name_args[1]
|
57
|
+
|
58
|
+
# make sure the topology bag directory exists
|
59
|
+
path = File.join(topologies_path, bag_name)
|
60
|
+
FileUtils.mkdir_p(path)
|
61
|
+
|
62
|
+
topologies.each do |topo_data|
|
63
|
+
|
64
|
+
topo_name = topo_data['name'] || topo_data['id']
|
65
|
+
topo_data['id'] ||= topo_name
|
66
|
+
|
67
|
+
# check against specific topology list
|
68
|
+
if topo_names
|
69
|
+
if topo_names.include?(topo_name)
|
70
|
+
topo_names.delete(topo_name)
|
71
|
+
else
|
72
|
+
next
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# write the databag for this topology
|
77
|
+
path = File.join(topologies_path, bag_name, topo_name + '.json')
|
78
|
+
File.open(path,"w") do |f|
|
79
|
+
f.write(Chef::JSONCompat.to_json_pretty(topo_data))
|
80
|
+
f.close()
|
81
|
+
ui.info "Imported topology #{topo_name} into #{path}"
|
82
|
+
end
|
83
|
+
|
84
|
+
# run topo cookbook to generate the cookbooks for this topology
|
85
|
+
@topo_cookbook_args[2] = topo_name
|
86
|
+
@topo_cookbook_args[3] = topo_file
|
87
|
+
run_cmd(Chef::Knife::TopoCookbookCreate, @topo_cookbook_args)
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
ui.info "Did not find topologies #{topo_names.join(', ')} in the exchange file" if topo_names && topo_names.length > 0
|
92
|
+
ui.info "Import finished"
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
include Chef::Knife::TopologyHelper
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|