Update for Ruby 2.5. Moderize configurability usage, update dependencies.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.gems Thu Jul 12 15:25:35 2018 -0700
@@ -0,0 +1,8 @@
+configurability -v3.2.0
+symphony -v0.11.1
+inversion -v1.1.1
+net-ssh -v5.0.2
+net-sftp -v2.1.2
+rspec -v3.7.0
+simplecov -v0.16.1
+pry -v0.11.3
--- a/.hgignore Wed May 28 11:45:41 2014 -0700
+++ b/.hgignore Thu Jul 12 15:25:35 2018 -0700
@@ -7,4 +7,4 @@
^ChangeLog$
^docs/
^coverage/
-
+Session.vim
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.ruby-gemset Thu Jul 12 15:25:35 2018 -0700
@@ -0,0 +1,1 @@
+symphony-ssh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.ruby-version Thu Jul 12 15:25:35 2018 -0700
@@ -0,0 +1,1 @@
+2.5
--- a/.rvmrc Wed May 28 11:45:41 2014 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-#!/usr/bin/env bash
-
-# This is an RVM Project .rvmrc file, used to automatically load the ruby
-# development environment upon cd'ing into the directory
-
-environment_id="2.0.0@symphony-ssh"
-
-if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
- && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]; then
- echo "Using ${environment_id}"
- . "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
-
- if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]; then
- . "${rvm_path:-$HOME/.rvm}/hooks/after_use"
- fi
-else
- # If the environment file has not yet been created, use the RVM CLI to select.
- if ! rvm --create use "$environment_id"
- then
- echo "Failed to create RVM environment '${environment_id}'."
- exit 1
- fi
-fi
-
-filename=".rvm.gems"
-if [[ -s "$filename" ]]; then
- rvm gemset import "$filename"
-fi
-
-
-
-
--- a/README.rdoc Wed May 28 11:45:41 2014 -0700
+++ b/README.rdoc Thu Jul 12 15:25:35 2018 -0700
@@ -22,22 +22,26 @@
Configurability[https://rubygems.org/gems/configurability] to determine
behavior. The configuration is a YAML[http://www.yaml.org/] file.
- symphony_ssh:
- path: /usr/bin/ssh
- user: root
- key: /path/to/a/private_key.rsa
- opts:
- - -e
- - none
- - -T
- - -x
- - -o
- - CheckHostIP=no'
- - -o
- - BatchMode=yes'
- - -o
- - StrictHostKeyChecking=no
+ symphony:
+ ssh:
+ path: /usr/bin/ssh
+ user: root
+ key: /path/to/a/private_key.rsa
+ opts:
+ - -e
+ - none
+ - -T
+ - -x
+ - -o
+ - CheckHostIP=no'
+ - -o
+ - BatchMode=yes'
+ - -o
+ - StrictHostKeyChecking=no
+**NOTE**: If you've upgrade from a version pre 0.2.0, the
+Configurability path has changed from `symphony_ssh`, to an `ssh` key
+under the `symphony` top level.
=== path
@@ -47,7 +51,7 @@
=== user
The default user to connect to remote hosts with. This can be
-changes per connection in the AMQP payload.
+changed per connection in the AMQP payload.
=== key
@@ -82,7 +86,7 @@
== License
-Copyright (c) 2014, Mahlon E. Smith and Michael Granger
+Copyright (c) 2014-2018, Mahlon E. Smith and Michael Granger
All rights reserved.
Redistribution and use in source and binary forms, with or without
--- a/Rakefile Wed May 28 11:45:41 2014 -0700
+++ b/Rakefile Thu Jul 12 15:25:35 2018 -0700
@@ -25,14 +25,14 @@
require 'rubygems'
require 'rubygems/package_task'
spec = Gem::Specification.new do |s|
- s.email = 'mahlon@martini.nu'
s.homepage = 'http://projects.martini.nu/ruby-modules'
- s.authors = [ 'Mahlon E. Smith <mahlon@martini.nu>', 'Michael Granger <ged@faeriemud.org>' ]
+ s.authors = [ 'Mahlon E. Smith', 'Michael Granger' ]
+ s.email = [ 'mahlon@martini.nu', 'ged@faeriemud.org' ]
s.platform = Gem::Platform::RUBY
s.summary = "Base classes for using Symphony with ssh."
s.name = 'symphony-ssh'
- s.version = '0.1.1'
- s.license = 'BSD'
+ s.version = '0.2.0'
+ s.license = 'BSD-3-Clause'
s.has_rdoc = true
s.require_path = 'lib'
s.bindir = 'bin'
@@ -48,12 +48,14 @@
s.required_rubygems_version = '>= 2.0.3'
s.required_ruby_version = '>= 2.0.0'
- s.add_dependency 'symphony', '~> 0.6'
- s.add_dependency 'net-ssh', '~> 2.9'
+ s.add_dependency 'configurability', '~> 3.2'
+ s.add_dependency 'symphony', '~> 0.11'
+ s.add_dependency 'inversion', '~> 1.1'
+ s.add_dependency 'net-ssh', '~> 5.0'
s.add_dependency 'net-sftp', '~> 2.1'
- s.add_development_dependency 'rspec', '~> 3.0'
- s.add_development_dependency 'simplecov', '~> 0.8'
+ s.add_development_dependency 'rspec', '~> 3.7'
+ s.add_development_dependency 'simplecov', '~> 0.16'
end
Gem::PackageTask.new( spec ) do |pkg|
--- a/lib/symphony/tasks/ssh.rb Wed May 28 11:45:41 2014 -0700
+++ b/lib/symphony/tasks/ssh.rb Thu Jul 12 15:25:35 2018 -0700
@@ -23,7 +23,7 @@
### key: (optional) The path to an SSH private key
###
###
-### Additionally, this class responds to the 'symphony_ssh' configurability
+### Additionally, this class responds to the 'symphony.ssh' configurability
### key. Currently, you can set the 'path' argument, which is the
### full path to the local ssh binary (defaults to '/usr/bin/ssh') and
### override the default ssh user, key, and client opts.
@@ -47,53 +47,42 @@
###
class Symphony::Task::SSH < Symphony::Task
extend Configurability
- config_key :symphony_ssh
- # SSH default options.
+ # The default set of ssh command line flags.
#
- CONFIG_DEFAULTS = {
- :path => '/usr/bin/ssh',
- :opts => [
- '-e', 'none',
- '-T',
- '-x',
- '-q',
- '-o', 'CheckHostIP=no',
- '-o', 'BatchMode=yes',
- '-o', 'StrictHostKeyChecking=no'
- ],
- :user => 'root',
- :key => nil
- }
+ DEFAULT_SSH_OPTS = %w[
+ -e none
+ -T
+ -x
+ -q
+ -o CheckHostIP=no
+ -o BatchMode=yes
+ -o StrictHostKeyChecking=no
+ ]
# SSH "informative" stdout output that should be cleaned from the
# command output.
SSH_CLEANUP = %r/Warning: no access to tty|Thus no job control in this shell/
- class << self
+
+ # Configurability API
+ #
+ configurability( :symphony__ssh ) do
+
# The full path to the ssh binary.
- attr_reader :path
+ setting :path, default: '/usr/bin/ssh'
- # A default set of ssh client options when connecting
+ # The default user to use when connecting.
+ setting :user, default: 'root'
+
+ # A default Array of ssh client options when connecting
# to remote hosts.
- attr_reader :opts
-
- # The default user to use when connecting. If unset, 'root' is used.
- attr_reader :user
+ setting :opts, default: DEFAULT_SSH_OPTS do |val|
+ Array( val )
+ end
# An absolute path to a password-free ssh private key.
- attr_reader :key
- end
-
- ### Configurability API.
- ###
- def self::configure( config=nil )
- config = Symphony::Task::SSH.defaults.merge( config || {} )
- @path = config.delete( :path )
- @opts = config.delete( :opts )
- @user = config.delete( :user )
- @key = config.delete( :key )
- super
+ setting :key
end
--- a/lib/symphony/tasks/sshscript.rb Wed May 28 11:45:41 2014 -0700
+++ b/lib/symphony/tasks/sshscript.rb Thu Jul 12 15:25:35 2018 -0700
@@ -1,12 +1,13 @@
#!/usr/bin/env ruby
# vim: set nosta noet ts=4 sw=4:
+require 'securerandom'
require 'net/ssh'
require 'net/sftp'
-require 'tmpdir'
require 'inversion'
require 'symphony'
require 'symphony/task'
+require 'symphony/tasks/ssh'
### A base class for connecting to a remote host, then uploading and
@@ -26,9 +27,10 @@
### key: (optional) The path to an SSH private key
### attributes: (optional) Additional data to attach to the template
### nocleanup: (optional) Leave the remote script after execution? (default to false)
+### tempdir: (optional) The destination temp directory. (defaults to /tmp)
###
###
-### Additionally, this class responds to the 'symphony_ssh' configurability
+### Additionally, this class responds to the 'symphony.ssh' configurability
### key. Currently, you can override the default ssh user and private key.
###
### Textual output of the command is stored in the @output instance variable.
@@ -49,53 +51,27 @@
### end
###
class Symphony::Task::SSHScript < Symphony::Task
- extend Configurability
- config_key :symphony_ssh
# Template config
#
TEMPLATE_OPTS = {
- :ignore_unknown_tags => false,
- :on_render_error => :propagate,
- :strip_tag_lines => true
+ ignore_unknown_tags: false,
+ on_render_error: :propagate,
+ strip_tag_lines: true
}
# The defaults to use when connecting via SSH
#
DEFAULT_SSH_OPTIONS = {
- :auth_methods => [ 'publickey' ],
- :compression => true,
- :config => false,
- :keys_only => true,
- :paranoid => false,
- :global_known_hosts_file => '/dev/null',
- :user_known_hosts_file => '/dev/null'
- }
-
- # SSH default options.
- #
- CONFIG_DEFAULTS = {
- :user => 'root',
- :key => nil
+ auth_methods: [ 'publickey' ],
+ compression: true,
+ config: false,
+ keys_only: true,
+ verify_host_key: :never,
+ global_known_hosts_file: '/dev/null',
+ user_known_hosts_file: '/dev/null'
}
- class << self
- # The default user to use when connecting. If unset, 'root' is used.
- attr_reader :user
-
- # An absolute path to a password-free ssh private key.
- attr_reader :key
- end
-
- ### Configurability API.
- ###
- def self::configure( config=nil )
- config = Symphony::Task::SSHScript.defaults.merge( config || {} )
- @user = config.delete( :user )
- @key = config.delete( :key )
- super
- end
-
### Perform the ssh connection, render the template, send it, and
### execute it.
@@ -104,20 +80,21 @@
template = payload[ 'template' ]
attributes = payload[ 'attributes' ] || {}
port = payload[ 'port' ] || 22
- user = payload[ 'user' ] || Symphony::Task::SSHScript.user
- key = payload[ 'key' ] || Symphony::Task::SSHScript.key
+ user = payload[ 'user' ] || Symphony::Task::SSH.user
+ key = payload[ 'key' ] || Symphony::Task::SSH.key
nocleanup = payload[ 'nocleanup' ]
+ tempdir = payload[ 'tempdir' ] || '/tmp'
raise ArgumentError, "Missing required option 'template'" unless template
- raise ArgumentError, "Missing required option 'host'" unless payload[ 'host' ]
+ raise ArgumentError, "Missing required option 'host'" unless payload[ 'host' ]
- remote_filename = self.make_remote_filename( template )
+ remote_filename = self.make_remote_filename( template, tempdir )
source = self.generate_script( template, attributes )
- ssh_options = DEFAULT_SSH_OPTIONS.merge( :port => port, :keys => [key] )
+ ssh_options = DEFAULT_SSH_OPTIONS.merge( port: port, keys: Array(key) )
ssh_options.merge!(
- :logger => Loggability[ Net::SSH ],
- :verbose => :debug
+ logger: Loggability[ Net::SSH ],
+ verbose: :debug
) if payload[ 'debug' ]
Net::SSH.start( payload['host'], user, ssh_options ) do |conn|
@@ -141,11 +118,15 @@
### Generate a unique filename for the script on the remote host,
### based on +template+ name.
###
- def make_remote_filename( template )
+ def make_remote_filename( template, tempdir="/tmp" )
basename = File.basename( template, File.extname(template) )
- tmpname = Dir::Tmpname.make_tmpname( basename, rand(10000) )
+ tmpname = "%s/%s-%s" % [
+ tempdir,
+ basename,
+ SecureRandom.hex( 6 )
+ ]
- return "/tmp/#{tmpname}"
+ return tmpname
end
--- a/spec/symphony/tasks/sshscript_spec.rb Wed May 28 11:45:41 2014 -0700
+++ b/spec/symphony/tasks/sshscript_spec.rb Thu Jul 12 15:25:35 2018 -0700
@@ -1,17 +1,30 @@
require_relative '../../helpers'
+require 'symphony/tasks/ssh'
require 'symphony/tasks/sshscript'
context Symphony::Task::SSHScript do
before( :each ) do
- described_class.configure(
+ Symphony::Task::SSH.configure(
key: '/tmp/sekrit.rsa',
user: 'symphony'
)
end
- it_should_behave_like "an object with Configurability"
+
+ describe 'utility' do
+
+ it "can generate an appropriate tempfile name" do
+ instance = Class.new( described_class ).new( 'queue' )
+ tmpname = instance.send( :make_remote_filename, "fancy-script.tmpl" )
+ expect( tmpname ).to match( %r|^/tmp/fancy-script-[[:xdigit:]]{6}| )
+
+ tmpname = instance.send( :make_remote_filename, "fancy-script.tmpl", "/var/tmp" )
+ expect( tmpname ).to match( %r|/var/tmp/fancy-script-[[:xdigit:]]{6}| )
+ end
+ end
+
describe 'subclassed' do
let( :instance ) { Class.new(described_class).new('queue') }
@@ -30,7 +43,7 @@
before( :each ) do
allow( Inversion::Template ).to receive( :load ).and_return( template )
- allow( Dir::Tmpname ).to receive( :make_tmpname ).and_return( "script_temp" )
+ allow( instance ).to receive( :make_remote_filename ).and_return( "/tmp/script_temp" )
end
it "aborts if there is no template in the payload" do