ruby-xen 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +6 -4
- data/README.rdoc +26 -20
- data/lib/ruby-xen.rb +60 -10
- data/lib/templates/domu.cfg.erb +1 -1
- data/lib/templates/exclude_from_backups +2 -0
- data/lib/templates/xen-tools.conf.erb +289 -0
- data/lib/xen/backup.rb +71 -33
- data/lib/xen/command.rb +94 -60
- data/lib/xen/config_file.rb +159 -0
- data/lib/xen/host.rb +59 -5
- data/lib/xen/instance.rb +53 -51
- data/lib/xen/lvm.rb +40 -0
- data/lib/xen/slice.rb +118 -65
- data/lib/xen/xen_tools_conf.rb +56 -0
- data/test/test_ruby-xen.rb +2 -2
- metadata +29 -7
- data/lib/xen/config.rb +0 -146
- data/lib/xen/image.rb +0 -12
data/lib/xen/instance.rb
CHANGED
@@ -1,66 +1,68 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module Xen
|
2
|
+
class Instance
|
3
|
+
include Xen::Parentable
|
4
|
+
attr_reader :name, :domid, :memory, :cpu_time, :vcpus, :state, :start_time
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
def initialize(options={})
|
7
|
+
@name = options[:name]
|
8
|
+
@domid = options[:domid]
|
9
|
+
@memory = options[:memory]
|
10
|
+
@cpu_time = options[:cpu_time]
|
11
|
+
@vcpus = options[:vcpus]
|
12
|
+
@state = options[:state]
|
13
|
+
@start_time = Time.at(options[:start_time].to_f) if options[:start_time]
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
def self.find(*args)
|
17
|
+
options = args.extract_options!
|
18
|
+
case args.first
|
19
|
+
when :all then all
|
20
|
+
else find_by_name(args.first)
|
21
|
+
end
|
20
22
|
end
|
21
|
-
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
def self.all
|
25
|
+
Xen::Command.detailed_instance_list.collect do |instance|
|
26
|
+
new(instance)
|
27
|
+
end
|
26
28
|
end
|
27
|
-
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
def self.find_by_name(name)
|
31
|
+
Xen::Command.detailed_instance_list(name).each do |instance|
|
32
|
+
return new(instance)
|
33
|
+
end
|
34
|
+
return false
|
32
35
|
end
|
33
|
-
return false
|
34
|
-
end
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def self.create(name)
|
38
|
+
output = Xen::Command.start_instance(name.to_s + Xen::CONFIG_FILE_EXTENSION)
|
39
|
+
$? == 0 ? true : false
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
def self.shutdown(name)
|
43
|
+
output = Xen::Command.shutdown_instance(name)
|
44
|
+
$? == 0 ? true : false
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
# A convenience wrapper for <tt>find(:dom0)</tt>.</tt>.
|
48
|
+
def self.dom0(*args)
|
49
|
+
find_by_name(:dom0)
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
def uptime
|
53
|
+
start_time ? Time.now - start_time : nil
|
54
|
+
end
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
def reboot
|
57
|
+
`xm reboot #{name}`
|
58
|
+
$? == 0 ? true : false
|
59
|
+
end
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
def destroy
|
62
|
+
end
|
62
63
|
|
63
|
-
|
64
|
-
|
64
|
+
def pause
|
65
|
+
end
|
65
66
|
|
66
|
-
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/xen/lvm.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'open4'
|
2
|
+
|
3
|
+
module Xen
|
4
|
+
|
5
|
+
class VolumeGroup
|
6
|
+
|
7
|
+
attr_reader :name, :size
|
8
|
+
|
9
|
+
def initialize(name, size)
|
10
|
+
@name = name
|
11
|
+
@size = size
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.find(name=nil)
|
15
|
+
name ||= nil
|
16
|
+
# XXX deal with not found error
|
17
|
+
cmd = "vgs --options=vg_name,vg_size --separator=' ' --noheadings --units=g --nosuffix #{name}"
|
18
|
+
begin
|
19
|
+
output = Xen::Command.run cmd
|
20
|
+
result = output.collect { |line|
|
21
|
+
name, size = line.strip.split(' ')
|
22
|
+
new name, size
|
23
|
+
}
|
24
|
+
rescue # don't die if `vgs` command missing
|
25
|
+
end
|
26
|
+
name ? result[0] : result
|
27
|
+
end
|
28
|
+
|
29
|
+
def free
|
30
|
+
cmd = "vgs --options=vg_free --separator=' ' --noheadings --units=g --nosuffix #{@name}"
|
31
|
+
begin
|
32
|
+
result = Xen::Command.run cmd
|
33
|
+
rescue # don't die if `vgs` command missing
|
34
|
+
end
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/xen/slice.rb
CHANGED
@@ -1,80 +1,133 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Xen
|
2
|
+
class Slice
|
3
|
+
attr_accessor :name, :image, :config_file, :backups
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
def self.find(*args)
|
6
|
+
options = args.extract_options!
|
7
|
+
case args.first
|
8
|
+
when :all then Xen::ConfigFile.find(:all, options).collect { |config_file| new :name => config_file.name }
|
9
|
+
when :running then Xen::Instance.find(:all, options).collect { |instance| new :name => instance.name }
|
10
|
+
# Retrieve a Slice by name
|
11
|
+
else Xen::ConfigFile.find_by_name(args.first) && new(:name => args.first)
|
12
|
+
end
|
11
13
|
end
|
12
|
-
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def self.all(options={})
|
16
|
+
self.find(:all, options)
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
def initialize(*args)
|
20
|
+
options = args.extract_options!
|
21
|
+
@name = options[:name]
|
22
|
+
@config_file = options[:config_file]
|
23
|
+
@instance = options[:instance]
|
24
|
+
@instance_cache_expires = Time.now
|
25
|
+
@backups = Array(options[:backups])
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
28
|
+
def create_image(*args)
|
29
|
+
options = args.extract_options!.stringify_keys
|
30
|
+
|
31
|
+
# Load default values for options that have not been set
|
32
|
+
options.reverse_merge! Xen::XenToolsConf.find.to_hash
|
33
|
+
|
34
|
+
# Set some derived options
|
35
|
+
options.reverse_merge! 'hostname' => name # Name host after this slice
|
36
|
+
options['dhcp'] = true unless options['ip']
|
37
|
+
options['swap'] ||= options['memory'].to_i * 2
|
38
|
+
if options['root_pass']
|
39
|
+
options['role'] = 'passwd'
|
40
|
+
options['role-args'] = options['root_pass']
|
41
|
+
end
|
42
|
+
unless [nil,''].include?(options['tarball'])
|
43
|
+
options['install-method'] = 'tar'
|
44
|
+
options['install-source'] = options['tarball']
|
45
|
+
options.delete('dist')
|
46
|
+
end
|
47
|
+
|
48
|
+
args = %w(hostname dist memory size
|
49
|
+
force boot
|
50
|
+
role role-args roledir
|
51
|
+
dir lvm mirror
|
52
|
+
ip mac netmask broadcast gateway dhcp
|
53
|
+
swap
|
54
|
+
accounts admins cache config fs image image-dev initrd
|
55
|
+
keep kernel modules output install hooks partitions
|
56
|
+
passwd tar-cmd extension swap-dev noswap ide arch
|
57
|
+
install-method install-source template evms)
|
58
|
+
# Remove options that are not in allowed argument list
|
59
|
+
options.keys.each { |key| options.delete(key) unless args.include?(key) }
|
60
|
+
|
61
|
+
Xen::Command.create_image(options)
|
41
62
|
end
|
42
|
-
|
63
|
+
|
64
|
+
# Cache Xen instance info to reduce system calls to xm command.
|
65
|
+
# It still needs to be checked regularly as operations like shutdown
|
66
|
+
# and create can take a while.
|
67
|
+
def instance
|
68
|
+
if @instance_cache_expires > Time.now
|
69
|
+
@instance
|
70
|
+
else
|
71
|
+
@instance_cache_expires = Time.now + Xen::INSTANCE_OBJECT_LIFETIME
|
72
|
+
@instance = Xen::Instance.find(@name) if @name
|
73
|
+
end
|
74
|
+
end
|
43
75
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
76
|
+
# XXX We're assuming other processes aren't going to edit config_files
|
77
|
+
# This is reasonable in simple cases.
|
78
|
+
def config_file
|
79
|
+
@config_file ||= Xen::ConfigFile.find(name) if @name
|
80
|
+
end
|
49
81
|
|
50
|
-
|
51
|
-
|
52
|
-
|
82
|
+
def backups
|
83
|
+
Xen::Backup.find(name)
|
84
|
+
end
|
85
|
+
|
86
|
+
def create_backup(options = {})
|
87
|
+
Xen::Backup.create(name, :options)
|
88
|
+
end
|
53
89
|
|
54
|
-
|
55
|
-
|
56
|
-
|
90
|
+
def state
|
91
|
+
self.instance ? :running : :stopped
|
92
|
+
end
|
57
93
|
|
58
|
-
|
59
|
-
|
60
|
-
|
94
|
+
def first_ip
|
95
|
+
config_file.vifs.first.ip if config_file and config_file.vifs
|
96
|
+
end
|
97
|
+
|
98
|
+
def running?
|
99
|
+
self.instance ? true : false
|
100
|
+
end
|
61
101
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
102
|
+
def start
|
103
|
+
Xen::Instance.create(@name)
|
104
|
+
@instance = Xen::Instance.find(@name)
|
105
|
+
end
|
66
106
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
107
|
+
def stop
|
108
|
+
Xen::Instance.shutdown(@name)
|
109
|
+
@instance = Xen::Instance.find(@name)
|
110
|
+
end
|
71
111
|
|
72
|
-
|
73
|
-
|
74
|
-
|
112
|
+
def config_file_newer_than_instance?
|
113
|
+
instance && config_file.updated_at > instance.start_time
|
114
|
+
end
|
75
115
|
|
76
|
-
|
77
|
-
|
78
|
-
|
116
|
+
def save
|
117
|
+
@config_file.save
|
118
|
+
end
|
119
|
+
|
120
|
+
def root_disk
|
121
|
+
config_file.vbds.detect { |vbd| vbd.name == "#{name}-disk" } unless config_file.nil?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Primary IP
|
125
|
+
def ip
|
126
|
+
config_file.vifs[0].ip
|
127
|
+
end
|
79
128
|
|
80
|
-
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Xen
|
2
|
+
# puts Xen::XenToolsConf.load.to_hash.inspect
|
3
|
+
|
4
|
+
class XenToolsConf
|
5
|
+
|
6
|
+
# XXX underscorize :install-method, install-source, copy_cmd, tar-cmd
|
7
|
+
attr_accessor :dir, :lvm, :install__method, :install__source, :copy_cmd,
|
8
|
+
:tar_cmd, :debootstrap__cmd, :size, :memory, :swap, :noswap,
|
9
|
+
:fs,
|
10
|
+
:dist, :image, :gateway,
|
11
|
+
:netmask, :broadcast, :dhcp, :cache, :passwd, :accounts,
|
12
|
+
:kernel, :initrd, :mirror, :ext3_options, :ext2_options,
|
13
|
+
:xfs_options, :reiser_options, :boot, :serial_device,
|
14
|
+
:disk_device, :output, :extension
|
15
|
+
|
16
|
+
def initialize(*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.find(file=nil)
|
20
|
+
file ||= Xen::XEN_TOOLS_CONFIG_FILE
|
21
|
+
xtc = new # Create a new XenToolsConf object
|
22
|
+
xtc.load_from_config_file(File.readlines(file))
|
23
|
+
xtc
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_from_config_file(file_contents)
|
27
|
+
file_contents.reject! { |line| line.match /^\s*#/ } # Ignore commented out lines
|
28
|
+
file_contents.grep(/(.*) = (.*)/).each { |setting|
|
29
|
+
setting.scan(/\s*(.+?)\s*=\s*([^#]+)/).each { |match|
|
30
|
+
key, val = match
|
31
|
+
instance_variable_set("@#{key.strip.underscorize}", val.strip)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_hash
|
37
|
+
self.instance_variables.inject({}) { |m, variable_name|
|
38
|
+
m[variable_name.sub('@','').ununderscorize] = instance_variable_get(variable_name); m
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_file
|
43
|
+
template = ERB.new(IO.read(File.join(TEMPLATES_BASE, 'xen-tools.conf.erb')))
|
44
|
+
template.result(binding)
|
45
|
+
end
|
46
|
+
|
47
|
+
def save(filename=nil)
|
48
|
+
filename ||= Xen::XEN_TOOLS_CONFIG_FILE
|
49
|
+
File.open(filename, 'w') do |f|
|
50
|
+
f.write(to_file)
|
51
|
+
end
|
52
|
+
# XXX check for errors
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/test/test_ruby-xen.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
require '../lib/ruby-xen'
|
2
|
-
c = Xen::
|
3
|
-
c.save
|
2
|
+
c = Xen::ConfigFile.new
|
3
|
+
c.save
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-xen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Bailey
|
@@ -10,10 +10,29 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2009-09-02 00:00:00 +10:00
|
14
14
|
default_executable:
|
15
|
-
dependencies:
|
16
|
-
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activesupport
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: open4
|
28
|
+
type: :runtime
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
version:
|
17
36
|
description: ruby-xen allows you to manage Xen virtual servers via Ruby. It currently wraps the command line tools provided by Xen (xm) as well as Steve Kemps excellent Xen-tools (http://www.xen-tools.org/software/xen-tools/).
|
18
37
|
email: mike@bailey.net.au
|
19
38
|
executables: []
|
@@ -34,12 +53,15 @@ files:
|
|
34
53
|
- test/test_ruby-xen.rb
|
35
54
|
- lib/xen/backup.rb
|
36
55
|
- lib/xen/command.rb
|
37
|
-
- lib/xen/
|
56
|
+
- lib/xen/config_file.rb
|
38
57
|
- lib/xen/host.rb
|
39
|
-
- lib/xen/image.rb
|
40
58
|
- lib/xen/instance.rb
|
59
|
+
- lib/xen/lvm.rb
|
41
60
|
- lib/xen/slice.rb
|
61
|
+
- lib/xen/xen_tools_conf.rb
|
42
62
|
- lib/templates/domu.cfg.erb
|
63
|
+
- lib/templates/exclude_from_backups
|
64
|
+
- lib/templates/xen-tools.conf.erb
|
43
65
|
has_rdoc: true
|
44
66
|
homepage: http://github.com/mbailey/ruby-xen
|
45
67
|
post_install_message:
|
@@ -63,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
85
|
requirements: []
|
64
86
|
|
65
87
|
rubyforge_project:
|
66
|
-
rubygems_version: 1.
|
88
|
+
rubygems_version: 1.3.1
|
67
89
|
signing_key:
|
68
90
|
specification_version: 2
|
69
91
|
summary: Ruby library for managing Xen virtual hosts
|