Reorganize for later support of various map types.

This commit is contained in:
Glenn Y. Rolland 2015-08-11 23:58:45 +02:00
parent c7a86f6938
commit a56389f9eb
6 changed files with 236 additions and 194 deletions

View file

@ -9,4 +9,91 @@ module Qasim ; module Map
class ParseError < RuntimeError ; end class ParseError < RuntimeError ; end
class ConnectError < 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 end ; end

5
lib/qasim/map/generic.rb Normal file
View file

@ -0,0 +1,5 @@
require 'fileutils'
require 'qasim/map'
class Qasim::Map::Generic
end

View file

@ -1,217 +1,148 @@
require 'fileutils' require 'fileutils'
require 'qasim/map' require 'qasim/map'
require 'qasim/map/generic'
module Qasim::Map class Qasim::Map::Ssh < Qasim::Map::Generic
class Ssh attr_reader :path,
attr_reader :path, :host,
:host, :port,
:port, :enable,
:enable, :user,
:user, :map,
:map, :name
:name
CYPHER_ARCFOUR = :arcfour CYPHER_ARCFOUR = :arcfour
CYPHER_AES256CBC = "aes-256-cbc".to_sym CYPHER_AES256CBC = "aes-256-cbc".to_sym
CYPHERS = [ CYPHER_ARCFOUR, CYPHER_AES256CBC ] CYPHERS = [ CYPHER_ARCFOUR, CYPHER_AES256CBC ]
# #
# Set defaults properties for maps # Set defaults properties for maps
# #
def initialize config, map_path def initialize config, map_path
@config = config @config = config
@path = map_path @path = map_path
@host = nil @host = nil
@port = 22 @port = 22
@enable = false @enable = false
@user = nil @user = nil
@cypher = :arcfour @cypher = :arcfour
@links = {} @links = {}
@debug = false @debug = false
@name = (File.basename map_path).gsub(/\.map$/,'') @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 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
# Load map description from file score -= 1
#
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
end end
if score == 0 then return true
else return false
# # FIXME: explain why ?
# Test map liveness (how ?)
# FIXME: not implemented
#
def online?
#rdebug "testing online? %s " % self.inspect
#FIXME: test liveness
end 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 # FIXME: test connexion with Net::SSH + timeout or ask password
# @links.each do |name, remotepath|
def connected? localpath = File.join ENV['HOME'], "mnt", name
f = File.open("/proc/mounts") FileUtils.mkdir_p localpath
sshfs_mounted = (f.readlines.select do |line| cmd = "sshfs"
line =~ /\s+fuse.sshfs\s+/ cmd_args = [
end).map do |line| "-o","allow_root" ,
line.split(/\s+/)[1] "-o","idmap=user" ,
end "-o","uid=%s" % Process.uid,
f.close "-o","gid=%s" % Process.gid,
"-o","reconnect", # auto-reconnection
score = 0 "-o","workaround=all",
@links.each do |name, remotepath| "-o","cache_timeout=900", # 15 min cache for files
score += 1 "-o","cache_stat_timeout=1800", # 30 min cache for directories
local_path = File.join @config.mnt_dir, name "-o","cache_link_timout=1800", # 30 min cache for links
"-o","attr_timeout=1800", # 30 min attr cache
if sshfs_mounted.include? local_path then "-o","entry_timeout=1800", # 30 min entry cache
score -= 1 "-o","ServerAliveInterval=15", # prevent I/O hang
end "-o","ServerAliveCountMax=3", # prevent I/O hang
end "-o","no_readahead",
if score == 0 then return true #"-o","Ciphers=arcfour", # force cypher
else return false "-o","Port=%s" % @port,
# FIXME: explain why ? "%s@%s:%s" % [@user,@host,remotepath],
end localpath ]
end #rdebug "command: %s" % [ cmd, cmd_args ].flatten.join(' ')
if block_given? then
yield name, cmd, cmd_args
# else
# Connect map system cmd, cmd_args
# if $?.exitstatus != 0 then
def connect &block raise ConnectError, self
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 end
end end
end
# #
# Disconnect map # Disconnect map
# #
def disconnect &block def disconnect &block
puts "Disconnecting map #{@path}" puts "Disconnecting map #{@path}"
@links.each do |name, remotepath| @links.each do |name, remotepath|
localpath = File.join ENV['HOME'], "mnt", name localpath = File.join ENV['HOME'], "mnt", name
cmd = "fusermount" cmd = "fusermount"
cmd_args = [ cmd_args = [
"-u", #umount "-u", #umount
"-z" ,#lazy "-z" ,#lazy
localpath ] localpath ]
#rdebug "command: %s" % [ cmd, cmd_args ].flatten.join(' ') #rdebug "command: %s" % [ cmd, cmd_args ].flatten.join(' ')
if block_given? then if block_given? then
yield name, cmd, cmd_args yield name, cmd, cmd_args
else else
system cmd, cmd_args system cmd, cmd_args
if $?.exitstatus != 0 then if $?.exitstatus != 0 then
raise ConnectError, self raise ConnectError, self
end
end end
end end
end end

11
lib/qasim/map/webdav.rb Normal file
View file

@ -0,0 +1,11 @@
require 'fileutils'
require 'qasim/map'
require 'qasim/map/generic'
class Qasim::Map::Webdav
# nothing
def initialize
end
end

View file

@ -1,7 +1,7 @@
require_relative 'spec_helper' require_relative 'spec_helper'
require 'qasim/map_ssh' require 'qasim/map/ssh'
describe Qasim::Config do describe Qasim::Map::Ssh do
# something # something
end end

8
spec/map_webdav_spec.rb Normal file
View file

@ -0,0 +1,8 @@
require_relative 'spec_helper'
require 'qasim/map/webdav'
describe Qasim::Map::Webdav do
# something
end