knife-topo 1.1.2 → 2.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 +4 -4
- data/README.md +125 -148
- data/knife-topo.gemspec +12 -12
- data/lib/chef/knife/topo/bootstrap_helper.rb +75 -0
- data/lib/chef/knife/topo/command_helper.rb +71 -0
- data/lib/chef/knife/topo/consts.rb +4 -0
- data/lib/chef/knife/topo/loader.rb +137 -0
- data/lib/chef/knife/topo/node_update_helper.rb +111 -0
- data/lib/chef/knife/topo/processor.rb +76 -0
- data/lib/chef/knife/topo/processor/via_cookbook.rb +118 -0
- data/lib/chef/knife/topo/processor/via_cookbook_print.rb +97 -0
- data/lib/chef/knife/topo/version.rb +3 -4
- data/lib/chef/knife/topo_bootstrap.rb +107 -79
- data/lib/chef/knife/topo_cookbook_create.rb +41 -144
- data/lib/chef/knife/topo_cookbook_upload.rb +40 -54
- data/lib/chef/knife/topo_create.rb +120 -132
- data/lib/chef/knife/topo_delete.rb +67 -65
- data/lib/chef/knife/topo_export.rb +108 -133
- data/lib/chef/knife/topo_import.rb +62 -76
- data/lib/chef/knife/topo_list.rb +18 -25
- data/lib/chef/knife/topo_search.rb +61 -61
- data/lib/chef/knife/topo_update.rb +25 -110
- data/lib/chef/topo/converter.rb +75 -0
- data/lib/chef/topo/converter/topo_v1.rb +123 -0
- data/lib/chef/topology.rb +137 -0
- metadata +13 -3
- data/lib/chef/knife/topology_helper.rb +0 -366
@@ -17,160 +17,135 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'chef/knife'
|
20
|
+
require 'chef/knife/topo/loader'
|
21
|
+
require 'chef/knife/topo/consts'
|
22
|
+
require 'chef/knife/topo/command_helper'
|
23
|
+
require 'chef/knife/topo/consts'
|
20
24
|
|
21
|
-
|
25
|
+
# NOTE: This command exports to stdout
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
class Chef
|
26
|
-
|
27
|
-
|
27
|
+
module KnifeTopo
|
28
|
+
# knife topo export
|
29
|
+
class TopoExport < Chef::Knife
|
30
|
+
deps do
|
31
|
+
end
|
28
32
|
|
29
|
-
|
33
|
+
banner 'knife topo export [ NODE ... ] (options)'
|
34
|
+
|
35
|
+
option(
|
36
|
+
:data_bag,
|
37
|
+
short: '-D DATA_BAG',
|
38
|
+
long: '--data-bag DATA_BAG',
|
39
|
+
description: 'The data bag the topologies are stored in'
|
40
|
+
)
|
41
|
+
|
42
|
+
option(
|
43
|
+
:min_priority,
|
44
|
+
long: '--min-priority PRIORITY',
|
45
|
+
default: 'default',
|
46
|
+
description: 'Export attributes with this priority or above'
|
47
|
+
)
|
48
|
+
|
49
|
+
option(
|
50
|
+
:topo,
|
51
|
+
long: '--topo TOPOLOGY',
|
52
|
+
description: 'Name to use for the topology',
|
53
|
+
default: 'topo1'
|
54
|
+
)
|
55
|
+
|
56
|
+
include KnifeTopo::Loader
|
57
|
+
include KnifeTopo::CommandHelper
|
58
|
+
|
59
|
+
def run
|
60
|
+
unless KnifeTopo::PRIORITIES.include?(config[:min_priority])
|
61
|
+
ui.warn('--min-priority should be one of ' \
|
62
|
+
"#{KnifeTopo::PRIORITIES.join(', ')}")
|
30
63
|
end
|
64
|
+
@topo_name = config[:topo]
|
65
|
+
@node_names = @name_args
|
66
|
+
output(Chef::JSONCompat.to_json_pretty(load_or_initialize_topo))
|
67
|
+
end
|
31
68
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
option :min_priority,
|
40
|
-
:long => "--min-priority PRIORITY",
|
41
|
-
:default => "default",
|
42
|
-
:description => "Export attributes with this priority or above"
|
43
|
-
|
44
|
-
option :topo,
|
45
|
-
:long => "--topo TOPOLOGY",
|
46
|
-
:description => "Name to use for the topology",
|
47
|
-
:default => "topo1"
|
48
|
-
|
49
|
-
option :all,
|
50
|
-
:long => "--all",
|
51
|
-
:description => "Export all topologies",
|
52
|
-
:boolean => true,
|
53
|
-
:default => false
|
54
|
-
|
55
|
-
def most_common (vals)
|
56
|
-
vals.group_by do |val|
|
57
|
-
val
|
58
|
-
end.values.max_by(&:size).first
|
69
|
+
def load_or_initialize_topo
|
70
|
+
topo = load_topo_from_server(@topo_name)
|
71
|
+
if topo
|
72
|
+
export = topo.raw_data
|
73
|
+
update_nodes!(export['nodes'])
|
74
|
+
else
|
75
|
+
export = new_topo
|
59
76
|
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
@bag_name = topo_bag_name(config[:data_bag])
|
77
|
+
export
|
78
|
+
end
|
64
79
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
unless ['default', 'normal', 'override'].include?(config[:min_priority])
|
69
|
-
ui.warn("--min-priority should be one of 'default', 'normal' or 'override'")
|
70
|
-
end
|
71
|
-
|
72
|
-
if @topo_name
|
73
|
-
if topo = load_from_server(@bag_name, @topo_name)
|
74
|
-
export = topo.raw_data
|
75
|
-
else
|
76
|
-
export = empty_topology
|
77
|
-
export['nodes'].push(empty_node("node1")) if @node_names.length == 0
|
78
|
-
end
|
79
|
-
|
80
|
-
# merge in data for nodes that user explicitly specified
|
81
|
-
@node_names.each do |node_name|
|
82
|
-
merge_node_properties!(export['nodes'], node_name)
|
83
|
-
end
|
84
|
-
|
85
|
-
# if a new topo, pick an topo environment based on the nodes
|
86
|
-
if !topo && @node_names.length != 0
|
87
|
-
envs = []
|
88
|
-
export['nodes'].each do |node|
|
89
|
-
envs << node['chef_environment'] if node['chef_environment']
|
90
|
-
end
|
91
|
-
export['chef_environment'] = most_common(envs) if envs.length > 0
|
92
|
-
end
|
80
|
+
def new_topo
|
81
|
+
topo = empty_topology
|
82
|
+
update_nodes!(topo['nodes'])
|
93
83
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
export << topo.raw_data
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
84
|
+
# pick an topo environment based on the nodes
|
85
|
+
return topo if @node_names.length == 0
|
86
|
+
env = pick_env(topo['nodes'])
|
87
|
+
topo['chef_environment'] = env if env
|
88
|
+
topo
|
89
|
+
end
|
105
90
|
|
106
|
-
|
91
|
+
def pick_env(nodes)
|
92
|
+
envs = []
|
93
|
+
nodes.each do |node|
|
94
|
+
envs << node['chef_environment'] if node['chef_environment']
|
107
95
|
end
|
96
|
+
most_common(envs)
|
97
|
+
end
|
108
98
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
}
|
122
|
-
end
|
99
|
+
# give user a template to get started
|
100
|
+
def empty_topology
|
101
|
+
{
|
102
|
+
'id' => @topo_name || 'topo1',
|
103
|
+
'name' => @topo_name || 'topo1',
|
104
|
+
'chef_environment' => '_default',
|
105
|
+
'tags' => [],
|
106
|
+
'strategy' => 'via_cookbook',
|
107
|
+
'strategy_data' => default_strategy_data,
|
108
|
+
'nodes' => @node_names.length == 0 ? [empty_node('node1')] : []
|
109
|
+
}
|
110
|
+
end
|
123
111
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
"normal" => {},
|
131
|
-
"tags" => []
|
132
|
-
}
|
133
|
-
end
|
112
|
+
def default_strategy_data
|
113
|
+
{
|
114
|
+
'cookbook' => @topo_name || 'topo1',
|
115
|
+
'filename' => 'topology'
|
116
|
+
}
|
117
|
+
end
|
134
118
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
rescue Net::HTTPServerException => e
|
154
|
-
raise unless e.to_s =~ /^404/
|
155
|
-
node_data = empty_node(node_name)
|
156
|
-
end
|
157
|
-
|
158
|
-
node_data
|
159
|
-
end
|
119
|
+
def empty_node(name)
|
120
|
+
{
|
121
|
+
'name' => name,
|
122
|
+
'run_list' => [],
|
123
|
+
'ssh_host' => name,
|
124
|
+
'ssh_port' => '22',
|
125
|
+
'normal' => {},
|
126
|
+
'tags' => []
|
127
|
+
}
|
128
|
+
end
|
129
|
+
|
130
|
+
# get actual node properties for export
|
131
|
+
def node_export(node_name)
|
132
|
+
load_node_data(node_name, config[:min_priority])
|
133
|
+
rescue Net::HTTPServerException => e
|
134
|
+
raise unless e.to_s =~ /^404/
|
135
|
+
empty_node(node_name)
|
136
|
+
end
|
160
137
|
|
161
|
-
|
162
|
-
|
138
|
+
# put node details in node array, overwriting existing details
|
139
|
+
def update_nodes!(nodes)
|
140
|
+
@node_names.each do |node_name|
|
163
141
|
# find out if the node is already in the array
|
164
|
-
found = nodes.index{|n| n[
|
142
|
+
found = nodes.index { |n| n['name'] == node_name }
|
165
143
|
if found.nil?
|
166
144
|
nodes.push(node_export(node_name))
|
167
145
|
else
|
168
146
|
nodes[found] = node_export(node_name)
|
169
147
|
end
|
170
148
|
end
|
171
|
-
|
172
|
-
include Chef::Knife::TopologyHelper
|
173
|
-
|
174
149
|
end
|
175
150
|
end
|
176
151
|
end
|
@@ -17,92 +17,78 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'chef/knife'
|
20
|
+
require 'chef/knife/cookbook_create'
|
21
|
+
require 'chef/knife/topo/command_helper'
|
22
|
+
require 'chef/knife/topo/loader'
|
20
23
|
|
21
|
-
|
22
|
-
|
24
|
+
module KnifeTopo
|
25
|
+
# knife topo import
|
26
|
+
class TopoImport < Chef::Knife
|
27
|
+
deps do
|
28
|
+
require 'chef/knife/topo/processor'
|
29
|
+
end
|
23
30
|
|
24
|
-
|
25
|
-
class Knife
|
26
|
-
class TopoImport < Chef::Knife
|
31
|
+
banner 'knife topo import [ TOPOLOGY_FILE ] (options)'
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
|
33
|
+
option(
|
34
|
+
: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
|
+
option(
|
40
|
+
:input_format,
|
41
|
+
long: '--input-format FORMAT',
|
42
|
+
description: 'The format to convert from (e.g. topo_v1)'
|
43
|
+
)
|
31
44
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
:short => '-D DATA_BAG',
|
36
|
-
:long => "--data-bag DATA_BAG",
|
37
|
-
:description => "The data bag to store the topologies in"
|
45
|
+
# Make called command options available
|
46
|
+
orig_opts = KnifeTopo::TopoImport.options
|
47
|
+
self.options = Chef::Knife::CookbookCreate.options.merge(orig_opts)
|
38
48
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
def initialize (args)
|
43
|
-
super
|
44
|
-
@topo_cookbook_args = initialize_cmd_args(args, [ 'topo', 'cookbook', '', '' ])
|
49
|
+
include KnifeTopo::CommandHelper
|
50
|
+
include KnifeTopo::Loader
|
45
51
|
|
46
|
-
|
47
|
-
|
48
|
-
|
52
|
+
def initialize(args)
|
53
|
+
super
|
54
|
+
@args = args
|
55
|
+
@topo_file = @name_args[0] || 'topology.json'
|
56
|
+
end
|
49
57
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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)
|
58
|
+
def run
|
59
|
+
@topo = load_topo_from_file_or_exit(@topo_file, config[:input_format])
|
60
|
+
@processor = KnifeTopo::Processor.for_topo(@topo)
|
61
|
+
create_topo_bag_dir
|
62
|
+
import_topo
|
63
|
+
end
|
61
64
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
# write the databag for this topology
|
83
|
-
path = File.join(topologies_path, bag_name, topo_name + '.json')
|
84
|
-
File.open(path,"w") do |f|
|
85
|
-
f.write(Chef::JSONCompat.to_json_pretty(topo_data))
|
86
|
-
f.close()
|
87
|
-
ui.info "Created topology data bag in #{path}"
|
88
|
-
end
|
89
|
-
|
90
|
-
# run topo cookbook to generate the cookbooks for this topology
|
91
|
-
@topo_cookbook_args[2] = topo_name
|
92
|
-
@topo_cookbook_args[3] = topo_file
|
93
|
-
run_cmd(Chef::Knife::TopoCookbookCreate, @topo_cookbook_args)
|
94
|
-
ui.info "Imported topology #{display_name(topo_data)}"
|
95
|
-
ui.info("Build information: " + topo_data['buildstamp']) if topo_data['buildstamp']
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
ui.info "Did not find topologies #{topo_names.join(', ')} in the topology json file" if topo_names && topo_names.length > 0
|
100
|
-
ui.info "Import finished"
|
101
|
-
|
65
|
+
def create_topo_bag_dir
|
66
|
+
# make sure the topology bag directory exists
|
67
|
+
path = File.join(topologies_path, topo_bag_name)
|
68
|
+
FileUtils.mkdir_p(path)
|
69
|
+
end
|
70
|
+
|
71
|
+
def import_topo
|
72
|
+
write_topo_to_file
|
73
|
+
do_create_artifacts
|
74
|
+
|
75
|
+
ui.info "Imported topology: #{@topo.display_info}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def write_topo_to_file
|
79
|
+
path = File.join(topologies_path, topo_bag_name, @topo['name'] + '.json')
|
80
|
+
File.open(path, 'w') do |f|
|
81
|
+
f.write(Chef::JSONCompat.to_json_pretty(@topo.raw_data))
|
82
|
+
f.close
|
83
|
+
ui.info "Created topology data bag: #{path}"
|
102
84
|
end
|
103
|
-
|
104
|
-
include Chef::Knife::TopologyHelper
|
85
|
+
end
|
105
86
|
|
87
|
+
def do_create_artifacts
|
88
|
+
@processor.generate_artifacts(
|
89
|
+
'cmd_args' => @args,
|
90
|
+
'cmd' => self
|
91
|
+
)
|
106
92
|
end
|
107
93
|
end
|
108
94
|
end
|
data/lib/chef/knife/topo_list.rb
CHANGED
@@ -17,36 +17,29 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'chef/knife'
|
20
|
-
|
20
|
+
require 'chef/knife/topo/loader'
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
require 'chef/data_bag'
|
28
|
-
end
|
29
|
-
|
30
|
-
banner "knife topo list (options)"
|
22
|
+
module KnifeTopo
|
23
|
+
# knife topo list
|
24
|
+
class TopoList < Chef::Knife
|
25
|
+
deps do
|
26
|
+
end
|
31
27
|
|
32
|
-
|
33
|
-
:short => '-D DATA_BAG',
|
34
|
-
:long => "--data-bag DATA_BAG",
|
35
|
-
:description => "The data bag the topologies are stored in"
|
36
|
-
|
28
|
+
banner 'knife topo list (options)'
|
37
29
|
|
38
|
-
|
30
|
+
option(
|
31
|
+
:data_bag,
|
32
|
+
short: '-D DATA_BAG',
|
33
|
+
long: '--data-bag DATA_BAG',
|
34
|
+
description: 'The data bag the topologies are stored in'
|
35
|
+
)
|
39
36
|
|
40
|
-
|
41
|
-
topo_bag = topo_bag_name(config[:data_bag])
|
42
|
-
output(format_list_for_display(Chef::DataBag.load(topo_bag)))
|
43
|
-
rescue Net::HTTPServerException => e
|
44
|
-
raise unless e.to_s =~ /^404/
|
45
|
-
end
|
37
|
+
include KnifeTopo::Loader
|
46
38
|
|
47
|
-
|
48
|
-
|
49
|
-
|
39
|
+
def run
|
40
|
+
output(format_list_for_display(list_topo_bag))
|
41
|
+
rescue Net::HTTPServerException => e
|
42
|
+
raise unless e.to_s =~ /^404/
|
50
43
|
end
|
51
44
|
end
|
52
45
|
end
|