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.
- data.tar.gz.sig +1 -0
- data/CHANGES.txt +100 -0
- data/Hoe.rake +35 -0
- data/Manifest.txt +111 -0
- data/README.txt +44 -0
- data/Rakefile +284 -0
- data/TESTING.txt +57 -0
- data/TODO.txt +26 -0
- data/TUTORIAL.txt +390 -0
- data/bin/ai +3 -0
- data/bin/aifield +82 -0
- data/bin/aitag +128 -0
- data/bin/automateit +117 -0
- data/docs/friendly_errors.txt +50 -0
- data/docs/previews.txt +86 -0
- data/env.sh +4 -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 +13 -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 +53 -0
- data/examples/basic/recipes/uninstall.rb +6 -0
- data/gpl.txt +674 -0
- data/lib/automateit.rb +66 -0
- data/lib/automateit/account_manager.rb +106 -0
- data/lib/automateit/account_manager/linux.rb +171 -0
- data/lib/automateit/account_manager/passwd.rb +69 -0
- data/lib/automateit/account_manager/portable.rb +136 -0
- data/lib/automateit/address_manager.rb +165 -0
- data/lib/automateit/address_manager/linux.rb +80 -0
- data/lib/automateit/address_manager/portable.rb +37 -0
- data/lib/automateit/cli.rb +80 -0
- data/lib/automateit/common.rb +65 -0
- data/lib/automateit/constants.rb +33 -0
- data/lib/automateit/edit_manager.rb +292 -0
- data/lib/automateit/error.rb +10 -0
- data/lib/automateit/field_manager.rb +103 -0
- data/lib/automateit/interpreter.rb +641 -0
- data/lib/automateit/package_manager.rb +242 -0
- data/lib/automateit/package_manager/apt.rb +63 -0
- data/lib/automateit/package_manager/egg.rb +64 -0
- data/lib/automateit/package_manager/gem.rb +179 -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 +47 -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 +25 -0
- data/lib/automateit/platform_manager/gentoo.rb +26 -0
- data/lib/automateit/platform_manager/lsb.rb +40 -0
- data/lib/automateit/platform_manager/struct.rb +78 -0
- data/lib/automateit/platform_manager/uname.rb +29 -0
- data/lib/automateit/platform_manager/windows.rb +33 -0
- data/lib/automateit/plugin.rb +7 -0
- data/lib/automateit/plugin/base.rb +32 -0
- data/lib/automateit/plugin/driver.rb +218 -0
- data/lib/automateit/plugin/manager.rb +232 -0
- data/lib/automateit/project.rb +460 -0
- data/lib/automateit/root.rb +14 -0
- data/lib/automateit/service_manager.rb +79 -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 +126 -0
- data/lib/automateit/service_manager/update_rcd.rb +35 -0
- data/lib/automateit/shell_manager.rb +261 -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 +421 -0
- data/lib/automateit/shell_manager/symlink.rb +32 -0
- data/lib/automateit/shell_manager/which.rb +25 -0
- data/lib/automateit/tag_manager.rb +63 -0
- data/lib/automateit/tag_manager/struct.rb +101 -0
- data/lib/automateit/tag_manager/tag_parser.rb +91 -0
- data/lib/automateit/tag_manager/yaml.rb +29 -0
- data/lib/automateit/template_manager.rb +55 -0
- data/lib/automateit/template_manager/base.rb +172 -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/hashcache.rb +22 -0
- data/lib/helpful_erb.rb +63 -0
- data/lib/nested_error.rb +33 -0
- data/lib/queued_logger.rb +68 -0
- data/lib/tempster.rb +239 -0
- data/misc/index_gem_repository.rb +303 -0
- data/misc/setup_egg.rb +12 -0
- data/misc/setup_gem_dependencies.sh +7 -0
- data/misc/setup_rubygems.sh +21 -0
- data/misc/which.cmd +6 -0
- data/spec/extras/automateit_service_sysv_test +50 -0
- data/spec/extras/scratch.rb +15 -0
- data/spec/extras/simple_recipe.rb +8 -0
- data/spec/integration/account_manager_spec.rb +218 -0
- data/spec/integration/address_manager_linux_spec.rb +119 -0
- data/spec/integration/address_manager_portable_spec.rb +30 -0
- data/spec/integration/cli_spec.rb +215 -0
- data/spec/integration/examples_spec.rb +54 -0
- data/spec/integration/examples_spec_editor.rb +71 -0
- data/spec/integration/package_manager_spec.rb +104 -0
- data/spec/integration/platform_manager_spec.rb +69 -0
- data/spec/integration/service_manager_sysv_spec.rb +115 -0
- data/spec/integration/shell_manager_spec.rb +471 -0
- data/spec/integration/template_manager_erb_spec.rb +31 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/unit/edit_manager_spec.rb +162 -0
- data/spec/unit/field_manager_spec.rb +79 -0
- data/spec/unit/hashcache_spec.rb +28 -0
- data/spec/unit/interpreter_spec.rb +98 -0
- data/spec/unit/platform_manager_spec.rb +44 -0
- data/spec/unit/plugins_spec.rb +253 -0
- data/spec/unit/tag_manager_spec.rb +189 -0
- data/spec/unit/template_manager_erb_spec.rb +137 -0
- metadata +249 -0
- metadata.gz.sig +0 -0
data/lib/automateit.rb
ADDED
|
@@ -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
|