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,71 +17,57 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'chef/knife'
|
20
|
-
|
20
|
+
require 'chef/knife/topo/loader'
|
21
|
+
require 'chef/knife/cookbook_upload' unless defined? Chef::Knife::CookbookUpload
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
module KnifeTopo
|
24
|
+
# knife topo cookbook upload
|
25
|
+
class TopoCookbookUpload < Chef::Knife
|
26
|
+
deps do
|
27
|
+
require 'chef/knife/topo/processor'
|
28
|
+
end
|
24
29
|
|
25
|
-
|
26
|
-
class Knife
|
27
|
-
class TopoCookbookUpload < Chef::Knife
|
28
|
-
|
29
|
-
deps do
|
30
|
-
Chef::Knife::CookbookUpload.load_deps
|
31
|
-
end
|
30
|
+
banner 'knife topo cookbook upload TOPOLOGY (options)'
|
32
31
|
|
33
|
-
|
32
|
+
option(
|
33
|
+
:data_bag,
|
34
|
+
short: '-D DATA_BAG',
|
35
|
+
long: '--data-bag DATA_BAG',
|
36
|
+
description: 'The data bag the topologies are stored in'
|
37
|
+
)
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
:description => "The data bag the topologies are stored in"
|
39
|
+
# Make called command options available
|
40
|
+
self.options = (Chef::Knife::CookbookUpload.options).merge(
|
41
|
+
TopoCookbookUpload.options)
|
39
42
|
|
40
|
-
|
41
|
-
self.options = (Chef::Knife::CookbookUpload.options).merge(self.options)
|
43
|
+
include KnifeTopo::Loader
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
def initialize(args)
|
46
|
+
super
|
47
|
+
@args = args
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
49
|
+
# All called commands need to accept union of options
|
50
|
+
Chef::Knife::CookbookUpload.options = options
|
51
|
+
end
|
57
52
|
|
58
|
-
|
59
|
-
|
53
|
+
def run
|
54
|
+
validate_args
|
60
55
|
|
61
|
-
|
62
|
-
|
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
|
-
cookbook_names = []
|
69
|
-
if topo['cookbook_attributes'] && topo['cookbook_attributes'].length > 0
|
70
|
-
argPos = 2
|
71
|
-
topo['cookbook_attributes'].each do |entry|
|
72
|
-
cookbook_name = entry['cookbook']
|
73
|
-
@topo_upload_args[argPos] = cookbook_name unless cookbook_names.include?(cookbook_name)
|
74
|
-
cookbook_names << cookbook_name
|
75
|
-
argPos += 1
|
76
|
-
end
|
77
|
-
run_cmd(Chef::Knife::CookbookUpload, @topo_upload_args)
|
78
|
-
else
|
79
|
-
ui.info("No cookbooks found for topology #{display_name(topo)}")
|
80
|
-
end
|
81
|
-
end
|
56
|
+
# Load the topology data
|
57
|
+
@topo = load_local_topo_or_exit(@topo_name)
|
82
58
|
|
83
|
-
|
59
|
+
# Run cookbook upload command on the topology cookbook
|
60
|
+
@processor = KnifeTopo::Processor.for_topo(@topo)
|
61
|
+
@processor.upload_artifacts('cmd' => self, 'cmd_args' => @args)
|
62
|
+
end
|
84
63
|
|
64
|
+
def validate_args
|
65
|
+
unless @name_args[0]
|
66
|
+
show_usage
|
67
|
+
ui.fatal('You must specify the name of a topology')
|
68
|
+
exit 1
|
69
|
+
end
|
70
|
+
@topo_name = @name_args[0]
|
85
71
|
end
|
86
72
|
end
|
87
73
|
end
|
@@ -17,146 +17,134 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'chef/knife'
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
class Knife
|
26
|
-
class TopoCreate < Chef::Knife
|
27
|
-
|
28
|
-
deps do
|
29
|
-
Chef::Knife::TopoCookbookUpload.load_deps
|
30
|
-
Chef::Knife::Bootstrap.load_deps
|
31
|
-
end
|
20
|
+
require 'chef/knife/topo_bootstrap'
|
21
|
+
require 'chef/knife/cookbook_upload' unless defined? Chef::Knife::CookbookUpload
|
22
|
+
require 'chef/knife/topo/loader'
|
23
|
+
require 'chef/knife/topo/command_helper'
|
24
|
+
require 'chef/knife/topo/node_update_helper'
|
32
25
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
option :bootstrap,
|
41
|
-
:long => "--bootstrap",
|
42
|
-
:description => "Whether to bootstrap newly created nodes",
|
43
|
-
:boolean => true
|
44
|
-
|
45
|
-
option :disable_upload,
|
46
|
-
:long => "--disable-upload",
|
47
|
-
:description => "Do not upload topo cookbooks",
|
48
|
-
:boolean => true
|
49
|
-
|
50
|
-
option :overwrite,
|
51
|
-
:long => "--overwrite",
|
52
|
-
:description => "Whether to overwrite existing nodes",
|
53
|
-
:boolean => true
|
54
|
-
|
55
|
-
# Make called command options available
|
56
|
-
opts = self.options
|
57
|
-
self.options = (Chef::Knife::Bootstrap.options).merge(Chef::Knife::TopoCookbookUpload.options)
|
58
|
-
self.options.merge!(opts)
|
59
|
-
|
60
|
-
def initialize (args)
|
61
|
-
super
|
62
|
-
@bootstrap_args = initialize_cmd_args(args, [ 'bootstrap', '' ])
|
63
|
-
@topo_upload_args = initialize_cmd_args(args, [ 'topo', 'cookbook', 'upload', @name_args[0] ])
|
64
|
-
|
65
|
-
# All called commands need to accept union of options
|
66
|
-
Chef::Knife::Bootstrap.options = options
|
67
|
-
Chef::Knife::TopoCookbookUpload.options = options
|
68
|
-
end
|
69
|
-
|
70
|
-
def run
|
71
|
-
if !@name_args[0]
|
72
|
-
show_usage
|
73
|
-
ui.fatal("You must specify the name of a topology")
|
74
|
-
exit 1
|
75
|
-
end
|
26
|
+
module KnifeTopo
|
27
|
+
# knife topo create
|
28
|
+
class TopoCreate < KnifeTopo::TopoBootstrap
|
29
|
+
deps do
|
30
|
+
require 'chef/knife/topo/processor'
|
31
|
+
KnifeTopo::TopoBootstrap.load_deps
|
32
|
+
end
|
76
33
|
|
77
|
-
|
78
|
-
topo_name = @name_args[0]
|
34
|
+
banner 'knife topo create TOPOLOGY (options)'
|
79
35
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
36
|
+
option(
|
37
|
+
:bootstrap,
|
38
|
+
long: '--bootstrap',
|
39
|
+
description: 'Whether to bootstrap newly created nodes',
|
40
|
+
boolean: true
|
41
|
+
)
|
42
|
+
|
43
|
+
option(
|
44
|
+
:disable_upload,
|
45
|
+
long: '--disable-upload',
|
46
|
+
description: 'Do not upload topo cookbooks',
|
47
|
+
boolean: true
|
48
|
+
)
|
49
|
+
|
50
|
+
# Make called command options available
|
51
|
+
orig_opts = KnifeTopo::TopoCreate.options
|
52
|
+
upload_opts = Chef::Knife::CookbookUpload.options
|
53
|
+
merged_opts = (KnifeTopo::TopoBootstrap.options).merge(upload_opts)
|
54
|
+
self.options = merged_opts.merge(orig_opts)
|
55
|
+
|
56
|
+
include KnifeTopo::CommandHelper
|
57
|
+
include KnifeTopo::NodeUpdateHelper
|
58
|
+
include KnifeTopo::Loader
|
59
|
+
|
60
|
+
def initialize(args)
|
61
|
+
super
|
62
|
+
@args = args
|
63
|
+
end
|
64
|
+
|
65
|
+
def bootstrap_msgs
|
66
|
+
msgs = super.dup
|
67
|
+
msgs[:existed] = 'Updated but did not bootstrap %{num} existing nodes '\
|
68
|
+
"[ %{list} ].\n Specify --overwrite to re-bootstrap existing nodes. \n"
|
69
|
+
msgs
|
70
|
+
end
|
71
|
+
|
72
|
+
def non_bootstrap_msgs
|
73
|
+
{
|
74
|
+
existed: 'Applied updates (if any) to %{num} nodes [ %{list} ]',
|
75
|
+
skipped_ssh: 'Unexpected error skipped_ssh',
|
76
|
+
skipped: 'Skipped %{num} nodes [ %{list} ] because they do not exist',
|
77
|
+
bootstrapped: 'Unexpected error bootstrapped',
|
78
|
+
failed: 'Unexpected error failed'
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def run
|
83
|
+
validate_args
|
84
|
+
create_or_update_topo
|
85
|
+
|
86
|
+
# make sure env and cookbooks are in place
|
87
|
+
check_chef_env(@topo['chef_environment'])
|
88
|
+
upload_artifacts unless config[:disable_upload]
|
89
|
+
update_nodes
|
97
90
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
ui.info("Skipped #{skipped.length} nodes [ #{skipped.join(', ')} ] because they do not exist") if skipped.length > 0
|
148
|
-
end
|
149
|
-
|
150
|
-
ui.warn("#{failed.length} nodes [ #{failed.join(', ')} ] failed to bootstrap due to errors") if failed.length > 0
|
151
|
-
|
91
|
+
report
|
92
|
+
end
|
93
|
+
|
94
|
+
def processor
|
95
|
+
@processor ||= KnifeTopo::Processor.for_topo(@topo)
|
96
|
+
end
|
97
|
+
|
98
|
+
def validate_args
|
99
|
+
super
|
100
|
+
@bootstrap = config[:bootstrap]
|
101
|
+
@msgs = @bootstrap ? bootstrap_msgs : non_bootstrap_msgs
|
102
|
+
config[:disable_editing] = true
|
103
|
+
end
|
104
|
+
|
105
|
+
def create_or_update_topo
|
106
|
+
# Load the topology data & create the topology bag
|
107
|
+
@topo = load_local_topo_or_exit(@topo_name)
|
108
|
+
create_topo_bag
|
109
|
+
|
110
|
+
# Add topology item to the data bag on the server
|
111
|
+
@topo.create
|
112
|
+
rescue Net::HTTPServerException => e
|
113
|
+
raise unless e.to_s =~ /^409/
|
114
|
+
confirm_and_update_topo
|
115
|
+
end
|
116
|
+
|
117
|
+
def update_nodes
|
118
|
+
nodes = processor.generate_nodes
|
119
|
+
nodes.each do |node_data|
|
120
|
+
bootstrap_or_update_node(node_data)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def confirm_and_update_topo
|
125
|
+
version = @topo.topo_version
|
126
|
+
to_version_str = " to version #{version}"
|
127
|
+
msg = "Topology #{@topo_name} already exists - do you want to " \
|
128
|
+
"update it#{to_version_str if version}"
|
129
|
+
ui.confirm(msg, true, false)
|
130
|
+
@topo.save
|
131
|
+
end
|
132
|
+
|
133
|
+
def bootstrap_or_update_node(node_data)
|
134
|
+
node_name = node_data['name']
|
135
|
+
if @bootstrap
|
136
|
+
update_node(node_data) unless node_bootstrap(node_data)
|
137
|
+
else
|
138
|
+
if update_node(node_data)
|
139
|
+
@results[:existed] << node_name
|
152
140
|
else
|
153
|
-
|
141
|
+
@results[:skipped] << node_name
|
154
142
|
end
|
155
|
-
|
156
143
|
end
|
144
|
+
end
|
157
145
|
|
158
|
-
|
159
|
-
|
146
|
+
def upload_artifacts
|
147
|
+
processor.upload_artifacts('cmd' => self, 'cmd_args' => @args)
|
160
148
|
end
|
161
149
|
end
|
162
150
|
end
|
@@ -17,80 +17,82 @@
|
|
17
17
|
#
|
18
18
|
|
19
19
|
require 'chef/knife'
|
20
|
-
|
20
|
+
require 'chef/knife/topo/loader'
|
21
|
+
require 'chef/knife/topo/command_helper'
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
module KnifeTopo
|
24
|
+
# knife topo delete
|
25
|
+
class TopoDelete < Chef::Knife
|
26
|
+
deps do
|
27
|
+
require 'chef/node'
|
28
|
+
end
|
29
|
+
|
30
|
+
banner 'knife topo delete TOPOLOGY (options)'
|
31
|
+
|
32
|
+
option(
|
33
|
+
:data_bag,
|
34
|
+
short: '-D DATA_BAG',
|
35
|
+
long: '--data-bag DATA_BAG',
|
36
|
+
description: 'The data bag the topologies are stored in'
|
37
|
+
)
|
25
38
|
|
26
|
-
|
27
|
-
|
39
|
+
include KnifeTopo::CommandHelper
|
40
|
+
include KnifeTopo::Loader
|
41
|
+
|
42
|
+
def run
|
43
|
+
validate_args
|
44
|
+
config[:disable_editing] = true
|
45
|
+
|
46
|
+
# remove each node
|
47
|
+
@topo = load_topo_from_server(@topo_name)
|
48
|
+
unless @topo
|
49
|
+
ui.info "Topology #{topo_bag_name}/#{@topo_name} does not " \
|
50
|
+
'exist on server'
|
51
|
+
exit(0)
|
28
52
|
end
|
29
53
|
|
30
|
-
|
54
|
+
confirm_and_delete_nodes
|
55
|
+
delete_topo
|
56
|
+
end
|
31
57
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
58
|
+
def validate_args
|
59
|
+
unless @name_args[0]
|
60
|
+
show_usage
|
61
|
+
ui.fatal('You must specify the name of a topology')
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
@topo_name = @name_args[0]
|
65
|
+
end
|
37
66
|
|
38
|
-
|
67
|
+
def confirm_and_delete_nodes
|
68
|
+
confirm("Do you want to delete topology #{@topo_name} - " \
|
69
|
+
'this does not delete nodes')
|
70
|
+
@topo['nodes'].each do |node|
|
71
|
+
remove_node_from_topology(node['name'])
|
72
|
+
end if @topo['nodes']
|
73
|
+
end
|
74
|
+
|
75
|
+
def delete_topo
|
76
|
+
@topo.destroy(topo_bag_name, @topo_name)
|
77
|
+
ui.info "Deleted topology #{@topo_name}"
|
78
|
+
end
|
39
79
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
# remove each node
|
46
|
-
|
47
|
-
unless topo = load_from_server(topo_bag, @topo_name)
|
48
|
-
ui.info "Topology #{topo_bag}/#{@topo_name} does not exist on server"
|
49
|
-
exit(0)
|
50
|
-
end
|
51
|
-
|
52
|
-
confirm("Do you want to delete topology #{@topo_name} - this does not delete nodes")
|
53
|
-
|
54
|
-
topo['nodes'].each do | node |
|
55
|
-
remove_node_from_topology(node['name'])
|
56
|
-
end if topo['nodes']
|
57
|
-
|
58
|
-
# delete the data bag item
|
59
|
-
topo.destroy(topo_bag, @topo_name)
|
80
|
+
# Remove the topo name attribute from all nodes, so topo search
|
81
|
+
# knows they are not in the topology
|
82
|
+
def remove_node_from_topology(node_name)
|
83
|
+
# load then update and save the node
|
84
|
+
node = Chef::Node.load(node_name)
|
60
85
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
exit 1
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Remove the topo name attribute from all nodes, so topo search knows they are not in the topology
|
70
|
-
def remove_node_from_topology(node_name)
|
71
|
-
|
72
|
-
config[:disable_editing] = true
|
73
|
-
begin
|
74
|
-
|
75
|
-
# load then update and save the node
|
76
|
-
node = Chef::Node.load(node_name)
|
77
|
-
|
78
|
-
if node['topo'] && node['topo']['name'] == @topo_name
|
79
|
-
node.rm('topo','name')
|
80
|
-
ui.info "Removing node #{node.name} from topology"
|
81
|
-
node.save
|
82
|
-
end
|
83
|
-
|
84
|
-
rescue Net::HTTPServerException => e
|
85
|
-
raise unless e.to_s =~ /^404/
|
86
|
-
# Node has not been created
|
87
|
-
end
|
88
|
-
|
89
|
-
return node
|
86
|
+
if node['topo'] && node['topo']['name'] == @topo_name
|
87
|
+
node.rm('topo', 'name')
|
88
|
+
ui.info "Removing node #{node.name} from topology"
|
89
|
+
node.save
|
90
90
|
end
|
91
|
-
|
92
|
-
include Chef::Knife::TopologyHelper
|
91
|
+
node
|
93
92
|
|
93
|
+
rescue Net::HTTPServerException => e
|
94
|
+
raise unless e.to_s =~ /^404/
|
95
|
+
# Node has not been created
|
94
96
|
end
|
95
97
|
end
|
96
|
-
end
|
98
|
+
end
|