syncwrap 1.5.2 → 2.0.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/History.rdoc +19 -0
- data/Manifest.txt +82 -34
- data/README.rdoc +96 -48
- data/Rakefile +0 -65
- data/bin/syncwrap +27 -0
- data/examples/LAYOUT.rdoc +70 -0
- data/examples/Rakefile +16 -0
- data/examples/ec2.rb +44 -0
- data/examples/hello.rb +14 -0
- data/examples/hello_binding.rb +27 -0
- data/examples/jruby.rb +11 -0
- data/examples/private/aws.json +4 -0
- data/examples/rput.rb +24 -0
- data/examples/sync/home/bob/.ssh/authorized_keys +1 -0
- data/examples/sync/tmp/sample.erb +3 -0
- data/lib/syncwrap/amazon_ec2.rb +236 -0
- data/lib/syncwrap/amazon_ws.rb +308 -0
- data/lib/syncwrap/base.rb +4 -2
- data/lib/syncwrap/cli.rb +328 -0
- data/lib/syncwrap/component.rb +443 -0
- data/lib/syncwrap/components/commercial_jdk.rb +76 -0
- data/lib/syncwrap/components/cruby_vm.rb +144 -0
- data/lib/syncwrap/components/etc_hosts.rb +44 -0
- data/lib/syncwrap/{geminabox.rb → components/geminabox.rb} +12 -17
- data/lib/syncwrap/components/hashdot.rb +97 -0
- data/lib/syncwrap/components/iyyov.rb +144 -0
- data/lib/syncwrap/components/iyyov_daemon.rb +125 -0
- data/lib/syncwrap/components/jruby_vm.rb +122 -0
- data/lib/syncwrap/components/mdraid.rb +204 -0
- data/lib/syncwrap/components/network.rb +99 -0
- data/lib/syncwrap/components/open_jdk.rb +70 -0
- data/lib/syncwrap/components/postgresql.rb +159 -0
- data/lib/syncwrap/components/qpid.rb +303 -0
- data/lib/syncwrap/components/rhel.rb +71 -0
- data/lib/syncwrap/components/run_user.rb +99 -0
- data/lib/syncwrap/components/ubuntu.rb +85 -0
- data/lib/syncwrap/components/users.rb +200 -0
- data/lib/syncwrap/context.rb +260 -0
- data/lib/syncwrap/distro.rb +53 -60
- data/lib/syncwrap/formatter.rb +149 -0
- data/lib/syncwrap/host.rb +134 -0
- data/lib/syncwrap/main.rb +62 -0
- data/lib/syncwrap/path_util.rb +55 -0
- data/lib/syncwrap/rsync.rb +227 -0
- data/lib/syncwrap/ruby_support.rb +110 -0
- data/lib/syncwrap/shell.rb +207 -0
- data/lib/syncwrap.rb +367 -1
- data/{etc → sync/etc}/gemrc +1 -3
- data/sync/etc/hosts.erb +8 -0
- data/{etc/init.d/iyyov → sync/etc/init.d/iyyov.erb} +35 -7
- data/sync/etc/sysconfig/pgsql/postgresql.erb +2 -0
- data/sync/src/hashdot/Makefile.erb +98 -0
- data/sync/src/hashdot/profiles/default.hdp.erb +25 -0
- data/sync/src/hashdot/profiles/jruby-common.hdp +28 -0
- data/sync/src/hashdot/profiles/jruby-shortlived.hdp +9 -0
- data/sync/src/hashdot/profiles/jruby.hdp.erb +13 -0
- data/sync/src/hashdot/profiles/shortlived.hdp +6 -0
- data/sync/var/iyyov/default/config.rb +1 -0
- data/sync/var/iyyov/default/daemon.rb.erb +15 -0
- data/sync/var/iyyov/jobs.rb.erb +4 -0
- data/test/muddled_sync.rb +13 -0
- data/test/setup.rb +39 -0
- data/test/sync/d1/bar +1 -0
- data/test/sync/d1/foo.erb +1 -0
- data/test/sync/d3/d2/bar +1 -0
- data/test/sync/d3/d2/foo.erb +1 -0
- data/test/test_components.rb +108 -0
- data/test/test_context.rb +107 -0
- data/test/test_context_rput.rb +289 -0
- data/test/test_rsync.rb +138 -0
- data/test/test_shell.rb +233 -0
- data/test/test_space.rb +218 -0
- data/test/test_space_main.rb +40 -0
- data/test/zfile +1 -0
- metadata +204 -71
- data/etc/sysconfig/pgsql/postgresql +0 -2
- data/lib/syncwrap/aws.rb +0 -448
- data/lib/syncwrap/common.rb +0 -161
- data/lib/syncwrap/ec2.rb +0 -59
- data/lib/syncwrap/hashdot.rb +0 -70
- data/lib/syncwrap/iyyov.rb +0 -139
- data/lib/syncwrap/java.rb +0 -61
- data/lib/syncwrap/jruby.rb +0 -118
- data/lib/syncwrap/postgresql.rb +0 -135
- data/lib/syncwrap/qpid.rb +0 -251
- data/lib/syncwrap/remote_task.rb +0 -199
- data/lib/syncwrap/rhel.rb +0 -67
- data/lib/syncwrap/ubuntu.rb +0 -78
- data/lib/syncwrap/user_run.rb +0 -102
- data/test/test_syncwrap.rb +0 -202
- data/var/iyyov/jobs.rb +0 -11
- /data/{etc → sync/etc}/corosync/corosync.conf +0 -0
- /data/{etc → sync/etc}/corosync/uidgid.d/qpid +0 -0
- /data/{etc → sync/etc}/init.d/qpidd +0 -0
- /data/{etc → sync/etc}/sysctl.d/61-postgresql-shm.conf +0 -0
- /data/{usr/local → sync/jruby}/bin/jgem +0 -0
- /data/{postgresql → sync/postgresql}/rhel/pg_hba.conf +0 -0
- /data/{postgresql → sync/postgresql}/rhel/pg_ident.conf +0 -0
- /data/{postgresql → sync/postgresql}/rhel/postgresql.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/environment +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/pg_ctl.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/pg_hba.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/pg_ident.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/postgresql.conf +0 -0
- /data/{postgresql → sync/postgresql}/ubuntu/start.conf +0 -0
- /data/{usr → sync/usr}/local/etc/qpidd.conf +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2011-2014 David Kellum
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
|
5
|
+
# may not use this file except in compliance with the License. You may
|
|
6
|
+
# obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
13
|
+
# implied. See the License for the specific language governing
|
|
14
|
+
# permissions and limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
require 'syncwrap/component'
|
|
18
|
+
require 'syncwrap/path_util'
|
|
19
|
+
|
|
20
|
+
module SyncWrap
|
|
21
|
+
|
|
22
|
+
# Provision developer user accounts, sudo access, and synchronize
|
|
23
|
+
# home directory files.
|
|
24
|
+
class Users < Component
|
|
25
|
+
include PathUtil
|
|
26
|
+
|
|
27
|
+
# The list of user names to install. If default nil, home_users
|
|
28
|
+
# will be determined by the set of home directories found in
|
|
29
|
+
# local_home_root - exclude_users.
|
|
30
|
+
attr_accessor :home_users
|
|
31
|
+
|
|
32
|
+
# Local home root directory, to be resolved against sync_paths.
|
|
33
|
+
# (Default: home)
|
|
34
|
+
attr_accessor :local_home_root
|
|
35
|
+
|
|
36
|
+
# Set of users to exclude from synchronization (default: [])
|
|
37
|
+
attr_accessor :exclude_users
|
|
38
|
+
|
|
39
|
+
# If set, override the :ssh_user for this Component install, since
|
|
40
|
+
# typically the 'normal' user (i.e your developer account) has not
|
|
41
|
+
# yet been created or given sudo access. (Default: nil)
|
|
42
|
+
attr_accessor :ssh_user
|
|
43
|
+
|
|
44
|
+
# A PEM file for the ssh_user. A relative path in interpreted as
|
|
45
|
+
# relative to the sync file from which this component is
|
|
46
|
+
# created. If the pem file is not found, a warning will be issued
|
|
47
|
+
# and ssh_user and ssh_user_pem will not be used.
|
|
48
|
+
# (Default: nil)
|
|
49
|
+
attr_accessor :ssh_user_pem
|
|
50
|
+
|
|
51
|
+
# Users should be the first component to attempt ssh access. On
|
|
52
|
+
# new host creation, install may be run before the ssh port is
|
|
53
|
+
# actually available (boot completed, etc.). This provides an
|
|
54
|
+
# additional timeout in seconds for establishing the first ssh
|
|
55
|
+
# session. (default: 180 seconds)
|
|
56
|
+
attr_accessor :ssh_access_timeout
|
|
57
|
+
|
|
58
|
+
# Use the StrictHostKeyChecking=no ssh option when connected to a
|
|
59
|
+
# newly created host (whose key will surely not be known yet.)
|
|
60
|
+
# (Default: true)
|
|
61
|
+
attr_accessor :lenient_host_key
|
|
62
|
+
|
|
63
|
+
def initialize( opts = {} )
|
|
64
|
+
@home_users = nil
|
|
65
|
+
@local_home_root = "home"
|
|
66
|
+
@exclude_users = []
|
|
67
|
+
@ssh_user = nil
|
|
68
|
+
@ssh_user_pem = nil
|
|
69
|
+
@ssh_access_timeout = 180.0
|
|
70
|
+
@lenient_host_key = true
|
|
71
|
+
super
|
|
72
|
+
|
|
73
|
+
if @ssh_user_pem
|
|
74
|
+
@ssh_user_pem =
|
|
75
|
+
relativize( path_relative_to_caller( @ssh_user_pem, caller ) )
|
|
76
|
+
unless File.exist?( @ssh_user_pem )
|
|
77
|
+
warn( "WARNING: Users pem #{@ssh_user_pem} not found. " +
|
|
78
|
+
"Will not use #{@ssh_user}.\n" +
|
|
79
|
+
"Components may fail without sudo access" )
|
|
80
|
+
@ssh_user = nil
|
|
81
|
+
@ssh_user_pem = nil
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def install
|
|
87
|
+
ensure_ssh_access if host[ :just_created ] && ssh_access_timeout > 0
|
|
88
|
+
|
|
89
|
+
rdir = find_source( local_home_root )
|
|
90
|
+
users = home_users
|
|
91
|
+
users ||= rdir && Dir.entries( rdir ).select do |d|
|
|
92
|
+
( d !~ /^\./ && File.directory?( File.join( rdir, d ) ) )
|
|
93
|
+
end
|
|
94
|
+
users ||= []
|
|
95
|
+
users -= exclude_users
|
|
96
|
+
|
|
97
|
+
users.each do |u|
|
|
98
|
+
create_user( u )
|
|
99
|
+
set_sudoers( u )
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
users.each do |u|
|
|
103
|
+
sync_home_files( u )
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
users.each do |u|
|
|
107
|
+
fix_home_permissions( u )
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
#FIXME: Add special case for 'root' user?
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def ensure_ssh_access
|
|
114
|
+
flags = ssh_flags
|
|
115
|
+
if lenient_host_key
|
|
116
|
+
flags[ :ssh_options ] ||= {}
|
|
117
|
+
flags[ :ssh_options ][ 'StrictHostKeyChecking' ] = 'no'
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
start = Time.now
|
|
121
|
+
loop do
|
|
122
|
+
accept = [0]
|
|
123
|
+
# Allow non-sucess until timeout
|
|
124
|
+
# 255: ssh (i.e. can't connect, sshd not yet up)
|
|
125
|
+
# 1: sudo error (user_data sudoers update has not yet completed)
|
|
126
|
+
accept += [1, 255] unless ( Time.now - start ) >= ssh_access_timeout
|
|
127
|
+
|
|
128
|
+
code,_ = capture( 'sudo true', flags.merge( accept: accept ) )
|
|
129
|
+
break if code == 0
|
|
130
|
+
sleep 1 # ssh timeouts also apply, but make sure we don't spin
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Create user if not already present
|
|
135
|
+
def create_user( user )
|
|
136
|
+
sudo <<-SH
|
|
137
|
+
if ! id #{user} >/dev/null 2>&1; then
|
|
138
|
+
useradd #{user}
|
|
139
|
+
fi
|
|
140
|
+
SH
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def sync_home_files( user )
|
|
144
|
+
rput( "#{local_home_root}/#{user}", user: user )
|
|
145
|
+
rescue SourceNotFound
|
|
146
|
+
false
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def fix_home_permissions( user )
|
|
150
|
+
sudo <<-SH
|
|
151
|
+
if [ -e '/home/#{user}/.ssh' ]; then
|
|
152
|
+
chmod 700 /home/#{user}/.ssh
|
|
153
|
+
chmod -R o-rwx /home/#{user}/.ssh
|
|
154
|
+
fi
|
|
155
|
+
SH
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def set_sudoers( user )
|
|
159
|
+
#FIXME: make this a template?
|
|
160
|
+
#FIXME: Use local_root for secure_path? (Order issue)
|
|
161
|
+
#Relax, less overrides needed for Ubuntu?
|
|
162
|
+
sudo <<-SH
|
|
163
|
+
echo '#{user} ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/#{user}
|
|
164
|
+
echo 'Defaults:#{user} !requiretty' >> /etc/sudoers.d/#{user}
|
|
165
|
+
echo 'Defaults:#{user} secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin' \
|
|
166
|
+
>> /etc/sudoers.d/#{user}
|
|
167
|
+
chmod 440 /etc/sudoers.d/#{user}
|
|
168
|
+
SH
|
|
169
|
+
|
|
170
|
+
#FIXME: Centos 6.5:
|
|
171
|
+
# secure_path is the same as above already
|
|
172
|
+
#FIXME: echo 'Defaults:#{user} always_set_home' >> /etc/sudoers.d/#{user}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
protected
|
|
176
|
+
|
|
177
|
+
def sh( command, opts = {}, &block )
|
|
178
|
+
super( command, ssh_flags.merge( opts ), &block )
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def rput( *args )
|
|
182
|
+
opts = args.last.is_a?( Hash ) ? ssh_flags.merge( args.pop ) : ssh_flags
|
|
183
|
+
super( *args, opts )
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def ssh_flags
|
|
187
|
+
flags = {}
|
|
188
|
+
if ssh_user
|
|
189
|
+
flags[ :ssh_user ] = ssh_user
|
|
190
|
+
if ssh_user_pem
|
|
191
|
+
flags[ :ssh_user_pem ] = ssh_user_pem
|
|
192
|
+
flags[ :ssh_options ] = { 'IdentitiesOnly' => 'yes' }
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
flags
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
end
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2011-2014 David Kellum
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
|
5
|
+
# may not use this file except in compliance with the License. You
|
|
6
|
+
# may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
13
|
+
# implied. See the License for the specific language governing
|
|
14
|
+
# permissions and limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
require 'syncwrap/shell'
|
|
18
|
+
require 'syncwrap/rsync'
|
|
19
|
+
|
|
20
|
+
module SyncWrap
|
|
21
|
+
|
|
22
|
+
# A single-thread execution context for a single Host.
|
|
23
|
+
#
|
|
24
|
+
# Context implements much of the interface and behavior defined by
|
|
25
|
+
# Component, via use of the Shell and Rsync module mixins.
|
|
26
|
+
class Context
|
|
27
|
+
include Shell
|
|
28
|
+
include Rsync
|
|
29
|
+
|
|
30
|
+
class << self
|
|
31
|
+
# Return the current (thread local) Context, or nil.
|
|
32
|
+
def current
|
|
33
|
+
Thread.current[:syncwrap_context]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Set the current Context to ctx and return any prior Context or
|
|
37
|
+
# nil.
|
|
38
|
+
def swap( ctx )
|
|
39
|
+
old = current
|
|
40
|
+
Thread.current[:syncwrap_context] = ctx
|
|
41
|
+
old
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The current Host of this context
|
|
46
|
+
attr_reader :host
|
|
47
|
+
|
|
48
|
+
# Construct given host and default_options to use for all #sh and
|
|
49
|
+
# #rput calls.
|
|
50
|
+
def initialize( host, opts = {} )
|
|
51
|
+
@host = host
|
|
52
|
+
reset_queue
|
|
53
|
+
@queue_locked = false
|
|
54
|
+
@default_options = opts
|
|
55
|
+
|
|
56
|
+
super()
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Set (thread local) current context to self, yield to block, then
|
|
60
|
+
# #flush and reset the context.
|
|
61
|
+
def with
|
|
62
|
+
prior = Context.swap( self )
|
|
63
|
+
yield
|
|
64
|
+
flush
|
|
65
|
+
ensure
|
|
66
|
+
Context.swap( prior )
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Return true if being executed, by constructed default options,
|
|
70
|
+
# in dryrun mode.
|
|
71
|
+
def dryrun?
|
|
72
|
+
@default_options[ :dryrun ]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Return true if :verbose is set in constructed default options.
|
|
76
|
+
def verbose?
|
|
77
|
+
@default_options[ :verbose ]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# See Component#sh for interface details
|
|
81
|
+
def sh( command, opts = {} )
|
|
82
|
+
opts = @default_options.merge( opts )
|
|
83
|
+
close = opts.delete( :close )
|
|
84
|
+
|
|
85
|
+
flush if opts != @queued_opts #may still be a no-op
|
|
86
|
+
|
|
87
|
+
@queued_cmd << command
|
|
88
|
+
@queued_opts = opts
|
|
89
|
+
|
|
90
|
+
if close
|
|
91
|
+
prev, @queue_locked = @queue_locked, true
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
begin
|
|
95
|
+
yield if block_given?
|
|
96
|
+
@queued_cmd << close if close
|
|
97
|
+
ensure
|
|
98
|
+
@queue_locked = prev if close
|
|
99
|
+
end
|
|
100
|
+
nil
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# See Component#flush for interface details
|
|
104
|
+
def flush
|
|
105
|
+
if @queued_cmd.length > 0
|
|
106
|
+
begin
|
|
107
|
+
if @queue_locked
|
|
108
|
+
raise NestingError, 'Queue at flush: ' + @queued_cmd.join( '\n' )
|
|
109
|
+
end
|
|
110
|
+
run_shell( @queued_cmd, @queued_opts )
|
|
111
|
+
ensure
|
|
112
|
+
reset_queue
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
nil
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# See Component#capture for interface details.
|
|
119
|
+
def capture( command, opts = {} )
|
|
120
|
+
opts = @default_options.merge( coalesce: false, dryrun: false ).merge( opts )
|
|
121
|
+
flush
|
|
122
|
+
capture_shell( command, opts )
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# See Component#rput for interface details.
|
|
126
|
+
def rput( *args )
|
|
127
|
+
opts = @default_options
|
|
128
|
+
opts = opts.merge( args.pop ) if args.last.is_a?( Hash )
|
|
129
|
+
opts = opts.merge( coalesce: false )
|
|
130
|
+
|
|
131
|
+
flush
|
|
132
|
+
|
|
133
|
+
srcs, target = expand_implied_target( args )
|
|
134
|
+
|
|
135
|
+
srcs = resolve_sources( srcs, Array( opts[ :sync_paths ] ) )
|
|
136
|
+
|
|
137
|
+
changes = []
|
|
138
|
+
|
|
139
|
+
if opts[:erb_process] != false
|
|
140
|
+
sdirs, sfiles = srcs.partition { |src| File.directory?( src ) }
|
|
141
|
+
serbs, sfiles = sfiles.partition { |src| src =~ /\.erb$/ }
|
|
142
|
+
plains = sdirs + sfiles #might not have/is not templates
|
|
143
|
+
maybes = sdirs + serbs #might have/is templates
|
|
144
|
+
|
|
145
|
+
if maybes.empty?
|
|
146
|
+
changes = rsync( plains, target, opts ) unless plains.empty?
|
|
147
|
+
else
|
|
148
|
+
process_templates( maybes, opts ) do |processed|
|
|
149
|
+
unless processed.empty? || plains.empty?
|
|
150
|
+
opts = opts.dup
|
|
151
|
+
opts[ :excludes ] = Array( opts[ :excludes ] ) + [ '*.erb' ]
|
|
152
|
+
end
|
|
153
|
+
new_srcs = plains + processed
|
|
154
|
+
changes = rsync( new_srcs, target, opts ) unless new_srcs.empty?
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
else
|
|
158
|
+
changes = rsync( srcs, target, opts ) unless srcs.empty?
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
changes
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Returns the path to the the specified src, first found in
|
|
165
|
+
# :sync_paths option. Returns nil if not found.
|
|
166
|
+
def find_source( src, opts = {} )
|
|
167
|
+
opts = @default_options.merge( opts )
|
|
168
|
+
resolve_source( src, Array( opts[ :sync_paths ] ) )
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
private
|
|
172
|
+
|
|
173
|
+
def ssh_host_name
|
|
174
|
+
host.space.ssh_host_name( host )
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def reset_queue
|
|
178
|
+
@queued_cmd = []
|
|
179
|
+
@queued_opts = {}
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def run_shell( command, opts = {} )
|
|
183
|
+
args = ssh_args( ssh_host_name, command, opts )
|
|
184
|
+
capture_stream( args, host, :sh, opts )
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def capture_shell( command, opts = {} )
|
|
188
|
+
args = ssh_args( ssh_host_name, command, opts )
|
|
189
|
+
exit_code, outputs = capture_stream( args, host, :capture, opts )
|
|
190
|
+
[ exit_code, collect_stream( opts[ :coalesce ] ? :err : :out, outputs ) ]
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def rsync( srcs, target, opts )
|
|
194
|
+
args = rsync_args( ssh_host_name, srcs, target, opts )
|
|
195
|
+
exit_code, outputs = capture_stream( args, host, :rsync, opts )
|
|
196
|
+
|
|
197
|
+
# Return array of --itemize-changes on standard out.
|
|
198
|
+
collect_stream( :out, outputs ).
|
|
199
|
+
split( "\n" ).
|
|
200
|
+
map { |l| l =~ /^(\S{11})\s(.+)$/ && [$1, $2] }. #itemize-changes
|
|
201
|
+
compact
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def capture_stream( args, host, mode, opts )
|
|
205
|
+
accept = opts[ :accept ] || [ 0 ]
|
|
206
|
+
success_msg = ( accept == [ 0 ] ) ? "success" : "accepted"
|
|
207
|
+
|
|
208
|
+
# When :verbose -> nil -> try_lock
|
|
209
|
+
stream_output = opts[ :verbose ] ? nil : false
|
|
210
|
+
fmt = host.space.formatter
|
|
211
|
+
do_color = !opts[ :coalesce ]
|
|
212
|
+
|
|
213
|
+
begin
|
|
214
|
+
exit_code, outputs = capture3( args ) do |stream, chunk|
|
|
215
|
+
if stream_output.nil?
|
|
216
|
+
if fmt.lock.try_lock
|
|
217
|
+
stream_output = true
|
|
218
|
+
fmt.write_header( host, mode, opts, :stream )
|
|
219
|
+
if mode == :rsync
|
|
220
|
+
cmd = args.join(' ') + "\n"
|
|
221
|
+
fmt.write_command_output( :cmd, cmd, do_color )
|
|
222
|
+
end
|
|
223
|
+
else
|
|
224
|
+
stream_output = false
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
if stream_output
|
|
229
|
+
fmt.write_command_output( stream, chunk, do_color )
|
|
230
|
+
fmt.flush
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
failed = !accept.include?( exit_code )
|
|
234
|
+
|
|
235
|
+
if stream_output
|
|
236
|
+
fmt.output_terminate
|
|
237
|
+
fmt.write_result( "Exit #{exit_code} (#{success_msg})" ) unless failed
|
|
238
|
+
end
|
|
239
|
+
ensure
|
|
240
|
+
fmt.lock.unlock if stream_output
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
if !stream_output && ( failed || opts[ :verbose ] )
|
|
244
|
+
fmt.sync do
|
|
245
|
+
fmt.write_header( host, mode, opts )
|
|
246
|
+
if mode == :rsync
|
|
247
|
+
fmt.write_command_output( :cmd, args.join(' ') + "\n", do_color )
|
|
248
|
+
end
|
|
249
|
+
fmt.write_command_outputs( outputs, do_color )
|
|
250
|
+
fmt.write_result( "Exit #{exit_code} (#{success_msg})" ) unless failed
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
raise CommandFailure, "#{args[0]} exit code: #{exit_code}" if failed
|
|
255
|
+
[ exit_code, outputs ]
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
end
|
data/lib/syncwrap/distro.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#--
|
|
2
|
-
# Copyright (c) 2011-
|
|
2
|
+
# Copyright (c) 2011-2014 David Kellum
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
|
5
5
|
# may not use this file except in compliance with the License. You may
|
|
@@ -16,77 +16,70 @@
|
|
|
16
16
|
|
|
17
17
|
require 'syncwrap/base'
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
module SyncWrap::Distro
|
|
19
|
+
module SyncWrap
|
|
21
20
|
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
attr_reader :packages_map
|
|
21
|
+
# Support module and inteface for (Linux) distribution components.
|
|
22
|
+
module Distro
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
# The root directory for local, non-distro managed installs
|
|
25
|
+
# (default: /usr/local)
|
|
26
|
+
attr_accessor :local_root
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
# A Hash of internal/common package names to distro specific package
|
|
29
|
+
# names.
|
|
30
|
+
attr_reader :packages_map
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
pkgs.flatten.compact.map { |pkg| packages_map[ pkg ] || pkg }
|
|
36
|
-
end
|
|
32
|
+
def initialize( *args )
|
|
33
|
+
@local_root = '/usr/local'
|
|
34
|
+
@packages_map = {}
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
# interpreted as options if it is a Hash.
|
|
41
|
-
# === Options
|
|
42
|
-
# :succeed:: Always succeed (useful for local rpms which might
|
|
43
|
-
# already be installed.
|
|
44
|
-
# :minimal:: Avoid additional "optional" packages when possible.
|
|
45
|
-
def dist_install( *args )
|
|
46
|
-
sudo( dist_install_s( *args ) )
|
|
47
|
-
end
|
|
36
|
+
super( *args )
|
|
37
|
+
end
|
|
48
38
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
raise "Include a distro-specific module, e.g. Ubuntu, RHEL"
|
|
54
|
-
end
|
|
39
|
+
# Return self, and in Context, the specific Distro component.
|
|
40
|
+
def distro
|
|
41
|
+
self
|
|
42
|
+
end
|
|
55
43
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
44
|
+
# Map internal/common names and return distro-specific names. If a
|
|
45
|
+
# mapping does not exist, return the original name.
|
|
46
|
+
def dist_map_packages( *pkgs )
|
|
47
|
+
pkgs.flatten.compact.map { |pkg| packages_map[ pkg ] || pkg }
|
|
48
|
+
end
|
|
61
49
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
# Install the specified packages using distro-specific mapped
|
|
51
|
+
# package names. A trailing hash is interpreted as options, see
|
|
52
|
+
# below.
|
|
53
|
+
#
|
|
54
|
+
# ==== Options
|
|
55
|
+
#
|
|
56
|
+
# :succeed:: Always succeed (useful for local rpms which might
|
|
57
|
+
# already be installed.
|
|
58
|
+
#
|
|
59
|
+
# :minimal:: Avoid additional "optional" packages when possible.
|
|
60
|
+
def dist_install( *pkgs )
|
|
61
|
+
raise "Include a distro-specific component, e.g. Ubuntu, RHEL"
|
|
62
|
+
end
|
|
67
63
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
# Uninstall specified packages using distro-specific mapped
|
|
65
|
+
# package names and command.
|
|
66
|
+
def dist_uninstall( *pkgs )
|
|
67
|
+
raise "Include a distro-specific component, e.g. Ubuntu, RHEL"
|
|
68
|
+
end
|
|
73
69
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
# Install a System V style init.d script (already placed at remote
|
|
71
|
+
# /etc/init.d/<name>) via distro-specific command
|
|
72
|
+
def dist_install_init_service( name )
|
|
73
|
+
raise "Include a distro-specific component, e.g. Ubuntu, RHEL"
|
|
74
|
+
end
|
|
79
75
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
# Run via sudo, the System V style, distro specific `service`
|
|
77
|
+
# command, typically supporting 'start', 'stop', 'restart',
|
|
78
|
+
# 'status', etc. arguments.
|
|
79
|
+
def dist_service( *args )
|
|
80
|
+
raise "Include a distro-specific component, e.g. Ubuntu, RHEL"
|
|
81
|
+
end
|
|
86
82
|
|
|
87
|
-
# Return the System V style, distro specific `service` command.
|
|
88
|
-
def dist_service_s( *args )
|
|
89
|
-
raise "Include a distro-specific module, e.g. Ubuntu, RHEL"
|
|
90
83
|
end
|
|
91
84
|
|
|
92
85
|
end
|