Class: Cheftacular::Helper

Inherits:
Object
  • Object
show all
Defined in:
lib/cheftacular/helper.rb

Instance Method Summary collapse

Constructor Details

#initialize(options, config) ⇒ Helper

Returns a new instance of Helper.



4
5
6
# File 'lib/cheftacular/helper.rb', line 4

def initialize options, config
  @options, @config  = options, config
end

Instance Method Details

#compare_strings(str1, str2) ⇒ Object

compares how close str1 is to str2



169
170
171
172
173
174
# File 'lib/cheftacular/helper.rb', line 169

def compare_strings str1, str2
  str1_chars = str1.split('').uniq
  str2_chars = str2.split('').uniq

  ((str1_chars + str2_chars).uniq.length * 1.0) / (str1_chars.length + str2_chars.length)
end

#compile_chef_repo_cheftacular_yml_as_hashObject



244
245
246
247
248
249
250
251
# File 'lib/cheftacular/helper.rb', line 244

def compile_chef_repo_cheftacular_yml_as_hash
  master_hash = get_cheftacular_yml_as_hash
  master_hash['replace_keys_in_chef_repo'].each_pair do |key, val|
    master_hash[key] = val
  end

  master_hash
end

#compile_documentation_lines(mode, out = []) ⇒ Object

the documentation hashes must be populated before this method runs for it to return anything!



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/cheftacular/helper.rb', line 140

def compile_documentation_lines mode, out=[]
  doc_arr = case mode
            when 'action'           then @config['documentation']['action']
            when 'application'      then @config['documentation']['application'].merge(@config['documentation']['action'])
            when 'stateless_action' then @config['documentation']['stateless_action']
            when 'devops'           then @config['documentation']['stateless_action'].merge(@config['documentation']['action'])
            end

  doc_arr = doc_arr.to_a.map { |doc| doc[1]['long_description'] }
  count   = 1

  doc_arr.sort {|a, b| a[0] <=> b[0]}.flatten(1).each do |line|
    out << "#{ count }. #{ line }" if line.class.to_s == 'String'

    out << line if line.class.to_s == 'Array'

    count += 1 if line.class.to_s == 'String'
  end

  out
end

#compile_short_context_descriptions(documentation_hash, padding_length = 25, out = []) ⇒ Object



162
163
164
165
166
# File 'lib/cheftacular/helper.rb', line 162

def compile_short_context_descriptions documentation_hash, padding_length=25, out=[]
  out << documentation_hash.to_a.map { |doc| "#{ doc[0].to_s.ljust(padding_length, '_') }_#{ doc[1]['short_description'] }" }

  out.flatten.sort {|a, b| a[0] <=> b[0]}.join("\n\n")
end

#completion_rate?(percent, mode) ⇒ Boolean

Returns:

  • (Boolean)


54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/cheftacular/helper.rb', line 54

def completion_rate? percent, mode
  case mode.to_s
  when 'initializer'           then print("Fetching initialization chef data for #{ @options['env'] }....0%") if !@options['quiet'] && percent == 0
  when 'get_true_node_objects' then print("Retrieving node data from chef server for #{ @config['chef_nodes'].count } nodes....0%") if !@options['quiet'] && percent == 0
  end

  case percent
  when 1..9   then print("\b\b#{ percent.to_i }%")       unless @options['quiet']
  when 10..99 then print("\b\b\b#{ percent.to_i }%")     unless @options['quiet']
  when 100    then print("\b\b\b\b#{ percent.to_i }%\n") unless @options['quiet']
  end
end

#declassifyObject



8
9
10
11
# File 'lib/cheftacular/helper.rb', line 8

def declassify
  #(self.class::TRUENAME.constantize).to_s.underscore.dasherize
  Cheftacular.to_s.underscore.dasherize
end

#display_readme(option = "", out = "") ⇒ Object



67
68
69
# File 'lib/cheftacular/helper.rb', line 67

def display_readme option="", out=""
  puts File.read(File.expand_path('../README.md', __FILE__))
end

#does_cheftacular_config_have?(key_array) ⇒ Boolean

Returns:

  • (Boolean)


184
185
186
187
188
189
190
191
192
193
194
# File 'lib/cheftacular/helper.rb', line 184

def does_cheftacular_config_have? key_array
  cheftacular = @config['cheftacular']
  key_array   = [key_array] if key_array.is_a?(String)
  key_checks  = []

  key_array.each do |key|
    key_checks << recursive_hash_check(key.split(':'), @config['cheftacular']).to_s
  end

  !key_checks.include?('false')
end

#fetch_remote_versionObject

TODO, fix for clients that block amazon hosted rubygems?



48
49
50
51
52
# File 'lib/cheftacular/helper.rb', line 48

def fetch_remote_version
  puts "Checking remote #{ declassify } version..."

  `gem list #{ declassify } --remote`[/(\d+\.\d+\.\d+)/]
end

#gen_pass(length = 20, mode = "truepass") ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/cheftacular/helper.rb', line 71

def gen_pass length=20, mode="truepass"
  lowercase = 'a'..'z'
  uppercase = 'A'..'Z'
  numbers   = 0..9

  length = @config['cheftacular']['server_pass_length'] if length.to_i <= @config['cheftacular']['server_pass_length']

  sets = case mode
         when "truepass"  then [lowercase, uppercase, numbers]
         when "numsonly"  then [numbers]
         when "lowernum"  then [lowercase, numbers]
         when "uppernum"  then [uppercase, numbers]
         when "lowercase" then [lowercase]
         when "uppercase" then [uppercase]
         end

  o = sets.flatten.map { |i| i.to_a }.flatten

  (0...length.to_i).map { o[rand(o.length)] }.join
end

#get_cheftacular_yml_as_hashObject

this must be in helpers because getter class is not yet loaded at the time this method is needed.



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/cheftacular/helper.rb', line 227

def get_cheftacular_yml_as_hash
  config_location = if File.exist?(File.join( Dir.getwd, 'config', 'cheftacular.yml' ))
                      File.join( Dir.getwd, 'config', 'cheftacular.yml' )
                    elsif File.exist?('/root/cheftacular.yml')
                      '/root/cheftacular.yml'
                    else
                      raise "cheftacular.yml configuration file could not be found in either #{ File.join( Dir.getwd, 'config', 'cheftacular.yml' ) } or /root/cheftacular.yml"
                    end

  YAML::load(ERB.new(IO.read(File.open(config_location))).result)
rescue StandardError => e
  puts "The cheftacular.yml configuration file could not be parsed."
  puts "Error message: #{ e }\n#{ e.backtrace.join("\n") }"
  
  exit
end

#install_rvm_sh_file(out = []) ⇒ Object



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/cheftacular/helper.rb', line 253

def install_rvm_sh_file out=[]
  puts("Starting rvm.sh installation...") unless @options['quiet']

  commands = [
    "#{ @config['helper'].sudo(@options['address']) } mv /home/deploy/rvm.sh /etc/profile.d",
    "#{ @config['helper'].sudo(@options['address']) } chmod 755 /etc/profile.d/rvm.sh",
    "#{ @config['helper'].sudo(@options['address']) } chown root:root /etc/profile.d/rvm.sh"
  ]

  out << `scp -oStrictHostKeyChecking=no #{ @config['locs']['cheftacular-lib-files'] }/rvm.sh #{ @config['cheftacular']['deploy_user'] }@#{ @options['address'] }:/home/#{ @config['cheftacular']['deploy_user'] }`

  commands.each do |command|
    out << `ssh -t -oStrictHostKeyChecking=no #{ @config['cheftacular']['deploy_user'] }@#{ @options['address'] } "#{ command }"`
  end

  puts("Completed rvm.sh installation into /etc/profile.d/rvm.sh") unless @options['quiet']
end

#is_command?(command = '') ⇒ Boolean

Returns:

  • (Boolean)


13
14
15
16
17
# File 'lib/cheftacular/helper.rb', line 13

def is_command? command=''
  command ||= ''

  @config['action'].public_methods(false).include?(command.to_sym)
end

#is_higher_version?(vstr1, vstr2) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/cheftacular/helper.rb', line 121

def is_higher_version? vstr1, vstr2
  Gem::Version.new(vstr1) > Gem::Version.new(vstr2)
end

#is_initialization_command?(command = '') ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
35
# File 'lib/cheftacular/helper.rb', line 31

def is_initialization_command? command=''
  command ||= ''

  @config['initialization_action'].public_methods(false).include?(command.to_sym) || command.blank?
end

#is_not_command_or_stateless_command?(command = '') ⇒ Boolean

Returns:

  • (Boolean)


25
26
27
28
29
# File 'lib/cheftacular/helper.rb', line 25

def is_not_command_or_stateless_command? command=''
  command ||= ''

  !@config['action'].public_methods(false).include?(command.to_sym) && !@config['stateless_action'].public_methods(false).include?(command.to_sym)
end

#is_stateless_command?(command = '') ⇒ Boolean

Returns:

  • (Boolean)


19
20
21
22
23
# File 'lib/cheftacular/helper.rb', line 19

def is_stateless_command? command=''
  command ||= ''
  
  @config['stateless_action'].public_methods(false).include?(command.to_sym)
end

#knife_bootstrap_commandObject



129
130
131
132
133
134
135
136
137
# File 'lib/cheftacular/helper.rb', line 129

def knife_bootstrap_command
  address  = @options['address']
  user     = @config['cheftacular']['deploy_user']
  password = @config['server_passwords'][@options['address']]
  nodename = @options['node_name']
  chef_ver = @config['cheftacular']['chef_version'].to_i >= 12 ? '12.4.0' : '11.16.4'

  "knife bootstrap #{ address } -x #{ user } -P #{ password } -N #{ nodename } --sudo --use-sudo-password --bootstrap-version #{ chef_ver }"
end

#output_run_statsObject



104
105
106
# File 'lib/cheftacular/helper.rb', line 104

def output_run_stats
  puts("\nDone in #{ Time.now - @config['start_time'] } seconds at #{ Time.now.strftime('%Y-%m-%d %l:%M:%S %P') }.") unless @options['quiet']
end

#parse_node_name_from_client_file(ret = "") ⇒ Object

this must be in helpers because parser class is not yet loaded at the time this method is needed.



216
217
218
219
220
221
222
223
224
# File 'lib/cheftacular/helper.rb', line 216

def parse_node_name_from_client_file ret=""
  config = File.read(File.expand_path("#{ @config['locs']['chef'] }/client.rb"))

  config.split("\n").each do |line|
    next unless line.include?('node_name')

    return line.split('node_name').last.strip.chomp.gsub('"', '')
  end
end

#recursive_hash_check(keys, hash) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/cheftacular/helper.rb', line 196

def recursive_hash_check keys, hash
  if hash.has_key?(keys[0]) 
    case hash[keys[0]].class.to_s
    when 'Hash'
      if !hash[keys[0]].empty?
        recursive_hash_check keys[1..keys.count-1], hash[keys[0]] 
      else
        return true
      end
    when 'String'
      return !hash[keys[0]].blank?
    when 'Array'
      return !hash[keys[0]].empty?
    end
  else
    return false
  end
end

#running_in_mode?(mode) ⇒ Boolean

Returns:

  • (Boolean)


43
44
45
# File 'lib/cheftacular/helper.rb', line 43

def running_in_mode? mode
  @config['cheftacular']['mode'] == mode
end

#running_on_chef_node?(ret = false) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
40
41
# File 'lib/cheftacular/helper.rb', line 37

def running_on_chef_node? ret = false
  Dir.entries('/etc').include?('chef') && File.exist?('/etc/chef/client.rb') && !File.size?('/etc/chef/client.rb').nil?
rescue StandardError => e
  @config['error'].exception_output "An error occurred while trying to see if this system is a chef node. Assuming the system is not a chef node.", e, false
end

#send_log_bag_hash_slack_notification(logs_bag_hash, method, on_failing_exit_status_message = '') ⇒ Object



271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/cheftacular/helper.rb', line 271

def send_log_bag_hash_slack_notification logs_bag_hash, method, on_failing_exit_status_message=''
  if @config['cheftacular']['slack']['webhook']
    logs_bag_hash.each_pair do |key, hash|
      next unless key.include?(method.to_s)

      if hash['exit_status'] && hash['exit_status'] == 1
        @config['stateless_action'].slack(hash['text'].prepend('```').insert(-1, '```'))

        @config['error'].exception_output(on_failing_exit_status_message) if !on_failing_exit_status_message.blank?
      end
    end
  end
end

#set_cloud_optionsObject



176
177
178
179
180
181
182
# File 'lib/cheftacular/helper.rb', line 176

def set_cloud_options
  @options['preferred_cloud']        = @options['preferred_cloud'].nil? ?        @config['cheftacular']['preferred_cloud'].downcase        : @options['preferred_cloud'].downcase
  @options['preferred_cloud_image']  = @options['preferred_cloud_image'].nil? ?  @config['cheftacular']['preferred_cloud_image']           : @options['preferred_cloud_image']
  @options['preferred_cloud_region'] = @options['preferred_cloud_region'].nil? ? @config['cheftacular']['preferred_cloud_region']          : @options['preferred_cloud_region']
  @options['virtualization_mode']    = @options['virtualization_mode'].nil? ?    @config['cheftacular']['virtualization_mode']             : @options['virtualization_mode']
  @options['route_dns_changes_via']  = @options['route_dns_changes_via'].nil? ?  @config['cheftacular']['route_dns_changes_via'].downcase  : @options['route_dns_changes_via'].downcase
end

#set_local_instance_varsObject



108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/cheftacular/helper.rb', line 108

def set_local_instance_vars
  [ 
    @options, 
    @config['locs'],
    @config['ridley'],
    @config[@options['env']]['logs_bag_hash'],
    @config[@options['env']]['chef_passwords_bag_hash'],
    @config['bundle_command'],
    @config['cheftacular'],
    @config['server_passwords']
  ]
end

#set_location_if_app(ret = "") ⇒ Object



92
93
94
95
96
97
98
# File 'lib/cheftacular/helper.rb', line 92

def set_location_if_app ret=""
  if get_codebase_from_role_name(Dir.getwd.split('/').last, "has_key?")
    ret = Dir.getwd.split('/').last
  end

  ret
end

#set_log_loc_and_timestampObject



125
126
127
# File 'lib/cheftacular/helper.rb', line 125

def set_log_loc_and_timestamp
  @config['dummy_sshkit'].set_log_loc_and_timestamp @config['locs']
end

#slack_current_deploy_argumentsObject



285
286
287
288
289
290
291
# File 'lib/cheftacular/helper.rb', line 285

def slack_current_deploy_arguments
  msg  = "#{ Socket.gethostname } just set for the repository #{ @config['getter'].get_repository_from_role_name(@options['role']) }:\n"
  msg << "the organization to #{ @options['deploy_organization'] }\n" if @options['deploy_organization']
  msg << "the revision to #{ @options['target_revision'] }"           if @options['target_revision']
  
  @config['stateless_action'].slack(msg.prepend('```').insert(-1, '```'), @config['cheftacular']['slack']['notify_on_deployment_args'])
end

#sudo(ip_address) ⇒ Object



100
101
102
# File 'lib/cheftacular/helper.rb', line 100

def sudo ip_address
  "echo #{ @config['server_passwords'][ip_address] } | sudo -S"
end