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.
@@ -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
- require_relative 'topology_helper'
25
+ # NOTE: This command exports to stdout
22
26
 
23
- # NOTE: This command exports to stdout
24
-
25
- class Chef
26
- class Knife
27
- class TopoExport < Chef::Knife
27
+ module KnifeTopo
28
+ # knife topo export
29
+ class TopoExport < Chef::Knife
30
+ deps do
31
+ end
28
32
 
29
- deps do
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
- 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
- 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
- def run
62
-
63
- @bag_name = topo_bag_name(config[:data_bag])
77
+ export
78
+ end
64
79
 
65
- @topo_name = config[:topo] unless config[:all]
66
- @node_names = @name_args
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
- else
95
- # export all topologies
96
- export = []
97
- if dbag = load_from_server(@bag_name)
98
- dbag.keys.each do |topo_name|
99
- if topo = load_from_server(@bag_name, topo_name)
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
- output(Chef::JSONCompat.to_json_pretty(export))
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
- # give user a template to get started
110
- def empty_topology
111
- {
112
- "id" => @topo_name || "topo1",
113
- "name" => @topo_name || "topo1",
114
- "chef_environment" => "_default",
115
- "tags" => [ ],
116
- "nodes" => [ ],
117
- "cookbook_attributes" => [{
118
- "cookbook" => @topo_name || "topo1",
119
- "filename" => "topology"
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
- def empty_node(name)
125
- {
126
- "name" => name,
127
- "run_list" => [],
128
- "ssh_host" => name,
129
- "ssh_port" => "22",
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
- # get actual node properties for export
136
- def node_export (node_name)
137
-
138
- node_data = {}
139
-
140
- begin
141
- node = Chef::Node.load(node_name)
142
-
143
- node_data['name'] = node.name
144
- node_data['tags'] = node.tags
145
- node_data['chef_environment'] = node.chef_environment
146
- node_data['run_list'] = node.run_list
147
-
148
- pri = config[:min_priority]
149
- node_data['default'] = node.default if pri == "default"
150
- node_data['normal'] = node.normal if pri == "default" || pri == "normal"
151
- node_data['override'] = node.override
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
- # merge hash properties with the actual node properties
162
- def merge_node_properties!(nodes, node_name)
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["name"] == node_name }
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
- require_relative 'topology_helper'
22
- require_relative 'topo_cookbook_create'
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
- class Chef
25
- class Knife
26
- class TopoImport < Chef::Knife
31
+ banner 'knife topo import [ TOPOLOGY_FILE ] (options)'
27
32
 
28
- deps do
29
- Chef::Knife::TopoCookbookCreate.load_deps
30
- end
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
- 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"
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
- # 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', '', '' ])
49
+ include KnifeTopo::CommandHelper
50
+ include KnifeTopo::Loader
45
51
 
46
- # All called commands need to accept union of options
47
- Chef::Knife::TopoCookbookCreate.options = options
48
- end
52
+ def initialize(args)
53
+ super
54
+ @args = args
55
+ @topo_file = @name_args[0] || 'topology.json'
56
+ end
49
57
 
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)
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
- topologies.each do |topo_data|
63
-
64
- topo_name = topo_data['name'] || topo_data['id']
65
- topo_data['id'] ||= topo_name
66
- topo_data['name'] ||= topo_name
67
-
68
- if (!topo_name)
69
- ui.error "Could not find a topology name - #{topo_file} does not appear to be a valid topology JSON file"
70
- exit(1)
71
- end
72
-
73
- # check against specific topology list
74
- if topo_names
75
- if topo_names.include?(topo_name)
76
- topo_names.delete(topo_name)
77
- else
78
- next
79
- end
80
- end
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
@@ -17,36 +17,29 @@
17
17
  #
18
18
 
19
19
  require 'chef/knife'
20
- require_relative 'topology_helper'
20
+ require 'chef/knife/topo/loader'
21
21
 
22
- class Chef
23
- class Knife
24
- class TopoList < Chef::Knife
25
-
26
- deps do
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
- 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
-
28
+ banner 'knife topo list (options)'
37
29
 
38
- def run
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
- begin
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
- end
48
-
49
- include Chef::Knife::TopologyHelper
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