automateit 0.70923

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.
Files changed (119) hide show
  1. data.tar.gz.sig +1 -0
  2. data/CHANGES.txt +100 -0
  3. data/Hoe.rake +35 -0
  4. data/Manifest.txt +111 -0
  5. data/README.txt +44 -0
  6. data/Rakefile +284 -0
  7. data/TESTING.txt +57 -0
  8. data/TODO.txt +26 -0
  9. data/TUTORIAL.txt +390 -0
  10. data/bin/ai +3 -0
  11. data/bin/aifield +82 -0
  12. data/bin/aitag +128 -0
  13. data/bin/automateit +117 -0
  14. data/docs/friendly_errors.txt +50 -0
  15. data/docs/previews.txt +86 -0
  16. data/env.sh +4 -0
  17. data/examples/basic/Rakefile +26 -0
  18. data/examples/basic/config/automateit_env.rb +16 -0
  19. data/examples/basic/config/fields.yml +3 -0
  20. data/examples/basic/config/tags.yml +13 -0
  21. data/examples/basic/dist/README.txt +9 -0
  22. data/examples/basic/dist/myapp_server.erb +30 -0
  23. data/examples/basic/install.log +15 -0
  24. data/examples/basic/lib/README.txt +10 -0
  25. data/examples/basic/recipes/README.txt +4 -0
  26. data/examples/basic/recipes/install.rb +53 -0
  27. data/examples/basic/recipes/uninstall.rb +6 -0
  28. data/gpl.txt +674 -0
  29. data/lib/automateit.rb +66 -0
  30. data/lib/automateit/account_manager.rb +106 -0
  31. data/lib/automateit/account_manager/linux.rb +171 -0
  32. data/lib/automateit/account_manager/passwd.rb +69 -0
  33. data/lib/automateit/account_manager/portable.rb +136 -0
  34. data/lib/automateit/address_manager.rb +165 -0
  35. data/lib/automateit/address_manager/linux.rb +80 -0
  36. data/lib/automateit/address_manager/portable.rb +37 -0
  37. data/lib/automateit/cli.rb +80 -0
  38. data/lib/automateit/common.rb +65 -0
  39. data/lib/automateit/constants.rb +33 -0
  40. data/lib/automateit/edit_manager.rb +292 -0
  41. data/lib/automateit/error.rb +10 -0
  42. data/lib/automateit/field_manager.rb +103 -0
  43. data/lib/automateit/interpreter.rb +641 -0
  44. data/lib/automateit/package_manager.rb +242 -0
  45. data/lib/automateit/package_manager/apt.rb +63 -0
  46. data/lib/automateit/package_manager/egg.rb +64 -0
  47. data/lib/automateit/package_manager/gem.rb +179 -0
  48. data/lib/automateit/package_manager/portage.rb +69 -0
  49. data/lib/automateit/package_manager/yum.rb +65 -0
  50. data/lib/automateit/platform_manager.rb +47 -0
  51. data/lib/automateit/platform_manager/darwin.rb +30 -0
  52. data/lib/automateit/platform_manager/debian.rb +26 -0
  53. data/lib/automateit/platform_manager/freebsd.rb +25 -0
  54. data/lib/automateit/platform_manager/gentoo.rb +26 -0
  55. data/lib/automateit/platform_manager/lsb.rb +40 -0
  56. data/lib/automateit/platform_manager/struct.rb +78 -0
  57. data/lib/automateit/platform_manager/uname.rb +29 -0
  58. data/lib/automateit/platform_manager/windows.rb +33 -0
  59. data/lib/automateit/plugin.rb +7 -0
  60. data/lib/automateit/plugin/base.rb +32 -0
  61. data/lib/automateit/plugin/driver.rb +218 -0
  62. data/lib/automateit/plugin/manager.rb +232 -0
  63. data/lib/automateit/project.rb +460 -0
  64. data/lib/automateit/root.rb +14 -0
  65. data/lib/automateit/service_manager.rb +79 -0
  66. data/lib/automateit/service_manager/chkconfig.rb +39 -0
  67. data/lib/automateit/service_manager/rc_update.rb +37 -0
  68. data/lib/automateit/service_manager/sysv.rb +126 -0
  69. data/lib/automateit/service_manager/update_rcd.rb +35 -0
  70. data/lib/automateit/shell_manager.rb +261 -0
  71. data/lib/automateit/shell_manager/base_link.rb +67 -0
  72. data/lib/automateit/shell_manager/link.rb +24 -0
  73. data/lib/automateit/shell_manager/portable.rb +421 -0
  74. data/lib/automateit/shell_manager/symlink.rb +32 -0
  75. data/lib/automateit/shell_manager/which.rb +25 -0
  76. data/lib/automateit/tag_manager.rb +63 -0
  77. data/lib/automateit/tag_manager/struct.rb +101 -0
  78. data/lib/automateit/tag_manager/tag_parser.rb +91 -0
  79. data/lib/automateit/tag_manager/yaml.rb +29 -0
  80. data/lib/automateit/template_manager.rb +55 -0
  81. data/lib/automateit/template_manager/base.rb +172 -0
  82. data/lib/automateit/template_manager/erb.rb +17 -0
  83. data/lib/ext/metaclass.rb +17 -0
  84. data/lib/ext/object.rb +18 -0
  85. data/lib/hashcache.rb +22 -0
  86. data/lib/helpful_erb.rb +63 -0
  87. data/lib/nested_error.rb +33 -0
  88. data/lib/queued_logger.rb +68 -0
  89. data/lib/tempster.rb +239 -0
  90. data/misc/index_gem_repository.rb +303 -0
  91. data/misc/setup_egg.rb +12 -0
  92. data/misc/setup_gem_dependencies.sh +7 -0
  93. data/misc/setup_rubygems.sh +21 -0
  94. data/misc/which.cmd +6 -0
  95. data/spec/extras/automateit_service_sysv_test +50 -0
  96. data/spec/extras/scratch.rb +15 -0
  97. data/spec/extras/simple_recipe.rb +8 -0
  98. data/spec/integration/account_manager_spec.rb +218 -0
  99. data/spec/integration/address_manager_linux_spec.rb +119 -0
  100. data/spec/integration/address_manager_portable_spec.rb +30 -0
  101. data/spec/integration/cli_spec.rb +215 -0
  102. data/spec/integration/examples_spec.rb +54 -0
  103. data/spec/integration/examples_spec_editor.rb +71 -0
  104. data/spec/integration/package_manager_spec.rb +104 -0
  105. data/spec/integration/platform_manager_spec.rb +69 -0
  106. data/spec/integration/service_manager_sysv_spec.rb +115 -0
  107. data/spec/integration/shell_manager_spec.rb +471 -0
  108. data/spec/integration/template_manager_erb_spec.rb +31 -0
  109. data/spec/spec_helper.rb +23 -0
  110. data/spec/unit/edit_manager_spec.rb +162 -0
  111. data/spec/unit/field_manager_spec.rb +79 -0
  112. data/spec/unit/hashcache_spec.rb +28 -0
  113. data/spec/unit/interpreter_spec.rb +98 -0
  114. data/spec/unit/platform_manager_spec.rb +44 -0
  115. data/spec/unit/plugins_spec.rb +253 -0
  116. data/spec/unit/tag_manager_spec.rb +189 -0
  117. data/spec/unit/template_manager_erb_spec.rb +137 -0
  118. metadata +249 -0
  119. metadata.gz.sig +0 -0
@@ -0,0 +1,66 @@
1
+ # == Dependencies
2
+
3
+ # Standard libraries
4
+ require 'etc'
5
+ require 'fileutils'
6
+ require 'find'
7
+ require 'logger'
8
+ require 'open3'
9
+ require 'pp'
10
+ require 'pathname'
11
+ require 'resolv'
12
+ require 'set'
13
+ require 'socket'
14
+ require 'yaml'
15
+
16
+ # Gems
17
+ require 'rubygems'
18
+ require 'open4'
19
+ require 'erb'
20
+
21
+ # Load ActiveSupport pieces individually to save ~0.5s
22
+ ### require 'active_support'
23
+ require 'active_support/core_ext/blank' # foo.blank?
24
+ require 'active_support/core_ext/class/attribute_accessors' # cattr_accessor
25
+ require 'active_support/core_ext/class/inheritable_attributes' # inheritable_cattr_accessor
26
+ require 'active_support/core_ext/module/aliasing' # alias_method_chain
27
+ require 'active_support/core_ext/string' # "asdf".demodulize.underscore
28
+ require 'active_support/clean_logger' # cleans up Logger output
29
+ require 'active_support/core_ext/symbol' # [:foo, :bar].map(&:to_s)
30
+
31
+ # Handle ActiveSupport includes
32
+ require 'active_support/core_ext/hash/keys' # {:foo => :bar}.stringify_keys
33
+ Hash.module_eval{include ActiveSupport::CoreExtensions::Hash::Keys}
34
+
35
+ # Extensions
36
+ require 'ext/object.rb'
37
+ require 'ext/metaclass.rb'
38
+
39
+ # Helpers
40
+ require 'hashcache'
41
+ require 'queued_logger'
42
+ require 'tempster'
43
+ require 'helpful_erb'
44
+ require 'nested_error'
45
+
46
+ # Core
47
+ require 'automateit/root'
48
+ require 'automateit/constants'
49
+ require 'automateit/error'
50
+ require 'automateit/common'
51
+ require 'automateit/interpreter'
52
+ require 'automateit/plugin'
53
+ require 'automateit/cli'
54
+ require 'automateit/project'
55
+
56
+ # Plugins which must be loaded early
57
+ require 'automateit/shell_manager'
58
+ require 'automateit/platform_manager' # requires shell
59
+ require 'automateit/address_manager' # requires shell
60
+ require 'automateit/tag_manager' # requires address, platform
61
+ require 'automateit/field_manager' # requires shell
62
+ require 'automateit/service_manager' # requires shell
63
+ require 'automateit/package_manager' # requires shell
64
+ require 'automateit/template_manager'
65
+ require 'automateit/edit_manager'
66
+ require 'automateit/account_manager'
@@ -0,0 +1,106 @@
1
+ # == AccountManager
2
+ #
3
+ # The AccountManager provides a way of managing system accounts, such as Unix
4
+ # users and groups.
5
+ class AutomateIt::AccountManager < AutomateIt::Plugin::Manager
6
+ # Find a user account. Method returns a query helper which takes a
7
+ # +username+ as an index argument and returns a Struct::Passwd entry as
8
+ # described in Etc::getpwent if the user exists or a nil if not.
9
+ #
10
+ # Example:
11
+ # users["root"] # => #<struct Struct::Passwd name="root"...
12
+ #
13
+ # users["does_not_exist"] # => nil
14
+ def users() dispatch() end
15
+
16
+ # Add the +username+ if not already created.
17
+ #
18
+ # Options:
19
+ # * :description -- User's full name. Defaults to username.
20
+ # * :home -- Path to user's home directory. If not specified, uses system
21
+ # default like "/home/username".
22
+ # * :create_home -- Create homedir. Defaults to true.
23
+ # * :groups -- Array of group names to add this user to.
24
+ # * :shell -- Path to login shell. If not specified, uses system default
25
+ # like "/bin/bash".
26
+ # * :uid -- Fixnum user ID for user. Default chooses an unused id.
27
+ # * :gid -- Fixnum group ID for user. Default chooses same gid as uid.
28
+ #
29
+ # Example:
30
+ # add_user("bob", :description => "Bob Smith")
31
+ def add_user(username, opts={}) dispatch(username, opts) end
32
+
33
+ # TODO AccountManager#update_user -- implement
34
+ ### def update_user(username, opts={}) dispatch(username, opts) end
35
+
36
+ # Remove the +username+ if present.
37
+ #
38
+ # Options:
39
+ # * :remove_home -- Delete user's home directory and mail spool. Default is
40
+ # true.
41
+ def remove_user(username, opts={}) dispatch(username, opts) end
42
+
43
+ # Is +user+ present?
44
+ def has_user?(user) dispatch(user) end
45
+
46
+ # Add +groups+ (array of groupnames) to +user+.
47
+ def add_groups_to_user(groups, user) dispatch(groups, user) end
48
+
49
+ # Remove +groups+ (array of groupnames) from +user+.
50
+ def remove_groups_from_user(groups, user) dispatch(groups, user) end
51
+
52
+ # Change the +password+ for the +user+.
53
+ def passwd(user, password) dispatch(user, password) end
54
+
55
+ #.......................................................................
56
+
57
+ # Find a group. Method returns a query helper which takes a
58
+ # +groupname+ as an index argument and returns a Struct::Group entry as
59
+ # described in Etc::getgrent if the group exists or a nil if not.
60
+ #
61
+ # Example:
62
+ # groups["root"] # => #<struct Struct::Group name="root"...
63
+ #
64
+ # groups["does_not_exist"] # => nil
65
+ def groups() dispatch() end
66
+
67
+ # Add +groupname+ if it doesn't exist. Options:
68
+ # * :members -- Array of usernames to add as members.
69
+ # * :gid -- Group ID to use. Default is to find an unused id.
70
+ def add_group(groupname, opts={}) dispatch(groupname, opts) end
71
+
72
+ # TODO AccountManager#update_group -- implement
73
+ ### def update_group(groupname, opts={}) dispatch(groupname, opts) end
74
+
75
+ # Remove +groupname+ if it exists.
76
+ def remove_group(groupname, opts={}) dispatch(groupname, opts) end
77
+
78
+ # Does +group+ exist?
79
+ def has_group?(group) dispatch(group) end
80
+
81
+ # Add +users+ (array of usernames) to +group+.
82
+ def add_users_to_group(users, group) dispatch(users, group) end
83
+
84
+ # Remove +users+ (array of usernames) from +group+.
85
+ def remove_users_from_group(users, group) dispatch(users, group) end
86
+
87
+ # Array of groupnames this user is a member of.
88
+ def groups_for_user(query) dispatch(query) end
89
+
90
+ # Array of usernames in group.
91
+ def users_for_group(query) dispatch(query) end
92
+
93
+ # Hash of usernames and the groupnames they're members of.
94
+ def users_to_groups() dispatch() end
95
+ end # class AccountManager
96
+
97
+ # == AccountManager::BaseDriver
98
+ #
99
+ # Base class for all AccountManager drivers.
100
+ class ::AutomateIt::AccountManager::BaseDriver < AutomateIt::Plugin::Driver
101
+ end
102
+
103
+ # Drivers
104
+ require 'automateit/account_manager/portable'
105
+ require 'automateit/account_manager/linux'
106
+ require 'automateit/account_manager/passwd'
@@ -0,0 +1,171 @@
1
+ # == AccountManager::Linux
2
+ #
3
+ # A Linux-specific driver for the AccountManager.
4
+ class ::AutomateIt::AccountManager::Linux < ::AutomateIt::AccountManager::Portable
5
+ depends_on \
6
+ :programs => %w(useradd usermod userdel groupadd groupmod groupdel),
7
+ :callbacks => [lambda{AutomateIt::AccountManager::Portable.has_etc?}]
8
+
9
+ def suitability(method, *args) # :nodoc:
10
+ # Level must be higher than Portable
11
+ return available? ? 2 : 0
12
+ end
13
+
14
+ def setup(*args) # :nodoc:
15
+ super(*args)
16
+ end
17
+
18
+ # Is "nscd" available on this platform?
19
+ def nscd?
20
+ @nscd ||= interpreter.which("nscd")
21
+ end
22
+
23
+ #.......................................................................
24
+
25
+ # See AccountManager#add_user
26
+ def add_user(username, opts={})
27
+ return false if has_user?(username)
28
+ cmd = "useradd"
29
+ cmd << " --comment #{opts[:description] || username}"
30
+ cmd << " --home #{opts[:home]}" if opts[:home]
31
+ cmd << " --create-home" unless opts[:create_home] == false
32
+ cmd << " --groups #{opts[:groups].join(' ')}" if opts[:groups]
33
+ cmd << " --shell #{opts[:shell] || "/bin/bash"}"
34
+ cmd << " --uid #{opts[:uid]}" if opts[:uid]
35
+ cmd << " --gid #{opts[:gid]}" if opts[:gid]
36
+ cmd << " #{username} < /dev/null"
37
+ cmd << " > /dev/null" if opts[:quiet]
38
+ interpreter.sh(cmd)
39
+ interpreter.sh("nscd --invalidate passwd") if nscd?
40
+
41
+ unless opts[:group] == false
42
+ groupname = opts[:group] || username
43
+ unless has_group?(groupname)
44
+ opts = {:members => [username]}
45
+ # In preview mode, user doesn't exist and has no UID
46
+ opts[:gid] = users[username].uid if writing?
47
+ add_group(groupname, opts)
48
+ end
49
+ end
50
+
51
+ interpreter.account_manager.passwd(username, opts[:passwd]) if opts[:passwd]
52
+
53
+ return users[username]
54
+ end
55
+
56
+ # TODO AccountManager#update_user -- implement
57
+ ### def update_user(username, opts={}) dispatch(username, opts) end
58
+
59
+ # See AccountManager#remove_user
60
+ def remove_user(username, opts={})
61
+ return false unless has_user?(username)
62
+ # Options: -r -- remove the home directory and mail spool
63
+ cmd = "userdel"
64
+ cmd << " -r" unless opts[:remove_home] == false
65
+ cmd << " #{username}"
66
+ cmd << " > /dev/null" if opts[:quiet]
67
+ interpreter.sh(cmd)
68
+ interpreter.sh("nscd --invalidate passwd") if nscd?
69
+ remove_group(username) if has_group?(username)
70
+ return true
71
+ end
72
+
73
+ # See AccountManager#add_groups_to_user
74
+ def add_groups_to_user(groups, username)
75
+ groups = [groups].flatten
76
+ present = groups_for_user(username)
77
+ missing = groups - present
78
+ return false if missing.empty?
79
+
80
+ cmd = "usermod -a -G #{missing.join(',')} #{username}"
81
+ interpreter.sh(cmd)
82
+ interpreter.sh("nscd --invalidate group") if nscd?
83
+ return missing
84
+ end
85
+
86
+ # See AccountManager#remove_groups_from_user
87
+ def remove_groups_from_user(groups, username)
88
+ groups = [groups].flatten
89
+ present = groups_for_user(username)
90
+ removeable = groups & present
91
+ return false if removeable.empty?
92
+
93
+ cmd = "usermod -G #{(present-groups).join(',')} #{username}"
94
+ interpreter.sh(cmd)
95
+ interpreter.sh("nscd --invalidate group") if nscd?
96
+ return removeable
97
+ end
98
+
99
+ #.......................................................................
100
+
101
+ # See AccountManager#add_group
102
+ def add_group(groupname, opts={})
103
+ return false if has_group?(groupname)
104
+ cmd = "groupadd"
105
+ cmd << " -g #{opts[:gid]}" if opts[:gid]
106
+ cmd << " #{groupname}"
107
+ interpreter.sh(cmd)
108
+ interpreter.sh("nscd --invalidate group") if nscd?
109
+ add_users_to_group(opts[:members], groupname) if opts[:members]
110
+ return groups[groupname]
111
+ end
112
+
113
+ # TODO AccountManager#update_group -- implement
114
+ ### def update_group(groupname, opts={}) dispatch(groupname, opts) end
115
+
116
+ # See AccountManager#remove_group
117
+ def remove_group(groupname, opts={})
118
+ return false unless has_group?(groupname)
119
+ cmd = "groupdel #{groupname}"
120
+ interpreter.sh(cmd)
121
+ interpreter.sh("nscd --invalidate group") if nscd?
122
+ return true
123
+ end
124
+
125
+ # See AccountManager#add_users_to_group
126
+ def add_users_to_group(users, groupname)
127
+ users = [users].flatten
128
+ # XXX Include pwent.gid?
129
+ grent = groups[groupname]
130
+ missing = \
131
+ if writing? and not grent
132
+ raise ArgumentError.new("no such group: #{groupname}")
133
+ elsif writing? or grent
134
+ users - grent.mem
135
+ else
136
+ users
137
+ end
138
+ return false if missing.empty?
139
+
140
+ for username in missing
141
+ cmd = "usermod -a -G #{groupname} #{username}"
142
+ interpreter.sh(cmd)
143
+ end
144
+ interpreter.sh("nscd --invalidate group") if nscd?
145
+ return missing
146
+ end
147
+
148
+ # See AccountManager#remove_users_from_group
149
+ def remove_users_from_group(users, groupname)
150
+ users = [users].flatten
151
+ grent = groups[groupname]
152
+ present = \
153
+ if writing? and not grent
154
+ raise ArgumentError.new("no such group: #{groupname}")
155
+ elsif writing? or grent
156
+ grent.mem & users
157
+ else
158
+ users
159
+ end
160
+ return false if present.empty?
161
+
162
+ u2g = users_to_groups
163
+ for username in present
164
+ user_groups = u2g[username]
165
+ cmd = "usermod -G #{(user_groups.to_a-[groupname]).join(',')} #{username}"
166
+ interpreter.sh(cmd)
167
+ end
168
+ interpreter.sh("nscd --invalidate group") if nscd?
169
+ return present
170
+ end
171
+ end
@@ -0,0 +1,69 @@
1
+ # == AccountManager::Passwd
2
+ #
3
+ # An AccountManager driver for the +passwd+ command found on Unix-like systems.
4
+ class ::AutomateIt::AccountManager::Passwd < ::AutomateIt::AccountManager::BaseDriver
5
+ depends_on \
6
+ :programs => %w(passwd),
7
+ :libraries => %w(open3 expect pty)
8
+
9
+ def suitability(method, *args) # :nodoc:
10
+ # Level must be higher than Linux
11
+ return available? ? 3 : 0
12
+ end
13
+
14
+ # See AccountManager#passwd
15
+ def passwd(user, password, opts={})
16
+ users = interpreter.account_manager.users
17
+
18
+ unless users[user]
19
+ if preview?
20
+ log.info(PNOTE+"Setting password for user: #{user}")
21
+ return true
22
+ else
23
+ raise ArgumentError.new("No such user: #{user}")
24
+ end
25
+ end
26
+
27
+ case user
28
+ when Symbol: user = user.to_s
29
+ when Integer: user = users[user]
30
+ when String: # leave it alone
31
+ else raise TypeError.new("Unknown user type: #{user.class}")
32
+ end
33
+
34
+ tries = 5
35
+ exitstatus = nil
36
+ begin
37
+ exitstruct = _passwd_raw(user, password, opts)
38
+ if exitstatus and not exitstruct.exitstatus.zero?
39
+ # 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.
40
+ raise Errno::EPIPE.new("bad exitstatus %s" % exitstruct.exitstatus)
41
+ end
42
+ rescue Errno::EPIPE => e
43
+ # 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?
44
+ if tries <= 0
45
+ raise e
46
+ else
47
+ tries -= 1
48
+ retry
49
+ end
50
+ end
51
+
52
+ return exitstruct.exitstatus.zero?
53
+ end
54
+
55
+ def _passwd_raw(user, password, opts={})
56
+ quiet = (opts[:quiet] or not log.info?)
57
+
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,136 @@
1
+ # == AccountManager::Portable
2
+ #
3
+ # A pure-Ruby, portable driver for the AccountManager. It is only suitable
4
+ # for doing queries and lacks methods such as +add_user+. Platform-specific
5
+ # drivers inherit from this class and provide these methods.
6
+ class ::AutomateIt::AccountManager::Portable < ::AutomateIt::AccountManager::BaseDriver
7
+ depends_on :callbacks => [lambda{AutomateIt::AccountManager::Portable.has_etc?}]
8
+
9
+ def suitability(method, *args) # :nodoc:
10
+ return 1
11
+ end
12
+
13
+ # Does this platform provide a way of querying users and groups through
14
+ # the 'etc' module?
15
+ def self.has_etc?
16
+ begin
17
+ require 'etc'
18
+ return defined?(Etc)
19
+ rescue LoadError
20
+ return false
21
+ end
22
+ end
23
+
24
+ # Alias for AccountManager::Portable.has_etc?
25
+ def has_etc?
26
+ self.has_etc?
27
+ end
28
+
29
+ #.......................................................................
30
+
31
+ # == UserQuery
32
+ #
33
+ # A class used for querying users. See AccountManager#users.
34
+ class UserQuery
35
+ # See AccountManager#users
36
+ def [](query)
37
+ Etc.endpwent
38
+ begin
39
+ case query
40
+ when String
41
+ return Etc.getpwnam(query)
42
+ when Fixnum
43
+ return Etc.getpwuid(query)
44
+ else
45
+ raise TypeError.new("unknonwn type for query: #{query.class}")
46
+ end
47
+ rescue ArgumentError
48
+ return nil
49
+ end
50
+ end
51
+ end
52
+
53
+ # See AccountManager#users
54
+ def users
55
+ return UserQuery.new
56
+ end
57
+
58
+ # See AccountManager#has_user?
59
+ def has_user?(query)
60
+ return ! users[query].nil?
61
+ end
62
+
63
+ #.......................................................................
64
+
65
+ # == GroupQuery
66
+ #
67
+ # A class used for querying groups. See AccountManager#groups.
68
+ class GroupQuery
69
+ # See AccountManager#groups
70
+ def [](query)
71
+ Etc.endgrent
72
+ begin
73
+ case query
74
+ when String
75
+ return Etc.getgrnam(query)
76
+ when Fixnum
77
+ return Etc.getgrgid(query)
78
+ else
79
+ raise TypeError.new("unknonwn type for query: #{query.class}")
80
+ end
81
+ rescue ArgumentError
82
+ return nil
83
+ end
84
+ end
85
+ end
86
+
87
+ # See AccountManager#groups
88
+ def groups
89
+ return GroupQuery.new
90
+ end
91
+
92
+ # See AccountManager#has_group?
93
+ def has_group?(query)
94
+ return ! groups[query].nil?
95
+ end
96
+
97
+ # See AccountManager#groups_for_user
98
+ def groups_for_user(query)
99
+ pwent = users[query]
100
+ return [] if preview? and not pwent
101
+ username = pwent.name
102
+ result = Set.new
103
+ result << groups[pwent.gid].name if groups[pwent.gid]
104
+ Etc.group do |grent|
105
+ result << grent.name if grent.mem.include?(username)
106
+ end
107
+ return result.to_a
108
+ end
109
+
110
+ # See AccountManager#users_for_group
111
+ def users_for_group(query)
112
+ grent = groups[query]
113
+ return (preview? || ! grent) ? [] : grent.mem
114
+ end
115
+
116
+ # See AccountManager#users_to_groups
117
+ def users_to_groups
118
+ result = {}
119
+ Etc.group do |grent|
120
+ grent.mem.each do |username|
121
+ result[username] ||= Set.new
122
+ result[username] << grent.name
123
+ end
124
+ end
125
+ Etc.passwd do |pwent|
126
+ grent = groups[pwent.gid]
127
+ unless grent
128
+ log.fatal(PNOTE+"WARNING: User's default group doesn't exist: user %s, gid %s" % [pwent.name, pwent.gid])
129
+ next
130
+ end
131
+ result[pwent.name] ||= Set.new
132
+ result[pwent.name] << grent.name
133
+ end
134
+ return result
135
+ end
136
+ end