symphony 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/ChangeLog +71 -2
- data/History.rdoc +9 -0
- data/Manifest.txt +0 -4
- data/Rakefile +7 -29
- data/TODO.md +0 -1
- data/lib/symphony/daemon.rb +1 -1
- data/lib/symphony/mixins.rb +0 -146
- data/lib/symphony/queue.rb +17 -4
- data/lib/symphony/task.rb +14 -0
- data/lib/symphony.rb +2 -2
- data/spec/symphony/mixins_spec.rb +0 -51
- data/spec/symphony/queue_spec.rb +10 -5
- data.tar.gz.sig +0 -0
- metadata +2 -35
- metadata.gz.sig +1 -1
- data/.gemtest +0 -0
- data/lib/symphony/intervalexpression.rb +0 -1216
- data/lib/symphony/tasks/ssh.rb +0 -126
- data/lib/symphony/tasks/sshscript.rb +0 -168
- data/spec/symphony/intervalexpression_spec.rb +0 -481
data/lib/symphony/tasks/ssh.rb
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'shellwords'
|
4
|
-
require 'symphony/task' unless defined?( Symphony::Task )
|
5
|
-
|
6
|
-
|
7
|
-
### A base SSH class for connecting to remote hosts, running commands,
|
8
|
-
### and collecting output.
|
9
|
-
class Symphony::Task::SSH < Symphony::Task
|
10
|
-
extend MethodUtilities
|
11
|
-
|
12
|
-
### Create a new SSH task for the given +job+ and +queue+.
|
13
|
-
def initialize( queue, job )
|
14
|
-
super
|
15
|
-
|
16
|
-
# The default path to the ssh binary.
|
17
|
-
@path = self.options[:ssh_path] || '/usr/bin/ssh'
|
18
|
-
|
19
|
-
# Default ssh behavior arguments.
|
20
|
-
@ssh_args = self.options[:ssh_args] || [
|
21
|
-
'-e', 'none',
|
22
|
-
'-T',
|
23
|
-
'-x',
|
24
|
-
'-q',
|
25
|
-
'-o', 'CheckHostIP=no',
|
26
|
-
'-o', 'BatchMode=yes',
|
27
|
-
'-o', 'StrictHostKeyChecking=no'
|
28
|
-
]
|
29
|
-
|
30
|
-
# required arguments
|
31
|
-
@hostname = self.options[:hostname] or raise ArgumentError, "no hostname specified"
|
32
|
-
@command = self.options[:command] or raise ArgumentError, "no command specified"
|
33
|
-
|
34
|
-
# optional arguments
|
35
|
-
@port = self.options[:port] || 22
|
36
|
-
@user = self.options[:user] || 'root'
|
37
|
-
@key = self.options[:key]
|
38
|
-
|
39
|
-
@output = nil
|
40
|
-
@return_value = nil
|
41
|
-
end
|
42
|
-
|
43
|
-
# The default path to the ssh binary.
|
44
|
-
attr_reader :path
|
45
|
-
|
46
|
-
# Default ssh behavior arguments.
|
47
|
-
attr_reader :ssh_args
|
48
|
-
|
49
|
-
# The hostname to connect to.
|
50
|
-
attr_reader :hostname
|
51
|
-
|
52
|
-
# The command to run on the remote host.
|
53
|
-
attr_reader :command
|
54
|
-
|
55
|
-
# The key to use for authentication.
|
56
|
-
attr_reader :key
|
57
|
-
|
58
|
-
# The remote ssh port.
|
59
|
-
attr_reader :port
|
60
|
-
|
61
|
-
# Connect to the remote host as this user. Defaults to 'root'.
|
62
|
-
attr_reader :user
|
63
|
-
|
64
|
-
|
65
|
-
### Call ssh and capture output.
|
66
|
-
def run
|
67
|
-
@return_value = self.open_connection do |reader, writer|
|
68
|
-
self.log.debug "Writing command #{self.command}..."
|
69
|
-
writer.puts( self.command )
|
70
|
-
self.log.debug " closing child's writer."
|
71
|
-
writer.close
|
72
|
-
self.log.debug " reading from child."
|
73
|
-
reader.read
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
### Emit the output from the remote ssh call
|
79
|
-
def on_completion
|
80
|
-
if @return_value
|
81
|
-
self.log.info "Remote exited with %d, output: %s" % [ @return_value.exitstatus, @output ]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
#########
|
87
|
-
protected
|
88
|
-
#########
|
89
|
-
|
90
|
-
### Call ssh and yield the remote IO objects to the caller,
|
91
|
-
### cleaning up afterwards.
|
92
|
-
def open_connection
|
93
|
-
raise LocalJumpError, "no block given" unless block_given?
|
94
|
-
|
95
|
-
fqdn = self.expand_hostname( self.hostname ).
|
96
|
-
find {|hostname| self.ping(hostname, self.port) } or
|
97
|
-
raise "Unable to find an on-network host for %s:%d" % [ self.hostname, self.port ]
|
98
|
-
|
99
|
-
cmd = []
|
100
|
-
cmd << self.path
|
101
|
-
cmd += self.ssh_args
|
102
|
-
cmd << '-p' << self.port.to_s
|
103
|
-
cmd << '-i' << self.key if self.key
|
104
|
-
cmd << '-l' << self.user
|
105
|
-
cmd << fqdn
|
106
|
-
cmd.flatten!
|
107
|
-
self.log.debug "Running SSH command with: %p" % [ Shellwords.shelljoin(cmd) ]
|
108
|
-
|
109
|
-
parent_reader, child_writer = IO.pipe
|
110
|
-
child_reader, parent_writer = IO.pipe
|
111
|
-
|
112
|
-
pid = spawn( *cmd, :out => child_writer, :in => child_reader, :close_others => true )
|
113
|
-
child_writer.close
|
114
|
-
child_reader.close
|
115
|
-
|
116
|
-
self.log.debug "Yielding back to the run block."
|
117
|
-
@output = yield( parent_reader, parent_writer )
|
118
|
-
self.log.debug " run block done."
|
119
|
-
|
120
|
-
pid, status = Process.waitpid2( pid )
|
121
|
-
return status
|
122
|
-
end
|
123
|
-
|
124
|
-
|
125
|
-
end # class Symphony::Task::SSH
|
126
|
-
|
@@ -1,168 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'net/ssh'
|
4
|
-
require 'net/sftp'
|
5
|
-
require 'tmpdir'
|
6
|
-
require 'inversion'
|
7
|
-
require 'symphony/task' unless defined?( Symphony::Task )
|
8
|
-
|
9
|
-
|
10
|
-
# A task to execute a script on a remote host via SSH.
|
11
|
-
class Symphony::Task::SSHScript < Symphony::Task
|
12
|
-
extend Loggability,
|
13
|
-
MethodUtilities
|
14
|
-
|
15
|
-
# Loggability API -- Log to symphony's logger
|
16
|
-
log_to :symphony
|
17
|
-
|
18
|
-
|
19
|
-
# Template config
|
20
|
-
TEMPLATE_OPTS = {
|
21
|
-
:ignore_unknown_tags => false,
|
22
|
-
:on_render_error => :propagate,
|
23
|
-
:strip_tag_lines => true
|
24
|
-
}
|
25
|
-
|
26
|
-
# The defaults to use when connecting via SSH
|
27
|
-
DEFAULT_SSH_OPTIONS = {
|
28
|
-
:auth_methods => [ "publickey" ],
|
29
|
-
:compression => true,
|
30
|
-
:config => false,
|
31
|
-
:keys_only => true,
|
32
|
-
# :logger => Loggability[ Net::SSH ],
|
33
|
-
:paranoid => false,
|
34
|
-
:timeout => 10.seconds,
|
35
|
-
# :verbose => :debug,
|
36
|
-
:global_known_hosts_file => '/dev/null',
|
37
|
-
:user_known_hosts_file => '/dev/null',
|
38
|
-
}
|
39
|
-
|
40
|
-
|
41
|
-
### Create a new SSH task for the given +job+ and +queue+.
|
42
|
-
def initialize( queue, job )
|
43
|
-
super
|
44
|
-
|
45
|
-
# required arguments
|
46
|
-
@hostname = self.options[:hostname] or raise ArgumentError, "no hostname specified"
|
47
|
-
@template = self.options[:template] or raise ArgumentError, "no script template specified"
|
48
|
-
@key = self.options[:key] or raise ArgumentError, "no private key specified"
|
49
|
-
|
50
|
-
# optional arguments
|
51
|
-
@port = self.options[:port] || 22
|
52
|
-
@user = self.options[:user] || 'root'
|
53
|
-
@attributes = self.options[:attributes] || {}
|
54
|
-
@nocleanup = self.options[:nocleanup] ? true : false
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
######
|
59
|
-
public
|
60
|
-
######
|
61
|
-
|
62
|
-
# The name of the host to connect to
|
63
|
-
attr_reader :hostname
|
64
|
-
|
65
|
-
# The path to the script template
|
66
|
-
attr_accessor :template
|
67
|
-
|
68
|
-
# The path to the SSH key to use for auth
|
69
|
-
attr_reader :key
|
70
|
-
|
71
|
-
# The SSH port to use
|
72
|
-
attr_reader :port
|
73
|
-
|
74
|
-
# The user to connect as
|
75
|
-
attr_reader :user
|
76
|
-
|
77
|
-
# Attributes that will be set on the script template.
|
78
|
-
attr_reader :attributes
|
79
|
-
|
80
|
-
# Flag that will cause the uploaded script to not be cleaned up after running. Useful for
|
81
|
-
# diagnostics.
|
82
|
-
attr_reader :nocleanup
|
83
|
-
|
84
|
-
|
85
|
-
### Load the script as an Inversion template, sending and executing
|
86
|
-
### it on the remote host.
|
87
|
-
def run
|
88
|
-
fqdn = self.expand_hostname( self.hostname ).
|
89
|
-
find {|hostname| self.ping(hostname, self.port) }
|
90
|
-
|
91
|
-
unless fqdn
|
92
|
-
self.log.debug "Unable to find an on-network host for %s:%d" %
|
93
|
-
[ self.hostname, self.port ]
|
94
|
-
return
|
95
|
-
end
|
96
|
-
|
97
|
-
remote_filename = self.make_remote_filename
|
98
|
-
source = self.generate_script
|
99
|
-
|
100
|
-
# Establish the SSH connection
|
101
|
-
ssh_options = DEFAULT_SSH_OPTIONS.merge( :port => self.port, :keys => [self.key] )
|
102
|
-
self.with_timeout do
|
103
|
-
Net::SSH.start( fqdn, self.user, ssh_options ) do |conn|
|
104
|
-
self.upload_script( conn, source, remote_filename )
|
105
|
-
self.run_script( conn, remote_filename )
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
|
111
|
-
#########
|
112
|
-
protected
|
113
|
-
#########
|
114
|
-
|
115
|
-
### Return a human-readable description of details of the task.
|
116
|
-
def description
|
117
|
-
return "Running script '%s' on '%s:%d' as '%s'" % [
|
118
|
-
File.basename( self.template ),
|
119
|
-
self.hostname,
|
120
|
-
self.port,
|
121
|
-
self.user,
|
122
|
-
]
|
123
|
-
end
|
124
|
-
|
125
|
-
|
126
|
-
### Generate a unique filename for the script on the remote host.
|
127
|
-
def make_remote_filename
|
128
|
-
template = self.template
|
129
|
-
basename = File.basename( template, File.extname(template) )
|
130
|
-
|
131
|
-
tmpname = Dir::Tmpname.make_tmpname( basename, Process.pid )
|
132
|
-
|
133
|
-
return "/tmp/#{tmpname}"
|
134
|
-
end
|
135
|
-
|
136
|
-
|
137
|
-
### Generate a script by loading the script template, populating it with
|
138
|
-
### attributes, and rendering it.
|
139
|
-
def generate_script
|
140
|
-
tmpl = Inversion::Template.load( self.template, TEMPLATE_OPTS )
|
141
|
-
|
142
|
-
tmpl.attributes.merge!( self.attributes )
|
143
|
-
tmpl.task = self
|
144
|
-
|
145
|
-
return tmpl.render
|
146
|
-
end
|
147
|
-
|
148
|
-
### Render the given +template+ as script source, then use the specified +conn+ object
|
149
|
-
### to upload it.
|
150
|
-
def upload_script( conn, source, remote_filename )
|
151
|
-
self.log.debug "Uploading script (%d bytes) to %s:%s." %
|
152
|
-
[ source.bytesize, self.hostname, remote_filename ]
|
153
|
-
conn.sftp.file.open( remote_filename, "w", 0755 ) do |fh|
|
154
|
-
fh.print( source )
|
155
|
-
end
|
156
|
-
self.log.debug " done with the upload."
|
157
|
-
end
|
158
|
-
|
159
|
-
|
160
|
-
### Run the script on the remote host.
|
161
|
-
def run_script( conn, remote_filename )
|
162
|
-
output = conn.exec!( remote_filename )
|
163
|
-
self.log.debug "Output was:\n#{output}"
|
164
|
-
conn.exec!( "rm #{remote_filename}" ) unless self.nocleanup
|
165
|
-
end
|
166
|
-
|
167
|
-
end # class Symphony::Task::SSHScript
|
168
|
-
|