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

Martin Steigerwald ms at teamix.de
Tue Apr 14 11:00:19 UTC 2015


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
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.

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.steigerwald at 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



More information about the Pkg-ruby-extras-maintainers mailing list