Bug#714606: help with fixing ruby-net-ssh: can't add a new key into hash during iteration during ssh.exec

2015-04-14 Thread Martin Steigerwald
Cc'ing the bug report as well, feel free to drop the cc for discussion on 
mailing list.


Hi!

I seek help with fixing

https://bugs.debian.org/714606

aka

https://github.com/net-ssh/net-ssh/issues/110


The error message on trying ssh.exec is:

/usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:305:in `open_channel': 
can't add a new key into hash during iteration (RuntimeError)


Here is the offending source:

https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/connection/session.rb#L306


As far as I get the error is due to method exed in same file using

open_channel do |channel|

which then puts the assignment

channels[local_id] = channel

in open_channel into an iteration.

But I asked on #ruby-de and the do / end there is a block, not an iteration.

However in the backtrace there is

/usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:305:in `open_channel': 
can't add a new key into hash during iteration (RuntimeError)
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:329:in 
`exec'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:363:in 
`exec!'
from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:174:in `block 
in commit'
from /usr/lib/ruby/vendor_ruby/net/sftp/request.rb:87:in `call'
from /usr/lib/ruby/vendor_ruby/net/sftp/request.rb:87:in `respond_to'
from /usr/lib/ruby/vendor_ruby/net/sftp/session.rb:948:in 
`dispatch_request'
from /usr/lib/ruby/vendor_ruby/net/sftp/session.rb:911:in 
`when_channel_polled'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/channel.rb:311:in 
`call'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/channel.rb:311:in 
`process'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:222:in 
`block in preprocess'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:222:in 
`each'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:222:in 
`preprocess'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:205:in 
`process'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:169:in 
`block in loop'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:169:in 
`loop'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:169:in 
`loop'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/channel.rb:269:in 
`wait'
from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:364:in 
`exec!'
from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:184:in `commit'
from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:628:in 
`handle_host'
from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:703:in `block 
in handle_gwhost'
from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:686:in `each'
from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:686:in 
`handle_gwhost'
from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:718:in `loop'
from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:828:in `main'

an each in session.rb, line 222.


Which looks quite central to the working of ruby-net-ssh to me

# This is called internally as part of #process. It dispatches any
# available incoming packets, and then runs 
Net::SSH::Connection::Channel#process
# for any active channels. If a block is given, it is invoked at the
# start of the method and again at the end, and if the block ever returns
# false, this method returns false. Otherwise, it returns true.
def preprocess
  return false if block_given?  !yield(self)
  dispatch_incoming_packets
  channels.each { |id, channel| channel.process unless channel.closing? }
  return false if block_given?  !yield(self)
  return true
end



The calling site inside distkeys is:

https://github.com/teamix/distkeys/blob/master/distkeys#L174



Do you see a way to fix this up without changing the semantics of open_channel?


Another conclusion would be to treat ruby-net-ssh as unfit for release
with Debian Jessie, as a central functionality just does not work with Ruby
1.9+, and Jessie does not have Ruby 1.8 anymore.

But even tough upstream appears to be basically unmaintained (see note
about maintenance note at https://github.com/net-ssh/net-ssh) I think it would
be nice to have this fixed. But anyway, if its unmaintained it may be better
to remove it? I don't know about any other free as in freedom alternative to
it tough.

Thanks,

-- 
Martin Steigerwald  | Consultant / Trainer

teamix GmbH
Südwestpark 43
90449 Nürnberg

Tel.:  +49 911 30999 55 | Fax: +49 911 30999 99
mail: martin.steigerw...@teamix.de | web:  http://www.teamix.de | blog: 
http://blog.teamix.de

Amtsgericht Nürnberg, HRB 18320 | Geschäftsführer: Oliver Kügow, Richard Müller


** Data Management Day | 29.04.2015 bei teamix **
Jetzt anmelden unter www.teamix.de/CommVault


--
To UNSUBSCRIBE, email to 

Bug#714606: help with fixing ruby-net-ssh: can't add a new key into hash during iteration during ssh.exec

2015-04-14 Thread Martin Steigerwald
Am Dienstag, 14. April 2015, 12:36:33 schrieb Martin Steigerwald:
 Cc'ing the bug report as well, feel free to drop the cc for discussion on 
 mailing list.
 
 
 Hi!
 
 I seek help with fixing
 
 https://bugs.debian.org/714606
 
 aka
 
 https://github.com/net-ssh/net-ssh/issues/110
 
 
 The error message on trying ssh.exec is:
 
 /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:305:in 
 `open_channel': can't add a new key into hash during iteration (RuntimeError)
 
 
 Here is the offending source:
 
 https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/connection/session.rb#L306
 
 
 As far as I get the error is due to method exed in same file using
 
 open_channel do |channel|
 
 which then puts the assignment
 
 channels[local_id] = channel
 
 in open_channel into an iteration.
 
 But I asked on #ruby-de and the do / end there is a block, not an iteration.
 
 However in the backtrace there is
 
 /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:305:in 
 `open_channel': can't add a new key into hash during iteration (RuntimeError)
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:329:in 
 `exec'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:363:in 
 `exec!'
 from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:174:in 
 `block in commit'
 from /usr/lib/ruby/vendor_ruby/net/sftp/request.rb:87:in `call'
 from /usr/lib/ruby/vendor_ruby/net/sftp/request.rb:87:in `respond_to'
 from /usr/lib/ruby/vendor_ruby/net/sftp/session.rb:948:in 
 `dispatch_request'
 from /usr/lib/ruby/vendor_ruby/net/sftp/session.rb:911:in 
 `when_channel_polled'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/channel.rb:311:in 
 `call'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/channel.rb:311:in 
 `process'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:222:in 
 `block in preprocess'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:222:in 
 `each'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:222:in 
 `preprocess'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:205:in 
 `process'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:169:in 
 `block in loop'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:169:in 
 `loop'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:169:in 
 `loop'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/channel.rb:269:in 
 `wait'
 from /usr/lib/ruby/vendor_ruby/net/ssh/connection/session.rb:364:in 
 `exec!'
 from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:184:in 
 `commit'
 from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:628:in 
 `handle_host'
 from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:703:in 
 `block in handle_gwhost'
 from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:686:in `each'
 from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:686:in 
 `handle_gwhost'
 from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:718:in `loop'
 from /homelokal/ms/Debian/distkeys/distkeys.git/distkeys:828:in 
 `main'
 
 an each in session.rb, line 222.
 
 
 Which looks quite central to the working of ruby-net-ssh to me
 
 # This is called internally as part of #process. It dispatches any
 # available incoming packets, and then runs 
 Net::SSH::Connection::Channel#process
 # for any active channels. If a block is given, it is invoked at the
 # start of the method and again at the end, and if the block ever returns
 # false, this method returns false. Otherwise, it returns true.
 def preprocess
   return false if block_given?  !yield(self)
   dispatch_incoming_packets
   channels.each { |id, channel| channel.process unless channel.closing? }
   return false if block_given?  !yield(self)
   return true
 end
 
 
 
 The calling site inside distkeys is:
 
 https://github.com/teamix/distkeys/blob/master/distkeys#L174
 
 
 
 Do you see a way to fix this up without changing the semantics of 
 open_channel?

Okay, I now got further help from #ruby-de and there is a fix I can do inside 
distkeys:

ok=false
@sftp.lstat( .ssh ) do |response| ok = response.ok?; end
if not ok then
puts ~/.ssh does not seem to exist, creating 
it with 700...
@ssh.exec!( mkdir ~/.ssh )
@ssh.exec!( chmod 700 ~/.ssh )
end

i.e. first finish sftp then to the ssh exec stuff.

Pushed:
https://github.com/teamix/distkeys/commit/1092384f54d6531ce1106c4fe7b2f6833a2bba5b


I can now fix all other occurences of this in my script.

I am not sure whether it is a work-around or whether it is a valid
contraint to be taken into account when using ruby-net-ssh. To me it

Bug#714606: help with fixing ruby-net-ssh: can't add a new key into hash during iteration during ssh.exec

2015-04-14 Thread Martin Steigerwald
Am Dienstag, 14. April 2015, 14:39:04 schrieb David Suarez:
 Hi,
 
 2015-04-14 13:00 GMT+02:00 Martin Steigerwald m...@teamix.de:
  Am Dienstag, 14. April 2015, 12:36:33 schrieb Martin Steigerwald:
  Cc'ing the bug report as well, feel free to drop the cc for discussion on 
  mailing list.
  an each in session.rb, line 222.
 
 
  Which looks quite central to the working of ruby-net-ssh to me
 
  # This is called internally as part of #process. It dispatches any
  # available incoming packets, and then runs 
  Net::SSH::Connection::Channel#process
  # for any active channels. If a block is given, it is invoked at the
  # start of the method and again at the end, and if the block ever 
  returns
  # false, this method returns false. Otherwise, it returns true.
  def preprocess
return false if block_given?  !yield(self)
dispatch_incoming_packets
channels.each { |id, channel| channel.process unless 
  channel.closing? }
return false if block_given?  !yield(self)
return true
  end
 
 
 
  The calling site inside distkeys is:
 
  https://github.com/teamix/distkeys/blob/master/distkeys#L174
 
 
 You are right, 'channels' Hash is modified inside 'channels.each' call.
 
  I am not sure whether it is a work-around or whether it is a valid
  contraint to be taken into account when using ruby-net-ssh. To me it
  feels like a work-around, but well… if it works this way.
 
  If you still have an idea how to fix it in ruby-net-ssh, please tell me.
 
 Seems like a valid constrain, due that the problem arise when you are
 trying to open a new channel (ssh.exec!) inside the processing block
 of the another channel (sftp.lstat) in the same ssh session.
 
 One fix could be that instead os reusing the actual ssh connection to
 open the sftp one @sftp = Net::SFTP::Session.new(@ssh), create a
 new sftp connection Net::SFTP.start(host, user, options).

Thanks.

I now just finish the sftp operation before doing the ssh.exec calls and
this appears to work. Just uploaded distkeys-1.1 to github including 1.1
debian package source. This also fixes the same for the replacing of
authorized_keys with authorized_keys-new which was racy before due to
work-arounding this issue by deleting first and then sftp.rename() which
in current ruby-net-sftp cannot overwrite a file.

This appears to work just nice. And I also documented this behavior in
the script.

Will test internally for a while and then probably reapproach with request
for sponsoring for distkeys. Maybe one day will get distkeys into Debian,
I think its quite useful, cause it can put ssh keys to hosts behind
firewalls using ssh port forwarding automatically. After Jessie release :).

As for this bug, if you think its a valid constraint, feel free to close it.

I still think it would be good to at least have this documented somewhere
with ruby-net-ssh, cause the interference between ssh and sftp calls are not
that obvious but due to a implementation detail.

But I can try to send a documentation patch upstream.


-- 
Martin Steigerwald  | Consultant / Trainer

teamix GmbH
Südwestpark 43
90449 Nürnberg

Tel.:  +49 911 30999 55 | Fax: +49 911 30999 99
mail: martin.steigerw...@teamix.de | web:  http://www.teamix.de | blog: 
http://blog.teamix.de

Amtsgericht Nürnberg, HRB 18320 | Geschäftsführer: Oliver Kügow, Richard Müller


** Data Management Day | 29.04.2015 bei teamix **
Jetzt anmelden unter www.teamix.de/CommVault


--
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of unsubscribe. Trouble? Contact listmas...@lists.debian.org



Bug#714606: help with fixing ruby-net-ssh: can't add a new key into hash during iteration during ssh.exec

2015-04-14 Thread David Suarez
Hi,

2015-04-14 13:00 GMT+02:00 Martin Steigerwald m...@teamix.de:
 Am Dienstag, 14. April 2015, 12:36:33 schrieb Martin Steigerwald:
 Cc'ing the bug report as well, feel free to drop the cc for discussion on 
 mailing list.
 an each in session.rb, line 222.


 Which looks quite central to the working of ruby-net-ssh to me

 # This is called internally as part of #process. It dispatches any
 # available incoming packets, and then runs 
 Net::SSH::Connection::Channel#process
 # for any active channels. If a block is given, it is invoked at the
 # start of the method and again at the end, and if the block ever returns
 # false, this method returns false. Otherwise, it returns true.
 def preprocess
   return false if block_given?  !yield(self)
   dispatch_incoming_packets
   channels.each { |id, channel| channel.process unless channel.closing? }
   return false if block_given?  !yield(self)
   return true
 end



 The calling site inside distkeys is:

 https://github.com/teamix/distkeys/blob/master/distkeys#L174


You are right, 'channels' Hash is modified inside 'channels.each' call.

 I am not sure whether it is a work-around or whether it is a valid
 contraint to be taken into account when using ruby-net-ssh. To me it
 feels like a work-around, but well… if it works this way.

 If you still have an idea how to fix it in ruby-net-ssh, please tell me.

Seems like a valid constrain, due that the problem arise when you are
trying to open a new channel (ssh.exec!) inside the processing block
of the another channel (sftp.lstat) in the same ssh session.

One fix could be that instead os reusing the actual ssh connection to
open the sftp one @sftp = Net::SFTP::Session.new(@ssh), create a
new sftp connection Net::SFTP.start(host, user, options).

Cheers,

  David


--
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of unsubscribe. Trouble? Contact listmas...@lists.debian.org