automateit 0.71006 → 0.71012

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,3 +45,4 @@ require 'automateit/platform_manager/gentoo'
45
45
  require 'automateit/platform_manager/darwin'
46
46
  require 'automateit/platform_manager/windows'
47
47
  require 'automateit/platform_manager/freebsd'
48
+ require 'automateit/platform_manager/sunos'
@@ -2,10 +2,10 @@
2
2
  #
3
3
  # A PlatformManager driver for Apple's Darwin.
4
4
  class AutomateIt::PlatformManager::Darwin < AutomateIt::PlatformManager::Struct
5
- depends_on :files => ["/usr/sbin/scutil"], :programs => ["which"]
5
+ depends_on :files => ["/usr/sbin/scutil"], :programs => ["which", "uname"]
6
6
 
7
7
  def suitability(method, *args) # :nodoc:
8
- # Must be higher than PlatformManager::Struct
8
+ # Must be higher than PlatformManager::Uname
9
9
  return available? ? 3 : 0
10
10
  end
11
11
 
@@ -2,6 +2,10 @@
2
2
  #
3
3
  # A PlatformManager driver for FreeBSD.
4
4
  class AutomateIt::PlatformManager::FreeBSD < AutomateIt::PlatformManager::Uname
5
+ def self.token
6
+ :freebsd
7
+ end
8
+
5
9
  depends_on :files => %w(/etc/portsnap.conf /etc/rc.conf)
6
10
 
7
11
  def suitability(method, *args) # :nodoc:
@@ -0,0 +1,39 @@
1
+ # == PlatformManager::SunOS
2
+ #
3
+ # A PlatformManager driver for SunOS.
4
+ class AutomateIt::PlatformManager::SunOS < AutomateIt::PlatformManager::Uname
5
+ def self.token
6
+ :sunos
7
+ end
8
+
9
+ depends_on \
10
+ :programs => %w(uname),
11
+ :callbacks => [lambda {
12
+ begin
13
+ not `uname -s`.match(/SunOS/i).nil?
14
+ rescue
15
+ false
16
+ end
17
+ }]
18
+
19
+ def suitability(method, *args) # :nodoc:
20
+ # Must be higher than PlatformManager::Struct and Uname
21
+ return available? ? 3 : 0
22
+ end
23
+
24
+ def _prepare
25
+ return if @struct[:release]
26
+ @struct[:distro] = "sun"
27
+ @struct[:release] = `uname -r`.strip.downcase
28
+ @struct
29
+ end
30
+
31
+ def query(search)
32
+ _prepare
33
+ super(search)
34
+ end
35
+
36
+ def single_vendor?
37
+ return true
38
+ end
39
+ end
@@ -45,6 +45,18 @@ module AutomateIt
45
45
  cattr_accessor :classes
46
46
  self.classes = {}
47
47
 
48
+ # Returns the Plugin::Manager instance for this Driver.
49
+ attr_accessor :manager
50
+
51
+ # Setup a Driver.
52
+ #
53
+ # Options:
54
+ # * :manager -- The Plugin::Manager instance controlling this driver.
55
+ def setup(opts={})
56
+ self.manager = opts[:manager] if opts[:manager]
57
+ super(opts)
58
+ end
59
+
48
60
  # Retrieve the manager token for this driver
49
61
  def self.manager_token
50
62
  fragments = base_driver.to_s.split(/::/)
@@ -70,10 +82,14 @@ module AutomateIt
70
82
  if subclass.base_driver?
71
83
  # Ignore, base drivers should never be registered
72
84
  elsif base_driver
73
- manager = subclass.manager_token
74
- classes[manager] ||= []
75
- classes[manager] << subclass unless classes[manager].include?(subclass)
76
- ### puts "manager %s / driver %s" % [manager, subclass]
85
+ manager_token = subclass.manager_token
86
+ classes[manager_token] ||= []
87
+
88
+ unless classes[manager_token].include?(subclass)
89
+ classes[manager_token] << subclass
90
+ end
91
+
92
+ ### puts "manager_token %s / driver %s" % [manager_token, subclass]
77
93
  else
78
94
  # XXX Should this really raise an exception?
79
95
  raise TypeError.new("Can't determine manager for driver: #{subclass}")
@@ -197,6 +213,7 @@ module AutomateIt
197
213
  raise NotImplementedError.new("Missing dependencies -- %s" % msg)
198
214
  end
199
215
  end
216
+ protected :_raise_unless_available
200
217
 
201
218
  # What is this driver's suitability for automatic detection? The Manager
202
219
  # queries its drivers when there isn't a driver specified with a
@@ -80,7 +80,8 @@ module AutomateIt
80
80
  end
81
81
  self.class.driver_classes.each do |driver_class|
82
82
  driver_token = driver_class.token
83
- @drivers[driver_token].setup(:interpreter => @interpreter)
83
+ @drivers[driver_token].setup(
84
+ :interpreter => @interpreter, :manager => self)
84
85
  end
85
86
  end
86
87
 
@@ -1,7 +1,7 @@
1
1
  # See AutomateIt::Interpreter for usage information.
2
2
  module AutomateIt # :nodoc:
3
3
  # AutomateIt version
4
- VERSION=Gem::Version.new("0.71006")
4
+ VERSION=Gem::Version.new("0.71012")
5
5
 
6
6
  # Instantiates a new Interpreter. See documentation for
7
7
  # Interpreter#setup.
@@ -60,7 +60,7 @@ class AutomateIt::ServiceManager::SYSV < AutomateIt::ServiceManager::BaseDriver
60
60
  end
61
61
 
62
62
  result = tell(service, :status, :check => true)
63
- ### puts "k %s r %s e %s" % [kind, result, expected]
63
+ nitpick("_sash top: k=%s r=%s e=%s" % [kind, result, expected])
64
64
  return result if expected == result
65
65
  if opts[:wait]
66
66
  timeout = Time.now + opts[:wait]
@@ -69,6 +69,7 @@ class AutomateIt::ServiceManager::SYSV < AutomateIt::ServiceManager::BaseDriver
69
69
  [kind, service, timeout - Time.now])
70
70
  sleep 0.5
71
71
  result = tell(service, :status, :check => true)
72
+ nitpick("_sash rep: k=%s r=%s e=%s" % [kind, result, expected])
72
73
  break if expected == result
73
74
  end
74
75
  log.info(PNOTE+" ServiceManager#%s finished waiting for '%s', got: %s" %
@@ -28,6 +28,9 @@ class AutomateIt::ShellManager < AutomateIt::Plugin::Manager
28
28
 
29
29
  # Backup +sources+ if they exist. Returns the names of the backups created.
30
30
  #
31
+ # Options:
32
+ # * :quiet -- Don't display output? Default is false.
33
+ #
31
34
  # These backups are copies of the original sources saved into the same
32
35
  # directories as the originals. The pathnames of these copies are timestamped
33
36
  # and guaranteed to be unique, so you can have multiple backups of the same
@@ -30,6 +30,8 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
30
30
 
31
31
  # See ShellManager#backup
32
32
  def backup(*sources)
33
+ sources, opts = args_and_opts(*sources)
34
+
33
35
  targets = []
34
36
  for source in sources
35
37
  is_dir = File.directory?(source)
@@ -46,17 +48,19 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
46
48
 
47
49
  target = ::Tempster.tempster(tempster_opts)
48
50
 
49
- if is_dir
50
- cp_opts = {}
51
- cp_opts[:recursive] = true if is_dir
52
- cp_opts[:preserve] = :try
51
+ log.silence(opts[:quiet] ? Logger::WARN : log.level) do
52
+ if is_dir
53
+ cp_opts = {}
54
+ cp_opts[:recursive] = true if is_dir
55
+ cp_opts[:preserve] = :try
53
56
 
54
- source_children = _directory_contents(source)
55
- #puts "sc: %s" % source_children.inspect
57
+ source_children = _directory_contents(source)
58
+ #puts "sc: %s" % source_children.inspect
56
59
 
57
- interpreter.cp_r(source_children, target, cp_opts)
58
- else
59
- interpreter.cp(source, target)
60
+ interpreter.cp_r(source_children, target, cp_opts)
61
+ else
62
+ interpreter.cp(source, target)
63
+ end
60
64
  end
61
65
 
62
66
  targets << target
@@ -393,6 +397,8 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
393
397
  end
394
398
 
395
399
  modified_entries = []
400
+ modified_ownership = false
401
+ modified_permission = false
396
402
  Find.find(*targets) do |path|
397
403
  modified = false
398
404
  stat = writing? || File.exists?(path) ? File.stat(path) : nil
@@ -401,15 +407,18 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
401
407
  mode = opts[:mode] | (stat.directory? ? DIRECTORY_MASK : FILE_MASK) if stat
402
408
  unless stat and (mode ^ stat.mode).zero?
403
409
  modified = true
410
+ modified_permission = true
404
411
  File.chmod(mode, path) if writing?
405
412
  end
406
413
  end
407
414
  if user and (not stat or user != stat.uid)
408
415
  modified = true
416
+ modified_ownership = true
409
417
  File.chown(user, nil, path) if writing?
410
418
  end
411
419
  if group and (not stat or group != stat.gid)
412
420
  modified = true
421
+ modified_ownership = true
413
422
  File.chown(nil, group, path) if writing?
414
423
  end
415
424
  modified_entries << path if modified
@@ -421,19 +430,18 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
421
430
  display_entries = opts[:details] ? modified_entries : targets
422
431
  display_entries = [display_entries].flatten
423
432
 
424
- if opts[:mode]
433
+ if modified_permission
425
434
  msg = "chmod"
426
435
  msg << " -R" if opts[:recursive]
427
436
  msg << " 0%o" % opts[:mode] if opts[:mode]
428
437
  msg << " " << display_entries.join(' ')
429
438
  log.info(PEXEC+msg)
430
439
  end
431
- if opts[:user] or opts[:group]
440
+ if modified_ownership
432
441
  msg = "chown"
433
442
  msg << " -R" if opts[:recursive]
434
443
  msg << " %s" % opts[:user] if opts[:user]
435
444
  msg << ":" if opts[:user] and opts[:group]
436
- msg << " " unless opts[:user] and opts[:group]
437
445
  msg << "%s" % opts[:group] if opts[:group]
438
446
  msg << " " << display_entries.join(' ')
439
447
  log.info(PEXEC+msg)
@@ -484,11 +492,11 @@ class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
484
492
  end
485
493
 
486
494
  unless quiet
487
- msg = PEXEC << "touch"
495
+ msg = "touch"
488
496
  msg << " --reference %s" % like if like
489
497
  msg << " --stamp %s" % stamp if stamp
490
498
  msg << " " << [targets].flatten.join(" ")
491
- log.info(msg)
499
+ log.info(PEXEC+msg)
492
500
  end
493
501
 
494
502
  results = []
@@ -17,9 +17,10 @@ class AutomateIt::TemplateManager < AutomateIt::Plugin::Manager
17
17
  # * :text -- Read the template from this string.
18
18
  # * :to -- Render to a file, otherwise returns the rendered string.
19
19
  # * :locals -- Hash of variables passed to template as local variables.
20
- # * :dependencies -- When checking timestamps, include this Array of
21
- # filenames when checking timestamps.
22
- # * :force -- Boolean to force rendering without checking timestamps.
20
+ # * :dependencies -- Array of filenames to check timestamps on, only used
21
+ # when :check is :timestamp.
22
+ # * :backup -- Make a backup? Default is true.
23
+ # * :force -- Render without making a check. Default is false.
23
24
  # * :check -- Determines when to render, otherwise uses value of
24
25
  # +default_check+, possible values:
25
26
  # * :compare -- Only render if rendered template is different than the
@@ -16,6 +16,10 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
16
16
  end
17
17
  end
18
18
 
19
+ #.......................................................................
20
+
21
+ protected
22
+
19
23
  # Return Array of +dependencies+ newer than +filename+. Will be empty if
20
24
  # +filename+ is newer than all of the +dependencies+.
21
25
  def _newer(filename, *dependencies)
@@ -26,13 +30,11 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
26
30
  end
27
31
  return updated
28
32
  end
29
- protected :_newer
30
33
 
31
34
  # Does +filename+ exist?
32
35
  def _exists?(filename)
33
36
  return File.exists?(filename)
34
37
  end
35
- protected :_exists?
36
38
 
37
39
  # Return the contents of +filename+.
38
40
  def _read(filename)
@@ -47,20 +49,22 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
47
49
  end
48
50
  end
49
51
  end
50
- protected :_read
51
52
 
52
53
  # Write +contents+ to +filename+.
53
54
  def _write(filename, contents)
54
55
  File.open(filename, "w+"){|writer| writer.write(contents)} if writing?
55
56
  return true
56
57
  end
57
- protected :_write
58
+
59
+ # Backup +filename+.
60
+ def _backup(filename)
61
+ interpreter.backup(filename)
62
+ end
58
63
 
59
64
  # Return the modification date for +filename+.
60
65
  def _mtime(filename)
61
66
  return _exists? ? File.mtime(filename) : nil
62
67
  end
63
- protected :_mtime
64
68
 
65
69
  # Render a template specified in the block. It takes the same arguments and
66
70
  # returns the same results as the #render call.
@@ -84,6 +88,7 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
84
88
  source_filename = args[0] || opts[:file]
85
89
  target_filename = args[1] || opts[:to]
86
90
  source_text = opts[:text]
91
+ opts[:backup] = true if opts[:backup].nil?
87
92
 
88
93
  raise ArgumentError.new("No source specified with :file or :text") if not source_filename and not source_text
89
94
  raise Errno::ENOENT.new(source_filename) if writing? and source_filename and not _exists?(source_filename)
@@ -155,11 +160,13 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
155
160
  log.debug(PNOTE+"Rendering for '#{target_filename}' skipped because contents are the same")
156
161
  return false
157
162
  else
158
- log.info(PNOTE+"Rendering '#{target_filename} because its contents changed")
163
+ log.info(PNOTE+"Rendering '#{target_filename}' because its contents changed")
159
164
  end
160
165
  when :timestamp
161
166
  log.info(PNOTE+"Rendering '#{target_filename}' because of updated: #{updates.join(' ')}")
162
167
  end
168
+
169
+ _backup(target_filename) if target_exists and opts[:backup]
163
170
  result = _write(target_filename, output)
164
171
  return result
165
172
  ensure
@@ -168,5 +175,4 @@ class AutomateIt::TemplateManager::BaseDriver < AutomateIt::Plugin::Driver
168
175
  end
169
176
  end
170
177
  end
171
- protected :_render_helper
172
178
  end
@@ -0,0 +1,8 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "/spec_helper.rb")
2
+
3
+ describe "Breaker" do
4
+ it "should breakpoint within the RSpec environment" do
5
+ require "breakpoint"
6
+ breakpoint
7
+ end
8
+ end
@@ -4,34 +4,26 @@ if not INTERPRETER.euid?
4
4
  puts "NOTE: Can't check 'euid' on this platform, #{__FILE__}"
5
5
  elsif not INTERPRETER.superuser?
6
6
  puts "NOTE: Must be root to check #{__FILE__}"
7
- elsif not INTERPRETER.address_manager[:linux].available?
8
- puts "NOTE: Can't check AddressManager::Linux on this platform, #{__FILE__}"
9
7
  else
10
- describe "AutomateIt::AddressManager::Linux" do
8
+ describe AutomateIt::AddressManager, :shared => true do
11
9
  before(:all) do
10
+ # Should examples be independent? True is correct and lets you run a
11
+ # single example. False is evil and requires you to run the entire suite,
12
+ # but it's much faster. On Linux false yields a 5x speed-up.
13
+ @independent = false
14
+
12
15
  @a = AutomateIt.new(:verbosity => Logger::WARN)
13
16
  @m = @a.address_manager
14
-
15
- @properties = {
16
- :device => "eth0",
17
- :label => "xxxx",
18
- :address => "10.0.0.249",
19
- :mask => "24",
20
- :announcements => 1,
21
- }
22
-
23
- @device_and_label = @properties[:device]+":"+@properties[:label]
24
-
25
- if @m.interfaces.include?(@device_and_label) \
26
- or @m.addresses.include?(@properties[:address])
27
- raise "ERROR: This computer already has the device/address used for testing! Either disable #{@device_and_label} and #{@properties[:address]}, or change the spec to test using different properties."
28
- end
29
17
  end
30
18
 
31
19
  after(:all) do
32
20
  @m.remove(@properties)
33
21
  end
34
22
 
23
+ after(:each) do
24
+ @m.remove(@properties) if @independent
25
+ end
26
+
35
27
  it "should find interfaces for top-level device" do
36
28
  @m.interfaces.should include(@properties[:device])
37
29
  end
@@ -50,36 +42,41 @@ else
50
42
 
51
43
  it "should add an address" do
52
44
  @m.add(@properties).should be_true
53
- # Leaves active interface behind for other tests
54
45
  end
55
46
 
56
47
  it "should find added interface" do
57
- # Depends on active interface being created by earlier test
48
+ @m.add(@properties).should be_true if @independent
49
+
58
50
  @m.interfaces.should include(@device_and_label)
59
51
  end
60
52
 
61
53
  it "should find added IP address" do
62
- # Depends on active interface being created by earlier test
54
+ @m.add(@properties).should be_true if @independent
55
+
63
56
  @m.addresses.should include(@properties[:address])
64
57
  end
65
58
 
66
59
  it "should find added address using a properties bundle" do
67
- # Depends on user to be created by previous tests
60
+ @m.add(@properties).should be_true if @independent
61
+
68
62
  @m.has?(@properties).should be_true
69
63
  end
70
64
 
71
65
  it "should find added address using the IP address" do
72
- # Depends on user to be created by previous tests
66
+ @m.add(@properties).should be_true if @independent
67
+
73
68
  @m.has?(:address => @properties[:address]).should be_true
74
69
  end
75
70
 
76
71
  it "should find added address using device and label" do
77
- # Depends on user to be created by previous tests
72
+ @m.add(@properties).should be_true if @independent
73
+
78
74
  @m.has?(:device => @properties[:device], :label => @properties[:label]).should be_true
79
75
  end
80
76
 
81
77
  it "should remove an address" do
82
- # Depends on active interface being created by earlier test
78
+ @m.add(@properties).should be_true if @independent
79
+
83
80
  @m.remove(@properties).should be_true
84
81
  end
85
82
 
@@ -116,4 +113,47 @@ else
116
113
  @m.hostnames_for("kagami").should == ["kagami"]
117
114
  end
118
115
  end
116
+
117
+ #---[ Targets ]---------------------------------------------------------
118
+
119
+ %w(linux sunos).each do |driver_name|
120
+ driver_token = driver_name.to_sym
121
+ driver = INTERPRETER.address_manager[driver_token]
122
+ if driver.available?
123
+ describe driver.class.to_s do
124
+ it_should_behave_like "AutomateIt::AddressManager"
125
+
126
+ before(:all) do
127
+
128
+ @properties = {
129
+ :device => @m.interfaces.reject{|t| t =~ /^lo\d+$/}.first,
130
+ :label => "1",
131
+ :address => "10.0.0.249",
132
+ :mask => "24",
133
+ }
134
+
135
+ case driver_token
136
+ when :sunos
137
+ # Accept defaults
138
+ when :linux
139
+ @properties[:label] = "atst"
140
+ @properties[:announcements] = 1
141
+ else
142
+ raise ArgumentError.new("Unknown AddressManager driver: #{driver_token}")
143
+ end
144
+
145
+ @device_and_label = @properties[:device]+":"+@properties[:label]
146
+
147
+ if @m.interfaces.include?(@device_and_label) \
148
+ or @m.addresses.include?(@properties[:address])
149
+ raise "ERROR: This computer already has the device/address used for testing! Either disable #{@device_and_label} and #{@properties[:address]}, or change the spec to test using different properties."
150
+ end
151
+
152
+ @d = @m[driver_token]
153
+ end
154
+ end
155
+ else
156
+ puts %{NOTE: Can't check %s on this platform, #{__FILE__}} % driver.class
157
+ end
158
+ end
119
159
  end