Module: Ironfan::KnifeCommon
- Included in:
- Chef::Knife::ClusterDiff, Chef::Knife::ClusterLaunch, Chef::Knife::ClusterList, Chef::Knife::ClusterPry, Chef::Knife::ClusterShow, Chef::Knife::ClusterSsh, Chef::Knife::EnvironmentFromRealm, Script
- Defined in:
- lib/chef/knife/ironfan_knife_common.rb
Defined Under Namespace
Modules: ClassMethods
Instance Attribute Summary collapse
-
#broker ⇒ Object
Returns the value of attribute broker.
-
#problems ⇒ Object
list of problems encountered.
Class Method Summary collapse
Instance Method Summary collapse
- #all_computers(slice_string, *args) ⇒ Object
- #bootstrapper(computer) ⇒ Object
-
#configure_dry_run ⇒ Object
Put Fog into mock mode if –dry_run.
-
#confirm_execution(*args) ⇒ Object
override in subclass to confirm risky actions.
- #confirm_or_exit(question, correct_answer) ⇒ Object
- #die(*args) ⇒ Object
-
#discover_computers(realm_name, cluster_name, facet_name, slice_indexes) ⇒ Object
Common code for calling broker.discover with an appropriately trimmed list of clusters to discover.
-
#display(target, display_style = nil, &block) ⇒ Object
passes target to Broker::Conductor#display, will show headings in server slice tables based on the –verbose flag.
- #exit_if_unhealthy! ⇒ Object
- #gemfile(realm_or_cluster_name) ⇒ Object
-
#get_relevant_slice(*predicate) ⇒ Object
Get a slice of nodes matching the given filter.
-
#get_slice(slice_string, *args) ⇒ Ironfan::ServerSlice
A slice of a cluster:.
-
#has_problem(desc) ⇒ Object
register that a problem was encountered.
-
#healthy? ⇒ Boolean
healthy if no problems.
- #load_ironfan ⇒ Object
- #pick_apart(slice_string, *args) ⇒ Object
- #predicate_str(realm_name, cluster_name, facet_name, slice_indexes) ⇒ Object
-
#progressbar_for_threads(threads) ⇒ Object
Show a pretty progress bar while we wait for a set of threads to finish.
-
#relevant?(computer) ⇒ Boolean
method to nodes should be filtered on.
- #run ⇒ Object
- #run_bootstrap(computer) ⇒ Object
-
#section(desc, *style) ⇒ Object
Announce a new section of tasks.
-
#sub_command ⇒ Object
Utilities.
- #wait_for_ssh(computer) ⇒ Object
Instance Attribute Details
#broker ⇒ Object
Returns the value of attribute broker.
3 4 5 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 3 def broker @broker end |
#problems ⇒ Object
list of problems encountered
244 245 246 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 244 def problems @problems end |
Class Method Details
.included(base) ⇒ Object
292 293 294 295 296 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 292 def self.included(base) base.class_eval do extend ClassMethods end end |
.load_deps ⇒ Object
5 6 7 8 9 10 11 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 5 def self.load_deps require 'formatador' require 'chef/node' require 'chef/api_client' require 'fog' require 'rbvmomi' end |
Instance Method Details
#all_computers(slice_string, *args) ⇒ Object
70 71 72 73 74 75 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 70 def all_computers(slice_string, *args) realm_name, cluster_name, facet_name, slice_indexes = pick_apart(slice_string, *args) computers = discover_computers(realm_name, cluster_name, facet_name, slice_indexes) ui.info("Loaded information for #{computers.size} computer(s) in cluster #{cluster_name}") computers end |
#bootstrapper(computer) ⇒ Object
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 157 def bootstrapper(computer) server = computer.server hostname = computer.dns_name # bootstrap = Chef::Knife::Bootstrap.new bootstrap.config.merge!(config) # bootstrap.name_args = [ hostname ] bootstrap.config[:computer] = computer bootstrap.config[:server] = server bootstrap.config[:run_list] = server.run_list bootstrap.config[:ssh_user] = config[:ssh_user] || computer.ssh_user bootstrap.config[:attribute] = config[:attribute] bootstrap.config[:identity_file] = config[:identity_file] || computer.ssh_identity_file bootstrap.config[:distro] = config[:distro] || computer.bootstrap_distro bootstrap.config[:use_sudo] = true unless config[:use_sudo] == false bootstrap.config[:chef_node_name] = server.full_name bootstrap.config[:client_key] = ( computer.client.private_key rescue nil ) # bootstrap end |
#configure_dry_run ⇒ Object
Put Fog into mock mode if –dry_run
129 130 131 132 133 134 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 129 def configure_dry_run if config[:dry_run] Fog.mock! Fog::Mock.delay = 0 end end |
#confirm_execution(*args) ⇒ Object
override in subclass to confirm risky actions
100 101 102 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 100 def confirm_execution(*args) # pass end |
#confirm_or_exit(question, correct_answer) ⇒ Object
235 236 237 238 239 240 241 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 235 def confirm_or_exit question, correct_answer response = ui.ask_question(question) unless response.chomp == correct_answer die "I didn't think so.", "Aborting!", 1 end ui.info("") end |
#die(*args) ⇒ Object
272 273 274 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 272 def die *args Ironfan.die(*args) end |
#discover_computers(realm_name, cluster_name, facet_name, slice_indexes) ⇒ Object
Common code for calling broker.discover with an appropriately trimmed list of clusters to discover.
48 49 50 51 52 53 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 48 def discover_computers(realm_name, cluster_name, facet_name, slice_indexes) realm = Ironfan.load_realm(realm_name) realm.clusters.each{ |cluster| Ironfan.load_cluster cluster.name } clusters = cluster_name ? Array(realm.clusters[cluster_name.to_sym]) : realm.clusters.to_a return broker.discover!(clusters, config[:cloud]) end |
#display(target, display_style = nil, &block) ⇒ Object
passes target to Broker::Conductor#display, will show headings in server slice tables based on the –verbose flag
121 122 123 124 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 121 def display(target, display_style=nil, &block) display_style ||= (config[:verbosity] == 0 ? :default : :expanded) broker.display(target, display_style, &block) end |
#exit_if_unhealthy! ⇒ Object
252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 252 def exit_if_unhealthy! return if healthy? problems.each do |problem| if problem.respond_to?(:call) problem.call else ui.warn(problem) end end exit(2) if not healthy? end |
#gemfile(realm_or_cluster_name) ⇒ Object
39 40 41 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 39 def gemfile(realm_or_cluster_name) "Gemfile.#{realm_or_cluster_name}" end |
#get_relevant_slice(*predicate) ⇒ Object
Get a slice of nodes matching the given filter
110 111 112 113 114 115 116 117 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 110 def get_relevant_slice( *predicate ) full_target = get_slice( *predicate ) display(full_target) do |mach| rel = relevant?(mach) { :relevant? => (rel ? "[green]#{rel}[reset]" : '-' ) } end full_target.select{|mach| relevant?(mach) } end |
#get_slice(slice_string, *args) ⇒ Ironfan::ServerSlice
A slice of a cluster:
60 61 62 63 64 65 66 67 68 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 60 def get_slice(slice_string, *args) realm_name, cluster_name, facet_name, slice_indexes = pick_apart(slice_string, *args) desc = predicate_str(realm_name, cluster_name, facet_name, slice_indexes) ui.info("Inventorying servers in #{desc}") computers = discover_computers(realm_name, cluster_name, facet_name, slice_indexes) Chef::Log.info("Inventoried #{computers.size} computers") return computers.slice(cluster_name, facet_name, slice_indexes) end |
#has_problem(desc) ⇒ Object
register that a problem was encountered
246 247 248 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 246 def has_problem(desc) (@problems||=[]) << desc end |
#healthy? ⇒ Boolean
healthy if no problems
250 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 250 def healthy?() problems.blank? ; end |
#load_ironfan ⇒ Object
13 14 15 16 17 18 19 20 21 22 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 13 def load_ironfan $LOAD_PATH << File.join(Chef::Config[:ironfan_path], '/lib') if Chef::Config[:ironfan_path] require 'ironfan' $stdout.sync = true Ironfan.ui = self.ui self.config[:cloud] = Chef::Config[:cloud] if Chef::Config.has_key?(:cloud) Ironfan.knife_config = self.config Ironfan.chef_config = Chef::Config self.broker = Ironfan.broker end |
#pick_apart(slice_string, *args) ⇒ Object
77 78 79 80 81 82 83 84 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 77 def pick_apart(slice_string, *args) if not args.empty? slice_string = [slice_string, args].flatten.join("-") ui.info("") ui.warn("Please specify server slices joined by dashes and not separate args:\n\n knife cluster #{sub_command} #{slice_string}\n\n") end slice_string.split(/[\s\-]/, 4) end |
#predicate_str(realm_name, cluster_name, facet_name, slice_indexes) ⇒ Object
86 87 88 89 90 91 92 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 86 def predicate_str(realm_name, cluster_name, facet_name, slice_indexes) [ "#{ui.color(realm_name, :bold)} realm", (cluster_name ? "#{ui.color(cluster_name, :bold)} cluster" : "#{ui.color("all", :bold)} clusters"), (facet_name ? "#{ui.color(facet_name, :bold)} facet" : "#{ui.color("all", :bold)} facets"), (slice_indexes ? "servers #{ui.color(slice_indexes, :bold)}" : "#{ui.color("all", :bold)} servers") ].join(', ') end |
#progressbar_for_threads(threads) ⇒ Object
Show a pretty progress bar while we wait for a set of threads to finish.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 137 def (threads) section "Waiting for servers:" total = threads.length remaining = threads.select(&:alive?) start_time = Time.now until remaining.empty? remaining = remaining.select(&:alive?) if config[:verbose] ui.info "waiting: #{total - remaining.length} / #{total}, #{(Time.now - start_time).to_i}s" sleep 5 else Formatador.(total - remaining.length, total, {:started_at => start_time }) sleep 1 end end # Collapse the threads threads.each(&:join) ui.info '' end |
#relevant?(computer) ⇒ Boolean
method to nodes should be filtered on
95 96 97 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 95 def relevant?(computer) computer.running? end |
#run ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 24 def run() gemfile_v = gemfile(@name_args.first.to_s.split(/[_-]/).first) if ENV['BUNDLE_GEMFILE'] == gemfile_v _run elsif not File.exist?(gemfile_v) ui.info("no realm-specific Gemfile found. using default Gemfile.") _run else cmd = "bundle exec knife #{ARGV.join(' ')}" ui.info("re-running `#{cmd}` with BUNDLE_GEMFILE=#{gemfile_v}") return Bundler.clean_exec({'BUNDLE_GEMFILE' => gemfile_v}, cmd) end end |
#run_bootstrap(computer) ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 179 def run_bootstrap(computer) bs = bootstrapper(computer) if config[:skip].to_s == 'true' ui.info "Skipping: bootstrap #{computer.name} with #{JSON.pretty_generate(bs.config)}" return end # Ironfan.step(computer.name, "Running bootstrap") Chef::Log.info("Bootstrapping:\n Computer #{computer}\n Bootstrap config #{bs.config}") Ironfan.safely([computer, bs.config].inspect) do bs.run end end |
#section(desc, *style) ⇒ Object
Announce a new section of tasks
267 268 269 270 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 267 def section(desc, *style) style = [:blue] if style.empty? ui.info(ui.color(desc, *style)) end |
#sub_command ⇒ Object
Utilities
231 232 233 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 231 def sub_command self.class.sub_command end |
#wait_for_ssh(computer) ⇒ Object
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/chef/knife/ironfan_knife_common.rb', line 193 def wait_for_ssh(computer) ssh = Chef::Knife::Ssh.new ssh.ui = ui ssh.name_args = [ computer.name, "ls" ] ssh.config[:ssh_user] = Chef::Config[:knife][:ssh_user] || config[:ssh_user] ssh.config[:ssh_password] = config[:ssh_password] ssh.config[:ssh_port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port] ssh.config[:ssh_gateway] = Chef::Config[:knife][:ssh_gateway] || config[:ssh_gateway] ssh.config[:forward_agent] = Chef::Config[:knife][:forward_agent] || config[:forward_agent] ssh.config[:identity_file] = Chef::Config[:knife][:identity_file] || config[:identity_file] ssh.config[:manual] = true ssh.config[:host_key_verify] = Chef::Config[:knife][:host_key_verify] || config[:host_key_verify] ssh.config[:on_error] = :raise session = ssh.session return true rescue Errno::ETIMEDOUT Chef::Log.debug("ssh to #{computer.name} timed out") return false rescue Errno::ECONNREFUSED Chef::Log.debug("ssh connection to #{computer.name} refused") yield return false rescue Errno::EHOSTUNREACH Chef::Log.debug("ssh host #{computer.name} unreachable") yield return false rescue Chef::Log.debug("something else went wrong while wating for ssh host #{computer.name}") raise return false else session && session.close session = nil end |