vmit 0.0.3

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/.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