mbailey-ruby-xen 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +5 -0
- data/Manifest.txt +8 -0
- data/README.rdoc +7 -8
- data/Rakefile +8 -8
- data/lib/ruby-xen.rb +13 -7
- data/lib/templates/domu.cfg.erb +40 -0
- data/lib/xen/command.rb +27 -5
- data/lib/xen/config.rb +95 -8
- data/lib/xen/host.rb +3 -4
- data/lib/xen/instance.rb +9 -26
- data/lib/xen/{domain.rb → slice.rb} +12 -4
- data/test/test_ruby-xen.rb +3 -0
- metadata +4 -3
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
data/README.rdoc
CHANGED
@@ -25,13 +25,12 @@ ruby-xen can also be used by ruby code or from irb.
|
|
25
25
|
require 'rubygems'
|
26
26
|
require 'ruby-xen'
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
domain.running? # true
|
28
|
+
slice = Xen::Slice.find(:example)
|
29
|
+
slice.running? # true
|
30
|
+
slice.stop
|
31
|
+
slice.running? # false
|
32
|
+
slice.start
|
33
|
+
slice.running? # true
|
35
34
|
|
36
35
|
== REQUIREMENTS:
|
37
36
|
|
@@ -49,7 +48,7 @@ or open source applications. More details found here:
|
|
49
48
|
http://www.gnu.org/licenses/gpl.html
|
50
49
|
|
51
50
|
ruby-xen
|
52
|
-
Copyright (C) 2008 Mike Bailey and Nick
|
51
|
+
Copyright (C) 2008 Mike Bailey and Nick Marfleet
|
53
52
|
|
54
53
|
This program is free software; you can redistribute it and/or
|
55
54
|
modify it under the terms of the GNU General Public License
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
|
3
|
-
require 'rubygems'
|
4
|
-
require 'hoe'
|
5
|
-
require './lib/ruby-xen.rb'
|
6
|
-
|
7
|
-
Hoe.new('ruby-xen',
|
8
|
-
|
9
|
-
|
10
|
-
end
|
3
|
+
# require 'rubygems'
|
4
|
+
# require 'hoe'
|
5
|
+
# require './lib/ruby-xen.rb'
|
6
|
+
#
|
7
|
+
# Hoe.new('ruby-xen', Xen::VERSION) do |p|
|
8
|
+
# # p.rubyforge_name = 'ruby-xenx' # if different than lowercase project name
|
9
|
+
# p.developer('Mike Bailey', 'mike@bailey.net.au')
|
10
|
+
# end
|
11
11
|
|
12
12
|
# vim: syntax=Ruby
|
data/lib/ruby-xen.rb
CHANGED
@@ -23,18 +23,24 @@ module Xen
|
|
23
23
|
# the object expires.
|
24
24
|
INSTANCE_OBJECT_LIFETIME = 1
|
25
25
|
|
26
|
-
|
26
|
+
TEMPLATE_DIR = File.expand_path(File.dirname(__FILE__) + '/../lib/templates')
|
27
|
+
|
28
|
+
# Extension for Xen domU config files
|
29
|
+
CONFIG_FILE_EXTENSION = '.cfg'
|
30
|
+
|
31
|
+
# DRY up some classes (children of Slice) with some module funkiness.
|
27
32
|
module Parentable
|
28
|
-
# Returns the parent
|
33
|
+
# Returns the parent Slice object (d) for a sub-object.
|
29
34
|
# We ensure d.instance.object_id == self.object_id
|
30
35
|
#
|
31
36
|
# ==== Example
|
32
37
|
# i = Xen::Instance.all[2]
|
33
|
-
#
|
34
|
-
#
|
38
|
+
# s = i.slice
|
39
|
+
# i.object_id == s.instance.object_id # true
|
35
40
|
#
|
36
|
-
def
|
37
|
-
d = Xen::
|
41
|
+
def slice
|
42
|
+
d = Xen::Slice.new(name)
|
43
|
+
# Insert the current object into the newly created Slice's attributes
|
38
44
|
d.instance_variable_set("@#{self.class.to_s.sub('Xen::','').downcase}", self)
|
39
45
|
d
|
40
46
|
end
|
@@ -44,7 +50,7 @@ end
|
|
44
50
|
require "#{File.dirname(__FILE__)}/xen/backup"
|
45
51
|
require "#{File.dirname(__FILE__)}/xen/command"
|
46
52
|
require "#{File.dirname(__FILE__)}/xen/config"
|
47
|
-
require "#{File.dirname(__FILE__)}/xen/
|
53
|
+
require "#{File.dirname(__FILE__)}/xen/slice"
|
48
54
|
require "#{File.dirname(__FILE__)}/xen/host"
|
49
55
|
require "#{File.dirname(__FILE__)}/xen/image"
|
50
56
|
require "#{File.dirname(__FILE__)}/xen/instance"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#
|
2
|
+
# Configuration file for the Xen instance <%= name %>, created
|
3
|
+
# by ruby-xen on <%= Time.now %>.
|
4
|
+
#
|
5
|
+
|
6
|
+
#
|
7
|
+
# Kernel + memory size
|
8
|
+
#
|
9
|
+
kernel = '<%= kernel %>'
|
10
|
+
ramdisk = '<%= ramdisk %>'
|
11
|
+
memory = '<%= memory %>'
|
12
|
+
|
13
|
+
#
|
14
|
+
# Disk device(s).
|
15
|
+
#
|
16
|
+
root = '<%= root %>'
|
17
|
+
disk = [
|
18
|
+
'<%= Array(vbds).collect{|d| d.to_str}.join("',\n\t'") %>'
|
19
|
+
]
|
20
|
+
|
21
|
+
#
|
22
|
+
# Hostname
|
23
|
+
#
|
24
|
+
name = '<%= name %>'
|
25
|
+
|
26
|
+
#
|
27
|
+
# Networking
|
28
|
+
#
|
29
|
+
vif = [
|
30
|
+
'<%= Array(vifs).collect{|v| v.to_str}.join("',\n\t'") %>'
|
31
|
+
]
|
32
|
+
|
33
|
+
#
|
34
|
+
# Behaviour
|
35
|
+
#
|
36
|
+
on_poweroff = '<%= on_poweroff %>'
|
37
|
+
on_reboot = '<%= on_reboot %>'
|
38
|
+
on_crash = '<%= on_crash %>'
|
39
|
+
|
40
|
+
extra = '<%= extra %>'
|
data/lib/xen/command.rb
CHANGED
@@ -1,8 +1,30 @@
|
|
1
1
|
class Xen::Command
|
2
|
-
def self.xm_list
|
3
|
-
|
2
|
+
# def self.xm_list
|
3
|
+
# raw = `xm list`.scan(/(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/)
|
4
|
+
# headers = raw.delete_at(0)
|
5
|
+
# raw.map do |row|
|
6
|
+
# headers.enum_with_index.inject({}) { |m, (head, i)| m[head] = row[i]; m }
|
7
|
+
# end
|
8
|
+
# end
|
9
|
+
|
10
|
+
def self.detailed_instance_list(name='')
|
11
|
+
raw_entries = `xm list --long #{name}`.split(/\n\(domain/)
|
12
|
+
raw_entries.collect do |entry|
|
13
|
+
attributes = entry.scan(/\((name|domid|memory|vcpus|state|cpu_time|start_time) (.*)\)/)
|
14
|
+
attributes.inject({}) { |m, (key, val)| m[key.to_sym] = val; m }
|
15
|
+
end
|
4
16
|
end
|
17
|
+
|
18
|
+
def self.create(config_file)
|
19
|
+
`xm create #{config_file}`
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.shutdown(name, blocking=false)
|
23
|
+
`xm shutdown #{'-w' if blocking} #{name}`
|
24
|
+
end
|
25
|
+
|
5
26
|
def self.xm_info
|
6
|
-
`xm info`
|
7
|
-
|
8
|
-
end
|
27
|
+
result = `xm info`
|
28
|
+
result.scan(/(\S+)\s*:\s*([^\n]+)/).inject({}){ |m, (i,j)| m[i.to_sym] = j; m }
|
29
|
+
end
|
30
|
+
end
|
data/lib/xen/config.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
1
3
|
# The Xen config files on disk
|
2
4
|
class Xen::Config
|
3
5
|
include Xen::Parentable
|
4
|
-
attr_accessor :name, :kernel, :ramdisk, :memory, :root, :
|
6
|
+
attr_accessor :name, :kernel, :ramdisk, :memory, :root, :vbds, :vifs, :on_poweroff, :on_reboot, :on_crash, :extra
|
5
7
|
|
6
8
|
def initialize(*args)
|
7
9
|
options = args.extract_options!
|
@@ -10,8 +12,8 @@ class Xen::Config
|
|
10
12
|
@ramdisk = options[:ramdisk]
|
11
13
|
@memory = options[:memory]
|
12
14
|
@root = options[:root]
|
13
|
-
@
|
14
|
-
@
|
15
|
+
@vbds = options[:vbds]
|
16
|
+
@vifs = options[:vifs]
|
15
17
|
@on_poweroff = options[:on_poweroff]
|
16
18
|
@on_reboot = options[:on_reboot]
|
17
19
|
@on_crash = options[:on_crash]
|
@@ -27,7 +29,7 @@ class Xen::Config
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def self.all
|
30
|
-
config_files = Dir.glob("#{Xen::XEN_DOMU_CONFIG_DIR}
|
32
|
+
config_files = Dir.glob("#{Xen::XEN_DOMU_CONFIG_DIR}/*#{Xen::CONFIG_FILE_EXTENSION}")
|
31
33
|
config_files.collect do |filename|
|
32
34
|
create_from_config_file(File.read(filename))
|
33
35
|
end
|
@@ -35,18 +37,103 @@ class Xen::Config
|
|
35
37
|
|
36
38
|
def self.find_by_name(name)
|
37
39
|
return new('Domain-0') if name == 'Domain-0'
|
38
|
-
filename = "#{Xen::XEN_DOMU_CONFIG_DIR}/#{name}
|
40
|
+
filename = "#{Xen::XEN_DOMU_CONFIG_DIR}/#{name}#{Xen::CONFIG_FILE_EXTENSION}"
|
39
41
|
create_from_config_file(File.read(filename))
|
40
42
|
end
|
43
|
+
|
44
|
+
def config_file
|
45
|
+
"#{Xen::XEN_DOMU_CONFIG_DIR}/#{name}#{Xen::CONFIG_FILE_EXTENSION}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def auto_file
|
49
|
+
"#{Xen::XEN_DOMU_CONFIG_DIR}/auto/#{name}#{Xen::CONFIG_FILE_EXTENSION}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def updated_at
|
53
|
+
File.mtime(config_file)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Set to true|false to enable|disable autostart of slice
|
57
|
+
def auto=(value)
|
58
|
+
filename = File.basename(config_file)
|
59
|
+
if value == true
|
60
|
+
File.symlink("../#{filename}", auto_file)
|
61
|
+
else
|
62
|
+
File.unlink(auto_file)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns true|false depending on whether slice is set to start automatically
|
67
|
+
def auto
|
68
|
+
File.symlink?(auto_file) && File.expand_path(File.readlink(auto_file), File.dirname(auto_file)) == config_file
|
69
|
+
end
|
41
70
|
|
42
71
|
def self.create_from_config_file(config)
|
43
72
|
name, kernel, ramdisk, memory, root, disk, vif, on_poweroff, on_reboot, on_crash, extra = nil
|
44
73
|
eval(config)
|
45
|
-
|
74
|
+
vifs = Array(vif).collect { |v| Xen::Vif.from_str(v) }
|
75
|
+
vbds = Array(disk).collect { |d| Xen::Vbd.from_str(d) }
|
76
|
+
new(name, :disk => disk, :kernel => kernel, :ramdisk => ramdisk, :memory => memory, :root => root, :vbds => vbds, :vifs => vifs, :on_poweroff => on_poweroff, :on_reboot => on_reboot, :on_crash => on_crash, :extra => extra)
|
46
77
|
end
|
47
78
|
|
48
79
|
def save
|
49
|
-
|
80
|
+
template = ERB.new IO.read(Xen::TEMPLATE_DIR + '/domu.cfg.erb')
|
81
|
+
File.open(config_file, 'w'){ |f| f.write template.result(binding) }
|
50
82
|
end
|
51
83
|
|
52
|
-
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Virtual Network Interface
|
88
|
+
#
|
89
|
+
# http://wiki.xensource.com/xenwiki/XenNetworking
|
90
|
+
#
|
91
|
+
class Xen::Vif
|
92
|
+
attr_accessor :ip, :mac, :bridge, :vifname
|
93
|
+
def initialize(*args)
|
94
|
+
options = args.extract_options!
|
95
|
+
@ip = options[:ip]
|
96
|
+
@mac = options[:mac]
|
97
|
+
@bridge = options[:bridge]
|
98
|
+
@vifname = options[:vifname]
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.from_str(value)
|
102
|
+
options = value.scan(/(\w+)=([^,]+)/).inject({}){ |m, (k, v)| m[k.to_sym] = v; m }
|
103
|
+
new(options)
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_str
|
107
|
+
%w(ip mac bridge vifname).collect { |key|
|
108
|
+
"#{key}=#{instance_variable_get('@' + key)}" if !instance_variable_get('@'+key).nil?
|
109
|
+
}.compact.join(',')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# Virtual Network Interface
|
115
|
+
#
|
116
|
+
# http://wiki.xensource.com/xenwiki/XenStorage
|
117
|
+
#
|
118
|
+
# == Example
|
119
|
+
#
|
120
|
+
# disk = [ 'phy:xendisks/example-disk,sda1,w',
|
121
|
+
# 'phy:xendisks/example-swap,sda2,w',
|
122
|
+
# 'phy:assets/example-assets,sdb1,w' ]
|
123
|
+
class Xen::Vbd
|
124
|
+
attr_accessor :dom0, :domu, :mode
|
125
|
+
def initialize(dom0, domu, mode='w')
|
126
|
+
@dom0, @domu, @mode = dom0, domu, mode
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.from_str(value)
|
130
|
+
dom0, domu, mode = value.split(',')
|
131
|
+
new(dom0, domu, mode)
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_str
|
135
|
+
"#{dom0},#{domu},#{mode}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
data/lib/xen/host.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
class Xen::Host
|
2
2
|
attr_reader :host, :machine, :total_memory, :free_memory
|
3
|
-
|
3
|
+
|
4
4
|
def initialize
|
5
|
-
|
6
|
-
result.scan(/(\S+)\s*:\s*([^\n]+)/).each do |i,j|
|
5
|
+
Xen::Command.xm_info.each do |i,j|
|
7
6
|
instance_variable_set("@#{i}", j)
|
8
7
|
end
|
9
8
|
end
|
10
|
-
end
|
9
|
+
end
|
data/lib/xen/instance.rb
CHANGED
@@ -9,7 +9,7 @@ class Xen::Instance
|
|
9
9
|
@cpu_time = options[:cpu_time]
|
10
10
|
@vcpus = options[:vcpus]
|
11
11
|
@state = options[:state]
|
12
|
-
@start_time = options[:start_time]
|
12
|
+
@start_time = Time.at(options[:start_time].to_f) if options[:start_time]
|
13
13
|
@object_expires = Time.now + Xen::INSTANCE_OBJECT_LIFETIME
|
14
14
|
end
|
15
15
|
|
@@ -22,37 +22,25 @@ class Xen::Instance
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.all
|
25
|
-
|
26
|
-
|
27
|
-
result_array = result.split("\n")
|
28
|
-
result_array.shift
|
29
|
-
result_array.collect do |domain|
|
30
|
-
name, domid, memory, vcpus, state, cpu_time = domain.scan(/[^ ,]+/)
|
31
|
-
new(name, :domid => domid, :memory => memory, :cpu_time => cpu_time)
|
25
|
+
Xen::Command.detailed_instance_list.collect do |instance|
|
26
|
+
new(name, instance)
|
32
27
|
end
|
33
28
|
end
|
34
29
|
|
35
30
|
def self.find_by_name(name)
|
36
|
-
|
31
|
+
Xen::Command.detailed_instance_list(name).each do |instance|
|
32
|
+
return new(name, instance)
|
33
|
+
end
|
34
|
+
return false
|
37
35
|
end
|
38
36
|
|
39
|
-
# XXX Rails version - we need some error checking!
|
40
|
-
#
|
41
|
-
# def self.find_by_name(name, options)
|
42
|
-
# if result = find_every(options)
|
43
|
-
# result.detect{ |domain| domain.name == name }
|
44
|
-
# else
|
45
|
-
# raise RecordNotFound, "Couldn't find domain with name=#{name}"
|
46
|
-
# end
|
47
|
-
# end
|
48
|
-
|
49
37
|
def self.create(name)
|
50
|
-
output =
|
38
|
+
output = Xen::Command.create(name.to_s + Xen::CONFIG_FILE_EXTENSION)
|
51
39
|
$? == 0 ? true : false
|
52
40
|
end
|
53
41
|
|
54
42
|
def self.shutdown(name)
|
55
|
-
output =
|
43
|
+
output = Xen::Command.shutdown(name)
|
56
44
|
$? == 0 ? true : false
|
57
45
|
end
|
58
46
|
|
@@ -65,11 +53,6 @@ class Xen::Instance
|
|
65
53
|
start_time ? Time.now - start_time : nil
|
66
54
|
end
|
67
55
|
|
68
|
-
def running?
|
69
|
-
output = `xm list #{name}`
|
70
|
-
$? == 0 ? true : false
|
71
|
-
end
|
72
|
-
|
73
56
|
def reboot
|
74
57
|
`xm reboot #{name}`
|
75
58
|
$? == 0 ? true : false
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Xen::
|
1
|
+
class Xen::Slice
|
2
2
|
attr_accessor :name, :image, :config
|
3
3
|
|
4
4
|
def initialize(name)
|
@@ -19,9 +19,9 @@ class Xen::Domain
|
|
19
19
|
def self.find(*args)
|
20
20
|
options = args.extract_options!
|
21
21
|
case args.first
|
22
|
-
when :all then Xen::Config.find(:all, options).collect { |config| config.
|
23
|
-
when :running then Xen::Instance.find(:all, options).collect { |instance| instance.
|
24
|
-
# Retrieve a
|
22
|
+
when :all then Xen::Config.find(:all, options).collect { |config| config.slice }
|
23
|
+
when :running then Xen::Instance.find(:all, options).collect { |instance| instance.slice }
|
24
|
+
# Retrieve a Slice by name
|
25
25
|
else Xen::Config.find_by_name(args.first) && self.new(args.first)
|
26
26
|
end
|
27
27
|
end
|
@@ -30,6 +30,10 @@ class Xen::Domain
|
|
30
30
|
self.find(:all, options)
|
31
31
|
end
|
32
32
|
|
33
|
+
def state
|
34
|
+
self.instance ? :running : :stopped
|
35
|
+
end
|
36
|
+
|
33
37
|
def running?
|
34
38
|
self.instance ? true : false
|
35
39
|
end
|
@@ -44,4 +48,8 @@ class Xen::Domain
|
|
44
48
|
@instance = Xen::Instance.find(@name)
|
45
49
|
end
|
46
50
|
|
51
|
+
def config_newer_than_instance?
|
52
|
+
instance && config.updated_at > instance.start_time
|
53
|
+
end
|
54
|
+
|
47
55
|
end
|
data/test/test_ruby-xen.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mbailey-ruby-xen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Bailey
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2008-09-
|
13
|
+
date: 2008-09-11 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -35,10 +35,11 @@ files:
|
|
35
35
|
- lib/xen/backup.rb
|
36
36
|
- lib/xen/command.rb
|
37
37
|
- lib/xen/config.rb
|
38
|
-
- lib/xen/
|
38
|
+
- lib/xen/slice.rb
|
39
39
|
- lib/xen/host.rb
|
40
40
|
- lib/xen/image.rb
|
41
41
|
- lib/xen/instance.rb
|
42
|
+
- lib/templates/domu.cfg.erb
|
42
43
|
has_rdoc: true
|
43
44
|
homepage: http://github.com/schacon/grit
|
44
45
|
post_install_message:
|