diff --git a/lib/qasim/map.rb b/lib/qasim/map.rb index c91f00a..b99e08a 100644 --- a/lib/qasim/map.rb +++ b/lib/qasim/map.rb @@ -9,4 +9,91 @@ module Qasim ; module Map class ParseError < RuntimeError ; end class ConnectError < RuntimeError ; end + module_function :from_file + + def from_file + + end + + def to_file + end + + + # + # replace magic values withing map lines + # + # Allowed values : + # + # $(var) => variable value from environment + # ${var} => variable value from environment + # + def env_substitute str, lineno + local_env = ENV.clone + while str =~ /\$(\w+)/ do + case str + when /\$\{(.+)\}/ then + pattern = $1 + str.gsub!(/\$\{#{pattern}\}/,local_env[pattern]) + when /\$(\w+)/ then + pattern = $1 + str.gsub!(/\$#{pattern}/,local_env[pattern]) + else + puts "w: unknown pattern: %s at str %d" % [str, lineno] + end + end + str + end + + # + # Load map description from file + # + def from_file filename + f = File.open filename + linect = 0 + f.each do |line| + line = line.strip + linect += 1 + + line = env_substitute(line, linect) + + 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 #{@filename}:#{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 end ; end diff --git a/lib/qasim/map/generic.rb b/lib/qasim/map/generic.rb new file mode 100644 index 0000000..1a3c915 --- /dev/null +++ b/lib/qasim/map/generic.rb @@ -0,0 +1,5 @@ +require 'fileutils' +require 'qasim/map' + +class Qasim::Map::Generic +end diff --git a/lib/qasim/map/ssh.rb b/lib/qasim/map/ssh.rb index 32a3747..f257084 100644 --- a/lib/qasim/map/ssh.rb +++ b/lib/qasim/map/ssh.rb @@ -1,217 +1,148 @@ require 'fileutils' require 'qasim/map' +require 'qasim/map/generic' -module Qasim::Map - class Ssh - attr_reader :path, - :host, - :port, - :enable, - :user, - :map, - :name +class Qasim::Map::Ssh < Qasim::Map::Generic + attr_reader :path, + :host, + :port, + :enable, + :user, + :map, + :name - CYPHER_ARCFOUR = :arcfour - CYPHER_AES256CBC = "aes-256-cbc".to_sym - CYPHERS = [ CYPHER_ARCFOUR, CYPHER_AES256CBC ] + 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$/,'') + # + # 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 + self.load @path + 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 - # - # 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 + if sshfs_mounted.include? local_path then + score -= 1 end end - - - # - # Test map liveness (how ?) - # FIXME: not implemented - # - def online? - #rdebug "testing online? %s " % self.inspect - #FIXME: test liveness + 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 # - # 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 + # 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 + # + # 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 diff --git a/lib/qasim/map/webdav.rb b/lib/qasim/map/webdav.rb new file mode 100644 index 0000000..4da6c6f --- /dev/null +++ b/lib/qasim/map/webdav.rb @@ -0,0 +1,11 @@ + +require 'fileutils' +require 'qasim/map' +require 'qasim/map/generic' + +class Qasim::Map::Webdav + # nothing + def initialize + end +end + diff --git a/spec/map_ssh_spec.rb b/spec/map_ssh_spec.rb index d8e1481..c56fc62 100644 --- a/spec/map_ssh_spec.rb +++ b/spec/map_ssh_spec.rb @@ -1,7 +1,7 @@ require_relative 'spec_helper' -require 'qasim/map_ssh' +require 'qasim/map/ssh' -describe Qasim::Config do +describe Qasim::Map::Ssh do # something end diff --git a/spec/map_webdav_spec.rb b/spec/map_webdav_spec.rb new file mode 100644 index 0000000..8bf0821 --- /dev/null +++ b/spec/map_webdav_spec.rb @@ -0,0 +1,8 @@ + +require_relative 'spec_helper' +require 'qasim/map/webdav' + +describe Qasim::Map::Webdav do + # something +end +