dust-deploy 0.16.4 → 0.16.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,7 +23,6 @@ class Sshd < Recipe
23
23
  def default_config
24
24
  { 'Port' => 22,
25
25
  'Protocol' => 2,
26
- 'AcceptEnv' => 'LANG LC_*',
27
26
  'HostKey' => [ '/etc/ssh/ssh_host_dsa_key',
28
27
  '/etc/ssh/ssh_host_ecdsa_key',
29
28
  '/etc/ssh/ssh_host_rsa_key' ],
@@ -38,7 +37,7 @@ class Sshd < Recipe
38
37
 
39
38
  def generate_default_config
40
39
  @config.boolean_to_string!
41
- @config = default_config.merge @config
40
+ @config = default_config.merge(@config)
42
41
 
43
42
  unless @config['sftp']
44
43
  @config['Subsystem'] ||= 'sftp /usr/lib/openssh/sftp-server' if @node.uses_apt?
@@ -66,11 +65,11 @@ class Sshd < Recipe
66
65
  if value.is_a? Hash
67
66
  value.each do |k, v|
68
67
  conditional_blocks << "#{key} #{k}\n"
69
- v.to_array.each { |x, y| conditional_blocks << " #{x} #{y}\n" }
68
+ Array(v).each { |x, y| conditional_blocks << " #{x} #{y}\n" }
70
69
  end
71
70
 
72
71
  else
73
- value.to_array.each { |value| @sshd_config << "#{key} #{value}\n" }
72
+ Array(value).each { |value| @sshd_config << "#{key} #{value}\n" }
74
73
  end
75
74
  end
76
75
 
@@ -12,7 +12,7 @@ class Sysctl < Recipe
12
12
 
13
13
  # apply template sysctls
14
14
  if templates
15
- templates.to_array.each do |template|
15
+ Array(templates).each do |template|
16
16
  @node.messages.add("configuring sysctls for template #{template}\n")
17
17
  apply template, self.send(template)
18
18
  end
@@ -67,7 +67,7 @@ class Users < Recipe
67
67
  authorized_keys = ''
68
68
 
69
69
  # create the authorized_keys hash for this user
70
- ssh_users.to_array.each do |ssh_user|
70
+ Array(ssh_users).each do |ssh_user|
71
71
  unless users[ssh_user]
72
72
  return @node.messages.add("#{ssh_user} cannot be found in #{@template_path}/public_keys.yaml").failed
73
73
  end
@@ -134,7 +134,7 @@ class ZabbixAgent < Recipe
134
134
 
135
135
  # check for security patches and system updates on emerge systems
136
136
  def enable_apt
137
- updates = [ 'apt.updates,aptitude search \'~U\' |wc -l' ]
137
+ updates = [ 'apt.updates,apt-cache search \'~U\' |wc -l' ]
138
138
  if @node.is_debian?
139
139
  @node.collect_facts
140
140
  updates << "debian.security,debsecan --suite #{@node['lsbdistcodename']} --only-fixed --format packages |wc -l"
@@ -104,7 +104,7 @@ module Dust
104
104
  end
105
105
 
106
106
 
107
- desc 'system_update', 'perform a full system upgrade (using aptitude, emerge, yum)'
107
+ desc 'system_update', 'perform a full system upgrade (using apt-get, emerge, yum)'
108
108
  default_options
109
109
 
110
110
  def system_update
@@ -321,7 +321,7 @@ module Dust
321
321
  exit
322
322
  end
323
323
 
324
- yaml_files.to_array.each do |file|
324
+ Array(yaml_files).each do |file|
325
325
  node = YAML.load ERB.new( File.read(file), nil, '%<>').result
326
326
 
327
327
  # if the file is empty, just skip it
@@ -344,7 +344,7 @@ module Dust
344
344
 
345
345
  # if more than one hostname is specified, create a node
346
346
  # with the same settings for each hostname
347
- node['hostname'].to_array.each do |hostname|
347
+ Array(node['hostname']).each do |hostname|
348
348
  n = node.clone
349
349
 
350
350
  # overwrite hostname with single hostname (in case there are multiple)
@@ -1,13 +1,9 @@
1
- require 'net/ssh'
2
- require 'net/scp'
3
- require 'net/ssh/proxy/socks5'
4
- require 'erb'
5
- require 'tempfile'
6
- require 'colorize'
1
+ # include all extensions
2
+ Dir["#{File.dirname(__FILE__)}/server/*.rb"].each { |file| require file }
7
3
 
8
4
  module Dust
9
5
  class Server
10
- attr_reader :ssh, :messages
6
+ attr_reader :messages
11
7
 
12
8
  def default_options options = {}
13
9
  { :quiet => false, :indent => 1 }.merge options
@@ -23,871 +19,6 @@ module Dust
23
19
  @messages = Messages.new
24
20
  end
25
21
 
26
- def connect
27
- messages.print_hostname_header(@node['hostname']) unless $parallel
28
-
29
- begin
30
- # connect to proxy if given
31
- if @node['proxy']
32
- host, port = @node['proxy'].split ':'
33
- proxy = Net::SSH::Proxy::SOCKS5.new(host, port)
34
- else
35
- proxy = nil
36
- end
37
-
38
- @ssh = Net::SSH.start @node['fqdn'], @node['user'],
39
- { :password => @node['password'],
40
- :port => @node['port'],
41
- :proxy => proxy }
42
- rescue Exception
43
- error_message = "coudln't connect to #{@node['fqdn']}"
44
- error_message << " (via socks5 proxy #{@node['proxy']})" if proxy
45
- messages.add(error_message, :indent => 0).failed
46
- return false
47
- end
48
-
49
- true
50
- end
51
-
52
- def disconnect
53
- @ssh.close
54
- end
55
-
56
- def exec command, options={:live => false, :as_user => false}
57
- sudo_authenticated = false
58
- stdout = ''
59
- stderr = ''
60
- exit_code = nil
61
- exit_signal = nil
62
-
63
- # prepend a newline, if output is live
64
- messages.add("\n", :indent => 0) if options[:live]
65
-
66
- @ssh.open_channel do |channel|
67
-
68
- # if :as_user => user is given, execute as user (be aware of ' usage)
69
- command = "su #{options[:as_user]} -l -c '#{command}'" if options[:as_user]
70
-
71
- # request a terminal (sudo needs it)
72
- # and prepend "sudo"
73
- # command is wrapped in ", escapes " in the command string
74
- # and then executed using "sh -c", so that
75
- # the use of > < && || | and ; doesn't screw things up
76
- if @node['sudo']
77
- channel.request_pty
78
- command = "sudo -k -- sh -c \"#{command.gsub('"','\\"')}\""
79
- end
80
-
81
- channel.exec command do |ch, success|
82
- abort "FAILED: couldn't execute command (ssh.channel.exec)" unless success
83
-
84
- channel.on_data do |ch, data|
85
- # only send password if sudo mode is enabled,
86
- # and only send password once in a session (trying to prevent attacks reading out the password)
87
- if data =~ /\[sudo\] password for #{@node['user']}/
88
-
89
- raise 'password requested, but none given in config!' if @node['password'].empty?
90
- raise 'already sent password, but sudo requested the password again. (wrong password?)' if sudo_authenticated
91
-
92
- # we're not authenticated yet, send password
93
- channel.send_data "#{@node['password']}\n"
94
- sudo_authenticated = true
95
-
96
- else
97
- # skip everything util authenticated (if sudo is used and password given in config)
98
- next if @node['sudo'] and not @node['password'].empty? and not sudo_authenticated
99
-
100
- stdout += data
101
- messages.add(data.green, :indent => 0) if options[:live] and not data.empty?
102
- end
103
- end
104
-
105
- channel.on_extended_data do |ch, type, data|
106
- stderr += data
107
- messages.add(data.red, :indent => 0) if options[:live] and not data.empty?
108
- end
109
-
110
- channel.on_request('exit-status') { |ch, data| exit_code = data.read_long }
111
- channel.on_request('exit-signal') { |ch, data| exit_signal = data.read_long }
112
- end
113
- end
114
-
115
- @ssh.loop
116
-
117
- # sudo usage provokes a heading newline that's unwanted.
118
- stdout.sub! /^(\r\n|\n|\r)/, '' if @node['sudo']
119
-
120
- { :stdout => stdout, :stderr => stderr, :exit_code => exit_code, :exit_signal => exit_signal }
121
- end
122
-
123
- def write destination, content, options = {}
124
- options = default_options.merge options
125
-
126
- msg = messages.add("deploying #{File.basename destination}", options)
127
-
128
- f = Tempfile.new 'dust-write'
129
- f.print content
130
- f.close
131
-
132
- ret = msg.parse_result(scp(f.path, destination, :quiet => true))
133
- f.unlink
134
-
135
- ret
136
- end
137
-
138
- def append destination, newcontent, options = {}
139
- options = default_options.merge options
140
-
141
- msg = messages.add("appending to #{File.basename destination}", options)
142
-
143
- content = exec("cat #{destination}")[:stdout]
144
- content.concat newcontent
145
-
146
- msg.parse_result(write(destination, content, :quiet => true))
147
- end
148
-
149
- def scp(source, destination, options = {})
150
- options = default_options.merge options
151
-
152
- # make sure scp is installed on client
153
- install_package('openssh-clients', :quiet => true) if uses_rpm?
154
-
155
- msg = messages.add("deploying #{File.basename source}", options)
156
-
157
- # check if destination is a directory
158
- is_dir = dir_exists?(destination, :quiet => true)
159
-
160
- # save permissions if the file already exists
161
- ret = exec("stat -c %a:%u:%g #{destination}")
162
- if ret[:exit_code] == 0 and not is_dir
163
- permissions, user, group = ret[:stdout].chomp.split(':')
164
- else
165
- # files = 644, dirs = 755
166
- permissions = 'ug-x,o-wx,u=rwX,g=rX,o=rX'
167
- user = 'root'
168
- group = 'root'
169
- end
170
-
171
- # if in sudo mode, copy file to temporary place, then move using sudo
172
- if @node['sudo']
173
- tmpdir = mktemp(:type => 'directory')
174
- return msg.failed('could not create temporary directory (needed for sudo)') unless tmpdir
175
-
176
- # temporary destination in tmpdir
177
- tmpdest = "#{tmpdir}/#{File.basename(destination)}"
178
-
179
- # allow user to write file without sudo (for scp)
180
- # then change file back to root, and copy to the destination
181
- chown(@node['user'], tmpdir, :quiet => true)
182
- @ssh.scp.upload!(source, tmpdest, :recursive => true)
183
-
184
- # set file permissions
185
- chown("#{user}:#{group}", tmpdest, :quiet => true) if user and group
186
- chmod(permissions, tmpdest, :quiet => true)
187
-
188
- # if destination is a directory, append real filename
189
- destination = "#{destination}/#{File.basename(source)}" if is_dir
190
-
191
- # move the file from the temporary location to where it actually belongs
192
- msg.parse_result(exec("mv -f #{tmpdest} #{destination}")[:exit_code])
193
-
194
- # remove temporary directory
195
- rm(tmpdir, :quiet => true)
196
-
197
- else
198
- @ssh.scp.upload!(source, destination, :recursive => true)
199
- msg.ok
200
-
201
- # set file permissions
202
- chown("#{user}:#{group}", destination, :quiet => true) if user and group
203
- chmod(permissions, destination, :quiet => true)
204
- end
205
-
206
- restorecon(destination, options) # restore SELinux labels
207
- end
208
-
209
- # download a file (sudo not yet supported)
210
- def download source, destination, options = {}
211
- options = default_options.merge options
212
-
213
- # make sure scp is installed on client
214
- install_package 'openssh-clients', :quiet => true if uses_rpm?
215
-
216
- msg = messages.add("downloading #{File.basename source}", options)
217
- msg.parse_result(@ssh.scp.download!(source, destination))
218
- end
219
-
220
- def symlink source, destination, options = {}
221
- options = default_options.merge options
222
-
223
- msg = messages.add("symlinking #{File.basename source} to '#{destination}'", options)
224
- ret = msg.parse_result(exec("ln -s #{source} #{destination}")[:exit_code])
225
- restorecon destination, options # restore SELinux labels
226
- ret
227
- end
228
-
229
- def chmod mode, file, options = {}
230
- options = default_options.merge options
231
-
232
- msg = messages.add("setting mode of #{File.basename file} to #{mode}", options)
233
- msg.parse_result(exec("chmod -R #{mode} #{file}")[:exit_code])
234
- end
235
-
236
- def chown user, file, options = {}
237
- options = default_options.merge options
238
-
239
- msg = messages.add("setting owner of #{File.basename file} to #{user}", options)
240
- msg.parse_result(exec("chown -R #{user} #{file}")[:exit_code])
241
- end
242
-
243
- def chcon(permissions, file, options = {})
244
- options = default_options.merge(options)
245
-
246
- # just return if selinux is not enabled
247
- return true unless selinuxenabled?
248
-
249
- args = ""
250
- args << " --type #{permissions['type']}" if permissions['type']
251
- args << " --recursive #{permissions['recursive']}" if permissions['recursive']
252
- args << " --user #{permissions['user']}" if permissions['user']
253
- args << " --range #{permissions['range']}" if permissions['range']
254
- args << " --role #{permissions['role']}" if permissions['role']
255
-
256
- msg = messages.add("setting selinux permissions of #{File.basename file}", options)
257
- msg.parse_result(exec("chcon #{args} #{file}")[:exit_code])
258
- end
259
-
260
- def selinuxenabled?
261
- return true if exec('selinuxenabled')[:exit_code] == 0
262
- false
263
- end
264
-
265
- def rm file, options = {}
266
- options = default_options.merge options
267
-
268
- msg = messages.add("deleting #{file}", options)
269
- msg.parse_result(exec("rm -rf #{file}")[:exit_code])
270
- end
271
-
272
- def cp source, destination, options = {}
273
- options = default_options.merge options
274
-
275
- # get rid of overly careful aliases
276
- exec 'unalias -a'
277
-
278
- msg = messages.add("copying #{source} to #{destination}", options)
279
- msg.parse_result(exec("cp -a #{source} #{destination}")[:exit_code])
280
- end
281
-
282
- def mv source, destination, options = {}
283
- options = default_options.merge options
284
-
285
- # get rid of overly careful aliases
286
- exec 'unalias -a'
287
-
288
- msg = messages.add("moving #{source} to #{destination}", options)
289
- msg.parse_result(exec("mv #{source} #{destination}")[:exit_code])
290
- end
291
-
292
- def mkdir dir, options = {}
293
- options = default_options.merge options
294
-
295
- return true if dir_exists? dir, :quiet => true
296
-
297
- msg = messages.add("creating directory #{dir}", options)
298
- ret = msg.parse_result(exec("mkdir -p #{dir}")[:exit_code])
299
- restorecon dir, options # restore SELinux labels
300
- ret
301
- end
302
-
303
- # check if restorecon (selinux) is available
304
- # if so, run it on "path" recursively
305
- def restorecon path, options = {}
306
- options = default_options.merge options
307
-
308
- # if selinux is not enabled, just return
309
- return true unless selinuxenabled?
310
-
311
- msg = messages.add("restoring selinux labels for #{path}", options)
312
- msg.parse_result(exec("restorecon -R #{path}")[:exit_code])
313
- end
314
-
315
- def get_system_users options = {}
316
- options = default_options.merge options
317
-
318
- msg = messages.add("getting all system users", options)
319
- ret = exec 'getent passwd |cut -d: -f1'
320
- msg.parse_result(ret[:exit_code])
321
-
322
- users = []
323
- ret[:stdout].each do |user|
324
- users.push user.chomp
325
- end
326
- users
327
- end
328
-
329
- # checks if one of the packages is installed
330
- def package_installed? packages, options = {}
331
- options = default_options.merge options
332
-
333
- packages = [ packages ] if packages.is_a? String
334
-
335
- msg = messages.add("checking if #{packages.join(' or ')} is installed", options)
336
-
337
- packages.each do |package|
338
- if uses_apt?
339
- return msg.ok if exec("dpkg -l #{package} |grep '^ii'")[:exit_code] == 0
340
- elsif uses_emerge?
341
- return msg.ok unless exec("qlist -I #{package}")[:stdout].empty?
342
- elsif uses_rpm?
343
- return msg.ok if exec("rpm -q #{package}")[:exit_code] == 0
344
- elsif uses_pacman?
345
- return msg.ok if exec("pacman -Q #{package}")[:exit_code] == 0
346
- elsif uses_opkg?
347
- return msg.ok unless exec("opkg status #{package}")[:stdout].empty?
348
- end
349
- end
350
-
351
- msg.failed
352
- end
353
-
354
- def install_package(package, options = {})
355
- options = default_options.merge(options)
356
- options[:env] ||= ''
357
-
358
- if package_installed?(package, :quiet => true)
359
- return messages.add("package #{package} already installed", options).ok
360
- end
361
-
362
- # if package is an url, download and install the package file
363
- if package =~ /^(http:\/\/|https:\/\/|ftp:\/\/)/
364
- if uses_apt?
365
- messages.add("installing #{package}\n", options)
366
- return false unless install_package('wget')
367
-
368
- msg = messages.add('downloading package', options.merge(:indent => options[:indent] + 1))
369
-
370
- # creating temporary file
371
- tmpfile = mktemp
372
- return msg.failed('could not create temporary file') unless tmpfile
373
-
374
- msg.parse_result(exec("wget #{package} -O #{tmpfile}")[:exit_code])
375
-
376
- msg = messages.add('installing package', options.merge(:indent => options[:indent] + 1))
377
- ret = msg.parse_result(exec("dpkg -i #{tmpfile}")[:exit_code])
378
-
379
- msg = messages.add('deleting downloaded file', options.merge(:indent => options[:indent] + 1))
380
- msg.parse_result(rm(tmpfile, :quiet => true))
381
-
382
- return ret
383
-
384
- elsif uses_rpm?
385
- msg = messages.add("installing #{package}", options)
386
- return msg.parse_result(exec("rpm -U #{package}")[:exit_code])
387
-
388
- else
389
- return msg.failed("\ninstalling packages from url not yet supported " +
390
- "for your distribution. feel free to contribute!").failed
391
- end
392
-
393
- # package is not an url, use package manager
394
- else
395
- msg = messages.add("installing #{package}", options)
396
-
397
- if uses_apt?
398
- exec "DEBIAN_FRONTEND=noninteractive aptitude install -y #{package}"
399
- elsif uses_emerge?
400
- exec "#{options[:env]} emerge #{package}"
401
- elsif uses_rpm?
402
- exec "yum install -y #{package}"
403
- elsif uses_pacman?
404
- exec "echo y |pacman -S #{package}"
405
- elsif uses_opkg?
406
- exec "opkg install #{package}"
407
- else
408
- return msg.failed("\ninstall_package only supports apt, emerge and yum systems at the moment")
409
- end
410
-
411
- # check if package actually was installed
412
- return msg.parse_result(package_installed?(package, :quiet => true))
413
- end
414
- end
415
-
416
- # check if installed package is at least version min_version
417
- def package_min_version?(package, min_version, options = {})
418
- msg = messages.add("checking if #{package} is at least version #{min_version}", options)
419
- return msg.failed unless package_installed?(package, :quiet => true)
420
-
421
- if uses_apt?
422
- v = exec("dpkg --list |grep #{package}")[:stdout].chomp
423
- elsif uses_rpm?
424
- v = exec("rpm -q #{package}")[:stdout].chomp
425
- elsif uses_pacman?
426
- v = exec("pacman -Q #{package}")[:stdout].chomp
427
- else
428
- return msg.failed('os not supported')
429
- end
430
-
431
- # convert version numbers to arrays
432
- current_version = v.to_s.split(/[-. ]/ ).select {|j| j =~ /^[0-9]+$/ }
433
- min_version = min_version.to_s.split(/[-. ]/ ).select {|j| j =~ /^[0-9]+$/ }
434
-
435
- # compare
436
- min_version.each_with_index do |i, pos|
437
- break unless current_version[pos]
438
- return msg.failed if i.to_i < current_version[pos].to_i
439
- end
440
-
441
- msg.ok
442
- end
443
-
444
- def remove_package package, options = {}
445
- options = default_options.merge options
446
-
447
- unless package_installed? package, :quiet => true
448
- return messages.add("package #{package} not installed", options).ok
449
- end
450
-
451
- msg = messages.add("removing #{package}", options)
452
- if uses_apt?
453
- msg.parse_result(exec("DEBIAN_FRONTEND=noninteractive aptitude purge -y #{package}")[:exit_code])
454
- elsif uses_emerge?
455
- msg.parse_result(exec("emerge --unmerge #{package}")[:exit_code])
456
- elsif uses_rpm?
457
- msg.parse_result(exec("yum erase -y #{package}")[:exit_code])
458
- elsif uses_pacman?
459
- msg.parse_result(exec("echo y |pacman -R #{package}")[:exit_code])
460
- elsif uses_opkg?
461
- msg.parse_result(exec("opkg remove #{package}")[:exit_code])
462
- else
463
- msg.failed
464
- end
465
- end
466
-
467
- def update_repos options = {}
468
- options = default_options.merge options
469
-
470
- msg = messages.add('updating system repositories', options)
471
-
472
- if uses_apt?
473
- ret = exec 'aptitude update', options
474
- elsif uses_emerge?
475
- ret = exec 'emerge --sync', options
476
- elsif uses_rpm?
477
- ret = exec 'yum check-update', options
478
-
479
- # yum returns != 0 if packages that need to be updated are found
480
- # we don't want that this is producing an error
481
- ret[:exit_code] = 0 if ret[:exit_code] == 100
482
- elsif uses_pacman?
483
- ret = exec 'pacman -Sy', options
484
- elsif uses_opkg?
485
- ret = exec 'opkg update', options
486
- else
487
- return msg.failed
488
- end
489
-
490
- unless options[:live]
491
- msg.parse_result(ret[:exit_code])
492
- end
493
-
494
- ret[:exit_code]
495
- end
496
-
497
- def system_update options = {}
498
- options = default_options.merge(:live => true).merge(options)
499
-
500
- update_repos
501
-
502
- msg = messages.add('installing system updates', options)
503
-
504
- if uses_apt?
505
- ret = exec 'DEBIAN_FRONTEND=noninteractive aptitude full-upgrade -y', options
506
- elsif uses_emerge?
507
- ret = exec 'emerge -uND @world', options
508
- elsif uses_rpm?
509
- ret = exec 'yum upgrade -y', options
510
- elsif uses_pacman?
511
- # pacman has no --yes option that i know of, so echoing y
512
- ret = exec 'echo y |pacman -Su', options
513
- elsif uses_opkg?
514
- # upgrading openwrt is very experimental, and should not used normally
515
- ret = exec 'opkg upgrade $(echo $(opkg list-upgradable |cut -d' ' -f1 |grep -v Multiple))', options
516
- else
517
- msg.failed('system not (yet) supported')
518
- return false
519
- end
520
-
521
- unless options[:live]
522
- msg.parse_result(ret[:exit_code])
523
- end
524
-
525
- ret[:exit_code]
526
- end
527
-
528
- # determining the system packet manager has to be done without facter
529
- # because it's used to find out whether facter is installed / install facter
530
- def uses_apt? options = {}
531
- options = default_options(:quiet => true).merge options
532
-
533
- return @uses_apt if defined? @uses_apt
534
- msg = messages.add('determining whether node uses apt', options)
535
- @uses_apt = msg.parse_result(exec('test -e /etc/debian_version')[:exit_code])
536
- end
537
-
538
- def uses_rpm? options = {}
539
- options = default_options(:quiet => true).merge options
540
-
541
- return @uses_rpm if defined? @uses_rpm
542
- msg = messages.add('determining whether node uses rpm', options)
543
- @uses_rpm = msg.parse_result(exec('test -e /etc/redhat-release')[:exit_code])
544
- end
545
-
546
- def uses_emerge? options = {}
547
- options = default_options(:quiet => true).merge options
548
-
549
- return @uses_emerge if defined? @uses_emerge
550
- msg = messages.add('determining whether node uses emerge', options)
551
- @uses_emerge = msg.parse_result(exec('test -e /etc/gentoo-release')[:exit_code])
552
- end
553
-
554
- def uses_pacman? options = {}
555
- options = default_options(:quiet => true).merge options
556
-
557
- return @uses_pacman if defined? @uses_pacman
558
- msg = messages.add('determining whether node uses pacman', options)
559
- @uses_pacman = msg.parse_result(exec('test -e /etc/arch-release')[:exit_code])
560
- end
561
-
562
- def uses_opkg? options = {}
563
- options = default_options(:quiet => true).merge options
564
-
565
- return @uses_opkg if defined? @uses_opkg
566
- msg = messages.add('determining whether node uses opkg', options)
567
- @uses_opkg = msg.parse_result(exec('test -e /etc/opkg.conf')[:exit_code])
568
- end
569
-
570
- def is_os? os_list, options = {}
571
- options = default_options(:quiet => true).merge options
572
-
573
- msg = messages.add("checking if this machine runs #{os_list.join(' or ')}", options)
574
- return msg.failed unless collect_facts options
575
-
576
- os_list.each do |os|
577
- if @node['operatingsystem'].downcase == os.downcase
578
- return msg.ok
579
- end
580
- end
581
-
582
- msg.failed
583
- false
584
- end
585
-
586
- def is_debian? options = {}
587
- options = default_options(:quiet => true).merge options
588
-
589
- return false unless uses_apt?
590
- is_os? ['debian'], options
591
- end
592
-
593
- def is_ubuntu? options = {}
594
- options = default_options(:quiet => true).merge options
595
-
596
- return false unless uses_apt?
597
- is_os? ['ubuntu'], options
598
- end
599
-
600
- def is_gentoo? options = {}
601
- options = default_options(:quiet => true).merge options
602
-
603
- return false unless uses_emerge?
604
- is_os? ['gentoo'], options
605
- end
606
-
607
- def is_centos? options = {}
608
- options = default_options(:quiet => true).merge options
609
-
610
- return false unless uses_rpm?
611
- is_os? ['centos'], options
612
- end
613
-
614
- def is_scientific? options = {}
615
- options = default_options(:quiet => true).merge options
616
-
617
- return false unless uses_rpm?
618
- is_os? ['scientific'], options
619
- end
620
-
621
- def is_fedora? options = {}
622
- options = default_options(:quiet => true).merge options
623
-
624
- return false unless uses_rpm?
625
- is_os? ['fedora'], options
626
- end
627
-
628
- def is_arch? options = {}
629
- options = default_options(:quiet => true).merge options
630
-
631
- return false unless uses_pacman?
632
- is_os? ['archlinux'], options
633
- end
634
-
635
- def is_executable? file, options = {}
636
- options = default_options.merge options
637
-
638
- msg = messages.add("checking if file #{file} exists and is executeable", options)
639
- msg.parse_result(exec("test -x $(which #{file})")[:exit_code])
640
- end
641
-
642
- def file_exists? file, options = {}
643
- options = default_options.merge options
644
-
645
- msg = messages.add("checking if file #{file} exists", options)
646
-
647
- # don't treat directories as files
648
- return msg.failed if dir_exists?(file, :quiet => true)
649
-
650
- msg.parse_result(exec("test -e #{file}")[:exit_code])
651
- end
652
-
653
- def dir_exists? dir, options = {}
654
- options = default_options.merge options
655
-
656
- msg = messages.add("checking if directory #{dir} exists", options)
657
- msg.parse_result(exec("test -d #{dir}")[:exit_code])
658
- end
659
-
660
- def autostart_service service, options = {}
661
- options = default_options.merge options
662
-
663
- msg = messages.add("autostart #{service} on boot", options)
664
-
665
- if uses_rpm?
666
- if file_exists? '/bin/systemctl', :quiet => true
667
- msg.parse_result(exec("systemctl enable #{service}.service")[:exit_code])
668
- else
669
- msg.parse_result(exec("chkconfig #{service} on")[:exit_code])
670
- end
671
-
672
- elsif uses_apt?
673
- msg.parse_result(exec("update-rc.d #{service} defaults")[:exit_code])
674
-
675
- elsif uses_emerge?
676
- msg.parse_result(exec("rc-update add #{service} default")[:exit_code])
677
-
678
- # archlinux needs his autostart daemons in /etc/rc.conf, in the DAEMONS line
679
- #elsif uses_pacman?
680
-
681
- else
682
- msg.failed
683
- end
684
- end
685
-
686
- # invoke 'command' on the service (e.g. @node.service 'postgresql', 'restart')
687
- def service service, command, options = {}
688
- options = default_options.merge options
689
-
690
- return messages.add("service: '#{service}' unknown", options).failed unless service.is_a? String
691
-
692
- # try systemd, then upstart, then sysvconfig, then rc.d, then initscript
693
- if file_exists? '/bin/systemctl', :quiet => true
694
- msg = messages.add("#{command}ing #{service} (via systemd)", options)
695
- ret = exec("systemctl #{command} #{service}.service")
696
-
697
- elsif file_exists? "/etc/init/#{service}", :quiet => true
698
- msg = messages.add("#{command}ing #{service} (via upstart)", options)
699
- ret = exec("#{command} #{service}")
700
-
701
- elsif file_exists? '/sbin/service', :quiet => true or file_exists? '/usr/sbin/service', :quiet => true
702
- msg = messages.add("#{command}ing #{service} (via sysvconfig)", options)
703
- ret = exec("service #{service} #{command}")
704
-
705
- elsif file_exists? '/usr/sbin/rc.d', :quiet => true
706
- msg = messages.add("#{command}ing #{service} (via rc.d)", options)
707
- ret = exec("rc.d #{command} #{service}")
708
-
709
- else
710
- msg = messages.add("#{command}ing #{service} (via initscript)", options)
711
- ret = exec("/etc/init.d/#{service} #{command}")
712
- end
713
-
714
- msg.parse_result(ret[:exit_code])
715
- ret
716
- end
717
-
718
- def restart_service service, options = {}
719
- options = default_options.merge options
720
-
721
- service service, 'restart', options
722
- end
723
-
724
- def reload_service service, options = {}
725
- options = default_options.merge options
726
-
727
- service service, 'reload', options
728
- end
729
-
730
- def print_service_status(service, options = {})
731
- options = default_options.merge(:indent => 0).merge(options)
732
- ret = service(service, 'status', options)
733
- messages.add('', options).print_output(ret)
734
- ret
735
- end
736
-
737
- # check whether a user exists on this node
738
- def user_exists? user, options = {}
739
- options = default_options.merge options
740
-
741
- msg = messages.add("checking if user #{user} exists", options)
742
- msg.parse_result(exec("id #{user}")[:exit_code])
743
- end
744
-
745
- # manages users (create, modify)
746
- def manage_user(user, options = {})
747
- options = default_options.merge(options)
748
- options = { 'home' => nil, 'shell' => nil, 'uid' => nil, 'remove' => false,
749
- 'gid' => nil, 'groups' => nil, 'system' => false }.merge(options)
750
-
751
- # delete user from system
752
- if options['remove']
753
- if user_exists?(user, :quiet => true)
754
- msg = messages.add("deleting user #{user} from system", { :indent => options[:indent] }.merge(options))
755
- return msg.parse_result(exec("userdel --remove #{user}")[:exit_code])
756
- end
757
-
758
- return messages.add("user #{user} not present in system", options).ok
759
- end
760
-
761
- if user_exists?(user, :quiet => true)
762
- args = ""
763
- args << " --move-home --home #{options['home']}" if options['home']
764
- args << " --shell #{options['shell']}" if options['shell']
765
- args << " --uid #{options['uid']}" if options['uid']
766
- args << " --gid #{options['gid']}" if options['gid']
767
- args << " --append --groups #{Array(options['groups']).join(',')}" if options['groups']
768
-
769
- if args.empty?
770
- ret = messages.add("user #{user} already set up correctly", options).ok
771
- else
772
- msg = messages.add("modifying user #{user}", { :indent => options[:indent] }.merge(options))
773
- ret = msg.parse_result(exec("usermod #{args} #{user}")[:exit_code])
774
- end
775
-
776
- else
777
- args = ""
778
- args = "--create-home" unless options['system']
779
- args << " --system" if options['system']
780
- args << " --home #{options['home']}" if options['home'] and not options['system']
781
- args << " --shell #{options['shell']}" if options['shell']
782
- args << " --uid #{options['uid']}" if options['uid']
783
- args << " --gid #{options['gid']}" if options['gid']
784
- args << " --groups #{Array(options['groups']).join(',')}" if options['groups']
785
-
786
- msg = messages.add("creating user #{user}", { :indent => options[:indent] }.merge(options))
787
- ret = msg.parse_result(exec("useradd #{user} #{args}")[:exit_code])
788
- end
789
-
790
- # set selinux permissions
791
- chcon({ 'type' => 'user_home_dir_t' }, get_home(user), options)
792
- return ret
793
- end
794
-
795
- # returns the home directory of this user
796
- def get_home(user, options = {})
797
- options = default_options(:quiet => true).merge(options)
798
-
799
- msg = messages.add("getting home directory of #{user}", options)
800
- ret = exec("getent passwd |cut -d':' -f1,6 |grep '^#{user}' |head -n1 |cut -d: -f2")
801
- if msg.parse_result(ret[:exit_code]) and not ret[:stdout].chomp.empty?
802
- return ret[:stdout].chomp
803
- else
804
- return false
805
- end
806
- end
807
-
808
- # returns shell of this user
809
- def get_shell(user, options = {})
810
- options = default_options(:quiet => true).merge(options)
811
-
812
- msg = messages.add("getting shell of #{user}", options)
813
- ret = exec("getent passwd |cut -d':' -f1,7 |grep '^#{user}' |head -n1 |cut -d: -f2")
814
- if msg.parse_result(ret[:exit_code])
815
- return ret[:stdout].chomp
816
- else
817
- return false
818
- end
819
- end
820
-
821
- # returns primary group id of this user
822
- def get_gid(user, options = {})
823
- options = default_options(:quiet => true).merge(options)
824
-
825
- msg = messages.add("getting primary gid of #{user}", options)
826
- ret = exec("id -g #{user}")
827
- if msg.parse_result(ret[:exit_code])
828
- return ret[:stdout].chomp
829
- else
830
- return false
831
- end
832
- end
833
-
834
- # collect additional system facts using puppets facter
835
- def collect_facts options = {}
836
- options = default_options.merge options
837
-
838
- # if facts already have been collected, just return
839
- return true if @node['operatingsystem']
840
-
841
- # check if lsb-release (on apt systems) and facter are installed
842
- # and install them if not
843
- if uses_apt? and not package_installed? 'lsb-release', :quiet => true
844
- install_package 'lsb-release', :quiet => false
845
- end
846
-
847
- unless package_installed? 'facter', :quiet => true
848
- return false unless install_package 'facter', :quiet => false
849
- end
850
-
851
- msg = messages.add("collecting additional system facts (using facter)", options)
852
-
853
- # run facter with -y for yaml output, and merge results into @node
854
- ret = exec 'facter -y'
855
- @node = YAML.load(ret[:stdout]).merge(@node)
856
-
857
- msg.parse_result(ret[:exit_code])
858
- end
859
-
860
- # if file is a regular file, copy it using scp
861
- # if it's an file.erb exists, render template and push to server
862
- def deploy_file file, destination, options = {}
863
- options = default_options(:binding => binding).merge options
864
-
865
- if File.exists? file
866
- scp file, destination, options
867
-
868
- elsif File.exists? "#{file}.erb"
869
- template = ERB.new( File.read("#{file}.erb"), nil, '%<>')
870
- write destination, template.result(options[:binding]), options
871
-
872
- else
873
- messages.add("'#{file}' was not found.", options).failed
874
- end
875
- end
876
-
877
- # create a temporary file
878
- def mktemp(options = { :type => 'file' })
879
- if options[:type] == 'file'
880
- ret = exec('mktemp --tmpdir dust.XXXXXXXXXX')
881
- elsif options[:type] == 'directory'
882
- ret = exec('mktemp -d --tmpdir dust.XXXXXXXXXX')
883
- else
884
- return messages.add("mktemp: unknown type '#{options[:type]}'").failed
885
- end
886
-
887
- return false if ret[:exit_code] != 0
888
- ret[:stdout].chomp
889
- end
890
-
891
22
 
892
23
  private
893
24
 
@@ -905,6 +36,5 @@ module Dust
905
36
  super
906
37
  end
907
38
  end
908
-
909
39
  end
910
40
  end