automate-it 0.9.0
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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.hgignore +10 -0
- data/.loadpath +5 -0
- data/.project +17 -0
- data/CHANGES.txt +314 -0
- data/Hoe.rake +40 -0
- data/Manifest.txt +164 -0
- data/README.txt +40 -0
- data/Rakefile +256 -0
- data/TESTING.txt +57 -0
- data/TODO.txt +50 -0
- data/TUTORIAL.txt +391 -0
- data/automate-it.gemspec +25 -0
- data/bin/ai +3 -0
- data/bin/aifield +75 -0
- data/bin/aissh +93 -0
- data/bin/aitag +134 -0
- data/bin/automateit +133 -0
- data/docs/friendly_errors.txt +50 -0
- data/docs/previews.txt +86 -0
- data/examples/basic/Rakefile +26 -0
- data/examples/basic/config/automateit_env.rb +16 -0
- data/examples/basic/config/fields.yml +3 -0
- data/examples/basic/config/tags.yml +7 -0
- data/examples/basic/dist/README.txt +9 -0
- data/examples/basic/dist/myapp_server.erb +30 -0
- data/examples/basic/install.log +15 -0
- data/examples/basic/lib/README.txt +10 -0
- data/examples/basic/recipes/README.txt +4 -0
- data/examples/basic/recipes/install.rb +61 -0
- data/examples/basic/recipes/uninstall.rb +6 -0
- data/gpl.txt +674 -0
- data/helpers/cpan_wrapper.pl +220 -0
- data/helpers/which.cmd +7 -0
- data/lib/automateit.rb +55 -0
- data/lib/automateit/account_manager.rb +114 -0
- data/lib/automateit/account_manager/base.rb +138 -0
- data/lib/automateit/account_manager/etc.rb +128 -0
- data/lib/automateit/account_manager/nscd.rb +33 -0
- data/lib/automateit/account_manager/passwd_expect.rb +40 -0
- data/lib/automateit/account_manager/passwd_pty.rb +69 -0
- data/lib/automateit/account_manager/posix.rb +138 -0
- data/lib/automateit/address_manager.rb +88 -0
- data/lib/automateit/address_manager/base.rb +171 -0
- data/lib/automateit/address_manager/bsd.rb +28 -0
- data/lib/automateit/address_manager/freebsd.rb +59 -0
- data/lib/automateit/address_manager/linux.rb +42 -0
- data/lib/automateit/address_manager/openbsd.rb +66 -0
- data/lib/automateit/address_manager/portable.rb +37 -0
- data/lib/automateit/address_manager/sunos.rb +34 -0
- data/lib/automateit/cli.rb +85 -0
- data/lib/automateit/common.rb +65 -0
- data/lib/automateit/constants.rb +35 -0
- data/lib/automateit/download_manager.rb +48 -0
- data/lib/automateit/edit_manager.rb +321 -0
- data/lib/automateit/error.rb +10 -0
- data/lib/automateit/field_manager.rb +103 -0
- data/lib/automateit/interpreter.rb +631 -0
- data/lib/automateit/package_manager.rb +257 -0
- data/lib/automateit/package_manager/apt.rb +27 -0
- data/lib/automateit/package_manager/cpan.rb +101 -0
- data/lib/automateit/package_manager/dpkg.rb +54 -0
- data/lib/automateit/package_manager/egg.rb +64 -0
- data/lib/automateit/package_manager/gem.rb +201 -0
- data/lib/automateit/package_manager/pear.rb +95 -0
- data/lib/automateit/package_manager/pecl.rb +80 -0
- data/lib/automateit/package_manager/portage.rb +69 -0
- data/lib/automateit/package_manager/yum.rb +65 -0
- data/lib/automateit/platform_manager.rb +49 -0
- data/lib/automateit/platform_manager/darwin.rb +30 -0
- data/lib/automateit/platform_manager/debian.rb +26 -0
- data/lib/automateit/platform_manager/freebsd.rb +29 -0
- data/lib/automateit/platform_manager/gentoo.rb +26 -0
- data/lib/automateit/platform_manager/lsb.rb +44 -0
- data/lib/automateit/platform_manager/openbsd.rb +28 -0
- data/lib/automateit/platform_manager/struct.rb +80 -0
- data/lib/automateit/platform_manager/sunos.rb +39 -0
- data/lib/automateit/platform_manager/uname.rb +29 -0
- data/lib/automateit/platform_manager/windows.rb +40 -0
- data/lib/automateit/plugin.rb +7 -0
- data/lib/automateit/plugin/base.rb +32 -0
- data/lib/automateit/plugin/driver.rb +256 -0
- data/lib/automateit/plugin/manager.rb +224 -0
- data/lib/automateit/project.rb +493 -0
- data/lib/automateit/root.rb +17 -0
- data/lib/automateit/service_manager.rb +93 -0
- data/lib/automateit/service_manager/chkconfig.rb +39 -0
- data/lib/automateit/service_manager/rc_update.rb +37 -0
- data/lib/automateit/service_manager/sysv.rb +139 -0
- data/lib/automateit/service_manager/update_rcd.rb +35 -0
- data/lib/automateit/shell_manager.rb +316 -0
- data/lib/automateit/shell_manager/base_link.rb +67 -0
- data/lib/automateit/shell_manager/link.rb +24 -0
- data/lib/automateit/shell_manager/portable.rb +523 -0
- data/lib/automateit/shell_manager/symlink.rb +32 -0
- data/lib/automateit/shell_manager/which_base.rb +30 -0
- data/lib/automateit/shell_manager/which_unix.rb +16 -0
- data/lib/automateit/shell_manager/which_windows.rb +20 -0
- data/lib/automateit/tag_manager.rb +127 -0
- data/lib/automateit/tag_manager/struct.rb +121 -0
- data/lib/automateit/tag_manager/tag_parser.rb +93 -0
- data/lib/automateit/tag_manager/yaml.rb +29 -0
- data/lib/automateit/template_manager.rb +56 -0
- data/lib/automateit/template_manager/base.rb +181 -0
- data/lib/automateit/template_manager/erb.rb +17 -0
- data/lib/ext/metaclass.rb +17 -0
- data/lib/ext/object.rb +18 -0
- data/lib/ext/shell_escape.rb +7 -0
- data/lib/hashcache.rb +22 -0
- data/lib/helpful_erb.rb +63 -0
- data/lib/inactive_support.rb +53 -0
- data/lib/inactive_support/basic_object.rb +6 -0
- data/lib/inactive_support/clean_logger.rb +127 -0
- data/lib/inactive_support/core_ext/array/extract_options.rb +19 -0
- data/lib/inactive_support/core_ext/blank.rb +50 -0
- data/lib/inactive_support/core_ext/class/attribute_accessors.rb +48 -0
- data/lib/inactive_support/core_ext/class/inheritable_attributes.rb +140 -0
- data/lib/inactive_support/core_ext/enumerable.rb +63 -0
- data/lib/inactive_support/core_ext/hash/keys.rb +54 -0
- data/lib/inactive_support/core_ext/module/aliasing.rb +70 -0
- data/lib/inactive_support/core_ext/numeric/time.rb +91 -0
- data/lib/inactive_support/core_ext/string/inflections.rb +153 -0
- data/lib/inactive_support/core_ext/symbol.rb +14 -0
- data/lib/inactive_support/core_ext/time/conversions.rb +96 -0
- data/lib/inactive_support/duration.rb +96 -0
- data/lib/inactive_support/inflections.rb +53 -0
- data/lib/inactive_support/inflector.rb +282 -0
- data/lib/nested_error.rb +33 -0
- data/lib/nitpick.rb +33 -0
- data/lib/queued_logger.rb +68 -0
- data/lib/tempster.rb +250 -0
- data/misc/index_gem_repository.rb +304 -0
- data/misc/setup_egg.rb +12 -0
- data/misc/setup_gem_dependencies.sh +6 -0
- data/misc/setup_rubygems.sh +21 -0
- metadata +279 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
# == AccountManager::Etc
|
2
|
+
#
|
3
|
+
# An AccountManager driver for Unix-like OSes that have the Ruby Etc module. It
|
4
|
+
# is only suitable for doing queries and lacks methods that perform
|
5
|
+
# modifications, such as +add_user+. Platform-specific drivers inherit from
|
6
|
+
# this class and provide methods that perform modifications.
|
7
|
+
class ::AutomateIt::AccountManager::Etc< ::AutomateIt::AccountManager::BaseDriver
|
8
|
+
depends_on :libraries => %w(etc),
|
9
|
+
:callbacks => lambda{
|
10
|
+
begin
|
11
|
+
! ::Etc.getpwnam(::Etc.getlogin).nil?
|
12
|
+
rescue
|
13
|
+
false
|
14
|
+
end
|
15
|
+
}
|
16
|
+
|
17
|
+
def suitability(method, *args) # :nodoc:
|
18
|
+
return available? ? 1 : 0
|
19
|
+
end
|
20
|
+
|
21
|
+
#.......................................................................
|
22
|
+
|
23
|
+
# == UserQuery
|
24
|
+
#
|
25
|
+
# A class used for querying users. See AccountManager#users.
|
26
|
+
class UserQuery
|
27
|
+
# See AccountManager#users
|
28
|
+
def [](query)
|
29
|
+
::Etc.endpwent
|
30
|
+
begin
|
31
|
+
case query
|
32
|
+
when String
|
33
|
+
return ::Etc.getpwnam(query)
|
34
|
+
when Fixnum
|
35
|
+
return ::Etc.getpwuid(query)
|
36
|
+
else
|
37
|
+
raise TypeError.new("unknonwn type for query: #{query.class}")
|
38
|
+
end
|
39
|
+
rescue ArgumentError
|
40
|
+
return nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# See AccountManager#users
|
46
|
+
def users
|
47
|
+
return UserQuery.new
|
48
|
+
end
|
49
|
+
|
50
|
+
# See AccountManager#has_user?
|
51
|
+
def has_user?(query)
|
52
|
+
return ! users[query].nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
#.......................................................................
|
56
|
+
|
57
|
+
# == GroupQuery
|
58
|
+
#
|
59
|
+
# A class used for querying groups. See AccountManager#groups.
|
60
|
+
class GroupQuery
|
61
|
+
# See AccountManager#groups
|
62
|
+
def [](query)
|
63
|
+
::Etc.endgrent
|
64
|
+
begin
|
65
|
+
case query
|
66
|
+
when String
|
67
|
+
return ::Etc.getgrnam(query)
|
68
|
+
when Fixnum
|
69
|
+
return ::Etc.getgrgid(query)
|
70
|
+
else
|
71
|
+
raise TypeError.new("unknonwn type for query: #{query.class}")
|
72
|
+
end
|
73
|
+
rescue ArgumentError
|
74
|
+
return nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# See AccountManager#groups
|
80
|
+
def groups
|
81
|
+
return GroupQuery.new
|
82
|
+
end
|
83
|
+
|
84
|
+
# See AccountManager#has_group?
|
85
|
+
def has_group?(query)
|
86
|
+
return ! groups[query].nil?
|
87
|
+
end
|
88
|
+
|
89
|
+
# See AccountManager#groups_for_user
|
90
|
+
def groups_for_user(query)
|
91
|
+
pwent = users[query]
|
92
|
+
return [] if preview? and not pwent
|
93
|
+
username = pwent.name
|
94
|
+
result = Set.new
|
95
|
+
result << groups[pwent.gid].name if groups[pwent.gid]
|
96
|
+
::Etc.group do |grent|
|
97
|
+
result << grent.name if grent.mem.include?(username)
|
98
|
+
end
|
99
|
+
return result.to_a
|
100
|
+
end
|
101
|
+
|
102
|
+
# See AccountManager#users_for_group
|
103
|
+
def users_for_group(query)
|
104
|
+
grent = groups[query]
|
105
|
+
return (preview? || ! grent) ? [] : grent.mem
|
106
|
+
end
|
107
|
+
|
108
|
+
# See AccountManager#users_to_groups
|
109
|
+
def users_to_groups
|
110
|
+
result = {}
|
111
|
+
::Etc.group do |grent|
|
112
|
+
grent.mem.each do |username|
|
113
|
+
result[username] ||= Set.new
|
114
|
+
result[username] << grent.name
|
115
|
+
end
|
116
|
+
end
|
117
|
+
::Etc.passwd do |pwent|
|
118
|
+
grent = groups[pwent.gid]
|
119
|
+
unless grent
|
120
|
+
log.fatal(PNOTE+"WARNING: User's default group doesn't exist: user %s, gid %s" % [pwent.name, pwent.gid])
|
121
|
+
next
|
122
|
+
end
|
123
|
+
result[pwent.name] ||= Set.new
|
124
|
+
result[pwent.name] << grent.name
|
125
|
+
end
|
126
|
+
return result
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# == AccountManager::NSCD
|
2
|
+
#
|
3
|
+
# AccountManager driver for invalidating records stored in the NSCD, Name
|
4
|
+
# Service Cache Daemon, found on Unix-like systems.
|
5
|
+
class ::AutomateIt::AccountManager::NSCD < ::AutomateIt::AccountManager::BaseDriver
|
6
|
+
depends_on :programs => %w(nscd ps),
|
7
|
+
# FIXME AccountManager.nscd - "ps -ef" isn't portable, may need to be "ps aux" or such
|
8
|
+
:callbacks => lambda{`ps -ef`.match(%r{/usr/sbin/nscd$})}
|
9
|
+
|
10
|
+
def suitability(method, *args) # :nodoc:
|
11
|
+
# Level must be higher than Portable
|
12
|
+
return available? ? 5 : 0
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the NSCD database for the specified shorthand +query+.
|
16
|
+
def database_for(query)
|
17
|
+
case query.to_sym
|
18
|
+
when :user, :users, :passwd, :password
|
19
|
+
:passwd
|
20
|
+
when :group, :groups
|
21
|
+
:group
|
22
|
+
else
|
23
|
+
raise ArgumentError.new("Unknown cache database: #{query}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Invalidates the NSCD database, thus forcing a cache reload.
|
28
|
+
def invalidate(database)
|
29
|
+
return false unless available?
|
30
|
+
|
31
|
+
interpreter.sh("nscd -i #{database_for(database)}")
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# == AccountManager::PasswdExpect
|
2
|
+
#
|
3
|
+
# An AccountManager driver for the +passwd+ command found on Unix-like systems
|
4
|
+
# using the +expect+ program as a wrapper because the Ruby PTY implementation
|
5
|
+
# is unreliable.
|
6
|
+
class ::AutomateIt::AccountManager::PasswdExpect < ::AutomateIt::AccountManager::BaseDriver
|
7
|
+
depends_on :programs => %w(passwd expect)
|
8
|
+
|
9
|
+
def suitability(method, *args) # :nodoc:
|
10
|
+
# Level must be higher than PasswdPTY
|
11
|
+
return available? ? 9 : 0
|
12
|
+
end
|
13
|
+
|
14
|
+
# See AccountManager#passwd
|
15
|
+
def passwd(user, password, opts={})
|
16
|
+
_passwd_helper(user, password, opts) do |user, password, opts|
|
17
|
+
log.silence(Logger::WARN) do
|
18
|
+
interpreter.mktemp do |filename|
|
19
|
+
# Script derived from /usr/share/doc/expect/examples/autopasswd
|
20
|
+
interpreter.render(:text => <<-HERE, :to => filename)
|
21
|
+
set password "#{password}"
|
22
|
+
spawn passwd "#{user}"
|
23
|
+
expect "assword:"
|
24
|
+
sleep 0.1
|
25
|
+
send "$password\\r"
|
26
|
+
expect "assword:"
|
27
|
+
sleep 0.1
|
28
|
+
send "$password\\r"
|
29
|
+
expect eof
|
30
|
+
HERE
|
31
|
+
|
32
|
+
cmd = "expect #{filename}"
|
33
|
+
cmd << " > /dev/null" if opts[:quiet]
|
34
|
+
return(interpreter.sh cmd)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# == AccountManager::PasswdPTY
|
2
|
+
#
|
3
|
+
# An AccountManager driver for +passwd+ command found on Unix-like systems
|
4
|
+
# using the Ruby PTY implementation.
|
5
|
+
#
|
6
|
+
# *WARNING*: The Ruby PTY module is unreliable or unavailable on most
|
7
|
+
# platforms. It may hang indefinitely or report incorrect results. Every
|
8
|
+
# attempt has been made to work around these problems, but this is a low-level
|
9
|
+
# problem. You are strongly encouraged to install the +expect+ program, which
|
10
|
+
# works flawlessly. Once the +expect+ program is installed, passwords will be
|
11
|
+
# changed using the AccountManager::PasswdExpect driver, which works properly.
|
12
|
+
class ::AutomateIt::AccountManager::PasswdPTY < ::AutomateIt::AccountManager::BaseDriver
|
13
|
+
depends_on \
|
14
|
+
:programs => %w(passwd uname),
|
15
|
+
:libraries => %w(open3 expect pty),
|
16
|
+
# Something is horribly wrong with Ruby PTY on Sun
|
17
|
+
:callbacks => lambda { `uname -s`.strip !~ /sunos|solaris|openbsd|freebsd/i }
|
18
|
+
|
19
|
+
def suitability(method, *args) # :nodoc:
|
20
|
+
# Level must be higher than Linux
|
21
|
+
return available? ? 3 : 0
|
22
|
+
end
|
23
|
+
|
24
|
+
# See AccountManager#passwd
|
25
|
+
def passwd(user, password, opts={})
|
26
|
+
log.info(PERROR+"Setting password with flaky Ruby PTY, which hangs or fails randomly. Install 'expect' (http://expect.nist.gov/) for reliable operation.")
|
27
|
+
_passwd_helper(user, password, opts) do
|
28
|
+
log.silence(Logger::WARN) do
|
29
|
+
interpreter.mktemp do |filename|
|
30
|
+
tries = 5
|
31
|
+
exitstatus = nil
|
32
|
+
begin
|
33
|
+
exitstruct = _passwd_raw(user, password, opts)
|
34
|
+
if exitstatus and not exitstruct.exitstatus.zero?
|
35
|
+
# FIXME AccountManager::Linux#passwd -- The `passwd` command randomly returns exit status 10 even when it succeeds. What does this mean and how to deal with it?! Temporary workaround is to throw an error and force a retry.
|
36
|
+
raise Errno::EPIPE.new("bad exitstatus %s" % exitstruct.exitstatus)
|
37
|
+
end
|
38
|
+
rescue Errno::EPIPE => e
|
39
|
+
# FIXME AccountManager::Linux#passwd -- EPIPE exception randomly thrown even when `passwd` succeeds. How to eliminate it? How to differentiate between this false error and a real one?
|
40
|
+
if tries <= 0
|
41
|
+
raise e
|
42
|
+
else
|
43
|
+
tries -= 1
|
44
|
+
retry
|
45
|
+
end
|
46
|
+
end
|
47
|
+
return exitstruct.exitstatus.zero?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def _passwd_raw(user, password, opts={})
|
55
|
+
quiet = (opts[:quiet] or not log.info?)
|
56
|
+
|
57
|
+
require 'open4'
|
58
|
+
return Open4::popen4("passwd %s 2>&1" % user) do |pid, sin, sout, serr|
|
59
|
+
$expect_verbose = ! quiet
|
60
|
+
2.times do
|
61
|
+
sout.expect(/:/)
|
62
|
+
sleep 0.1 # Reduce chance of passwd thinking we're a robot :(
|
63
|
+
sin.puts password
|
64
|
+
puts "*" * 12 unless quiet
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
protected :_passwd_raw
|
69
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# == AccountManager::POSIX
|
2
|
+
#
|
3
|
+
# A POSIX driver for the AccountManager.
|
4
|
+
class ::AutomateIt::AccountManager::POSIX < ::AutomateIt::AccountManager::BaseDriver
|
5
|
+
depends_on :programs => %w(useradd usermod userdel groupadd groupmod groupdel)
|
6
|
+
|
7
|
+
def suitability(method, *args) # :nodoc:
|
8
|
+
# Level must be higher than Portable
|
9
|
+
return available? ? 2 : 0
|
10
|
+
end
|
11
|
+
|
12
|
+
#.......................................................................
|
13
|
+
|
14
|
+
# See AccountManager#add_user
|
15
|
+
def add_user(username, opts={})
|
16
|
+
return _add_user_helper(username, opts) do |username, opts|
|
17
|
+
cmd = "useradd"
|
18
|
+
cmd << " -c #{opts[:description] || username}"
|
19
|
+
cmd << " -d #{opts[:home]}" if opts[:home]
|
20
|
+
cmd << " -m" unless opts[:create_home] == false
|
21
|
+
cmd << " -G #{opts[:groups].join(',')}" if opts[:groups]
|
22
|
+
cmd << " -s #{opts[:shell] || "/bin/bash"}"
|
23
|
+
cmd << " -u #{opts[:uid]}" if opts[:uid]
|
24
|
+
cmd << " -g #{opts[:gid]}" if opts[:gid]
|
25
|
+
cmd << " #{username} < /dev/null"
|
26
|
+
cmd << " > /dev/null 2>&1 | grep -v blocks" if opts[:quiet]
|
27
|
+
interpreter.sh(cmd)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO AccountManager#update_user -- implement
|
32
|
+
### def update_user(username, opts={}) dispatch(username, opts) end
|
33
|
+
|
34
|
+
# See AccountManager#remove_user
|
35
|
+
def remove_user(username, opts={})
|
36
|
+
return _remove_user_helper(username, opts) do |username, opts|
|
37
|
+
# Options: -r -- remove the home directory and mail spool
|
38
|
+
cmd = "userdel"
|
39
|
+
cmd << " -r" unless opts[:remove_home] == false
|
40
|
+
cmd << " #{username}"
|
41
|
+
cmd << " > /dev/null" if opts[:quiet]
|
42
|
+
interpreter.sh(cmd)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# See AccountManager#add_groups_to_user
|
47
|
+
def add_groups_to_user(groups, username)
|
48
|
+
return _add_groups_to_user_helper(groups, username) do |missing, username|
|
49
|
+
targets = (groups_for_user(username) + missing).uniq
|
50
|
+
|
51
|
+
cmd = "usermod -G #{targets.join(',')} #{username}"
|
52
|
+
interpreter.sh(cmd)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# See AccountManager#remove_groups_from_user
|
57
|
+
def remove_groups_from_user(groups, username)
|
58
|
+
return _remove_groups_from_user_helper(groups, username) do |present, username|
|
59
|
+
matches = (groups_for_user(username) - [groups].flatten).uniq
|
60
|
+
cmd = "usermod -G #{matches.join(',')} #{username}"
|
61
|
+
interpreter.sh(cmd)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#.......................................................................
|
66
|
+
|
67
|
+
# See AccountManager#add_group
|
68
|
+
def add_group(groupname, opts={})
|
69
|
+
modified = false
|
70
|
+
unless has_group?(groupname)
|
71
|
+
modified = true
|
72
|
+
|
73
|
+
cmd = "groupadd"
|
74
|
+
cmd << " -g #{opts[:gid]}" if opts[:gid]
|
75
|
+
cmd << " #{groupname}"
|
76
|
+
interpreter.sh(cmd)
|
77
|
+
|
78
|
+
manager.invalidate(:groups)
|
79
|
+
end
|
80
|
+
|
81
|
+
if opts[:members]
|
82
|
+
modified = true
|
83
|
+
add_users_to_group(opts[:members], groupname)
|
84
|
+
end
|
85
|
+
|
86
|
+
return modified ? groups[groupname] : false
|
87
|
+
end
|
88
|
+
|
89
|
+
# TODO AccountManager#update_group -- implement
|
90
|
+
### def update_group(groupname, opts={}) dispatch(groupname, opts) end
|
91
|
+
|
92
|
+
# See AccountManager#remove_group
|
93
|
+
def remove_group(groupname, opts={})
|
94
|
+
return false unless has_group?(groupname)
|
95
|
+
cmd = "groupdel #{groupname}"
|
96
|
+
interpreter.sh(cmd)
|
97
|
+
|
98
|
+
manager.invalidate(:groups)
|
99
|
+
|
100
|
+
return true
|
101
|
+
end
|
102
|
+
|
103
|
+
# See AccountManager#add_users_to_group
|
104
|
+
def add_users_to_group(users, groupname)
|
105
|
+
_add_users_to_group_helper(users, groupname) do |missing, groupname|
|
106
|
+
for username in missing
|
107
|
+
targets = (groups_for_user(username) + [groupname]).uniq
|
108
|
+
cmd = "usermod -G #{targets.join(',')} #{username}"
|
109
|
+
interpreter.sh(cmd)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# See AccountManager#remove_users_from_group
|
115
|
+
def remove_users_from_group(users, groupname)
|
116
|
+
_remove_users_from_group_helper(users, groupname) do |present, groupname|
|
117
|
+
u2g = users_to_groups
|
118
|
+
for username in present
|
119
|
+
user_groups = u2g[username]
|
120
|
+
# FIXME tries to include non-present groups, should use some variant of present
|
121
|
+
cmd = "usermod -G #{(user_groups.to_a-[groupname]).join(',')} #{username}"
|
122
|
+
interpreter.sh(cmd)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Dispatch common names to Etc, but don't define these methods here because
|
128
|
+
# that would make available? and suitability think these exist, when in fact,
|
129
|
+
# they're just wrappers.
|
130
|
+
def method_missing(symbol, *args, &block)
|
131
|
+
case symbol
|
132
|
+
when :users, :has_user?, :groups, :has_group?, :groups_for_user, :users_for_group, :users_to_groups
|
133
|
+
manager.send(symbol, *args, &block)
|
134
|
+
else
|
135
|
+
super(symbol, *args, &block)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# == AddressManager
|
2
|
+
#
|
3
|
+
# The AddressManager provides a way to query, add and remove network
|
4
|
+
# addresses on a host.
|
5
|
+
class AutomateIt::AddressManager < AutomateIt::Plugin::Manager
|
6
|
+
# Does host have an address or interface? Arguments hash must include
|
7
|
+
# either a :device (e.g., "eth0") or :address (e.g., "10.0.0.10"), and an
|
8
|
+
# optional :label (e.g., "foo"). Note that an interface is the combination
|
9
|
+
# of a :device and :label, so "eth0" isn't the same as "eth0:foo".
|
10
|
+
#
|
11
|
+
# Examples on a host with address "10.0.0.10" on interface "eth0:foo":
|
12
|
+
# has?(:address => "10.0.0.10")
|
13
|
+
# => true
|
14
|
+
# has?(:address => "10.0.0.10", :device => "eth0")
|
15
|
+
# => false
|
16
|
+
# has?(:address => "10.0.0.10", :device => "eth0", :label => "foo")
|
17
|
+
# => true
|
18
|
+
# has?(:device => "eth0")
|
19
|
+
# => false
|
20
|
+
# has?(:device => "eth0", :label => "foo")
|
21
|
+
# => true
|
22
|
+
def has?(opts) dispatch(opts) end
|
23
|
+
|
24
|
+
# Add address to host if it doesn't have it. Requires root-level access.
|
25
|
+
# Returns +true+ if action was taken and succeeded.
|
26
|
+
#
|
27
|
+
# Arguments hash must include either a :device (e.g., "eth0") or :address
|
28
|
+
# (e.g., "10.0.0.10"), and an optional :label (e.g., "foo") and :mask (e.g.
|
29
|
+
# "24").
|
30
|
+
#
|
31
|
+
# An optional number of ARP :announcements may be specified, defaulting to
|
32
|
+
# AutomateIt::AddressManager::DEFAULT_ANNOUNCEMENTS. Drivers that handle
|
33
|
+
# announcements will block an extra second while making each announcement.
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
# add(:address => "10.0.0.10", :mask => 24, :device => "eth0",
|
37
|
+
# :label => "foo", :announcements => 3)
|
38
|
+
def add(opts) dispatch(opts) end
|
39
|
+
|
40
|
+
# Number of ARP announcements to make by default during #add.
|
41
|
+
DEFAULT_ANNOUNCEMENTS = 3
|
42
|
+
|
43
|
+
# Remove address from host if it has it. Requires root-level access.
|
44
|
+
# Returns +true+ if action was taken and succeeded.
|
45
|
+
#
|
46
|
+
# Arguments hash must include either a :device (e.g., "eth0") or :address
|
47
|
+
# (e.g., "10.0.0.10"), and an optional :label (e.g., "foo") and :mask (e.g.
|
48
|
+
# "24").
|
49
|
+
#
|
50
|
+
# Example:
|
51
|
+
# remove(:address => "10.0.0.10", :mask => 24, :device => "eth0",
|
52
|
+
# :label => "foo")
|
53
|
+
def remove(opts) dispatch(opts) end
|
54
|
+
|
55
|
+
# Array of addresses for this host. Example:
|
56
|
+
# addresses
|
57
|
+
# => ["10.0.0.10", "127.0.0.1"]
|
58
|
+
def addresses() dispatch() end
|
59
|
+
|
60
|
+
# Array of interfaces for this host. Example:
|
61
|
+
# interfaces
|
62
|
+
# => ["eth0", "lo"]
|
63
|
+
def interfaces() dispatch() end
|
64
|
+
|
65
|
+
# Array of hostnames for this host, including variants by trying to resolve
|
66
|
+
# names for all addresses owned by this host. Example:
|
67
|
+
# hostnames
|
68
|
+
# => ["kagami", "kagami.lucky-channel", "kagami.lucky-channel.jp"]
|
69
|
+
def hostnames() dispatch() end
|
70
|
+
|
71
|
+
# Array of hostname variants for this +hostname+. This method performs no
|
72
|
+
# name resolution and simply infers a less qualified name from a more
|
73
|
+
# qualified hostname argument. Example:
|
74
|
+
# hostnames_for("kagami.lucky-channel")
|
75
|
+
# => ["kagami", "kagami.lucky-channel"]
|
76
|
+
# hostnames_for("kagami")
|
77
|
+
# => ["kagami"]
|
78
|
+
def hostnames_for(hostname) dispatch(hostname) end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Drivers
|
82
|
+
require 'automateit/address_manager/base'
|
83
|
+
require 'automateit/address_manager/portable'
|
84
|
+
require 'automateit/address_manager/bsd'
|
85
|
+
require 'automateit/address_manager/linux'
|
86
|
+
require 'automateit/address_manager/sunos'
|
87
|
+
require 'automateit/address_manager/openbsd'
|
88
|
+
require 'automateit/address_manager/freebsd'
|