ruby-xen 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,13 @@
1
+ === 0.0.3 / 2008-09-21
2
+
3
+ * fleshed out :backup class
4
+ * Xen::Commands are now easily called by backgroundjob (bj)
5
+
6
+ === 0.0.2 / 2008-09-11
7
+
8
+ * Broke out classes into separate files
9
+ * Added rspec outline
10
+
1
11
  === 0.0.1 / 2008-09-08
2
12
 
3
13
  * Initial import
@@ -4,5 +4,13 @@ README.rdoc
4
4
  Rakefile
5
5
  bin/ruby-xen
6
6
  lib/ruby-xen.rb
7
- test/test-ruby-xen.rb
7
+ test/test_ruby-xen.rb
8
8
  lib/ruby-xen/domain.rb
9
+ lib/xen/backup.rb
10
+ lib/xen/command.rb
11
+ lib/xen/config.rb
12
+ lib/xen/slice.rb
13
+ lib/xen/host.rb
14
+ lib/xen/image.rb
15
+ lib/xen/instance.rb
16
+ lib/templates/domu.cfg.erb
@@ -1,6 +1,9 @@
1
1
  = ruby-xen
2
2
 
3
- * FIX (url)
3
+ # Warning! Not ready yet - project started Sep 2008
4
+
5
+ http://github.com/mbailey/ruby-xen
6
+
4
7
 
5
8
  == DESCRIPTION:
6
9
 
@@ -19,11 +22,20 @@ ruby-xen can also be used by ruby code or from irb.
19
22
 
20
23
  == SYNOPSIS:
21
24
 
22
- FIX (code sample of usage)
25
+ require 'rubygems'
26
+ require 'ruby-xen'
27
+
28
+ slice = Xen::Slice.find(:example)
29
+ slice.running? # true
30
+ slice.stop
31
+ slice.running? # false
32
+ slice.start
33
+ slice.running? # true
23
34
 
24
35
  == REQUIREMENTS:
25
36
 
26
- xen-tools (http://www.xen-tools.org/software/xen-tools/)
37
+ ruby-xen must be run as root as it uses Xen's 'xm' command.
38
+ xen-tools must be installed (http://www.xen-tools.org/software/xen-tools/)
27
39
 
28
40
  == INSTALL:
29
41
 
@@ -36,7 +48,7 @@ or open source applications. More details found here:
36
48
  http://www.gnu.org/licenses/gpl.html
37
49
 
38
50
  ruby-xen
39
- Copyright (C) 2008 Mike Bailey and Nick Markfleet
51
+ Copyright (C) 2008 Mike Bailey and Nick Marfleet
40
52
 
41
53
  This program is free software; you can redistribute it and/or
42
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', RubyXen::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
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
@@ -1,4 +1,80 @@
1
- class RubyXen
2
- VERSION = '1.0.0'
1
+ module Xen
2
+ # General configuration for ruby-xen
3
+
4
+ # Location of Xen config files
5
+ XEN_DOMU_CONFIG_DIR = '/etc/xen'
6
+ # XEN_DOMU_CONFIG_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '/spec/fixtures/xen_domu_configs'))
7
+
8
+ # We don't want out library to hit Xen too often (premature optimization perhaps?)
9
+ # so we keep information about Xen instances in an object. Specify how long before
10
+ # the object expires.
11
+ INSTANCE_OBJECT_LIFETIME = 5 # seconds
12
+
13
+ # General location for config file templates
14
+ TEMPLATE_DIR = File.expand_path(File.dirname(__FILE__) + '/../lib/templates')
15
+
16
+ # Extension for Xen domU config files
17
+ CONFIG_FILE_EXTENSION = '.cfg'
18
+
19
+ # Directory for backups of system images
20
+ BACKUP_DIR='/var/xen_images'
21
+
22
+ # FIle extension for backups
23
+ BACKUP_FILE_EXT = '.tar'
3
24
  end
4
- require "#{File.dirname(__FILE__)}/ruby-xen/domain"
25
+
26
+ class Array #:nodoc:
27
+ # Extracts options from a set of arguments. Removes and returns the last
28
+ # element in the array if it's a hash, otherwise returns a blank hash.
29
+ #
30
+ # def options(*args)
31
+ # args.extract_options!
32
+ # end
33
+ #
34
+ # options(1, 2) # => {}
35
+ # options(1, 2, :a => :b) # => {:a=>:b}
36
+ def extract_options!
37
+ last.is_a?(::Hash) ? pop : {}
38
+ end
39
+ end
40
+
41
+ class Hash #:nodoc:
42
+ # Converts a Hash into an array of key=val formatted strings
43
+ #
44
+ # puts { :nics => 2, :vcpus => 1, :memory => 64 }.to_args
45
+ #
46
+ # produces:
47
+ #
48
+ # ["memory=64", "nics=2", "vcpus=1"]
49
+ def to_args
50
+ collect{|k,v| "#{k}=#{v}"}
51
+ end
52
+ end
53
+
54
+ module Xen
55
+ # DRY up some classes (children of Slice) with some module funkiness.
56
+ module Parentable
57
+ # Returns the parent Slice object (d) for a sub-object.
58
+ # We ensure d.instance.object_id == self.object_id
59
+ #
60
+ # ==== Example
61
+ # i = Xen::Instance.all[2]
62
+ # s = i.slice
63
+ # i.object_id == s.instance.object_id # true
64
+ #
65
+ def slice
66
+ d = Xen::Slice.new(name)
67
+ # Insert the current object into the newly created Slice's attributes
68
+ d.instance_variable_set("@#{self.class.to_s.sub('Xen::','').downcase}", self)
69
+ d
70
+ end
71
+ end
72
+ end
73
+
74
+ require "#{File.dirname(__FILE__)}/xen/backup"
75
+ require "#{File.dirname(__FILE__)}/xen/command"
76
+ require "#{File.dirname(__FILE__)}/xen/config"
77
+ require "#{File.dirname(__FILE__)}/xen/slice"
78
+ require "#{File.dirname(__FILE__)}/xen/host"
79
+ require "#{File.dirname(__FILE__)}/xen/image"
80
+ 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 %>'
@@ -0,0 +1,42 @@
1
+ class Xen::Backup
2
+ include Xen::Parentable
3
+
4
+ attr_accessor :name, :version
5
+
6
+ def self.create(*args)
7
+ options = args.extract_options!
8
+ name = args.first
9
+ version = options[:version] || generate_version
10
+ Xen::Command.backup_slice(name, version)
11
+ new(name, version)
12
+ end
13
+
14
+ def initialize(*args)
15
+ options = args.extract_options!
16
+ @name = args.first
17
+ @version = options[:version]
18
+ end
19
+
20
+ def self.find(*args)
21
+ # return all
22
+ slice = args.first
23
+ Dir.glob("#{Xen::BACKUP_DIR}/*-*#{Xen::BACKUP_FILE_EXT}").collect { |file|
24
+ if match = File.basename(file, Xen::BACKUP_FILE_EXT).match(/(#{ slice || '.*' })-(.*)/)
25
+ new(match[1], :version => match[2])
26
+ end
27
+ }.compact
28
+ end
29
+
30
+ def filename
31
+ "#{@name}-#{@version}#{Xen::BACKUP_FILE_EXT}"
32
+ end
33
+
34
+ def fullpath
35
+ File.join(Xen::BACKUP_DIR, filename)
36
+ end
37
+
38
+ def size
39
+ File.size(fullpath)
40
+ end
41
+
42
+ end
@@ -0,0 +1,73 @@
1
+ class Xen::Command
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
+ # Return the size of a logical volume in gigabytes
11
+ def self.lv_size(vg_name, lv_name)
12
+ cmd = "lvs --noheadings --nosuffix --options lv_size --units g #{vg_name}/#{lv_name}"
13
+ `#{cmd}`.strip
14
+ end
15
+
16
+ # Return list of logical volumes
17
+ def self.lv_list(vg_name)
18
+ cmd = "lvs --noheadings --nosuffix --options vg_name,lv_name,lv_size --units g #{vg_name}"
19
+ raw = `#{cmd}`
20
+ raw.scan(/(\S+)\s+(\S+)\s+(\S+)/).collect{ |vg_name, lv_name, size|
21
+ {
22
+ :vg => vg_name,
23
+ :name => lv_name,
24
+ :size => size
25
+ }
26
+ }
27
+ end
28
+
29
+ def self.vg_list
30
+ cmd = "vgs --noheadings --units g --nosuffix --options vg_name,vg_size,vg_free,lv_count,max_lv"
31
+ raw = `#{cmd}`
32
+ raw.scan(/(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/).collect{ |vg_name, vg_size, vg_free, lv_count, max_lv|
33
+ {
34
+ :name => vg_name,
35
+ :size => vg_size,
36
+ :free => vg_free,
37
+ :lv_count => lv_count,
38
+ :max_lv => max_lv
39
+ }
40
+ }
41
+ end
42
+
43
+ def self.detailed_instance_list(name='')
44
+ cmd = "xm list --long #{name}"
45
+ raw_entries = `#{cmd}`.split(/\n\(domain/)
46
+ raw_entries.collect do |entry|
47
+ attributes = entry.scan(/\((name|domid|memory|vcpus|state|cpu_time|start_time) (.*)\)/)
48
+ attributes.inject({}) { |m, (key, val)| m[key.to_sym] = val; m }
49
+ end
50
+ end
51
+
52
+ def self.start_instance(config_file)
53
+ `xm create #{config_file}`
54
+ end
55
+
56
+ def self.shutdown_instance(name, blocking=false)
57
+ `xm shutdown #{'-w' if blocking} #{name}`
58
+ end
59
+
60
+ # Xen::Command.create_image('memory=512', :size => '10Gb')
61
+ # => "xm-create-image memory=512 size=10Gb"
62
+ #
63
+ def self.create_image(*args)
64
+ options = args.extract_options!
65
+ cmd = "xm-create-image #{args.concat(options.to_args).join(' ')}"
66
+ `cmd`
67
+ end
68
+
69
+ def self.xm_info
70
+ result = `xm info`
71
+ result.scan(/(\S+)\s*:\s*([^\n]+)/).inject({}){ |m, (i,j)| m[i.to_sym] = j; m }
72
+ end
73
+ end
@@ -0,0 +1,146 @@
1
+ require 'erb'
2
+
3
+ class Xen::Config
4
+ # The config files for each Xen domU
5
+ include Xen::Parentable
6
+ attr_accessor :name, :kernel, :ramdisk, :memory, :root, :vbds, :vifs, :on_poweroff, :on_reboot, :on_crash, :extra
7
+
8
+ def initialize(*args)
9
+ options = args.extract_options!
10
+ @name = args.first
11
+ @kernel = options[:kernel]
12
+ @ramdisk = options[:ramdisk]
13
+ @memory = options[:memory]
14
+ @root = options[:root]
15
+ @vbds = options[:vbds]
16
+ @vifs = options[:vifs]
17
+ @on_poweroff = options[:on_poweroff]
18
+ @on_reboot = options[:on_reboot]
19
+ @on_crash = options[:on_crash]
20
+ @extra = options[:extra]
21
+ end
22
+
23
+ def self.find(*args)
24
+ options = args.extract_options!
25
+ case args.first
26
+ when :all then all
27
+ else find_by_name(args.first)
28
+ end
29
+ end
30
+
31
+ def self.all
32
+ config_files = Dir.glob("#{Xen::XEN_DOMU_CONFIG_DIR}/*#{Xen::CONFIG_FILE_EXTENSION}")
33
+ config_files.collect do |filename|
34
+ create_from_config_file(File.read(filename))
35
+ end
36
+ end
37
+
38
+ def self.find_by_name(name)
39
+ return new('Domain-0') if name == 'Domain-0'
40
+ filename = "#{Xen::XEN_DOMU_CONFIG_DIR}/#{name}#{Xen::CONFIG_FILE_EXTENSION}"
41
+ create_from_config_file(File.read(filename)) if File.exists?(filename)
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
70
+
71
+ def self.create_from_config_file(config)
72
+ name, kernel, ramdisk, memory, root, disk, vif, on_poweroff, on_reboot, on_crash, extra = nil
73
+ eval(config)
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)
77
+ end
78
+
79
+ def save
80
+ template = ERB.new IO.read(Xen::TEMPLATE_DIR + '/domu.cfg.erb')
81
+ File.open(config_file, 'w'){ |f| f.write template.result(binding) }
82
+ end
83
+
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 Block Device
115
+ #
116
+ # We're only supporting Logical Volumes. No loopback devices.
117
+ #
118
+ # http://wiki.xensource.com/xenwiki/XenStorage
119
+ #
120
+ # == Example
121
+ #
122
+ # disk = [ 'phy:xendisks/example-disk,sda1,w',
123
+ # 'phy:xendisks/example-swap,sda2,w',
124
+ # 'phy:assets/example-assets,sdb1,w' ]
125
+ class Xen::Vbd
126
+ attr_accessor :name, :vg, :domu, :mode
127
+ def initialize(name, vg, domu, mode='w')
128
+ @name, @vg, @domu, @mode = name, vg, domu, mode
129
+ end
130
+
131
+ def self.from_str(value)
132
+ dom0, domu, mode = value.split(',')
133
+ vg, name = dom0.split(/[\/:]/).slice(-2, 2)
134
+ new(name, vg, domu, mode)
135
+ end
136
+
137
+ def size
138
+ Xen::Command.lv_size(@vg, @name)
139
+ end
140
+
141
+ def to_str
142
+ "phy:#{vg}/#{lv},#{domu},#{mode}"
143
+ end
144
+ end
145
+
146
+
@@ -0,0 +1,10 @@
1
+ class Xen::Host
2
+ attr_reader :host, :machine, :total_memory, :free_memory
3
+
4
+ def initialize
5
+ Xen::Command.xm_info.each do |i,j|
6
+ instance_variable_set("@#{i}", j)
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,12 @@
1
+ # class Xen::Image
2
+ # include Xen::Parentable
3
+ # attr_accessor :name
4
+ #
5
+ # def initialize(name)
6
+ # @name = name
7
+ # end
8
+ #
9
+ # def self.find(name)
10
+ # new name
11
+ # end
12
+ # end
@@ -0,0 +1,66 @@
1
+ class Xen::Instance
2
+ include Xen::Parentable
3
+ attr_reader :name, :domid, :memory, :cpu_time, :vcpus, :state, :start_time
4
+
5
+ def initialize(name, options={})
6
+ @name = name
7
+ @domid = options[:domid]
8
+ @memory = options[:memory]
9
+ @cpu_time = options[:cpu_time]
10
+ @vcpus = options[:vcpus]
11
+ @state = options[:state]
12
+ @start_time = Time.at(options[:start_time].to_f) if options[:start_time]
13
+ end
14
+
15
+ def self.find(*args)
16
+ options = args.extract_options!
17
+ case args.first
18
+ when :all then all
19
+ else find_by_name(args.first)
20
+ end
21
+ end
22
+
23
+ def self.all
24
+ Xen::Command.detailed_instance_list.collect do |instance|
25
+ new(name, instance)
26
+ end
27
+ end
28
+
29
+ def self.find_by_name(name)
30
+ Xen::Command.detailed_instance_list(name).each do |instance|
31
+ return new(name, instance)
32
+ end
33
+ return false
34
+ end
35
+
36
+ def self.create(name)
37
+ output = Xen::Command.start_instance(name.to_s + Xen::CONFIG_FILE_EXTENSION)
38
+ $? == 0 ? true : false
39
+ end
40
+
41
+ def self.shutdown(name)
42
+ output = Xen::Command.shutdown_instance(name)
43
+ $? == 0 ? true : false
44
+ end
45
+
46
+ # A convenience wrapper for <tt>find(:dom0)</tt>.</tt>.
47
+ def self.dom0(*args)
48
+ find_by_name(:dom0)
49
+ end
50
+
51
+ def uptime
52
+ start_time ? Time.now - start_time : nil
53
+ end
54
+
55
+ def reboot
56
+ `xm reboot #{name}`
57
+ $? == 0 ? true : false
58
+ end
59
+
60
+ def destroy
61
+ end
62
+
63
+ def pause
64
+ end
65
+
66
+ end
@@ -0,0 +1,80 @@
1
+ class Xen::Slice
2
+ attr_accessor :name, :image, :config, :backups
3
+
4
+ def self.find(*args)
5
+ options = args.extract_options!
6
+ case args.first
7
+ when :all then Xen::Config.find(:all, options).collect { |config| config.slice }
8
+ when :running then Xen::Instance.find(:all, options).collect { |instance| instance.slice }
9
+ # Retrieve a Slice by name
10
+ else Xen::Config.find_by_name(args.first) && self.new(args.first)
11
+ end
12
+ end
13
+
14
+ def self.all(options={})
15
+ self.find(:all, options)
16
+ end
17
+
18
+ def initialize(*args)
19
+ options = args.extract_options! # remove trailing hash (not used)
20
+ @name = args.first
21
+ @config = options[:config]
22
+ @instance = options[:instance]
23
+ @instance_cache_expires = Time.now
24
+ @backups = Array(options[:backups])
25
+ end
26
+
27
+ def create_image(args)
28
+ args = hash.collect{|k,v| "#{k}=#{v}"}
29
+ Xen::Command.create_image
30
+ end
31
+
32
+ # Cache Xen instance info to reduce system calls to xm command.
33
+ # It still needs to be checked regularly as operations like shutdown
34
+ # and create can take a while.
35
+ def instance
36
+ if @instance_cache_expires > Time.now
37
+ @instance
38
+ else
39
+ @instance_cache_expires = Time.now + Xen::INSTANCE_OBJECT_LIFETIME
40
+ @instance = Xen::Instance.find(@name) if @name
41
+ end
42
+ end
43
+
44
+ # XXX We're assuming other processes aren't going to edit configs
45
+ # This is reasonable in simple cases.
46
+ def config
47
+ @config ||= Xen::Config.find(name) if @name
48
+ end
49
+
50
+ def backups
51
+ Xen::Backup.find(name)
52
+ end
53
+
54
+ def state
55
+ self.instance ? :running : :stopped
56
+ end
57
+
58
+ def running?
59
+ self.instance ? true : false
60
+ end
61
+
62
+ def start
63
+ Xen::Instance.create(@name)
64
+ @instance = Xen::Instance.find(@name)
65
+ end
66
+
67
+ def stop
68
+ Xen::Instance.shutdown(@name)
69
+ @instance = Xen::Instance.find(@name)
70
+ end
71
+
72
+ def config_newer_than_instance?
73
+ instance && config.updated_at > instance.start_time
74
+ end
75
+
76
+ def save
77
+ @config.save
78
+ end
79
+
80
+ end
@@ -0,0 +1,3 @@
1
+ require '../lib/ruby-xen'
2
+ c = Xen::Config.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.1
4
+ version: 0.0.3
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-08 00:00:00 +10:00
13
+ date: 2008-09-21 00:00:00 +10:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -32,13 +32,20 @@ files:
32
32
  - bin/ruby-xen
33
33
  - lib/ruby-xen.rb
34
34
  - test/test_ruby-xen.rb
35
- - lib/ruby-xen/domain.rb
35
+ - lib/xen/backup.rb
36
+ - lib/xen/command.rb
37
+ - lib/xen/config.rb
38
+ - lib/xen/host.rb
39
+ - lib/xen/image.rb
40
+ - lib/xen/instance.rb
41
+ - lib/xen/slice.rb
42
+ - lib/templates/domu.cfg.erb
36
43
  has_rdoc: true
37
- homepage: http://github.com/schacon/grit
44
+ homepage: http://github.com/mbailey/ruby-xen
38
45
  post_install_message:
39
46
  rdoc_options:
40
47
  - --main
41
- - README.txt
48
+ - README.rdoc
42
49
  require_paths:
43
50
  - lib
44
51
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -1,229 +0,0 @@
1
- class Array #:nodoc:
2
- # Extracts options from a set of arguments. Removes and returns the last
3
- # element in the array if it's a hash, otherwise returns a blank hash.
4
- #
5
- # def options(*args)
6
- # args.extract_options!
7
- # end
8
- #
9
- # options(1, 2) # => {}
10
- # options(1, 2, :a => :b) # => {:a=>:b}
11
- def extract_options!
12
- last.is_a?(::Hash) ? pop : {}
13
- end
14
- end
15
-
16
- module Xen
17
- class Host
18
-
19
- attr_reader :host, :machine, :total_memory, :free_memory
20
- def initialize
21
- result = `xm info`
22
- result.scan(/(\S+)\s*:\s*([^\n]+)/).each do |i,j|
23
- instance_variable_set("@#{i}", j)
24
- end
25
- end
26
-
27
- end
28
-
29
-
30
- class Domain
31
-
32
- attr_accessor :name, :image, :config, :instance
33
-
34
- def initialize(name)
35
- @name = name
36
- @config = Xen::Config.find(name)
37
- @instance = Xen::Instance.find(name)
38
- @image = Xen::Image.find(name)
39
- end
40
-
41
- def self.find(*args)
42
- options = args.extract_options!
43
- case args.first
44
- when :all then Xen::Config.find(:all, options).collect { |config| Xen::Domain.new(config.name) }
45
- when :running then Xen::Instance.find(:all, options).collect { |instance| Xen::Domain.new(instance.name) }
46
- # Retrieve a Domain by name
47
- else Xen::Config.find_by_name(args.first) && self.new(args.first)
48
- end
49
- end
50
-
51
- def running?
52
- @instance
53
- end
54
-
55
- end
56
-
57
-
58
- class Config
59
-
60
- attr_reader :name, :memory, :ip
61
-
62
- def initialize(*args)
63
- options = args.extract_options!
64
- @name = args.first
65
- @memory = options[:memory] || nil
66
- @ip = options[:ip] || nil
67
- end
68
-
69
- def self.find(*args)
70
- options = args.extract_options!
71
- case args.first
72
- when :all then all
73
- else find_by_name(args.first)
74
- end
75
- end
76
-
77
- def self.all
78
- result = `xen-list-images`
79
- configs = result.scan(/Name: (\w+)\nMemory: (\w+)\nIP: (\S+)/)
80
- configs.collect do |config|
81
- name, memory, ip = config
82
- new(name, :memory => memory, :ip => ip)
83
- end
84
- end
85
-
86
- def self.find_by_name(name)
87
- return new('Domain-0') if name == 'Domain-0'
88
- all.detect {|config| puts config; config.name == name.to_s}
89
- end
90
-
91
- end
92
-
93
-
94
- class Image
95
-
96
- attr_accessor :name
97
-
98
- def initialize(name)
99
- @name = name
100
- end
101
-
102
- def self.find(name)
103
- new name
104
- end
105
-
106
- def find_one(name, options)
107
- if result = find_every(options).first
108
- result
109
- else
110
- raise RecordNotFound, "Couldn't find domain with name=#{name}"
111
- end
112
- end
113
- end
114
-
115
-
116
- class Instance
117
-
118
- attr_reader :name, :domid, :memory, :cpu_time, :vcpus, :state, :start_time
119
-
120
- def initialize(name, options={})
121
- @name = name
122
- @domid = options[:domid] || nil
123
- @memory = options[:memory] || nil
124
- @cpu_time = options[:cpu_time] || nil
125
- @vcpus = options[:vcpus] || nil
126
- @state = options[:state] || nil
127
- @start_time = options[:start_time] || nil
128
- end
129
-
130
- def self.find(*args)
131
- options = args.extract_options!
132
- case args.first
133
- when :all then all
134
- else find_by_name(args.first)
135
- end
136
- end
137
-
138
- def self.all
139
- result = `xm list`
140
- # XXX check for failed command
141
- result_array = result.split("\n")
142
- result_array.shift
143
- result_array.collect do |domain|
144
- name, domid, memory, vcpus, state, cpu_time = domain.scan(/[^ ,]+/)
145
- new(name, :domid => domid, :memory => memory, :cpu_time => cpu_time)
146
- end
147
- end
148
-
149
- def self.find_by_name(name)
150
- all.detect{|domain| domain.name == name.to_s }
151
- end
152
-
153
- # XXX Rails version - we need some error checking!
154
- #
155
- # def self.find_by_name(name, options)
156
- # if result = find_every(options)
157
- # result.detect{ |domain| domain.name == name }
158
- # else
159
- # raise RecordNotFound, "Couldn't find domain with name=#{name}"
160
- # end
161
- # end
162
-
163
- # A convenience wrapper for <tt>find(:dom0)</tt>.</tt>.
164
- def dom0(*args)
165
- find_by_name(:dom0)
166
- end
167
-
168
- # This is an alias for find(:all). You can pass in all the same arguments to this method as you can
169
- # to find(:all)
170
- def all(*args)
171
- find(:all, *args)
172
- end
173
-
174
- def uptime
175
- start_time ? Time.now - start_time : nil
176
- end
177
-
178
- def running?
179
- output = `xm list #{name}`
180
- $? == 0 ? true : false
181
- end
182
-
183
- def start
184
- output = `xm create #{name}.cfg`
185
- $? == 0 ? true : false
186
- end
187
-
188
- def shutdown
189
- output = `xm shutdown #{name}`
190
- $? == 0 ? true : false
191
- end
192
-
193
- def reboot
194
- `xm reboot #{name}`
195
- $? == 0 ? true : false
196
- end
197
-
198
- def destroy
199
- end
200
-
201
- def pause
202
- end
203
-
204
- end
205
-
206
- class Backup
207
- end
208
-
209
- # class XenTools
210
- #
211
- # def self.xen_list_images
212
- # puts "returning list of images"
213
- # end
214
- #
215
- # def xen_create_image
216
- # puts "creating image"
217
- # end
218
- #
219
- # def xen_delete_image
220
- # puts "creating image"
221
- # end
222
- #
223
- # def xen_archive_image
224
- # puts "archiving image"
225
- # end
226
- #
227
- # end
228
-
229
- end