vmit 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in vmit.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+
2
+ Copyright (c) 2013 Duncan Mac-Vicar P. <dmacvicar@suse.de>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
data/README.rdoc ADDED
@@ -0,0 +1,119 @@
1
+
2
+ = Vmit
3
+
4
+ * http://guthub.com/dmacvicar/vmit
5
+
6
+ == Introduction
7
+
8
+ Vmit is a simple tool to manage virtual kvm machines for development/testing.
9
+
10
+ I wrote in desperation for after having various directories with images, scripts to
11
+ launch qemu, network setup scripts, etc.
12
+
13
+ == Philosophy
14
+
15
+ * Inspired in git: the directory where you are gives the context of the virtual machine
16
+ you are working with.
17
+ * No XML (virsh)
18
+ * Good defaults: the default configuration is no configuration
19
+ * Changing the mac address, RAM size and other parameters should be posible when launching
20
+ the VM (one time value) or persistent (per VM workspace)
21
+ * Easy creation of a snapshot to test something. Easy rollback.
22
+
23
+ == Usage
24
+
25
+ === First steps
26
+
27
+ Just create a directory for your VM:
28
+
29
+ mkdir myvm
30
+ cd myvm
31
+
32
+ You don't need any configuration, but without a disk image:
33
+
34
+ $ vmit run
35
+ I, [2012-03-14T16:40:07.368677 #19781] INFO -- : Starting VM...
36
+ I, [2012-03-14T16:40:07.368774 #19781] INFO -- : => memory : 1G
37
+ I, [2012-03-14T16:40:07.368840 #19781] INFO -- : => mac_address : 0e:86:d7:76:94:89
38
+ F, [2012-03-14T16:40:07.369028 #19781] FATAL -- : No hard disk image available
39
+
40
+ So try init first. You can specify disk size or memory as parameter. Any option which is
41
+ not a default wil be written into a config.yml file:
42
+
43
+ $ vmit init
44
+ I, [2012-03-14T16:45:23.477649 #20129] INFO -- : Writing config.yml...
45
+ I, [2012-03-14T16:45:23.607814 #20129] INFO -- : Formatting '/space/vm/minix3/sda-1331739923.qcow2', fmt=qcow2 size=10737418240 encryption=off cluster_size=65536
46
+
47
+ The just launch the vm. You can pass a cdrom with --cdrom
48
+
49
+ $ vmit run --cdrom minix_R3.2.0-116fcea.iso
50
+ I, [2012-03-14T16:46:59.130827 #20189] INFO -- : Starting VM...
51
+ I, [2012-03-14T16:46:59.130929 #20189] INFO -- : => memory : 1G
52
+ I, [2012-03-14T16:46:59.130996 #20189] INFO -- : => cdrom : minix_R3.2.0-116fcea.iso
53
+ I, [2012-03-14T16:46:59.131024 #20189] INFO -- : => mac_address : 2a:eb:6c:6d:77:86
54
+ I, [2012-03-14T16:46:59.241318 #20189] INFO -- : Bringing interface tap1 up
55
+ I, [2012-03-14T16:46:59.244394 #20189] INFO -- : Connecting tap1 --> br0
56
+
57
+ You don't care about network setup. If you don't say anything vmit will connect
58
+ all virtual machines to a bridge in the 192.168.58.0/24 network. If this bridge
59
+ does not exist it will setup it for you and also setup NAT so that your virtual machines
60
+ get internet access. A DHCP server will give an ip to the virtual machine.
61
+
62
+ === Snapshots
63
+
64
+ Once you installed your base OS, you can keep the base image as read only and use copy-on-write
65
+ to your further changes:
66
+
67
+ $ vmit disk-snapshot
68
+ I, [2012-03-14T16:48:13.187875 #20278] INFO -- : Formatting '/space/vm/minix3/sda-1331740093.qcow2', fmt=qcow2 size=10737418240 backing_file='/space/vm/minix3/sda-1331739923.qcow2' encryption=off cluster_size=65536
69
+
70
+ You can then rollback to the previous version:
71
+
72
+ $ vmit disk-rollback
73
+ I, [2012-03-14T16:54:02.080964 #20716] INFO -- : Removing /space/vm/minix3/sda-1331740209.qcow2
74
+
75
+ vmit init
76
+ vmit run
77
+ vmit disk-snapshot
78
+ vmit disk-rollback
79
+ vmit disk-images
80
+
81
+ == Configuration
82
+
83
+ Per-VM configuration is stored in the virtual machine directory in a file called config.yml.
84
+
85
+ === General
86
+
87
+ Automatically generated configuration is stored in config.yml
88
+
89
+ ---
90
+ :mac_address: 8e:55:c5:de:a0:16
91
+ :uuid: 7c6ff9eb-fe14-4444-bbbf-a6d954870978
92
+
93
+ === Networking
94
+
95
+ If you don't do anything, the VM will be attached to 192.168.58.0/24 on a bridge, and NAT will be
96
+ setup on the network.
97
+
98
+ You can override the network in config.yml:
99
+
100
+ :network:
101
+ :address: 192.168.51.0/24
102
+
103
+ Or, you can edit /root/.vmit/networks.yml
104
+
105
+ ---
106
+ myalias:
107
+ address: 192.168.51.0/24
108
+
109
+ And then in config.yml
110
+
111
+ :network: myalias
112
+
113
+ == Authors
114
+
115
+ * Duncan Mac-Vicar P. <dmacvicar@suse.de>
116
+
117
+ == License
118
+
119
+ See MIT-LICENSE file.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/vmit ADDED
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
3
+ require 'rubygems'
4
+ require 'active_support/inflector'
5
+ require 'clamp'
6
+ require 'vmit'
7
+
8
+ #Vmit.logger = Logger.new(STDERR)
9
+ # Don't show by default anything
10
+ #Vmit.logger.level = Logger::INFO
11
+ #Vmit.logger.level = Logger::DEBUG if ENV['DEBUG']
12
+ # TODO find a good format
13
+ #Vmit.logger.formatter = proc do |severity, datetime, progname, msg|
14
+ # "#{datetime}: #{severity} #{msg}\n"
15
+ #end
16
+
17
+ module Vmit
18
+
19
+ class BaseVmCommand < Clamp::Command
20
+ option ["-m", "--memory"], "N", "Amount of RAM" do |memory|
21
+ if not memory =~ /(\d)+(M|K|G)/
22
+ raise ArgumentError, "Memory should be given as 1M, 2G, etc"
23
+ end
24
+ memory
25
+ end
26
+
27
+ option ['-u', '--uuid'], "UUID", "unique id for the virtual machine"
28
+ end
29
+
30
+ class InitCommand < BaseVmCommand
31
+
32
+ OPTION_KEYS = [:disk_size, :memory, :uuid]
33
+
34
+ option ["-s","--disk-size"], "SIZE",
35
+ "Initialize disk with SIZE (eg: 10M, 10G, 10K)" do |disk_size|
36
+ if not disk_size =~ /(\d)+(M|K|G)/
37
+ raise ArgumentError, "Disk size should be given as 1M, 2G, etc"
38
+ end
39
+ disk_size
40
+ end
41
+
42
+ def execute
43
+ options = {}
44
+ vm = Vmit::VirtualMachine.new(File.expand_path(Dir.pwd))
45
+
46
+ OPTION_KEYS.each do |k|
47
+ val = self.send(k)
48
+ options[k] = val if val
49
+ end
50
+
51
+ vm.options.merge!(options)
52
+ vm.save_config!
53
+
54
+ vm.disk_image_init!(options)
55
+
56
+ end
57
+
58
+ end
59
+
60
+ class RunCommand < BaseVmCommand
61
+
62
+ OPTION_KEYS = [:memory, :cdrom]
63
+
64
+ option ["-cdrom","--cdrom"], "CD", "Use CD as cdrom device (ISO, dev)" do |cdrom|
65
+ if not File.exist?(cdrom)
66
+ raise ArgumentError, "CDROM cdevice #{cdrom} not found"
67
+ end
68
+ cdrom
69
+ end
70
+
71
+ def execute
72
+ options = {}
73
+ vm = Vmit::VirtualMachine.new(File.expand_path(Dir.pwd))
74
+
75
+ OPTION_KEYS.each do |k|
76
+ val = self.send(k)
77
+ options[k] = val if val
78
+ end
79
+
80
+ vm.run(options)
81
+ end
82
+
83
+ end
84
+
85
+ class DiskSnapshotCommand < Clamp::Command
86
+
87
+ def execute
88
+ vm = Vmit::VirtualMachine.new(File.expand_path(Dir.pwd))
89
+ vm.disk_snapshot!
90
+ end
91
+
92
+ end
93
+
94
+ class DiskImagesCommand < Clamp::Command
95
+
96
+ def execute
97
+ vm = Vmit::VirtualMachine.new(File.expand_path(Dir.pwd))
98
+ puts vm.disk_images.last
99
+ end
100
+
101
+ end
102
+
103
+ class DiskRollbackCommand < Clamp::Command
104
+
105
+ def execute
106
+ vm = Vmit::VirtualMachine.new(File.expand_path(Dir.pwd))
107
+ vm.disk_rollback!
108
+ end
109
+
110
+ end
111
+
112
+ class MainCommand < Clamp::Command
113
+
114
+ subcommand "init", "Initialize the vm", InitCommand
115
+ subcommand "run", "Run the vm", RunCommand
116
+ subcommand "disk-images", "List disk images", DiskImagesCommand
117
+ subcommand "disk-snapshot", "Creates a new disk-snapshot", DiskSnapshotCommand
118
+ subcommand "disk-rollback", "Rollbacks to previous disk snapshot", DiskRollbackCommand
119
+
120
+ # Add commands offered via plugins
121
+ Vmit.plugins.each do |plugin|
122
+ if plugin.is_a?(Class) && plugin.ancestors.include?(::Clamp::Command)
123
+ plugin_id = plugin.to_s.split('::').last.underscore
124
+ subcommand plugin_id, "Plugin command", plugin
125
+ Vmit.logger.debug "Enabling plugin #{plugin_id}"
126
+ end
127
+ end
128
+ end
129
+
130
+
131
+ end
132
+
133
+ begin
134
+ Vmit::MainCommand.run
135
+ rescue SystemExit, Interrupt
136
+ Vmit.logger.fatal "interrupted"
137
+ exit(1)
138
+ rescue Exception => e
139
+ Vmit.logger.fatal e.message
140
+ e.backtrace.each do |bt_line|
141
+ Vmit.logger.debug " #{bt_line}"
142
+ end
143
+ exit(1)
144
+ end
145
+ exit(0)
data/bin/vmit-ifdown ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
3
+ require 'rubygems'
4
+ require 'vmit'
5
+ require 'drb'
6
+
7
+ DRb.start_service
8
+ vmit = DRbObject.new nil, ENV['VMIT_SERVER']
9
+
10
+ vmit.ifdown(ARGV[0])
data/bin/vmit-ifup ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
3
+
4
+ #/sbin/brctl setfd ${switch} 0
5
+ #/sbin/brctl stp ${switch} off
6
+
7
+ require 'rubygems'
8
+ require 'vmit'
9
+ require 'drb'
10
+
11
+ DRb.start_service
12
+ vmit = DRbObject.new nil, ENV['VMIT_SERVER']
13
+
14
+ vmit.ifup(ARGV[0])
15
+
16
+
17
+
18
+
data/lib/vmit.rb ADDED
@@ -0,0 +1,67 @@
1
+ #
2
+ # Copyright (C) 2013 Duncan Mac-Vicar P. <dmacvicar@suse.de>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'vmit/version'
22
+ require 'vmit/bootstrap'
23
+ require 'vmit/logger'
24
+ require 'vmit/refcounted_resource'
25
+ require 'vmit/network'
26
+ require 'vmit/vfs'
27
+ require 'vmit/virtual_machine'
28
+ require 'vmit/ext'
29
+ require 'pidfile'
30
+
31
+ module Vmit
32
+
33
+ RUN_DIR = case Process.uid
34
+ when 0 then '/run/vmit'
35
+ else File.join(Dir::tmpdir, 'vmit')
36
+ end
37
+
38
+ module Plugins
39
+ end
40
+ # Your code goes here...
41
+
42
+ def self.add_plugin(plugin)
43
+ Vmit.plugins << plugin
44
+ end
45
+
46
+ def self.plugins
47
+ @plugins ||= []
48
+ end
49
+
50
+ end
51
+
52
+ # Scan plugins
53
+ plugin_glob = File.join(File.dirname(__FILE__), 'vmit', 'plugins', '*.rb')
54
+ Dir.glob(plugin_glob).each do |plugin|
55
+ Vmit.logger.debug("Loading file: #{plugin}")
56
+ #puts "Loading file: #{plugin}"
57
+ load plugin
58
+ end
59
+
60
+ # instantiate plugins
61
+ ::Vmit::Plugins.constants.each do |cnt|
62
+ pl_class = ::Vmit::Plugins.const_get(cnt)
63
+ #pl_instance = pl_class.new
64
+ Vmit.add_plugin(pl_class)
65
+ Vmit.logger.debug("Loaded: #{pl_class}")
66
+ #puts "Loaded: #{pl_class}"
67
+ end
@@ -0,0 +1,110 @@
1
+ #
2
+ # Copyright (C) 2013 Duncan Mac-Vicar P. <dmacvicar@suse.de>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'nokogiri'
22
+
23
+ module Vmit
24
+
25
+ class AutoYaST
26
+
27
+ attr_accessor :patterns
28
+ attr_accessor :packages
29
+
30
+ def initialize
31
+ @net_udev = {}
32
+ @patterns = []
33
+ @packages = []
34
+ end
35
+
36
+ def minimal_opensuse!
37
+ @patterns << 'base'
38
+ end
39
+
40
+ def minimal_sle!
41
+ @patterns << 'Minimal'
42
+ end
43
+
44
+ # Map a network device name and make
45
+ # it persistent
46
+ #
47
+ # @param [String] MAC mac address
48
+ # @param [String] device name
49
+ def name_network_device(mac, name)
50
+ if @net_udev.has_key?(mac) or @net_udev.has_value?(mac)
51
+ raise "Device with MAC #{mac} is already assigned to #{@net_udev[name]}"
52
+ end
53
+ @net_udev[mac] = name
54
+ end
55
+
56
+ def to_xml
57
+ builder = Nokogiri::XML::Builder.new do |xml|
58
+ xml.profile('xmlns' => 'http://www.suse.com/1.0/yast2ns',
59
+ 'xmlns:config' => 'http://www.suse.com/1.0/configns') {
60
+ xml.users('config:type' => 'list') {
61
+ xml.user {
62
+ xml.username 'root'
63
+ xml.user_password 'linux'
64
+ xml.encrypted(false,'config:type' => 'boolean')
65
+ xml.forename
66
+ xml.surname
67
+ }
68
+ }
69
+ xml.general {
70
+ xml.mode {
71
+ xml.confirm(false, 'config:type' => 'boolean')
72
+ xml.forceboot('config:type' => 'boolean')
73
+ xml.final_reboot(true, 'config:type' => 'boolean')
74
+ xml.second_stage(true, 'config:type' => 'boolean')
75
+ }
76
+ }
77
+ xml.runlevel {
78
+ xml.default 3
79
+ xml.services {
80
+ xml.service {
81
+ xml.service_name 'sshd'
82
+ xml.service_status 'enable'
83
+ xml.service_start '3 5'
84
+ xml.service_stop '3 5'
85
+ }
86
+ }
87
+ }
88
+ xml.software {
89
+ xml.patterns('config:type' => 'list') {
90
+ @patterns.each do |pat|
91
+ xml.pattern pat
92
+ end
93
+ }
94
+ }
95
+ # SLE 11 can do without this basic partitioning but
96
+ # SLE 10 is not that smart.
97
+ xml.partitioning('config:type' => 'list') {
98
+ xml.drive {
99
+ xml.use 'all'
100
+ }
101
+ }
102
+ xml.networking {
103
+ xml.keep_install_network(true, 'config:type' => 'boolean')
104
+ }
105
+ }
106
+ end
107
+ builder.to_xml
108
+ end
109
+ end
110
+ end