xen-ruby 0.7

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,74 @@
1
+ A simple ruby module to admin xen instances
2
+ This gem includes a log mechanism (log4r) with various modes (DEBUG, INFO, WARN ...).
3
+
4
+
5
+ How to use it :
6
+
7
+ ###########################
8
+ # To get instance informations
9
+ instance = Xen::Instance.find_by_name(name)
10
+
11
+ # To get all instaces
12
+ puts Xen::Instance.all
13
+
14
+ ###########################
15
+ # To start an instance
16
+
17
+ instance.start(name)
18
+
19
+ # or
20
+ instance = Xen::Instance.find_by_name(name)
21
+ instance.start
22
+
23
+ # or
24
+ instance = Xen::Instance.new(name)
25
+ instance.start
26
+
27
+ ###########################
28
+ # To create a new instance
29
+ # attributes includes {:mem => "", :size => "", :name => "", :ip => "", :vcpus: => "",
30
+ # :arch => "", :dist => ""}
31
+ # mem = Memory
32
+ # size = HDD size
33
+ # name = Hostname
34
+ # ip = Ip address
35
+ # vcpus = Virtual cpu's
36
+ # arch = System architecture [i386|amd64]
37
+ # dist = distribution [lucid, hardy, etc.]
38
+ Xen::Instance.create(attributes)
39
+
40
+ ##########################
41
+ # Instance actions
42
+ instance = Xen::Instance.find_by_name(name)
43
+
44
+ # start
45
+ instance.start
46
+
47
+ # stop
48
+ instance.shutdown
49
+
50
+ # reboot
51
+ instance.reboot
52
+
53
+ # pause
54
+ instance.pause
55
+
56
+ # unpause
57
+ instance.unpause
58
+
59
+ # kill
60
+ instance.destroy
61
+
62
+
63
+
64
+ ##################################
65
+ Creating & installing the gem :
66
+
67
+ gem build xen.gemspec
68
+ sudo gem install xen-<version>.gem
69
+
70
+
71
+ todo:
72
+ - Xen::Instance.create have a small bug (timeout)
73
+ - Tests
74
+
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
15
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.name = "xen-ruby"
17
+ gem.homepage = "http://github.com/foexle/ruby-xen"
18
+ gem.license = "GPL"
19
+ gem.summary = %Q{simple gem to controle xen dom0}
20
+ gem.description = %Q{simple gem to controle xen dom0}
21
+ gem.email = "kraemer@avarteq.de"
22
+ gem.authors = ["Heiko Krämer","Clemens Kofler"]
23
+ gem.version = "#{version}"
24
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
25
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
26
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
27
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
28
+ end
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ require 'rake/testtask'
32
+ Rake::TestTask.new(:test) do |test|
33
+ test.libs << 'lib' << 'test'
34
+ test.pattern = 'test/**/test_*.rb'
35
+ test.verbose = true
36
+ end
37
+
38
+ require 'rcov/rcovtask'
39
+ Rcov::RcovTask.new do |test|
40
+ test.libs << 'test'
41
+ test.pattern = 'test/**/test_*.rb'
42
+ test.verbose = true
43
+ end
44
+
45
+ task :default => :test
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : "0.7"
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "xen-ruby #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.7
data/lib/log/logger.rb ADDED
@@ -0,0 +1,53 @@
1
+ require 'log4r'
2
+
3
+ module Log
4
+ # Singleton Class to logging debugging and error states in logfile
5
+ class Logger
6
+ attr_accessor :log
7
+
8
+
9
+ # Check if exists a logging class. If not i'll be create
10
+ # ==Params
11
+ # * +filename+ : Path and filename of logdatei
12
+ # * +log_level+ : Which loglevel are using
13
+ def self.log(options = {:log_level => 1}, filename = "/tmp/xen-gem.log")
14
+ if @log
15
+ return @log
16
+ else
17
+ initialize_logger(filename, options[:log_level])
18
+ return @log
19
+ end
20
+ end
21
+
22
+ # Initializing and configuring the logger object
23
+ def self.initialize_logger(file_name, log_level)
24
+ @log = Log4r::Logger.new("xen_log")
25
+
26
+ @log.outputters = Log4r::Outputter.stdout
27
+
28
+ file = Log4r::FileOutputter.new('fileOutputter', :filename => file_name, :trunc => true)
29
+
30
+
31
+ @log.add(file)
32
+ @log.level = self.convert_loglevel(log_level)
33
+ format = Log4r::PatternFormatter.new(:pattern => "[%l] %d :: %m")
34
+ file.formatter = format
35
+ end
36
+
37
+ private
38
+
39
+ # Converting loglevel configurations for log4r
40
+ def self.convert_loglevel(log_level)
41
+ case log_level
42
+ when 1
43
+ return Log4r::DEBUG
44
+ when 2
45
+ return Log4r::INFO
46
+ when 3
47
+ return Log4r::ERROR
48
+ else
49
+ return Log4r::INFO
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,50 @@
1
+ require 'log/logger'
2
+
3
+ module System
4
+ class Command
5
+ LEVEL_WARN = 1
6
+ LEVEL_FATAL = 2
7
+
8
+ attr_reader :command, :expected_exit_status, :message, :command_level, :output, :exit_status
9
+
10
+ class << self
11
+ def logger
12
+ @@logger ||= Log::Logger.log
13
+ end
14
+ end
15
+
16
+ def initialize(command, options = {})
17
+ @command = command
18
+ @expected_exit = options[:expected_exit_status] || 0
19
+ @message = options[:message] unless options[:message].nil? || options[:message].empty?
20
+ @command_level = options[:command_level] || LEVEL_WARN
21
+ end
22
+
23
+ def execute
24
+ @output = `#{command} 2>&1`
25
+ @exit_status = $?.exitstatus
26
+ log if error?
27
+ end
28
+
29
+ def error?
30
+ ![0, expected_exit_status].include?(exit_status)
31
+ end
32
+
33
+ def error_message
34
+ message || output
35
+ end
36
+
37
+ def log
38
+ case @command_level
39
+ when LEVEL_WARN: logger.warn(error_message)
40
+ when LEVEL_FATAL: logger.fatal(error_message)
41
+ end
42
+ end
43
+
44
+ def logger
45
+ self.class.logger
46
+ end
47
+
48
+
49
+ end
50
+ end
@@ -0,0 +1,194 @@
1
+ require 'log/logger'
2
+ require 'system/command'
3
+ require 'xen/server'
4
+ require 'xen/util'
5
+
6
+ # TODO extract sudo to be used as an option
7
+ module Xen
8
+ class Instance
9
+ STATE_RUNNING = 'r'
10
+ STATE_BLOCKED = 'b'
11
+ STATE_SHUTDOWN = 's'
12
+ STATE_CRASHED = 'c'
13
+ STATE_DYING = 'd'
14
+ STATE_PAUSED = 'p'
15
+
16
+ attr_accessor :dom_id, :name, :memory, :vcpus, :state, :time
17
+
18
+ class << self
19
+
20
+ # Gets all running instances on dom0
21
+ def all
22
+ get_all = System::Command.new("sudo xm list" , :command_level => 1)
23
+ get_all.execute
24
+ return [] unless get_all.exit_status == 0
25
+
26
+ instances_from_output(get_all.output)
27
+ end
28
+
29
+ # Gets an instance object
30
+ # ==Params:
31
+ # => +name+: Name of instance
32
+ def find_by_name(name)
33
+ find = System::Command.new("sudo xm list #{name}", :command_level => 1)
34
+ find.execute
35
+ instance_from_output(find.output.split("\n").last)
36
+ end
37
+ alias :[] :find_by_name
38
+
39
+ # Gets all attributs of an instance
40
+
41
+ def find_attributes_by_name(name)
42
+ find = System::Command.new("sudo xm list #{name}", :command_level => 1)
43
+ find.execute
44
+ attributes_from_output(find.output)
45
+ end
46
+
47
+ # Vars = :id, :name, :memory, :hdd, :cpus, :status
48
+ # Note: debootstrap installation is the slowest, better are copy in xen
49
+ def create(attributes = {})
50
+ logger.info("Creating new Xen instance with name #{attributes[:name]} ...")
51
+
52
+ exist_instance = find_by_name(attributes[:name])
53
+ if exist_instance
54
+ Logger.info("Running instance detected. Shutting down to create a new one")
55
+ exist_instance.shutdown
56
+ end
57
+
58
+ password = Xen::Util.generate_root_password
59
+
60
+ if password.exit_status == 0
61
+ command = <<-cmd.split("\n").map { |l| l.strip }.join(' ').squeeze(' ')
62
+ sudo xen-create-image --hostname=#{attributes[:name]} --ip=#{attributes[:ip]} --password=#{password[:stdout].strip}
63
+ --vcpus=#{attributes[:vcpus]} --memory=#{attributes[:memory]} --size=#{attributes[:size]}
64
+ --arch=#{attributes[:arch]} --dist=#{attributes[:dist]} --force &
65
+ cmd
66
+
67
+ create_image = System::Command.new(command, :command_level => 2)
68
+ create_image.execute
69
+ attributes.merge(:password => password.output.strip)
70
+ end
71
+ end
72
+
73
+ def start(name)
74
+ instance = new(name)
75
+ instance.start
76
+ return instance
77
+ end
78
+
79
+ def instances_from_output(output)
80
+ output.split("\n")[1..-1].map do |line|
81
+ instance_from_output(line)
82
+ end
83
+ end
84
+
85
+ def instance_from_output(output)
86
+ logger.debug("Finding #{output} ...")
87
+
88
+ attributes = attributes_from_output(output)
89
+ return unless attributes
90
+
91
+ Instance.new(attributes[:name], attributes) #:time => $6.strip)
92
+ end
93
+
94
+ def attributes_from_output(output)
95
+ return unless output.match(/(.*)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.*?)\s+(\d+.\d)/)
96
+
97
+ { :name => $1.strip, :dom_id => $2.strip, :memory => $3.strip, :vcpus => $4.strip, :state => $5.strip.gsub("-","") }
98
+ end
99
+
100
+ def logger
101
+ @@logger ||= Log::Logger.log(:log_level => Xen::Server::LOG_LEVEL)
102
+ end
103
+ end
104
+
105
+
106
+
107
+
108
+
109
+ def initialize(name, options = {})
110
+ @name = name
111
+ @memory, @dom_id, @vcpus, @state, @time = options.values_at(:memory, :dom_id, :vcpus, :state, :time)
112
+ end
113
+
114
+ def start
115
+ start = System::Command.new("sudo xm create #{name}.cfg", :command_level => 2)
116
+ start.execute
117
+ update_info
118
+ end
119
+
120
+
121
+ def reboot
122
+ reboot = System::Command.new("sudo xm reboot #{dom_id}", :command_level => 2)
123
+ reboot.execute
124
+ end
125
+
126
+ def shutdown
127
+ shutdown = System::Command.new("sudo xm shutdown #{dom_id}", :command_level => 2)
128
+ shutdown.execute
129
+ end
130
+
131
+ def migrate(destination)
132
+ migrate = System::Command.new("sudo xm migrate --live #{name} #{destination}", :command_level => 2)
133
+ migrate.execute
134
+ end
135
+
136
+ def destroy
137
+ destroy = System::Command.new("sudo xm destroy #{dom_id}", :command_level => 1)
138
+ destroy.execute
139
+ end
140
+
141
+ def pause
142
+ unless paused?
143
+ pause = System::Command.new("sudo xm pause #{dom_id}", :command_level => 1)
144
+ pause.execute
145
+ end
146
+ end
147
+
148
+ def unpause
149
+ if paused?
150
+ unpause = System::Command.new("sudo xm unpause #{dom_id}", :command_level => 1)
151
+ unpause.execute
152
+ end
153
+ end
154
+
155
+ def state_text
156
+ case state
157
+ when STATE_RUNNING: 'running'
158
+ when STATE_BLOCKED: 'blocked'
159
+ when STATE_SHUTDOWN: 'shutdown'
160
+ when STATE_CRASHED: 'crashed'
161
+ when STATE_DYING: 'dying'
162
+ when STATE_PAUSED: 'paused'
163
+ end
164
+ end
165
+
166
+ def running?
167
+ state == STATE_RUNNING
168
+ end
169
+
170
+ def blocked?
171
+ state == STATE_BLOCKED
172
+ end
173
+
174
+ def shutdown?
175
+ state == STATE_SHUTDOWN
176
+ end
177
+
178
+ def crashed?
179
+ state == STATE_CRASHED
180
+ end
181
+
182
+ def dying?
183
+ state == STATE_DYING
184
+ end
185
+
186
+ def paused?
187
+ state == STATE_PAUSED
188
+ end
189
+
190
+ def update_info
191
+ @memory, @dom_id, @vcpus, @state, @time = self.class.find_attributes_by_name(name).values_at(:memory, :dom_id, :vcpus, :state, :time)
192
+ end
193
+ end
194
+ end
data/lib/xen/server.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'xen/instance'
2
+ require 'log/logger'
3
+ require 'system/command'
4
+
5
+ module Xen
6
+ class Server
7
+ # Loglevel
8
+ # => 1 DEBUG
9
+ # => 2 Info
10
+ # => 3 Warning
11
+ # => 4 Critcal
12
+ LOG_LEVEL = 1
13
+
14
+ class << self
15
+ def logger
16
+ @@logger ||= Log::Logger.log(:log_level => LOG_LEVEL)
17
+ end
18
+ end
19
+
20
+ def initialize
21
+ end
22
+
23
+ def instances
24
+ Xen::Instance.all
25
+ end
26
+
27
+
28
+ def logger
29
+ self.class.logger
30
+ end
31
+ end
32
+ end
data/lib/xen/util.rb ADDED
@@ -0,0 +1,10 @@
1
+ module Xen
2
+ module Util
3
+ class << self
4
+ def generate_root_password
5
+ pwgen = System::Command.new("pwgen 16 1", :command_level => 1)
6
+ return pwgen.execute
7
+ end
8
+ end
9
+ end
10
+ end
data/ruby-xen.gemspec ADDED
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ruby-xen}
8
+ s.version = "0.7"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Heiko Kr\303\244mer", "Clemens Kofler"]
12
+ s.date = %q{2011-04-12}
13
+ s.description = %q{simple gem to controle xen dom0}
14
+ s.email = %q{kraemer@avarteq.de}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README"
18
+ ]
19
+ s.files = [
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "LICENSE",
23
+ "README",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/log/logger.rb",
27
+ "lib/system/command.rb",
28
+ "lib/xen/instance.rb",
29
+ "lib/xen/server.rb",
30
+ "lib/xen/util.rb",
31
+ "ruby-xen.gemspec"
32
+ ]
33
+ s.homepage = %q{http://github.com/foexle/ruby-xen}
34
+ s.licenses = ["GPL"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.7.2}
37
+ s.summary = %q{simple gem to controle xen dom0}
38
+
39
+ if s.respond_to? :specification_version then
40
+ s.specification_version = 3
41
+
42
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
+ s.add_runtime_dependency(%q<log4r>, [">= 0"])
44
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
45
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
46
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
47
+ s.add_development_dependency(%q<rcov>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<log4r>, [">= 0"])
50
+ s.add_dependency(%q<shoulda>, [">= 0"])
51
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
52
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
53
+ s.add_dependency(%q<rcov>, [">= 0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<log4r>, [">= 0"])
57
+ s.add_dependency(%q<shoulda>, [">= 0"])
58
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
59
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
60
+ s.add_dependency(%q<rcov>, [">= 0"])
61
+ end
62
+ end
63
+
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xen-ruby
3
+ version: !ruby/object:Gem::Version
4
+ hash: 5
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 7
9
+ version: "0.7"
10
+ platform: ruby
11
+ authors:
12
+ - "Heiko Kr\xC3\xA4mer"
13
+ - Clemens Kofler
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-12 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ hash: 3
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ name: log4r
31
+ prerelease: false
32
+ type: :runtime
33
+ requirement: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ version_requirements: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ hash: 3
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ name: shoulda
45
+ prerelease: false
46
+ type: :development
47
+ requirement: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ version_requirements: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ hash: 23
55
+ segments:
56
+ - 1
57
+ - 0
58
+ - 0
59
+ version: 1.0.0
60
+ name: bundler
61
+ prerelease: false
62
+ type: :development
63
+ requirement: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ version_requirements: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ hash: 7
71
+ segments:
72
+ - 1
73
+ - 5
74
+ - 2
75
+ version: 1.5.2
76
+ name: jeweler
77
+ prerelease: false
78
+ type: :development
79
+ requirement: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ version_requirements: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ name: rcov
91
+ prerelease: false
92
+ type: :development
93
+ requirement: *id005
94
+ description: simple gem to controle xen dom0
95
+ email: kraemer@avarteq.de
96
+ executables: []
97
+
98
+ extensions: []
99
+
100
+ extra_rdoc_files:
101
+ - LICENSE
102
+ - README
103
+ files:
104
+ - Gemfile
105
+ - Gemfile.lock
106
+ - LICENSE
107
+ - README
108
+ - Rakefile
109
+ - VERSION
110
+ - lib/log/logger.rb
111
+ - lib/system/command.rb
112
+ - lib/xen/instance.rb
113
+ - lib/xen/server.rb
114
+ - lib/xen/util.rb
115
+ - ruby-xen.gemspec
116
+ homepage: http://github.com/foexle/ruby-xen
117
+ licenses:
118
+ - GPL
119
+ post_install_message:
120
+ rdoc_options: []
121
+
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: 3
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ hash: 3
139
+ segments:
140
+ - 0
141
+ version: "0"
142
+ requirements: []
143
+
144
+ rubyforge_project:
145
+ rubygems_version: 1.7.2
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: simple gem to controle xen dom0
149
+ test_files: []
150
+