diff --git a/lib/qasim/config.rb b/lib/qasim/config.rb index 94a68a8..766be48 100644 --- a/lib/qasim/config.rb +++ b/lib/qasim/config.rb @@ -4,7 +4,8 @@ require 'ostruct' require 'pp' require 'find' -require 'qasim' +require 'qasim/map' +require 'qasim/map_ssh' module Qasim class Config @@ -38,7 +39,7 @@ module Qasim next unless File.basename( path ) =~ /.map$/ begin - map = Map.new self, path + map = Map::Ssh.new self, path yield map if block_given? maps.push map rescue diff --git a/lib/qasim/map.rb b/lib/qasim/map.rb index bb4df14..6c85d9b 100644 --- a/lib/qasim/map.rb +++ b/lib/qasim/map.rb @@ -4,222 +4,9 @@ require 'fileutils' #require 'rdebug/base' require 'qasim' -module Qasim +module Qasim ; module Map - class Map - attr_reader :path, - :host, - :port, - :enable, - :user, - :map, - :name + class ParseError < RuntimeError ; end + class ConnectError < RuntimeError ; end - class MapParseError < RuntimeError ; end - class ConnectError < RuntimeError ; end - - CYPHER_ARCFOUR = :arcfour - CYPHER_AES256CBC = "aes-256-cbc".to_sym - CYPHERS = [ CYPHER_ARCFOUR, CYPHER_AES256CBC ] - - - # - # Set defaults properties for maps - # - def initialize config, map_path - @config = config - @path = map_path - @host = nil - @port = 22 - @enable = false - @user = nil - @cypher = :arcfour - @links = {} - @debug = false - @name = (File.basename map_path).gsub(/\.map$/,'') - - self.load @path - end - - - # - # Load map description from file - # - def load path=nil - @path=path unless path.nil? - #rdebug "Parsing map #{@path}" - f = File.open @path - linect = 0 - local_env = ENV.clone - f.each do |line| - line = line.strip - linect += 1 - - while line =~ /\$(\w+)/ do - #puts "FOUND PATTERN %s => %s" % [$1, local_env[$1]] - case line - when /\$\{(.+)\}/ then - pattern = $1 - puts pattern - line.gsub!(/\$\{#{pattern}\}/,local_env[pattern]) - when /\$(\w+)/ then - pattern = $1 - line.gsub!(/\$#{pattern}/,local_env[pattern]) - else - puts "w: unknown pattern: %s" % line - end - end - - case line - when /^\s*REMOTE_USER\s*=\s*(.*)\s*$/ then - @user = $1 - #rdebug "d: remote_user => #{$1}" - when /^\s*REMOTE_PORT\s*=\s*(.*)\s*$/ then - @port = $1.to_i - #rdebug "d: remote_port => #{$1}" - when /^\s*REMOTE_HOST\s*=\s*(.*)\s*$/ then - @host = $1 - #rdebug "d: remote_host => #{$1}" - when /^\s*REMOTE_CYPHER\s*=\s*(.*)\s*$/ then - if CYPHERS.map{|x| x.to_s}.include? $1 then - @host = $1.to_sym - end - when /^\s*MAP\s*=\s*(.*)\s+(.*)\s*$/ then - @links[$1] = $2 - #rdebug "d: link #{$1} => #{$2}" - when /^\s*$/,/^\s*#/ then - #rdebug "d: dropping empty line" - else - raise MapParseError, "parse error at #{@path}:#{linect}" - end - end - f.close - end - - - # - # Write map description to file - # - def write path=nil - @path=path unless path.nil? - - File.open(@path, "w") do |f| - f.puts "REMOTE_USER=%s" % @user - f.puts "REMOTE_PORT=%s" % @port - f.puts "REMOTE_HOST=%s" % @host - f.puts "REMOTE_CYPHER=%s" % @cypher - end - end - - - # - # Test map liveness (how ?) - # FIXME: not implemented - # - def online? - #rdebug "testing online? %s " % self.inspect - #FIXME: test liveness - end - - - # - # Test if map is connected / mounted - # - def connected? - f = File.open("/proc/mounts") - sshfs_mounted = (f.readlines.select do |line| - line =~ /\s+fuse.sshfs\s+/ - end).map do |line| - line.split(/\s+/)[1] - end - f.close - - score = 0 - @links.each do |name, remotepath| - score += 1 - local_path = File.join @config.mnt_dir, name - - if sshfs_mounted.include? local_path then - score -= 1 - end - end - if score == 0 then return true - else return false - # FIXME: explain why ? - end - end - - - # - # Connect map - # - def connect &block - puts "[#{File.basename @path}] Connecting..." - puts " #{@user}@#{@host}:#{@port}" - #puts " links = %s" % @links.map{ |k,v| "%s => %s" % [ k, v ] }.join(', ') - # do something - # test server connection - # mount - # - # FIXME: test connexion with Net::SSH + timeout or ask password - @links.each do |name, remotepath| - localpath = File.join ENV['HOME'], "mnt", name - FileUtils.mkdir_p localpath - cmd = "sshfs" - cmd_args = [ - "-o","allow_root" , - "-o","idmap=user" , - "-o","uid=%s" % Process.uid, - "-o","gid=%s" % Process.gid, - "-o","reconnect", # auto-reconnection - "-o","workaround=all", - "-o","cache_timeout=900", # 15 min cache for files - "-o","cache_stat_timeout=1800", # 30 min cache for directories - "-o","cache_link_timout=1800", # 30 min cache for links - "-o","attr_timeout=1800", # 30 min attr cache - "-o","entry_timeout=1800", # 30 min entry cache - "-o","ServerAliveInterval=15", # prevent I/O hang - "-o","ServerAliveCountMax=3", # prevent I/O hang - "-o","no_readahead", - #"-o","Ciphers=arcfour", # force cypher - "-o","Port=%s" % @port, - "%s@%s:%s" % [@user,@host,remotepath], - localpath ] - #rdebug "command: %s" % [ cmd, cmd_args ].flatten.join(' ') - if block_given? then - yield name, cmd, cmd_args - else - system cmd, cmd_args - if $?.exitstatus != 0 then - raise ConnectError, self - end - end - end - end - - - # - # Disconnect map - # - def disconnect &block - puts "Disconnecting map #{@path}" - @links.each do |name, remotepath| - localpath = File.join ENV['HOME'], "mnt", name - cmd = "fusermount" - cmd_args = [ - "-u", #umount - "-z" ,#lazy - localpath ] - #rdebug "command: %s" % [ cmd, cmd_args ].flatten.join(' ') - if block_given? then - yield name, cmd, cmd_args - else - system cmd, cmd_args - if $?.exitstatus != 0 then - raise ConnectError, self - end - end - end - end - end -end +end ; end diff --git a/lib/qasim/map_ssh.rb b/lib/qasim/map_ssh.rb new file mode 100644 index 0000000..32a3747 --- /dev/null +++ b/lib/qasim/map_ssh.rb @@ -0,0 +1,219 @@ + +require 'fileutils' +require 'qasim/map' + +module Qasim::Map + class Ssh + attr_reader :path, + :host, + :port, + :enable, + :user, + :map, + :name + + CYPHER_ARCFOUR = :arcfour + CYPHER_AES256CBC = "aes-256-cbc".to_sym + CYPHERS = [ CYPHER_ARCFOUR, CYPHER_AES256CBC ] + + + # + # Set defaults properties for maps + # + def initialize config, map_path + @config = config + @path = map_path + @host = nil + @port = 22 + @enable = false + @user = nil + @cypher = :arcfour + @links = {} + @debug = false + @name = (File.basename map_path).gsub(/\.map$/,'') + + self.load @path + end + + + # + # Load map description from file + # + def load path=nil + @path=path unless path.nil? + #rdebug "Parsing map #{@path}" + f = File.open @path + linect = 0 + local_env = ENV.clone + f.each do |line| + line = line.strip + linect += 1 + + while line =~ /\$(\w+)/ do + #puts "FOUND PATTERN %s => %s" % [$1, local_env[$1]] + case line + when /\$\{(.+)\}/ then + pattern = $1 + puts pattern + line.gsub!(/\$\{#{pattern}\}/,local_env[pattern]) + when /\$(\w+)/ then + pattern = $1 + line.gsub!(/\$#{pattern}/,local_env[pattern]) + else + puts "w: unknown pattern: %s" % line + end + end + + case line + when /^\s*REMOTE_USER\s*=\s*(.*)\s*$/ then + @user = $1 + #rdebug "d: remote_user => #{$1}" + when /^\s*REMOTE_PORT\s*=\s*(.*)\s*$/ then + @port = $1.to_i + #rdebug "d: remote_port => #{$1}" + when /^\s*REMOTE_HOST\s*=\s*(.*)\s*$/ then + @host = $1 + #rdebug "d: remote_host => #{$1}" + when /^\s*REMOTE_CYPHER\s*=\s*(.*)\s*$/ then + if CYPHERS.map{|x| x.to_s}.include? $1 then + @host = $1.to_sym + end + when /^\s*MAP\s*=\s*(.*)\s+(.*)\s*$/ then + @links[$1] = $2 + #rdebug "d: link #{$1} => #{$2}" + when /^\s*$/,/^\s*#/ then + #rdebug "d: dropping empty line" + else + raise MapParseError, "parse error at #{@path}:#{linect}" + end + end + f.close + end + + + # + # Write map description to file + # + def write path=nil + @path=path unless path.nil? + + File.open(@path, "w") do |f| + f.puts "REMOTE_USER=%s" % @user + f.puts "REMOTE_PORT=%s" % @port + f.puts "REMOTE_HOST=%s" % @host + f.puts "REMOTE_CYPHER=%s" % @cypher + end + end + + + # + # Test map liveness (how ?) + # FIXME: not implemented + # + def online? + #rdebug "testing online? %s " % self.inspect + #FIXME: test liveness + end + + + # + # Test if map is connected / mounted + # + def connected? + f = File.open("/proc/mounts") + sshfs_mounted = (f.readlines.select do |line| + line =~ /\s+fuse.sshfs\s+/ + end).map do |line| + line.split(/\s+/)[1] + end + f.close + + score = 0 + @links.each do |name, remotepath| + score += 1 + local_path = File.join @config.mnt_dir, name + + if sshfs_mounted.include? local_path then + score -= 1 + end + end + if score == 0 then return true + else return false + # FIXME: explain why ? + end + end + + + # + # Connect map + # + def connect &block + puts "[#{File.basename @path}] Connecting..." + puts " #{@user}@#{@host}:#{@port}" + #puts " links = %s" % @links.map{ |k,v| "%s => %s" % [ k, v ] }.join(', ') + # do something + # test server connection + # mount + # + # FIXME: test connexion with Net::SSH + timeout or ask password + @links.each do |name, remotepath| + localpath = File.join ENV['HOME'], "mnt", name + FileUtils.mkdir_p localpath + cmd = "sshfs" + cmd_args = [ + "-o","allow_root" , + "-o","idmap=user" , + "-o","uid=%s" % Process.uid, + "-o","gid=%s" % Process.gid, + "-o","reconnect", # auto-reconnection + "-o","workaround=all", + "-o","cache_timeout=900", # 15 min cache for files + "-o","cache_stat_timeout=1800", # 30 min cache for directories + "-o","cache_link_timout=1800", # 30 min cache for links + "-o","attr_timeout=1800", # 30 min attr cache + "-o","entry_timeout=1800", # 30 min entry cache + "-o","ServerAliveInterval=15", # prevent I/O hang + "-o","ServerAliveCountMax=3", # prevent I/O hang + "-o","no_readahead", + #"-o","Ciphers=arcfour", # force cypher + "-o","Port=%s" % @port, + "%s@%s:%s" % [@user,@host,remotepath], + localpath ] + #rdebug "command: %s" % [ cmd, cmd_args ].flatten.join(' ') + if block_given? then + yield name, cmd, cmd_args + else + system cmd, cmd_args + if $?.exitstatus != 0 then + raise ConnectError, self + end + end + end + end + + + # + # Disconnect map + # + def disconnect &block + puts "Disconnecting map #{@path}" + @links.each do |name, remotepath| + localpath = File.join ENV['HOME'], "mnt", name + cmd = "fusermount" + cmd_args = [ + "-u", #umount + "-z" ,#lazy + localpath ] + #rdebug "command: %s" % [ cmd, cmd_args ].flatten.join(' ') + if block_given? then + yield name, cmd, cmd_args + else + system cmd, cmd_args + if $?.exitstatus != 0 then + raise ConnectError, self + end + end + end + end + end +end