wakame-vdc-dcmgr 10.12.0 → 11.06.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/LICENSE +164 -201
  2. data/Rakefile +6 -11
  3. data/bin/collector +10 -24
  4. data/config/dcmgr.conf.example +18 -6
  5. data/config/initializers/isono.rb +7 -23
  6. data/config/initializers/sequel.rb +11 -2
  7. data/lib/dcmgr.rb +70 -11
  8. data/lib/dcmgr/cli/base.rb +74 -0
  9. data/lib/dcmgr/cli/errors.rb +59 -0
  10. data/lib/dcmgr/cli/group.rb +101 -0
  11. data/lib/dcmgr/cli/host.rb +101 -0
  12. data/lib/dcmgr/cli/image.rb +108 -0
  13. data/lib/dcmgr/cli/keypair.rb +72 -0
  14. data/lib/dcmgr/cli/network.rb +198 -0
  15. data/lib/dcmgr/cli/quota.rb +28 -0
  16. data/lib/dcmgr/cli/spec.rb +82 -0
  17. data/lib/dcmgr/cli/storage.rb +88 -0
  18. data/lib/dcmgr/cli/tag.rb +81 -0
  19. data/lib/dcmgr/cli/vlan.rb +53 -0
  20. data/lib/dcmgr/drivers/hypervisor.rb +33 -0
  21. data/lib/dcmgr/drivers/iijgio_storage.rb +37 -0
  22. data/lib/dcmgr/drivers/kvm.rb +118 -0
  23. data/lib/dcmgr/drivers/lxc.rb +167 -0
  24. data/lib/dcmgr/drivers/s3_storage.rb +39 -0
  25. data/lib/dcmgr/drivers/snapshot_storage.rb +51 -0
  26. data/lib/dcmgr/endpoints/core_api.rb +188 -324
  27. data/lib/dcmgr/endpoints/core_api_mock.rb +52 -3
  28. data/lib/dcmgr/endpoints/errors.rb +73 -32
  29. data/lib/dcmgr/endpoints/metadata.rb +163 -16
  30. data/lib/dcmgr/helpers/cli_helper.rb +1 -1
  31. data/lib/dcmgr/helpers/nic_helper.rb +35 -0
  32. data/lib/dcmgr/logger.rb +5 -1
  33. data/lib/dcmgr/messaging_client.rb +117 -0
  34. data/lib/dcmgr/models/account.rb +27 -3
  35. data/lib/dcmgr/models/base_new.rb +21 -7
  36. data/lib/dcmgr/models/host_pool.rb +27 -7
  37. data/lib/dcmgr/models/image.rb +31 -3
  38. data/lib/dcmgr/models/instance.rb +72 -23
  39. data/lib/dcmgr/models/instance_nic.rb +12 -2
  40. data/lib/dcmgr/models/instance_spec.rb +16 -0
  41. data/lib/dcmgr/models/ip_lease.rb +37 -1
  42. data/lib/dcmgr/models/netfilter_group.rb +7 -7
  43. data/lib/dcmgr/models/network.rb +42 -3
  44. data/lib/dcmgr/models/quota.rb +25 -0
  45. data/lib/dcmgr/models/request_log.rb +26 -11
  46. data/lib/dcmgr/models/ssh_key_pair.rb +14 -1
  47. data/lib/dcmgr/models/storage_pool.rb +19 -72
  48. data/lib/dcmgr/models/tag.rb +5 -0
  49. data/lib/dcmgr/models/vlan_lease.rb +8 -0
  50. data/lib/dcmgr/models/volume.rb +26 -8
  51. data/lib/dcmgr/models/volume_snapshot.rb +37 -0
  52. data/lib/dcmgr/node_modules/hva_collector.rb +56 -36
  53. data/lib/dcmgr/node_modules/instance_ha.rb +1 -1
  54. data/lib/dcmgr/node_modules/instance_monitor.rb +70 -0
  55. data/lib/dcmgr/node_modules/service_netfilter.rb +914 -0
  56. data/lib/dcmgr/node_modules/sta_collector.rb +7 -30
  57. data/lib/dcmgr/rack/request_logger.rb +60 -0
  58. data/lib/dcmgr/rack/run_initializer.rb +42 -0
  59. data/lib/dcmgr/rpc/hva_handler.rb +388 -0
  60. data/lib/dcmgr/rubygems.rb +7 -0
  61. data/lib/dcmgr/storage_service.rb +98 -0
  62. data/lib/dcmgr/tags.rb +2 -2
  63. data/lib/dcmgr/version.rb +8 -0
  64. data/lib/ext/time.rb +8 -0
  65. data/lib/sinatra/respond_to.rb +3 -0
  66. data/lib/sinatra/sequel_transaction.rb +20 -5
  67. data/web/api/config.ru +9 -13
  68. data/web/metadata/config.ru +10 -13
  69. metadata +162 -120
  70. data/lib/dcmgr/models/physical_host.rb +0 -67
  71. data/lib/dcmgr/web/base.rb +0 -21
@@ -0,0 +1,28 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Cli
4
+ class Quota < Base
5
+ namespace :quota
6
+ M = Dcmgr::Models
7
+
8
+ desc "modify ACCOUNT_UUID [options]", "Modify the quota settings for an account"
9
+ method_option :weight, :type => :numeric, :aliases => "-w", :desc => "The instance total weight for this account's quota"
10
+ method_option :size, :type => :numeric, :aliases => "-s", :desc => "The volume total size for this account's quota"
11
+ def modify(account_uuid)
12
+ acc = M::Account[account_uuid] || UnknownUUIDError.raise(account_uuid)
13
+ super(M::Quota,acc.quota.canonical_uuid,{:instance_total_weight => options[:weight], :volume_total_size => options[:size]})
14
+ end
15
+
16
+ desc "show ACCOUNT_UUID", "Show the quota settings for an account"
17
+ def show(account_uuid)
18
+ acc = M::Account[account_uuid] || raise(Thor::Error, "Unknown Account UUID: #{account_uuid}")
19
+ puts ERB.new(<<__END, nil, '-').result(binding)
20
+ Instance total weight:
21
+ <%= acc.quota.instance_total_weight %>
22
+ Volume total size:
23
+ <%= acc.quota.volume_total_size %>
24
+ __END
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Cli
4
+ class Spec < Base
5
+ namespace :spec
6
+ M = Dcmgr::Models
7
+
8
+ desc "add [options]", "Register a new machine spec"
9
+ method_option :uuid, :type => :string, :aliases => "-u", :desc => "The UUID for the new machine spec"
10
+ method_option :account_id, :type => :string, :aliases => "-a", :required => true, :desc => "The UUID of the account that this machine spec belongs to"
11
+ method_option :arch, :type => :string, :default => 'x86_64', :aliases => "-r", :desc => "The architecture for the new machine image. [#{M::HostPool::SUPPORTED_ARCH.join(', ')}]"
12
+ method_option(:hypervisor, :type => :string, :aliases => "-p", :default => M::HostPool::HYPERVISOR_KVM.to_s,
13
+ :desc => "The hypervisor type for the new instance. [#{M::HostPool::SUPPORTED_HYPERVISOR.join(', ')}]")
14
+ method_option :cpu_cores, :type => :numeric, :aliases => "-c", :default => 1, :desc => "The initial cpu cores for the new instance"
15
+ method_option :memory_size, :type => :numeric, :aliases => "-m", :default => 1024, :desc => "The memory size for the new instance"
16
+ method_option :quota_weight, :type => :numeric, :aliases => "-w", :default => 1.0, :desc => "The cost weight factor for the new instance"
17
+ #method_option :is_public, :type => :boolean, :aliases => "-p", :default => false, :desc => "A flag that determines whether the new machine image is public or not."
18
+ def add
19
+ UnknownUUIDError.raise(options[:account_id]) if M::Account[options[:account_id]].nil?
20
+ UnsupportedArchError.raise(options[:arch]) unless M::HostPool::SUPPORTED_ARCH.member?(options[:arch])
21
+ UnsupportedHypervisorError.raise(options[:hypervisor]) unless M::HostPool::SUPPORTED_HYPERVISOR.member?(options[:hypervisor])
22
+ fields = options.dup
23
+ fields[:config] = {
24
+ }
25
+ puts super(M::InstanceSpec, fields)
26
+ end
27
+
28
+ desc "modify UUID [options]", "Modify an existing machine spec"
29
+ method_option :account_id, :type => :string, :aliases => "-a", :desc => "The UUID of the account that this machine spec belongs to"
30
+ method_option :arch, :type => :string, :aliases => "-r", :desc => "The architecture for the new machine image. [#{M::HostPool::SUPPORTED_ARCH.join(', ')}]"
31
+ method_option(:hypervisor, :type => :string, :aliases => "-p",
32
+ :desc => "The hypervisor type for the new instance. [#{M::HostPool::SUPPORTED_HYPERVISOR.join(', ')}]")
33
+ method_option :cpu_cores, :type => :numeric, :aliases => "-c", :desc => "The initial cpu cores for the new instance"
34
+ method_option :memory_size, :type => :numeric, :aliases => "-m", :desc => "The memory size for the new instance"
35
+ method_option :quota_weight, :type => :numeric, :aliases => "-w", :desc => "The cost weight factor for the new instance"
36
+ def modify(uuid)
37
+ UnknownUUIDError.raise(options[:account_id]) if options[:account_id] && M::Account[options[:account_id]].nil?
38
+ UnsupportedArchError.raise(options[:arch]) unless options[:arch].nil? || M::HostPool::SUPPORTED_ARCH.member?(options[:arch])
39
+ UnsupportedHypervisorError.raise(options[:hypervisor]) unless options[:hypervisor].nil? || M::HostPool::SUPPORTED_HYPERVISOR.member?(options[:hypervisor])
40
+ super(M::InstanceSpec,uuid,options)
41
+ end
42
+
43
+ desc "del UUID", "Delete registered machine spec"
44
+ def del(uuid)
45
+ UnknownUUIDError.raise(uuid) if M::InstanceSpec[uuid].nil?
46
+ super(M::InstanceSpec, uuid)
47
+ end
48
+
49
+ desc "show [UUID]", "Show list of machine spec and details"
50
+ def show(uuid=nil)
51
+ if uuid
52
+ spec = M::InstanceSpec[uuid]
53
+ print ERB.new(<<__END, nil, '-').result(binding)
54
+ UUID:
55
+ <%= spec.canonical_uuid %>
56
+ Account ID:
57
+ <%= spec.account_id %>
58
+ Hypervisor:
59
+ <%= spec.hypervisor %>
60
+ Arch:
61
+ <%= spec.arch %>
62
+ CPU Cores:
63
+ <%= spec.cpu_cores %>
64
+ Memory Size:
65
+ <%= spec.memory_size %>
66
+ Quota Weight:
67
+ <%= spec.quota_weight %>
68
+ Hypervisor Configuration:
69
+ <%= spec.config.inspect %>
70
+ __END
71
+ else
72
+ cond = {}
73
+ specs = M::InstanceSpec.filter(cond).all
74
+ print ERB.new(<<__END, nil, '-').result(binding)
75
+ <%- specs.each { |row| -%>
76
+ <%= "%-20s %-15s %-15s" % [row.canonical_uuid, row.account_id, row.arch] %>
77
+ <%- } -%>
78
+ __END
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,88 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'thor'
4
+ require 'isono'
5
+
6
+ module Dcmgr::Cli
7
+ class Storage < Base
8
+ namespace :storage
9
+ include Dcmgr::Models
10
+
11
+ desc "add NODE_ID [options]", "Register a new storage node"
12
+ method_option :uuid, :type => :string, :aliases => "-u", :desc => "The uuid for the new storage pool."
13
+ method_option :base_path, :type => :string, :aliases => "-b", :required => true, :desc => "Base path to store volume files"
14
+ method_option :snapshot_base_path, :type => :string, :aliases => "-n", :required => true, :desc => "Base path to store snapshot files"
15
+ method_option :disk_space, :type => :numeric, :aliases => "-s", :required => true, :desc => "Amount of disk size to be exported (in MB)."
16
+ method_option :transport_type, :type => :string, :aliases => "-t", :default=>'iscsi', :desc => "Transport type [iscsi]"
17
+ method_option :ipaddr, :type => :string, :aliases => "-i", :required=>true, :desc => "IP address of transport target"
18
+ method_option :storage_type, :type => :string, :aliases => "-o", :default=>'zfs', :desc => "Storage type [zfs]"
19
+ method_option :account_id, :type => :string, :default=>'a-shpool', :aliases => "-a", :desc => "The account ID to own this."
20
+ def add(node_id)
21
+ unless (options[:force] == false && Isono::Models::NodeState.exists?(:node_id=>options[:node_id]))
22
+ abort("Node ID is not registered yet: #{options[:node_id]}")
23
+ end
24
+
25
+ fields = {:node_id=>options[:node_id],
26
+ :offering_disk_space=>options[:disk_space],
27
+ :transport_type=>options[:transport_type],
28
+ :storage_type=>options[:storage_type],
29
+ :export_path=>options[:base_path],
30
+ :snapshot_base_path => options[:snapshot_base_path],
31
+ :ipaddr=>options[:ipaddr],
32
+ :account_id=>options[:account_id],
33
+ }
34
+ fields.merge!({:uuid => options[:uuid]}) unless options[:uuid].nil?
35
+
36
+ puts super(StoragePool,fields)
37
+ end
38
+
39
+ desc "del UUID", "Deregister a storage node"
40
+ def del(uuid)
41
+ super(StoragePool,uuid)
42
+ end
43
+
44
+ desc "show [UUID]", "Show list of storage nodes and details"
45
+ def show(uuid=nil)
46
+ if uuid
47
+ st = StoragePool[uuid]
48
+ puts ERB.new(<<__END, nil, '-').result(binding)
49
+ UUID:
50
+ <%= st.canonical_uuid %>
51
+ Node ID:
52
+ <%= st.node_id %>
53
+ Disk space (offerring):
54
+ <%= st.offering_disk_space %>MB
55
+ Storage:
56
+ <%= st.storage_type %>
57
+ Transport:
58
+ <%= st.transport_type %>
59
+ IP Address:
60
+ <%= st.ipaddr %>
61
+ Export path:
62
+ <%= st.export_path %>
63
+ Snapshot base path:
64
+ <%= st.snapshot_base_path %>
65
+ __END
66
+ else
67
+ cond = {}
68
+ all = StoragePool.filter(cond).all
69
+ puts ERB.new(<<__END, nil, '-').result(binding)
70
+ <%- all.each { |row| -%>
71
+ <%= "%-15s %-20s %-10s" % [row.canonical_uuid, row.node_id, row.status] %>
72
+ <%- } -%>
73
+ __END
74
+ end
75
+ end
76
+
77
+ desc "shownodes", "Show node (agents)"
78
+ def shownodes
79
+ nodes = Isono::Models::NodeState.filter.all
80
+
81
+ puts ERB.new(<<__END, nil, '-').result(binding)
82
+ <%- nodes.each { |row| -%>
83
+ <%= "%-20s %-10s" % [row.node_id, row.state] %>
84
+ <%- } -%>
85
+ __END
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,81 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Cli
4
+ class Tag < Base
5
+ namespace :tag
6
+ M = Dcmgr::Models
7
+
8
+ desc "add [options]", "Create a new tag"
9
+ method_option :uuid, :type => :string, :aliases => "-u", :desc => "The UUID for the new tag"
10
+ method_option :account_id, :type => :string, :aliases => "-a", :desc => "The UUID of the account that this tag belongs to", :required => true
11
+ method_option :type_id, :type => :numeric, :aliases => "-t", :desc => "The type for the new tag. Valid types are '#{Dcmgr::Tags::KEY_MAP.keys.join(", ")}'", :required => true
12
+ method_option :name, :type => :string, :aliases => "-n", :desc => "The name for the new tag", :required => true
13
+ method_option :attributes, :type => :string, :aliases => "-b", :desc => "The attributes for the new tag"
14
+ def add
15
+ UnknownUUIDError.raise(options[:account_id]) if M::Account[options[:account_id]].nil?
16
+ Error.raise("Invalid type_id: '#{options[:type_id]}'. Valid types are '#{Dcmgr::Tags::KEY_MAP.keys.join(", ")}'.",100) unless Dcmgr::Tags::KEY_MAP.member? options[:type_id]
17
+
18
+ puts super(M::Tag,options)
19
+ end
20
+
21
+ desc "modify UUID [options]", "Modify an existing tag"
22
+ method_option :account_id, :type => :string, :aliases => "-a", :desc => "The UUID of the account that this tag belongs to"
23
+ method_option :type_id, :type => :numeric, :aliases => "-t", :desc => "The type for the new tag. Valid types are '#{Dcmgr::Tags::KEY_MAP.keys.join(", ")}'"
24
+ method_option :name, :type => :string, :aliases => "-n", :desc => "The name for the new tag"
25
+ method_option :attributes, :type => :string, :aliases => "-b", :desc => "The attributes for the new tag"
26
+ def modify(uuid)
27
+ UnknownUUIDError.raise(options[:account_id]) if options[:account_id] && M::Account[options[:account_id]].nil?
28
+ Error.raise("Invalid type_id: '#{options[:type_id]}'. Valid types are '#{Dcmgr::Tags::KEY_MAP.keys.join(", ")}'.",100) unless options[:type_id].nil? || Dcmgr::Tags::KEY_MAP.member?(options[:type_id])
29
+ super(M::Tag,uuid,options)
30
+ end
31
+
32
+ desc "show [UUID]", "Show the existing tag(s)"
33
+ def show(uuid=nil)
34
+ if uuid
35
+ tag = M::Tag[uuid] || UnknownUUIDError.raise(uuid)
36
+ puts ERB.new(<<__END, nil, '-').result(binding)
37
+ Tag UUID:
38
+ <%= tag.canonical_uuid %>
39
+ Account id:
40
+ <%= tag.account_id %>
41
+ Name:
42
+ <%= tag.name %>
43
+ Type id:
44
+ <%= tag.type_id %>
45
+ Attributes:
46
+ <%= tag.attributes %>
47
+ __END
48
+ else
49
+ puts ERB.new(<<__END, nil, '-').result(binding)
50
+ <%- M::Tag.each { |row| -%>
51
+ <%= row.canonical_uuid %>\t<%= row.account_id %>\t<%= row.type_id %>\t<%= row.name%>
52
+ <%- } -%>
53
+ __END
54
+ end
55
+ end
56
+
57
+ desc "del UUID", "Delete an existing tag"
58
+ def del(uuid)
59
+ super(M::Tag,uuid)
60
+ end
61
+
62
+ desc "map UUID [options]", "Map a tag to a taggable object"
63
+ method_option :object_id, :type => :string, :aliases => "-o", :desc => "The canonical UUID for the object to map this tag to.", :required => true
64
+ def map(uuid)
65
+ #Quick hack to get all models in Dcmgr::Models loaded in Taggable.uuid_prefix_collection
66
+ #This is so the Taggable.find method can be used to determine the Model class based on canonical uuid
67
+ M.constants.each {|c| eval("M::#{c}")}
68
+
69
+ object = M::Taggable.find(options[:object_id])
70
+
71
+ UnknownUUIDError.raise(uuid) if M::Tag[uuid].nil?
72
+ UnknownUUIDError.raise(options[:object_id]) if object.nil?
73
+ Error.raise("Tag '#{uuid}' can not be mapped to a '#{object.class}'.",100) unless M::Tag[uuid].accept_mapping?(object)
74
+
75
+ M::TagMapping.create(
76
+ :tag_id => M::Tag[uuid].id,
77
+ :uuid => object.canonical_uuid
78
+ )
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,53 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Cli
4
+ class Vlan < Base
5
+ namespace :vlan
6
+ M = Dcmgr::Models
7
+
8
+ desc "add [options]", "Create a new vlan lease"
9
+ method_option :uuid, :type => :string, :aliases => "-u", :desc => "The UUID for the new vlan lease"
10
+ method_option :account_id, :type => :string, :aliases => "-a", :desc => "The UUID of the account for this vlan lease"
11
+ method_option :tag_id, :type => :numeric, :aliases => "-t", :desc => "The ethernet tag for this vlan lease"
12
+ def add
13
+ UnknownUUIDError.raise(options[:account_id]) if M::Account[options[:account_id]].nil?
14
+ Error.raise("Tag_id already exists",100) unless M::VlanLease.find(:tag_id => options[:tag_id]).nil?
15
+
16
+ puts super(M::VlanLease,options)
17
+ end
18
+
19
+ desc "del UUID", "Delete an existing vlan lease"
20
+ def del(uuid)
21
+ super(M::VlanLease,uuid)
22
+ end
23
+
24
+ desc "modify UUID [options]", "Modify an existing vlan lease"
25
+ method_option :account_id, :type => :string, :aliases => "-a", :desc => "The UUID of the account for this vlan lease"
26
+ method_option :tag_id, :type => :numeric, :aliases => "-t", :desc => "The ethernet tag for this vlan lease"
27
+ def modify(uuid)
28
+ UnknownUUIDError.raise(options[:account_id]) if options[:account_id] && M::Account[options[:account_id]].nil?
29
+ super(M::VlanLease,uuid,options)
30
+ end
31
+
32
+ desc "show [UUID]", "Show existing vlan lease(s)"
33
+ def show(uuid=nil)
34
+ if uuid
35
+ lease = M::VlanLease[uuid] || UnknownUUIDError.raise(uuid)
36
+ puts ERB.new(<<__END, nil, '-').result(binding)
37
+ Vlan Lease UUID:
38
+ <%= lease.canonical_uuid %>
39
+ Account id:
40
+ <%= lease.account_id %>
41
+ Tag id:
42
+ <%= lease.tag_id %>
43
+ __END
44
+ else
45
+ puts ERB.new(<<__END, nil, '-').result(binding)
46
+ <%- M::VlanLease.each { |row| -%>
47
+ <%= row.canonical_uuid %>\t<%= row.account_id %>\t<%= row.tag_id %>
48
+ <%- } -%>
49
+ __END
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ module Dcmgr
2
+ module Drivers
3
+ class Hypervisor
4
+
5
+ def run_instance(hc)
6
+ end
7
+
8
+ def terminate_instance(hc)
9
+ end
10
+
11
+ def reboot_instance(hc)
12
+ end
13
+
14
+ def attach_volume_to_guest(hc)
15
+ end
16
+
17
+ def detach_volume_from_guest(hc)
18
+ end
19
+
20
+ def self.select_hypervisor(hypervisor)
21
+ case hypervisor
22
+ when "kvm"
23
+ hv = Dcmgr::Drivers::Kvm.new
24
+ when "lxc"
25
+ hv = Dcmgr::Drivers::Lxc.new
26
+ else
27
+ raise "Unknown hypervisor type: #{hypervisor}"
28
+ end
29
+ hv
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Drivers
4
+
5
+ class IIJGIOStorage < SnapshotStorage
6
+
7
+ def download(keyname, filename, path)
8
+ cmd = "get %s %s %s"
9
+ args = [@bucket, keyname, File.join(path, filename)]
10
+ execute(cmd, args)
11
+ end
12
+
13
+ def upload(keyname, file)
14
+ cmd = "put %s %s %s"
15
+ args = [@bucket, keyname, file]
16
+ execute(cmd, args)
17
+ end
18
+
19
+ def delete(keyname)
20
+ cmd = "rm %s %s"
21
+ args = [@bucket, keyname]
22
+ execute(cmd, args)
23
+ end
24
+
25
+ def check(keyname)
26
+ cmd = "test %s %s"
27
+ args = [@bucket, keyname]
28
+ execute(cmd, args)
29
+ end
30
+
31
+ def list
32
+ cmd = "ls %s"
33
+ args = [@bucket]
34
+ execute(cmd, args)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,118 @@
1
+ module Dcmgr
2
+ module Drivers
3
+ class Kvm < Hypervisor
4
+ include Dcmgr::Logger
5
+ include Dcmgr::Helpers::CliHelper
6
+ include Dcmgr::Rpc::KvmHelper
7
+ include Dcmgr::Helpers::NicHelper
8
+
9
+ def run_instance(hc)
10
+ # run vm
11
+ inst = hc.inst
12
+ cmd = "kvm -m %d -smp %d -name vdc-%s -vnc :%d -drive file=%s -pidfile %s -daemonize -monitor telnet::%d,server,nowait"
13
+ args=[inst[:instance_spec][:memory_size],
14
+ inst[:instance_spec][:cpu_cores],
15
+ inst[:uuid],
16
+ inst[:runtime_config][:vnc_port],
17
+ hc.os_devpath,
18
+ File.expand_path('kvm.pid', hc.inst_data_dir),
19
+ inst[:runtime_config][:telnet_port]
20
+ ]
21
+ if vnic = inst[:instance_nics].first
22
+ cmd += " -net nic,macaddr=%s -net tap,ifname=%s,script=,downscript="
23
+ args << vnic[:mac_addr].unpack('A2'*6).join(':')
24
+ args << vnic[:uuid]
25
+ end
26
+ sh(cmd, args)
27
+
28
+ unless vnic.nil?
29
+ sh("/sbin/ifconfig %s 0.0.0.0 up", [vnic[:uuid]])
30
+ sh("/usr/sbin/brctl addif %s %s", [hc.bridge_if, vnic[:uuid]])
31
+ end
32
+
33
+ sleep 1
34
+ end
35
+
36
+ def terminate_instance(hc)
37
+ kvm_pid=`pgrep -u root -f vdc-#{hc.inst_id}`
38
+ if $?.exitstatus == 0 && kvm_pid.to_s =~ /^\d+$/
39
+ sh("/bin/kill #{kvm_pid}")
40
+ else
41
+ logger.error("Can not find the KVM process. Skipping: kvm -name vdc-#{hc.inst_id}")
42
+ end
43
+ end
44
+
45
+ def reboot_instance(hc)
46
+ inst = hc.inst
47
+ connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
48
+ t.cmd("system_reset")
49
+ }
50
+ end
51
+
52
+ def attach_volume_to_guest(hc)
53
+ # pci_devddr consists of three hex numbers with colon separator.
54
+ # dom <= 0xffff && bus <= 0xff && val <= 0x1f
55
+ # see: qemu-0.12.5/hw/pci.c
56
+ # /*
57
+ # * Parse [[<domain>:]<bus>:]<slot>, return -1 on error
58
+ # */
59
+ # static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
60
+ pci_devaddr = nil
61
+ inst = hc.inst
62
+
63
+ sddev = File.expand_path(File.readlink(hc.os_devpath), '/dev/disk/by-path')
64
+ connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
65
+ # success message:
66
+ # OK domain 0, bus 0, slot 4, function 0
67
+ # error message:
68
+ # failed to add file=/dev/xxxx,if=virtio
69
+ c = t.cmd("pci_add auto storage file=#{sddev},if=scsi")
70
+ # Note: pci_parse_devaddr() called in "pci_add" uses strtoul()
71
+ # with base 16 so that the input is expected in hex. however
72
+ # at the result display, void pci_device_hot_add_print() uses
73
+ # %d for showing bus and slot addresses. use hex to preserve
74
+ # those values to keep consistent.
75
+ if c =~ /\nOK domain ([0-9a-fA-F]+), bus ([0-9a-fA-F]+), slot ([0-9a-fA-F]+), function/m
76
+ # numbers in OK result is decimal. convert them to hex.
77
+ pci_devaddr = [$1, $2, $3].map{|i| i.to_i.to_s(16) }
78
+ else
79
+ raise "Error in qemu console: #{c}"
80
+ end
81
+
82
+ # double check the pci address.
83
+ c = t.cmd("info pci")
84
+
85
+ # static void pci_info_device(PCIBus *bus, PCIDevice *d)
86
+ # called in "info pci" gets back PCI bus info with %d.
87
+ if c.split(/\n/).grep(/^\s+Bus\s+#{pci_devaddr[1].to_i(16)}, device\s+#{pci_devaddr[2].to_i(16)}, function/).empty?
88
+ raise "Could not find new disk device attached to qemu-kvm: #{pci_devaddr.join(':')}"
89
+ end
90
+ }
91
+ pci_devaddr.join(':')
92
+ end
93
+
94
+ def detach_volume_from_guest(hc)
95
+ inst = hc.inst
96
+ vol = hc.vol
97
+ pci_devaddr = vol[:guest_device_name]
98
+
99
+ connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
100
+ t.cmd("pci_del #{pci_devaddr}")
101
+ #
102
+ # Bus 0, device 4, function 0:
103
+ # SCSI controller: PCI device 1af4:1001
104
+ # IRQ 0.
105
+ # BAR0: I/O at 0x1000 [0x103f].
106
+ # BAR1: 32 bit memory at 0x08000000 [0x08000fff].
107
+ # id ""
108
+ c = t.cmd("info pci")
109
+ pci_devaddr = pci_devaddr.split(':')
110
+ unless c.split(/\n/).grep(/\s+Bus\s+#{pci_devaddr[1].to_i(16)}, device\s+#{pci_devaddr[2].to_i(16)}, function/).empty?
111
+ raise "Detached disk device still be attached in qemu-kvm: #{pci_devaddr.join(':')}"
112
+ end
113
+ }
114
+ end
115
+
116
+ end
117
+ end
118
+ end