vagrant-kvm 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +14 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +10 -0
- data/LICENSE +8 -0
- data/README.md +90 -0
- data/Rakefile +15 -0
- data/example_box/README.md +18 -0
- data/example_box/box.xml +78 -0
- data/example_box/metadata.json +3 -0
- data/lib/vagrant-kvm.rb +20 -0
- data/lib/vagrant-kvm/action.rb +268 -0
- data/lib/vagrant-kvm/action/boot.rb +22 -0
- data/lib/vagrant-kvm/action/check_box.rb +36 -0
- data/lib/vagrant-kvm/action/check_created.rb +21 -0
- data/lib/vagrant-kvm/action/check_kvm.rb +23 -0
- data/lib/vagrant-kvm/action/check_running.rb +21 -0
- data/lib/vagrant-kvm/action/created.rb +20 -0
- data/lib/vagrant-kvm/action/destroy.rb +19 -0
- data/lib/vagrant-kvm/action/destroy_confirm.rb +17 -0
- data/lib/vagrant-kvm/action/export.rb +57 -0
- data/lib/vagrant-kvm/action/forced_halt.rb +21 -0
- data/lib/vagrant-kvm/action/import.rb +54 -0
- data/lib/vagrant-kvm/action/init_storage_pool.rb +19 -0
- data/lib/vagrant-kvm/action/is_paused.rb +20 -0
- data/lib/vagrant-kvm/action/is_running.rb +20 -0
- data/lib/vagrant-kvm/action/is_saved.rb +20 -0
- data/lib/vagrant-kvm/action/match_mac_address.rb +21 -0
- data/lib/vagrant-kvm/action/message_not_created.rb +16 -0
- data/lib/vagrant-kvm/action/message_will_not_destroy.rb +17 -0
- data/lib/vagrant-kvm/action/network.rb +69 -0
- data/lib/vagrant-kvm/action/package.rb +20 -0
- data/lib/vagrant-kvm/action/package_vagrantfile.rb +31 -0
- data/lib/vagrant-kvm/action/prepare_nfs_settings.rb +61 -0
- data/lib/vagrant-kvm/action/prune_nfs_exports.rb +20 -0
- data/lib/vagrant-kvm/action/resume.rb +25 -0
- data/lib/vagrant-kvm/action/setup_package_files.rb +51 -0
- data/lib/vagrant-kvm/action/share_folders.rb +76 -0
- data/lib/vagrant-kvm/action/suspend.rb +20 -0
- data/lib/vagrant-kvm/config.rb +31 -0
- data/lib/vagrant-kvm/driver/driver.rb +271 -0
- data/lib/vagrant-kvm/errors.rb +11 -0
- data/lib/vagrant-kvm/plugin.rb +73 -0
- data/lib/vagrant-kvm/provider.rb +104 -0
- data/lib/vagrant-kvm/util.rb +12 -0
- data/lib/vagrant-kvm/util/kvm_template_renderer.rb +20 -0
- data/lib/vagrant-kvm/util/network_definition.rb +106 -0
- data/lib/vagrant-kvm/util/vm_definition.rb +192 -0
- data/lib/vagrant-kvm/version.rb +5 -0
- data/locales/en.yml +4 -0
- data/templates/libvirt_domain.erb +64 -0
- data/vagrant-kvm.gemspec +58 -0
- metadata +191 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
begin
|
2
|
+
require "vagrant"
|
3
|
+
rescue LoadError
|
4
|
+
raise "The Vagrant KVM plugin must be run within Vagrant."
|
5
|
+
end
|
6
|
+
|
7
|
+
# This is a sanity check to make sure no one is attempting to install
|
8
|
+
# this into an early Vagrant version.
|
9
|
+
if Vagrant::VERSION < "1.1.0"
|
10
|
+
raise "The Vagrant KVM plugin is only compatible with Vagrant 1.1+"
|
11
|
+
end
|
12
|
+
|
13
|
+
module VagrantPlugins
|
14
|
+
module ProviderKvm
|
15
|
+
class Plugin < Vagrant.plugin("2")
|
16
|
+
name "KVM provider"
|
17
|
+
description <<-EOF
|
18
|
+
The KVM provider allows Vagrant to manage and control
|
19
|
+
QEMU/KVM virtual machines with libvirt.
|
20
|
+
EOF
|
21
|
+
|
22
|
+
config(:kvm, :provider) do
|
23
|
+
require_relative "config"
|
24
|
+
Config
|
25
|
+
end
|
26
|
+
|
27
|
+
provider(:kvm) do
|
28
|
+
# Setup logging and i18n
|
29
|
+
setup_logging
|
30
|
+
setup_i18n
|
31
|
+
|
32
|
+
# Return the provider
|
33
|
+
require_relative "provider"
|
34
|
+
Provider
|
35
|
+
end
|
36
|
+
|
37
|
+
# This initializes the internationalization strings.
|
38
|
+
def self.setup_i18n
|
39
|
+
I18n.load_path << File.expand_path("locales/en.yml", ProviderKvm.source_root)
|
40
|
+
I18n.reload!
|
41
|
+
end
|
42
|
+
|
43
|
+
# This sets up our log level to be whatever VAGRANT_LOG is.
|
44
|
+
def self.setup_logging
|
45
|
+
require "log4r"
|
46
|
+
|
47
|
+
level = nil
|
48
|
+
begin
|
49
|
+
level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
|
50
|
+
rescue NameError
|
51
|
+
# This means that the logging constant wasn't found,
|
52
|
+
# which is fine. We just keep `level` as `nil`. But
|
53
|
+
# we tell the user.
|
54
|
+
level = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
# Some constants, such as "true" resolve to booleans, so the
|
58
|
+
# above error checking doesn't catch it. This will check to make
|
59
|
+
# sure that the log level is an integer, as Log4r requires.
|
60
|
+
level = nil if !level.is_a?(Integer)
|
61
|
+
|
62
|
+
# Set the logging level on all "vagrant" namespaced
|
63
|
+
# logs as long as we have a valid level.
|
64
|
+
if level
|
65
|
+
logger = Log4r::Logger.new("vagrant_kvm")
|
66
|
+
logger.outputters = Log4r::Outputter.stderr
|
67
|
+
logger.level = level
|
68
|
+
logger = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require "vagrant"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ProviderKvm
|
6
|
+
class Provider < Vagrant.plugin("2", :provider)
|
7
|
+
attr_reader :driver
|
8
|
+
|
9
|
+
def initialize(machine)
|
10
|
+
@logger = Log4r::Logger.new("vagrant_kvm")
|
11
|
+
@machine = machine
|
12
|
+
|
13
|
+
# This method will load in our driver, so we call it now to
|
14
|
+
# initialize it.
|
15
|
+
machine_id_changed
|
16
|
+
end
|
17
|
+
|
18
|
+
def action(name)
|
19
|
+
# Attempt to get the action method from the Action class if it
|
20
|
+
# exists, otherwise return nil to show that we don't support the
|
21
|
+
# given action.
|
22
|
+
action_method = "action_#{name}"
|
23
|
+
return Action.send(action_method) if Action.respond_to?(action_method)
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
# If the machine ID changed, then we need to rebuild our underlying
|
28
|
+
# driver.
|
29
|
+
def machine_id_changed
|
30
|
+
id = @machine.id
|
31
|
+
|
32
|
+
begin
|
33
|
+
@logger.debug("Instantiating the driver for machine ID: #{@machine.id.inspect}")
|
34
|
+
@driver = Driver::Driver.new(id)
|
35
|
+
rescue Driver::Driver::VMNotFound
|
36
|
+
# The virtual machine doesn't exist, so we probably have a stale
|
37
|
+
# ID. Just clear the id out of the machine and reload it.
|
38
|
+
@logger.debug("VM not found! Clearing saved machine ID and reloading.")
|
39
|
+
id = nil
|
40
|
+
retry
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the SSH info for accessing the VM.
|
45
|
+
def ssh_info
|
46
|
+
# If the VM is not created then we cannot possibly SSH into it, so
|
47
|
+
# we return nil.
|
48
|
+
return nil if state == :not_created
|
49
|
+
|
50
|
+
#ip_addr = @driver.read_ip(@machine.config.vm.base_mac)
|
51
|
+
return {
|
52
|
+
:host => read_machine_ip,
|
53
|
+
:port => "22" # XXX should be somewhere in default config
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
# XXX duplicated from prepare_nfs_settings
|
58
|
+
# Returns the IP address of the guest by looking at the first
|
59
|
+
# enabled host only network.
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
def read_machine_ip
|
63
|
+
@machine.config.vm.networks.each do |type, options|
|
64
|
+
if type == :private_network && options[:ip].is_a?(String)
|
65
|
+
return options[:ip]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
# Return the state of the VM
|
73
|
+
#
|
74
|
+
# @return [Symbol]
|
75
|
+
def state
|
76
|
+
# XXX: What happens if we destroy the VM but the UUID is still
|
77
|
+
# set here?
|
78
|
+
|
79
|
+
# Determine the ID of the state here.
|
80
|
+
state_id = nil
|
81
|
+
state_id = :not_created if !@driver.uuid
|
82
|
+
state_id = @driver.read_state if !state_id
|
83
|
+
state_id = :unknown if !state_id
|
84
|
+
|
85
|
+
# TODO Translate into short/long descriptions
|
86
|
+
short = state_id
|
87
|
+
long = I18n.t("vagrant.commands.status.#{state_id}")
|
88
|
+
|
89
|
+
# Return the state
|
90
|
+
Vagrant::MachineState.new(state_id, short, long)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns a human-friendly string version of this provider which
|
94
|
+
# includes the machine's ID that this provider represents, if it
|
95
|
+
# has one.
|
96
|
+
#
|
97
|
+
# @return [String]
|
98
|
+
def to_s
|
99
|
+
id = @machine.id ? @machine.id : "new VM"
|
100
|
+
"QEMU/KVM (#{id})"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module ProviderKvm
|
5
|
+
module Util
|
6
|
+
util_root = Pathname.new(File.expand_path("../util", __FILE__))
|
7
|
+
autoload :VmDefinition, util_root.join("vm_definition")
|
8
|
+
autoload :NetworkDefinition, util_root.join("network_definition")
|
9
|
+
autoload :KvmTemplateRenderer, util_root.join("kvm_template_renderer")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'vagrant/util/template_renderer'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module ProviderKvm
|
5
|
+
module Util
|
6
|
+
# For TemplateRenderer
|
7
|
+
include Vagrant::Util
|
8
|
+
class KvmTemplateRenderer < TemplateRenderer
|
9
|
+
|
10
|
+
# Returns the full path to the template, taking into accoun the gem directory
|
11
|
+
# and adding the `.erb` extension to the end.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
def full_template_path
|
15
|
+
ProviderKvm.source_root.join('templates', "#{template}.erb").to_s.squeeze("/")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Utility class to manage libvirt network definition
|
2
|
+
require "nokogiri"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ProviderKvm
|
6
|
+
module Util
|
7
|
+
class NetworkDefinition
|
8
|
+
# Attributes of the Network
|
9
|
+
attr_reader :name
|
10
|
+
attr_reader :domain_name
|
11
|
+
attr_reader :base_ip
|
12
|
+
|
13
|
+
def initialize(name, definition=nil)
|
14
|
+
@name = name
|
15
|
+
if definition
|
16
|
+
doc = Nokogiri::XML(definition)
|
17
|
+
@forward = doc.at_css("network forward")["mode"] if doc.at_css("network forward")
|
18
|
+
@domain_name = doc.at_css("network domain")["name"] if doc.at_css("network domain")
|
19
|
+
@base_ip = doc.at_css("network ip")["address"]
|
20
|
+
@netmask = doc.at_css("network ip")["netmask"]
|
21
|
+
@range = {
|
22
|
+
:start => doc.at_css("network ip dhcp range")["start"],
|
23
|
+
:end => doc.at_css("network ip dhcp range")["end"]
|
24
|
+
}
|
25
|
+
@hosts = []
|
26
|
+
doc.css("network ip dhcp host").each do |host|
|
27
|
+
@hosts << {
|
28
|
+
:mac => host["mac"],
|
29
|
+
:name => host["name"],
|
30
|
+
:ip => host["ip"]
|
31
|
+
}
|
32
|
+
end
|
33
|
+
else
|
34
|
+
# create with defaults
|
35
|
+
# XXX defaults should move to config
|
36
|
+
@forward = "nat"
|
37
|
+
@domain_name = "vagrant.local"
|
38
|
+
@base_ip = "192.168.192.1"
|
39
|
+
@netmask = "255.255.255.0"
|
40
|
+
@range = {
|
41
|
+
:start => "192.168.192.100",
|
42
|
+
:end => "192.168.192.200"}
|
43
|
+
@hosts = []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def configure(config)
|
48
|
+
config = {
|
49
|
+
:forward => @forward,
|
50
|
+
:domain_name => @domain_name,
|
51
|
+
:base_ip => @base_ip,
|
52
|
+
:netmask => @netmask,
|
53
|
+
:range => @range,
|
54
|
+
:hosts => @hosts}.merge(config)
|
55
|
+
|
56
|
+
@forward = config[:forward]
|
57
|
+
@domain_name = config[:domain_name]
|
58
|
+
@base_ip = config[:base_ip]
|
59
|
+
@netmask = config[:netmask]
|
60
|
+
@range = config[:range]
|
61
|
+
@hosts = config[:hosts]
|
62
|
+
end
|
63
|
+
|
64
|
+
def as_xml
|
65
|
+
xml = <<-EOXML
|
66
|
+
<network>
|
67
|
+
<name>#{@name}</name>
|
68
|
+
<forward mode='#{@forward}'/>
|
69
|
+
<domain name='#{@domain_name}'/>
|
70
|
+
<ip address='#{@base_ip}' netmask='#{@netmask}'>
|
71
|
+
<dhcp>
|
72
|
+
<range start='#{@range[:start]}' end='#{@range[:end]}' />
|
73
|
+
</dhcp>
|
74
|
+
</ip>
|
75
|
+
</network>
|
76
|
+
EOXML
|
77
|
+
xml = inject_hosts(xml) if @hosts.length > 0
|
78
|
+
xml
|
79
|
+
end
|
80
|
+
|
81
|
+
def add_host(host)
|
82
|
+
cur_host = @hosts.detect {|h| h[:mac] == host[:mac]}
|
83
|
+
if cur_host
|
84
|
+
cur_host[:ip] = host[:ip]
|
85
|
+
cur_host[:name] = host[:name]
|
86
|
+
else
|
87
|
+
@hosts << {
|
88
|
+
:mac => host[:mac],
|
89
|
+
:name => host[:name],
|
90
|
+
:ip => host[:ip]}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def inject_hosts(xml)
|
95
|
+
doc = Nokogiri::XML(xml)
|
96
|
+
entry_point = doc.at_css("network ip dhcp range")
|
97
|
+
@hosts.each do |host|
|
98
|
+
entry_point.add_next_sibling "<host mac='#{host[:mac]}' name='#{host[:name]}' ip='#{host[:ip]}' />"
|
99
|
+
end
|
100
|
+
doc.to_xml
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# Utility class to translate ovf definition to libvirt XML
|
2
|
+
# and manage XML formatting for libvirt interaction
|
3
|
+
# Not a full OVF converter, only the minimal needed definition
|
4
|
+
require "nokogiri"
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module ProviderKvm
|
8
|
+
module Util
|
9
|
+
class VmDefinition
|
10
|
+
# Attributes of the VM
|
11
|
+
attr_reader :name
|
12
|
+
attr_reader :cpus
|
13
|
+
attr_accessor :disk
|
14
|
+
attr_reader :mac
|
15
|
+
attr_reader :arch
|
16
|
+
attr_reader :network
|
17
|
+
|
18
|
+
def self.list_interfaces(definition)
|
19
|
+
nics = {}
|
20
|
+
ifcount = 0
|
21
|
+
doc = Nokogiri::XML(definition)
|
22
|
+
# look for user mode interfaces
|
23
|
+
doc.css("devices interface[type='user']").each do |item|
|
24
|
+
ifcount += 1
|
25
|
+
adapter = ifcount
|
26
|
+
nics[adapter] ||= {}
|
27
|
+
nics[adapter][:type] = :user
|
28
|
+
end
|
29
|
+
# look for interfaces on virtual network
|
30
|
+
doc.css("devices interface[type='netwok']").each do |item|
|
31
|
+
ifcount += 1
|
32
|
+
adapter = ifcount
|
33
|
+
nics[adapter] ||= {}
|
34
|
+
nics[adapter][:network] = item.at_css("source")["network"]
|
35
|
+
nics[adapter][:type] = :network
|
36
|
+
end
|
37
|
+
nics
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(definition, source_type='libvirt')
|
41
|
+
@uuid = nil
|
42
|
+
@network = 'default'
|
43
|
+
if source_type == 'ovf'
|
44
|
+
create_from_ovf(definition)
|
45
|
+
else
|
46
|
+
create_from_libvirt(definition)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_from_ovf(definition)
|
51
|
+
doc = Nokogiri::XML(definition)
|
52
|
+
# we don't need no namespace
|
53
|
+
doc.remove_namespaces!
|
54
|
+
@name = doc.at_css("VirtualSystemIdentifier").content
|
55
|
+
devices = doc.css("VirtualHardwareSection Item")
|
56
|
+
for device in devices
|
57
|
+
case device.at_css("ResourceType").content
|
58
|
+
# CPU
|
59
|
+
when "3"
|
60
|
+
@cpus = device.at_css("VirtualQuantity").content
|
61
|
+
# Memory
|
62
|
+
when "4"
|
63
|
+
@memory = size_in_bytes(device.at_css("VirtualQuantity").content,
|
64
|
+
device.at_css("AllocationUnits").content)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# disk volume
|
69
|
+
diskref = doc.at_css("DiskSection Disk")["fileRef"]
|
70
|
+
@disk = doc.at_css("References File[id='#{diskref}']")["href"]
|
71
|
+
|
72
|
+
# mac address
|
73
|
+
# XXX we use only the first nic
|
74
|
+
@mac = format_mac(doc.at_css("Machine Hardware Adapter[enabled='true']")['MACAddress'])
|
75
|
+
|
76
|
+
# the architecture is not defined in the ovf file
|
77
|
+
# we try to guess from OSType
|
78
|
+
# see https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Main/include/ovfreader.h
|
79
|
+
@arch = doc.at_css("VirtualSystemIdentifier").
|
80
|
+
content[-2..-1] == '64' ? "x86_64" : "i686"
|
81
|
+
end
|
82
|
+
|
83
|
+
def create_from_libvirt(definition)
|
84
|
+
doc = Nokogiri::XML(definition)
|
85
|
+
@name = doc.at_css("domain name").content
|
86
|
+
@uuid = doc.at_css("domain uuid").content if doc.at_css("domain uuid")
|
87
|
+
memory_unit = doc.at_css("domain memory")["unit"]
|
88
|
+
@memory = size_in_bytes(doc.at_css("domain memory").content,
|
89
|
+
memory_unit)
|
90
|
+
@cpus = doc.at_css("domain vcpu").content
|
91
|
+
@arch = doc.at_css("domain os type")["arch"]
|
92
|
+
@disk = doc.at_css("devices disk source")["file"]
|
93
|
+
@mac = doc.at_css("devices interface mac")["address"]
|
94
|
+
@network = doc.at_css("devices interface source")["network"]
|
95
|
+
end
|
96
|
+
|
97
|
+
def as_libvirt
|
98
|
+
xml = KvmTemplateRenderer.render("libvirt_domain", {
|
99
|
+
:name => @name,
|
100
|
+
:uuid => @uuid,
|
101
|
+
:memory => size_from_bytes(@memory, "KiB"),
|
102
|
+
:cpus => @cpus,
|
103
|
+
:arch => @arch,
|
104
|
+
:disk => @disk,
|
105
|
+
:mac => format_mac(@mac),
|
106
|
+
:network => @network
|
107
|
+
})
|
108
|
+
xml
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_memory(unit="bytes")
|
112
|
+
size_from_bytes(@memory, unit)
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_mac(mac)
|
116
|
+
@mac = format_mac(mac)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Takes a quantity and a unit
|
120
|
+
# returns quantity in bytes
|
121
|
+
# mib = true to use mebibytes, etc
|
122
|
+
# defaults to false because ovf MB != megabytes
|
123
|
+
def size_in_bytes(qty, unit, mib=false)
|
124
|
+
qty = qty.to_i
|
125
|
+
unit = unit.downcase
|
126
|
+
if !mib
|
127
|
+
case unit
|
128
|
+
when "kb", "kilobytes"
|
129
|
+
unit = "kib"
|
130
|
+
when "mb", "megabytes"
|
131
|
+
unit = "mib"
|
132
|
+
when "gb", "gigabytes"
|
133
|
+
unit = "gib"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
case unit
|
137
|
+
when "b", "bytes"
|
138
|
+
qty.to_s
|
139
|
+
when "kb", "kilobytes"
|
140
|
+
(qty * 1000).to_s
|
141
|
+
when "kib", "kibibytes"
|
142
|
+
(qty * 1024).to_s
|
143
|
+
when "mb", "megabytes"
|
144
|
+
(qty * 1000000).to_s
|
145
|
+
when "m", "mib", "mebibytes"
|
146
|
+
(qty * 1048576).to_s
|
147
|
+
when "gb", "gigabytes"
|
148
|
+
(qty * 1000000000).to_s
|
149
|
+
when "g", "gib", "gibibytes"
|
150
|
+
(qty * 1073741824).to_s
|
151
|
+
else
|
152
|
+
raise ArgumentError, "Unknown unit #{unit}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Takes a qty and a unit
|
157
|
+
# returns byte quantity in that unit
|
158
|
+
def size_from_bytes(qty, unit)
|
159
|
+
qty = qty.to_i
|
160
|
+
case unit.downcase
|
161
|
+
when "b", "bytes"
|
162
|
+
qty.to_s
|
163
|
+
when "kb", "kilobytes"
|
164
|
+
(qty / 1000).to_s
|
165
|
+
when "kib", "kibibytes"
|
166
|
+
(qty / 1024).to_s
|
167
|
+
when "mb", "megabytes"
|
168
|
+
(qty / 1000000).to_s
|
169
|
+
when "m", "mib", "mebibytes"
|
170
|
+
(qty / 1048576).to_s
|
171
|
+
when "gb", "gigabytes"
|
172
|
+
(qty / 1000000000).to_s
|
173
|
+
when "g", "gib", "gibibytes"
|
174
|
+
(qty / 1073741824).to_s
|
175
|
+
else
|
176
|
+
raise ArgumentError, "Unknown unit #{unit}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def format_mac(mac)
|
181
|
+
if mac.length == 12
|
182
|
+
mac = mac[0..1] + ":" + mac[2..3] + ":" +
|
183
|
+
mac[4..5] + ":" + mac[6..7] + ":" +
|
184
|
+
mac[8..9] + ":" + mac[10..11]
|
185
|
+
end
|
186
|
+
mac
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|