lib/chef/knife/topo_create.rb in knife-topo-1.1.2 vs lib/chef/knife/topo_create.rb in knife-topo-2.0.1
- old
+ new
@@ -15,148 +15,136 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/knife'
-require_relative 'topology_helper'
-require_relative 'topo_bootstrap'
-require_relative 'topo_cookbook_upload'
+require 'chef/knife/topo_bootstrap'
+require 'chef/knife/cookbook_upload' unless defined? Chef::Knife::CookbookUpload
+require 'chef/knife/topo/loader'
+require 'chef/knife/topo/command_helper'
+require 'chef/knife/topo/node_update_helper'
-class Chef
- class Knife
- class TopoCreate < Chef::Knife
-
- deps do
- Chef::Knife::TopoCookbookUpload.load_deps
- Chef::Knife::Bootstrap.load_deps
- end
+module KnifeTopo
+ # knife topo create
+ class TopoCreate < KnifeTopo::TopoBootstrap
+ deps do
+ require 'chef/knife/topo/processor'
+ KnifeTopo::TopoBootstrap.load_deps
+ end
- banner "knife topo create TOPOLOGY (options)"
+ banner 'knife topo create TOPOLOGY (options)'
- option :data_bag,
- :short => '-D DATA_BAG',
- :long => "--data-bag DATA_BAG",
- :description => "The data bag the topologies are stored in"
+ option(
+ :bootstrap,
+ long: '--bootstrap',
+ description: 'Whether to bootstrap newly created nodes',
+ boolean: true
+ )
- option :bootstrap,
- :long => "--bootstrap",
- :description => "Whether to bootstrap newly created nodes",
- :boolean => true
+ option(
+ :disable_upload,
+ long: '--disable-upload',
+ description: 'Do not upload topo cookbooks',
+ boolean: true
+ )
- option :disable_upload,
- :long => "--disable-upload",
- :description => "Do not upload topo cookbooks",
- :boolean => true
-
- option :overwrite,
- :long => "--overwrite",
- :description => "Whether to overwrite existing nodes",
- :boolean => true
-
- # Make called command options available
- opts = self.options
- self.options = (Chef::Knife::Bootstrap.options).merge(Chef::Knife::TopoCookbookUpload.options)
- self.options.merge!(opts)
+ # Make called command options available
+ orig_opts = KnifeTopo::TopoCreate.options
+ upload_opts = Chef::Knife::CookbookUpload.options
+ merged_opts = (KnifeTopo::TopoBootstrap.options).merge(upload_opts)
+ self.options = merged_opts.merge(orig_opts)
- def initialize (args)
- super
- @bootstrap_args = initialize_cmd_args(args, [ 'bootstrap', '' ])
- @topo_upload_args = initialize_cmd_args(args, [ 'topo', 'cookbook', 'upload', @name_args[0] ])
+ include KnifeTopo::CommandHelper
+ include KnifeTopo::NodeUpdateHelper
+ include KnifeTopo::Loader
- # All called commands need to accept union of options
- Chef::Knife::Bootstrap.options = options
- Chef::Knife::TopoCookbookUpload.options = options
- end
-
- def run
- if !@name_args[0]
- show_usage
- ui.fatal("You must specify the name of a topology")
- exit 1
- end
+ def initialize(args)
+ super
+ @args = args
+ end
- bag_name = topo_bag_name(config[:data_bag])
- topo_name = @name_args[0]
+ def bootstrap_msgs
+ msgs = super.dup
+ msgs[:existed] = 'Updated but did not bootstrap %{num} existing nodes '\
+ "[ %{list} ].\n Specify --overwrite to re-bootstrap existing nodes. \n"
+ msgs
+ end
- # Load the topology data & create the topology bag
- unless topo = load_from_file(bag_name, topo_name )
- ui.fatal("Topology file #{topologies_path}/#{bag_name}/#{topo_name}.json not found - use 'knife topo import' first")
- exit(1)
- end
- @data_bag = create_bag(bag_name)
-
- # Add topology item to the data bag on the server
- begin
- topo.create
- rescue Net::HTTPServerException => e
- raise unless e.to_s =~ /^409/
- msg = "Topology #{topo_name} already exists - do you want to update it"
- msg = msg + " to version " + format_topo_version(topo) if topo['version']
- ui.confirm(msg, true, false)
- topo.save
- end
+ def non_bootstrap_msgs
+ {
+ existed: 'Applied updates (if any) to %{num} nodes [ %{list} ]',
+ skipped_ssh: 'Unexpected error skipped_ssh',
+ skipped: 'Skipped %{num} nodes [ %{list} ] because they do not exist',
+ bootstrapped: 'Unexpected error bootstrapped',
+ failed: 'Unexpected error failed'
+ }
+ end
- # make sure env and cookbooks are in place
- check_chef_env(topo['chef_environment']) if topo['chef_environment']
- upload_cookbooks(@topo_upload_args) if (!config[:disable_upload])
+ def run
+ validate_args
+ create_or_update_topo
- # update any existing nodes
- topo_hash = topo.raw_data
- nodes = merge_topo_properties(topo_hash['nodes'], topo_hash)
- config[:disable_editing] = true
-
- bootstrapped = []
- updated = []
- skipped = []
- failed = []
-
- if nodes && nodes.length > 0
-
- nodes.each do |node_data|
- node_name = node_data['name']
-
- exists = resource_exists?("nodes/#{node_name}")
- if(node_data['ssh_host'] && config[:bootstrap] && (config[:overwrite] || !exists))
- if run_bootstrap(node_data, @bootstrap_args, exists)
- bootstrapped << node_name
- else
- failed << node_name
- end
- else
- if(exists)
- updated << node_name
- node = update_node(node_data)
- else
- skipped << node_name
- end
- end
- end
-
- ui.info("Topology #{display_name(topo_hash)} created, containing #{nodes.length} nodes")
- ui.info("Build information: " + topo_hash['buildstamp']) if topo_hash['buildstamp']
-
- if(config[:bootstrap])
- ui.info("Bootstrapped #{bootstrapped.length} nodes [ #{bootstrapped.join(', ')} ]")
- if updated.length > 0
- ui.info("Updated #{updated.length} nodes [ #{updated.join(', ')} ] because they already exist. " +
- "Specify --overwrite to re-bootstrap existing nodes. " +
- "If you are using Chef Vault, you may need to use --bootstrap-vault options in this case.")
- end
- ui.info("Skipped #{skipped.length} nodes [ #{skipped.join(', ')} ] because they had no ssh_host information") if skipped.length > 0
- else
- ui.info("Updated #{updated.length} nodes [ #{updated.join(', ')} ]")
- ui.info("Skipped #{skipped.length} nodes [ #{skipped.join(', ')} ] because they do not exist") if skipped.length > 0
- end
-
- ui.warn("#{failed.length} nodes [ #{failed.join(', ')} ] failed to bootstrap due to errors") if failed.length > 0
-
+ # make sure env and cookbooks are in place
+ check_chef_env(@topo['chef_environment'])
+ upload_artifacts unless config[:disable_upload]
+ update_nodes
+
+ report
+ end
+
+ def processor
+ @processor ||= KnifeTopo::Processor.for_topo(@topo)
+ end
+
+ def validate_args
+ super
+ @bootstrap = config[:bootstrap]
+ @msgs = @bootstrap ? bootstrap_msgs : non_bootstrap_msgs
+ config[:disable_editing] = true
+ end
+
+ def create_or_update_topo
+ # Load the topology data & create the topology bag
+ @topo = load_local_topo_or_exit(@topo_name)
+ create_topo_bag
+
+ # Add topology item to the data bag on the server
+ @topo.create
+ rescue Net::HTTPServerException => e
+ raise unless e.to_s =~ /^409/
+ confirm_and_update_topo
+ end
+
+ def update_nodes
+ nodes = processor.generate_nodes
+ nodes.each do |node_data|
+ bootstrap_or_update_node(node_data)
+ end
+ end
+
+ def confirm_and_update_topo
+ version = @topo.topo_version
+ to_version_str = " to version #{version}"
+ msg = "Topology #{@topo_name} already exists - do you want to " \
+ "update it#{to_version_str if version}"
+ ui.confirm(msg, true, false)
+ @topo.save
+ end
+
+ def bootstrap_or_update_node(node_data)
+ node_name = node_data['name']
+ if @bootstrap
+ update_node(node_data) unless node_bootstrap(node_data)
+ else
+ if update_node(node_data)
+ @results[:existed] << node_name
else
- ui.info "No nodes found for topology #{display_name(topo_hash)}"
+ @results[:skipped] << node_name
end
-
end
+ end
- include Chef::Knife::TopologyHelper
-
+ def upload_artifacts
+ processor.upload_artifacts('cmd' => self, 'cmd_args' => @args)
end
end
end