svengali 0.2.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +0 -0
- data/README.rdoc +17 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/api_document020_en.pdf +0 -0
- data/api_document020_ja.pdf +0 -0
- data/api_document_en.pptx +0 -0
- data/api_document_ja.pptx +0 -0
- data/lib/svengali.rb +2 -0
- data/lib/svengali/config.rb +78 -0
- data/lib/svengali/ext_string.rb +55 -0
- data/lib/svengali/ext_string/command.yml +6 -0
- data/lib/svengali/ext_string/path.yml +6 -0
- data/lib/svengali/file_io.rb +106 -0
- data/lib/svengali/machine.rb +123 -0
- data/lib/svengali/platforms/debian.rb +5 -0
- data/lib/svengali/platforms/default.rb +4 -0
- data/lib/svengali/plugins/eucalyptus.rb +339 -0
- data/lib/svengali/plugins/machine_config.rb +126 -0
- data/lib/svengali/plugins/package.rb +7 -0
- data/lib/svengali/ssh.rb +106 -0
- data/lib/svengali/svengali.rb +19 -0
- data/lib/svengali/util.rb +117 -0
- data/rdoc/classes/CLibIPAddr.html +230 -0
- data/rdoc/classes/Cloud.html +506 -0
- data/rdoc/classes/Config.html +151 -0
- data/rdoc/classes/Config/ConfigFile.html +319 -0
- data/rdoc/classes/ExtStr.html +209 -0
- data/rdoc/classes/ExtStrAccessor.html +183 -0
- data/rdoc/classes/FileIO.html +415 -0
- data/rdoc/classes/Machine.html +771 -0
- data/rdoc/classes/MachineMaster.html +117 -0
- data/rdoc/classes/Platform.html +121 -0
- data/rdoc/classes/SSH.html +315 -0
- data/rdoc/created.rid +1 -0
- data/rdoc/files/README.html +101 -0
- data/rdoc/files/README_rdoc.html +133 -0
- data/rdoc/files/lib/svengali/config_rb.html +114 -0
- data/rdoc/files/lib/svengali/ext_string_rb.html +108 -0
- data/rdoc/files/lib/svengali/file_io_rb.html +115 -0
- data/rdoc/files/lib/svengali/machine_rb.html +108 -0
- data/rdoc/files/lib/svengali/platforms/debian_rb.html +107 -0
- data/rdoc/files/lib/svengali/platforms/default_rb.html +107 -0
- data/rdoc/files/lib/svengali/plugins/eucalyptus_rb.html +389 -0
- data/rdoc/files/lib/svengali/plugins/machine_config_rb.html +101 -0
- data/rdoc/files/lib/svengali/plugins/package_rb.html +101 -0
- data/rdoc/files/lib/svengali/ssh_rb.html +110 -0
- data/rdoc/files/lib/svengali/svengali_rb.html +125 -0
- data/rdoc/files/lib/svengali/util_rb.html +439 -0
- data/rdoc/files/lib/svengali_rb.html +108 -0
- data/rdoc/fr_class_index.html +37 -0
- data/rdoc/fr_file_index.html +41 -0
- data/rdoc/fr_method_index.html +100 -0
- data/rdoc/index.html +26 -0
- data/rdoc/rdoc-style.css +208 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/svengali_spec.rb +7 -0
- data/svengali.gemspec +113 -0
- data/svengali_sample.rb +43 -0
- data/test/scenario.sh +3 -0
- metadata +179 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Ryo Kanbayashi
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= svengali
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2010 Ryo Kanbayashi. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "svengali"
|
8
|
+
gem.summary = "distributed machine operating library of cloud age. please see http://sourceforge.jp/projects/svengali/wiki/FrontPage"
|
9
|
+
gem.description = "Svengali offers means to manage and operate distributed machines easier than by other tools like shell script"
|
10
|
+
gem.email = "ryo.contact [at] gmail.com"
|
11
|
+
gem.homepage = "http://sourceforge.jp/projects/svengali/"
|
12
|
+
gem.authors = ["Ryo Kanbayashi"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.add_dependency "net-ssh", ">= 2.0.17"
|
15
|
+
gem.add_dependency "net-sftp", ">= 2.0.4"
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
|
+
end
|
18
|
+
Jeweler::GemcutterTasks.new
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'spec/rake/spectask'
|
24
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
25
|
+
spec.libs << 'lib' << 'spec'
|
26
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
end
|
28
|
+
|
29
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
32
|
+
spec.rcov = true
|
33
|
+
end
|
34
|
+
|
35
|
+
task :spec => :check_dependencies
|
36
|
+
|
37
|
+
task :default => :spec
|
38
|
+
|
39
|
+
require 'rake/rdoctask'
|
40
|
+
Rake::RDocTask.new do |rdoc|
|
41
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "svengali #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.7.2
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/svengali.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
#for StringIO
|
2
|
+
require "stringio"
|
3
|
+
|
4
|
+
module Config
|
5
|
+
|
6
|
+
# if there isn't a file which has specified file name, New file is created.
|
7
|
+
def get_config_file(remote_filepath_str)
|
8
|
+
# passed @sftp_session is not one of ConfigFile
|
9
|
+
return ConfigFile.new(remote_filepath_str,@sftp_session)
|
10
|
+
end
|
11
|
+
|
12
|
+
class ConfigFile
|
13
|
+
include FileIO
|
14
|
+
|
15
|
+
@remote_filepath_str
|
16
|
+
@sftp_session
|
17
|
+
#Net::SFTP::Request
|
18
|
+
@config_file_contents
|
19
|
+
|
20
|
+
#ssh_session => Net::SFTP::Session
|
21
|
+
#ConfigFile class doesn't manage passed sftp_session value
|
22
|
+
def initialize(remote_path_str,sftp_session)
|
23
|
+
@sftp_session = sftp_session
|
24
|
+
|
25
|
+
@remote_filepath_str = remote_path_str
|
26
|
+
if is_exist(remote_path_str)
|
27
|
+
# config_file = @sftp_session.open!(remote_path_str)
|
28
|
+
@config_file_contents = get_contents_remote(@remote_filepath_str)
|
29
|
+
else
|
30
|
+
@config_file_contents = ""
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
#replace columns which has specified content
|
36
|
+
def replace_col(original_col_str,replaced_col_str)
|
37
|
+
orig_contents_io = StringIO.new(@config_file_contents)
|
38
|
+
replaced_contents_io = StringIO.new()
|
39
|
+
orig_contents_io.each_line { |line|
|
40
|
+
replaced_contents_io.puts(line.gsub(original_col_str,replaced_col_str))
|
41
|
+
}
|
42
|
+
orig_contents_io.close()
|
43
|
+
replaced_contents_io.close()
|
44
|
+
|
45
|
+
@config_file_contents = replaced_contents_io.string
|
46
|
+
end
|
47
|
+
|
48
|
+
def append_str(str)
|
49
|
+
@config_file_contents += str
|
50
|
+
end
|
51
|
+
|
52
|
+
#remove all columns which contains passed string
|
53
|
+
def remove_col_by_str(str)
|
54
|
+
orig_contents_io = StringIO.new(@config_file_contents)
|
55
|
+
removed_contents_io = StringIO.new()
|
56
|
+
orig_contents_io.each_line { |line|
|
57
|
+
unless line.index(str)
|
58
|
+
removed_contents_io.puts(line)
|
59
|
+
end
|
60
|
+
}
|
61
|
+
orig_contents_io.close()
|
62
|
+
removed_contents_io.close()
|
63
|
+
|
64
|
+
@config_file_contents = removed_contents_io.string
|
65
|
+
end
|
66
|
+
|
67
|
+
#remove columns which matched passed regular expression
|
68
|
+
def remove_col_by_regexp(regexp)
|
69
|
+
not_inp()
|
70
|
+
end
|
71
|
+
|
72
|
+
#save modified content
|
73
|
+
def save
|
74
|
+
write_contents_remote(@remote_filepath_str,@config_file_contents)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
# manages externarized strings on YAML files
|
4
|
+
class ExtStr
|
5
|
+
@@command_accessor = nil
|
6
|
+
@@path_accessor = nil
|
7
|
+
|
8
|
+
def self.path()
|
9
|
+
unless @@command_accessor && @@path_accessor
|
10
|
+
self.init()
|
11
|
+
end
|
12
|
+
|
13
|
+
return @@path_accessor
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.cmd()
|
17
|
+
unless @@command_accessor && @@path_accessor
|
18
|
+
self.init()
|
19
|
+
end
|
20
|
+
|
21
|
+
return @@command_accessor
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.init()
|
25
|
+
@@command_accessor = ExtStrAccessor.new(File::dirname(__FILE__) + "/ext_string/command.yml",$platform_name)
|
26
|
+
@@path_accessor = ExtStrAccessor.new( File::dirname(__FILE__) + "/ext_string/path.yml",$platform_name)
|
27
|
+
end
|
28
|
+
# private_class_method :init
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class ExtStrAccessor
|
33
|
+
@contents_hash
|
34
|
+
@first_level
|
35
|
+
|
36
|
+
def initialize(file_name_str,first_level_name)
|
37
|
+
@contents_hash = YAML.load_file( file_name_str )
|
38
|
+
@first_level = first_level_name
|
39
|
+
end
|
40
|
+
|
41
|
+
def [](key)
|
42
|
+
val = @contents_hash[@first_level][key]
|
43
|
+
if val
|
44
|
+
return val
|
45
|
+
else
|
46
|
+
default_val = @contents_hash["default"][val]
|
47
|
+
if default_val
|
48
|
+
return default_val
|
49
|
+
else
|
50
|
+
debug_p "key( #{key.to_s} ) is not found on even default hash!"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
#in this file methods for file trasfer is defined
|
2
|
+
require 'rubygems'
|
3
|
+
gem 'net-sftp'
|
4
|
+
require 'net/sftp'
|
5
|
+
|
6
|
+
module FileIO
|
7
|
+
BUFFER_SIZE = 1024
|
8
|
+
|
9
|
+
def push_a_file(local_path,remote_path)
|
10
|
+
debug_p("push_a_file from #{local_path} to #{remote_path}")
|
11
|
+
@sftp_session.upload!(local_path,remote_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def pull_a_file(remote_path,local_path)
|
15
|
+
debug_p("pull_a_file from #{remote_path} to #{local_path}")
|
16
|
+
|
17
|
+
begin
|
18
|
+
@sftp_session.download!(remote_path,local_path)
|
19
|
+
rescue
|
20
|
+
debug_p remote_path + " is not found on remote!!"
|
21
|
+
return nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# push files on specified dir. only one level.
|
26
|
+
# directories are not copied.
|
27
|
+
def push_files(local_path,remote_path)
|
28
|
+
debug_p("push_files from #{local_path} to #{remote_path}")
|
29
|
+
local_dir = Dir.new(local_path)
|
30
|
+
local_dir.each{ |path|
|
31
|
+
unless File::ftype(local_path + "/" + path) == "directory"
|
32
|
+
@sftp_session.upload!(local_path + "/" + path,remote_path + "/" + path)
|
33
|
+
end
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
#pull files on specified dir. only one level.
|
38
|
+
def pull_files(remote_path,local_path)
|
39
|
+
debug_p("pull_files from #{remote_path} to #{local_path}")
|
40
|
+
@sftp_session.dir.foreach(remote_path){ |path|
|
41
|
+
#unless path.name == "." || path.name == ".."
|
42
|
+
#not directory
|
43
|
+
unless /^d/ =~ path.longname
|
44
|
+
@sftp_session.download!(remote_path + "/" + path.name,local_path + "/" + path.name)
|
45
|
+
end
|
46
|
+
#end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
# Note: if there is a directory which has same name with *local_path*, remote_directory is removed before coping directory
|
51
|
+
def push_dir(local_path,remote_path)
|
52
|
+
debug_p("push_dir from #{local_path} to #{remote_path}")
|
53
|
+
begin
|
54
|
+
@sftp_session.upload!(local_path,remote_path)
|
55
|
+
rescue
|
56
|
+
@ssh.exec!("rm -rf #{remote_path}")
|
57
|
+
retry
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def pull_dir(remote_path,local_path)
|
62
|
+
debug_p("pull_dir from #{remote_path} to #{local_path}")
|
63
|
+
begin
|
64
|
+
@sftp_session.download!(remote_path,local_path,:recursive => true)
|
65
|
+
rescue
|
66
|
+
debug_p remote_path + " is not found on remote!!"
|
67
|
+
return nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# return -> boolean :
|
72
|
+
def is_exist(remote_path)
|
73
|
+
begin
|
74
|
+
@sftp_session.stat!(remote_path) { |response|
|
75
|
+
#returns whether exists or not
|
76
|
+
next response.ok?
|
77
|
+
}
|
78
|
+
rescue => e
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def get_contents_remote(remote_filepath_str)
|
85
|
+
debug_p("get_contents_remote from #{remote_filepath_str}")
|
86
|
+
handle = @sftp_session.open!(remote_filepath_str)
|
87
|
+
contents = String.new()
|
88
|
+
offset = 0
|
89
|
+
while (data = @sftp_session.read!(handle, offset, BUFFER_SIZE)) != nil
|
90
|
+
contents += data
|
91
|
+
offset += BUFFER_SIZE
|
92
|
+
end
|
93
|
+
@sftp_session.close!(handle)
|
94
|
+
|
95
|
+
return contents
|
96
|
+
end
|
97
|
+
|
98
|
+
# over writes contens from the start
|
99
|
+
def write_contents_remote(remote_filepath_str,contents_str)
|
100
|
+
debug_p("write_contents_remote to #{remote_filepath_str}")
|
101
|
+
handle = @sftp_session.open!(remote_filepath_str,"w")
|
102
|
+
@sftp_session.write!(handle, 0, contents_str)
|
103
|
+
@sftp_session.close!(handle)
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require "thread"
|
2
|
+
require "#{LIBNAME}/ssh"
|
3
|
+
require "#{LIBNAME}/config"
|
4
|
+
require "#{LIBNAME}/util"
|
5
|
+
require "#{LIBNAME}/ext_string"
|
6
|
+
|
7
|
+
#module Machine
|
8
|
+
class MachineMaster
|
9
|
+
@@group = ThreadGroup.new
|
10
|
+
end
|
11
|
+
|
12
|
+
class Machine < MachineMaster
|
13
|
+
include Config
|
14
|
+
include FileIO
|
15
|
+
|
16
|
+
#fields
|
17
|
+
@user_name
|
18
|
+
@host
|
19
|
+
@ssh
|
20
|
+
@sftp_session
|
21
|
+
@password
|
22
|
+
@passphrase
|
23
|
+
@private_key_path
|
24
|
+
|
25
|
+
attr_reader :ssh
|
26
|
+
|
27
|
+
def initialize(host=nil)
|
28
|
+
if host == nil #substitute of constructor which has no argument
|
29
|
+
else
|
30
|
+
@host = host.to_s()
|
31
|
+
initialize()
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def cleanup
|
36
|
+
debug_p "start cleanup instance for " + @host
|
37
|
+
@sftp_session.close_channel()
|
38
|
+
@ssh.close()
|
39
|
+
debug_p "finished cleanup instance for " + @host
|
40
|
+
# @@group.list.each {|th| th.join }
|
41
|
+
end
|
42
|
+
|
43
|
+
# def set_auth_info(user_name)
|
44
|
+
# @user_name = user_name
|
45
|
+
# end
|
46
|
+
|
47
|
+
def set_auth_info(user_name,password = nil)
|
48
|
+
@user_name = user_name
|
49
|
+
@password = password
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_auth_info_pki(user_name,passphrase,private_key_path)
|
53
|
+
@user_name = user_name
|
54
|
+
@passphrase = passphrase
|
55
|
+
@private_key_path = private_key_path
|
56
|
+
end
|
57
|
+
|
58
|
+
def establish_session()
|
59
|
+
debug_p "start establish_session to " + @host
|
60
|
+
# Spawn worker threads
|
61
|
+
|
62
|
+
th = Thread.new do
|
63
|
+
debug_p "Initialization of Machine ##{@host} is started."
|
64
|
+
if @private_key_path
|
65
|
+
if @user_name && @passphrase
|
66
|
+
@ssh = SSH.new(@host,@user_name,@passphrase)
|
67
|
+
else
|
68
|
+
debug_p "please set user name and password when you want to use public key authentication"
|
69
|
+
exit()
|
70
|
+
end
|
71
|
+
elsif @user_name && @password
|
72
|
+
@ssh = SSH.new(@host,@user_name,@password)
|
73
|
+
elsif @user_name
|
74
|
+
@ssh = SSH.new(@userneme)
|
75
|
+
else
|
76
|
+
debug_p "please set user name at leaset"
|
77
|
+
exit()
|
78
|
+
end
|
79
|
+
debug_p "Initialization of Machine ##{@host} is finished."
|
80
|
+
|
81
|
+
@sftp_session = @ssh.sftp_session
|
82
|
+
@@group.add(th)
|
83
|
+
end
|
84
|
+
|
85
|
+
#wait until finishing initialize of @ssh object
|
86
|
+
while @ssh == nil
|
87
|
+
sleep(1)
|
88
|
+
end
|
89
|
+
|
90
|
+
debug_p "finished establish_session to " + @host
|
91
|
+
end
|
92
|
+
|
93
|
+
def exec(command_str)
|
94
|
+
return @ssh.exec(command_str)
|
95
|
+
end
|
96
|
+
|
97
|
+
def exec!(command_str,timeout = nil)
|
98
|
+
return @ssh.exec!(command_str,timeout)
|
99
|
+
end
|
100
|
+
|
101
|
+
# call exec!( command ) on specified path
|
102
|
+
# TODO: change function name to exec_on!
|
103
|
+
def exec_on!(command_str,current_path_str)
|
104
|
+
exec!("cd #{current_path_str};" + command_str)
|
105
|
+
end
|
106
|
+
|
107
|
+
# execute local script on remote
|
108
|
+
# current_path_str -> string: if change of directory is not needed, please pass "."
|
109
|
+
# use remote /tmp directory to store script file
|
110
|
+
# TODO: change function name to exec_script_on!
|
111
|
+
def exec_script_on(script_path_str,arguments_str,current_path_str)
|
112
|
+
fname_str = File.basename(script_path_str)
|
113
|
+
rempte_path_str = "/tmp/" + fname_str
|
114
|
+
push_a_file(script_path_str,rempte_path_str)
|
115
|
+
exec_on!("sh #{rempte_path_str} " + arguments_str,current_path_str)
|
116
|
+
end
|
117
|
+
|
118
|
+
def sftp()
|
119
|
+
return @ssh.sftp_session
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
#end
|