Module: Ironfan::KnifeCommon

Included in:
Chef::Knife::ClusterLaunch, Chef::Knife::ClusterList, Chef::Knife::ClusterPry, Chef::Knife::ClusterShow, Chef::Knife::ClusterSsh, Script
Defined in:
lib/chef/knife/ironfan_knife_common.rb

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Instance Attribute Details

- (Object) broker

Returns the value of attribute broker



5
6
7
# File 'lib/chef/knife/ironfan_knife_common.rb', line 5

def broker
  @broker
end

- (Object) problems

list of problems encountered



186
187
188
# File 'lib/chef/knife/ironfan_knife_common.rb', line 186

def problems
  @problems
end

Class Method Details

+ (Object) included(base)



234
235
236
237
238
# File 'lib/chef/knife/ironfan_knife_common.rb', line 234

def self.included(base)
  base.class_eval do
    extend ClassMethods
  end
end

+ (Object) load_deps



7
8
9
10
11
12
13
# File 'lib/chef/knife/ironfan_knife_common.rb', line 7

def self.load_deps
  require 'formatador'
  require 'chef/node'
  require 'chef/api_client'
  require 'fog'
  require 'rbvmomi'
end

Instance Method Details

- (Object) all_computers(slice_string, *args)



47
48
49
50
51
52
# File 'lib/chef/knife/ironfan_knife_common.rb', line 47

def all_computers(slice_string, *args)
  cluster_name, facet_name, slice_indexes = pick_apart(slice_string, *args)
  computers = broker.discover! Ironfan.load_cluster(cluster_name)
  ui.info("Loaded information for #{computers.size} computer(s) in cluster #{cluster_name}")
  computers
end

- (Object) bootstrapper(computer)



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/chef/knife/ironfan_knife_common.rb', line 133

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

- (Object) configure_dry_run

Put Fog into mock mode if --dry_run



105
106
107
108
109
110
# File 'lib/chef/knife/ironfan_knife_common.rb', line 105

def configure_dry_run
  if config[:dry_run]
    Fog.mock!
    Fog::Mock.delay = 0
  end
end

- (Object) confirm_execution(*args)

override in subclass to confirm risky actions



76
77
78
# File 'lib/chef/knife/ironfan_knife_common.rb', line 76

def confirm_execution(*args)
  # pass
end

- (Object) confirm_or_exit(question, correct_answer)



177
178
179
180
181
182
183
# File 'lib/chef/knife/ironfan_knife_common.rb', line 177

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

- (Object) die(*args)



214
215
216
# File 'lib/chef/knife/ironfan_knife_common.rb', line 214

def die *args
  Ironfan.die(*args)
end

- (Object) display(target, display_style = nil, &block)

passes target to Broker::Conductor#display, will show headings in server slice tables based on the --verbose flag



97
98
99
100
# File 'lib/chef/knife/ironfan_knife_common.rb', line 97

def display(target, display_style=nil, &block)
  display_style ||= (config[:verbosity] == 0 ? :default : :expanded)
  broker.display(target, display_style, &block)
end

- (Object) exit_if_unhealthy!



194
195
196
197
198
199
200
201
202
203
204
# File 'lib/chef/knife/ironfan_knife_common.rb', line 194

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

- (Object) get_relevant_slice(*predicate)

Get a slice of nodes matching the given filter

Examples:

target = get_relevant_slice(* @name_args)


86
87
88
89
90
91
92
93
# File 'lib/chef/knife/ironfan_knife_common.rb', line 86

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

- (Ironfan::ServerSlice) get_slice(slice_string, *args)

A slice of a cluster:

Parameters:

  • cluster_name (String)

    -- cluster to slice

  • facet_name (String)

    -- facet to slice (or nil for all in cluster)

  • slice_indexes (Array, String)

    -- servers in that facet (or nil for all in facet). You must specify a facet if you use slice_indexes.

Returns:

  • (Ironfan::ServerSlice)

    the requested slice



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/chef/knife/ironfan_knife_common.rb', line 34

def get_slice(slice_string, *args)
  cluster_name, facet_name, slice_indexes = pick_apart(slice_string, *args)
  desc = predicate_str(cluster_name, facet_name, slice_indexes)
  #
  ui.info("Inventorying servers in #{desc}")
  cluster   = Ironfan.load_cluster(cluster_name)
  Chef::Config[:knife][:region] = cluster.servers.to_a.first.cloud(:ec2).region
  computers =  broker.discover! cluster
  Chef::Log.info("Inventoried #{computers.size} computers")
  #
  computers.slice(facet_name, slice_indexes)
end

- (Object) has_problem(desc)

register that a problem was encountered



188
189
190
# File 'lib/chef/knife/ironfan_knife_common.rb', line 188

def has_problem(desc)
  (@problems||=[]) << desc
end

- (Boolean) healthy?

healthy if no problems

Returns:

  • (Boolean)


192
# File 'lib/chef/knife/ironfan_knife_common.rb', line 192

def healthy?() problems.blank? ; end

- (Object) load_ironfan



15
16
17
18
19
20
21
22
23
# File 'lib/chef/knife/ironfan_knife_common.rb', line 15

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.chef_config = self.config
  self.broker         = Ironfan.broker
end

- (Object) pick_apart(slice_string, *args)



54
55
56
57
58
59
60
61
# File 'lib/chef/knife/ironfan_knife_common.rb', line 54

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\-]/, 3)
end

- (Object) predicate_str(cluster_name, facet_name, slice_indexes)



63
64
65
66
67
68
# File 'lib/chef/knife/ironfan_knife_common.rb', line 63

def predicate_str(cluster_name, facet_name, slice_indexes)
  [ "#{ui.color(cluster_name, :bold)} cluster",
    (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

- (Object) progressbar_for_threads(threads)

Show a pretty progress bar while we wait for a set of threads to finish.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/chef/knife/ironfan_knife_common.rb', line 113

def progressbar_for_threads(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.redisplay_progressbar(total - remaining.length, total, {:started_at => start_time })
      sleep 1
    end
  end
  # Collapse the threads
  threads.each(&:join)
  ui.info ''
end

- (Boolean) relevant?(computer)

method to nodes should be filtered on

Returns:

  • (Boolean)


71
72
73
# File 'lib/chef/knife/ironfan_knife_common.rb', line 71

def relevant?(computer)
  computer.running?
end

- (Object) run_bootstrap(computer)



155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/chef/knife/ironfan_knife_common.rb', line 155

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

- (Object) section(desc, *style)

Announce a new section of tasks



209
210
211
212
# File 'lib/chef/knife/ironfan_knife_common.rb', line 209

def section(desc, *style)
  style = [:blue] if style.empty?
  ui.info(ui.color(desc, *style))
end

- (Object) sub_command

Utilities



173
174
175
# File 'lib/chef/knife/ironfan_knife_common.rb', line 173

def sub_command
  self.class.sub_command
end