wakame-vdc-dcmgr 11.06.0 → 11.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. data/Rakefile +19 -31
  2. data/bin/collector +6 -1
  3. data/config/db/migrations/0001_v1110_origin.rb +446 -0
  4. data/config/dcmgr.conf.example +51 -0
  5. data/lib/dcmgr.rb +99 -22
  6. data/lib/dcmgr/cli/base.rb +34 -1
  7. data/lib/dcmgr/cli/host.rb +24 -20
  8. data/lib/dcmgr/cli/image.rb +38 -19
  9. data/lib/dcmgr/cli/keypair.rb +16 -12
  10. data/lib/dcmgr/cli/network.rb +189 -81
  11. data/lib/dcmgr/cli/quota.rb +2 -2
  12. data/lib/dcmgr/cli/security_group.rb +106 -0
  13. data/lib/dcmgr/cli/spec.rb +144 -39
  14. data/lib/dcmgr/cli/storage.rb +16 -15
  15. data/lib/dcmgr/cli/tag.rb +20 -14
  16. data/lib/dcmgr/cli/vlan.rb +5 -5
  17. data/lib/dcmgr/drivers/backing_store.rb +32 -0
  18. data/lib/dcmgr/drivers/comstar.rb +81 -0
  19. data/lib/dcmgr/drivers/iijgio_storage.rb +9 -19
  20. data/lib/dcmgr/drivers/iscsi_target.rb +41 -0
  21. data/lib/dcmgr/drivers/kvm.rb +161 -28
  22. data/lib/dcmgr/drivers/linux_iscsi.rb +60 -0
  23. data/lib/dcmgr/drivers/local_storage.rb +24 -0
  24. data/lib/dcmgr/drivers/lxc.rb +167 -125
  25. data/lib/dcmgr/drivers/raw.rb +74 -0
  26. data/lib/dcmgr/drivers/s3_storage.rb +7 -19
  27. data/lib/dcmgr/drivers/snapshot_storage.rb +18 -28
  28. data/lib/dcmgr/drivers/storage_initiator.rb +28 -0
  29. data/lib/dcmgr/drivers/sun_iscsi.rb +32 -0
  30. data/lib/dcmgr/drivers/zfs.rb +77 -0
  31. data/lib/dcmgr/endpoints/core_api.rb +315 -263
  32. data/lib/dcmgr/endpoints/errors.rb +21 -10
  33. data/lib/dcmgr/endpoints/metadata.rb +360 -23
  34. data/lib/dcmgr/helpers/cli_helper.rb +6 -3
  35. data/lib/dcmgr/helpers/ec2_metadata_helper.rb +9 -0
  36. data/lib/dcmgr/helpers/nic_helper.rb +11 -0
  37. data/lib/dcmgr/helpers/snapshot_storage_helper.rb +34 -0
  38. data/lib/dcmgr/models/account.rb +0 -6
  39. data/lib/dcmgr/models/account_resource.rb +0 -4
  40. data/lib/dcmgr/models/base_new.rb +14 -2
  41. data/lib/dcmgr/models/dhcp_range.rb +38 -0
  42. data/lib/dcmgr/models/frontend_system.rb +0 -6
  43. data/lib/dcmgr/models/history.rb +0 -11
  44. data/lib/dcmgr/models/host_node.rb +131 -0
  45. data/lib/dcmgr/models/hostname_lease.rb +0 -8
  46. data/lib/dcmgr/models/image.rb +31 -18
  47. data/lib/dcmgr/models/instance.rb +137 -143
  48. data/lib/dcmgr/models/instance_nic.rb +52 -29
  49. data/lib/dcmgr/models/instance_security_group.rb +9 -0
  50. data/lib/dcmgr/models/instance_spec.rb +163 -31
  51. data/lib/dcmgr/models/ip_lease.rb +10 -21
  52. data/lib/dcmgr/models/mac_lease.rb +30 -11
  53. data/lib/dcmgr/models/network.rb +148 -27
  54. data/lib/dcmgr/models/physical_network.rb +18 -0
  55. data/lib/dcmgr/models/quota.rb +0 -10
  56. data/lib/dcmgr/models/request_log.rb +3 -18
  57. data/lib/dcmgr/models/security_group.rb +66 -0
  58. data/lib/dcmgr/models/security_group_rule.rb +145 -0
  59. data/lib/dcmgr/models/ssh_key_pair.rb +16 -19
  60. data/lib/dcmgr/models/{storage_pool.rb → storage_node.rb} +35 -25
  61. data/lib/dcmgr/models/tag.rb +0 -14
  62. data/lib/dcmgr/models/tag_mapping.rb +1 -7
  63. data/lib/dcmgr/models/vlan_lease.rb +2 -8
  64. data/lib/dcmgr/models/volume.rb +49 -37
  65. data/lib/dcmgr/models/volume_snapshot.rb +15 -17
  66. data/lib/dcmgr/node_modules/hva_collector.rb +69 -28
  67. data/lib/dcmgr/node_modules/instance_ha.rb +23 -12
  68. data/lib/dcmgr/node_modules/instance_monitor.rb +16 -2
  69. data/lib/dcmgr/node_modules/openflow_controller.rb +784 -0
  70. data/lib/dcmgr/node_modules/scheduler.rb +189 -0
  71. data/lib/dcmgr/node_modules/service_netfilter.rb +452 -227
  72. data/lib/dcmgr/node_modules/service_openflow.rb +731 -0
  73. data/lib/dcmgr/node_modules/sta_collector.rb +20 -0
  74. data/lib/dcmgr/node_modules/sta_tgt_initializer.rb +35 -0
  75. data/lib/dcmgr/rack/request_logger.rb +11 -6
  76. data/lib/dcmgr/rpc/hva_handler.rb +256 -110
  77. data/lib/dcmgr/rpc/sta_handler.rb +244 -0
  78. data/lib/dcmgr/scheduler.rb +122 -8
  79. data/lib/dcmgr/scheduler/host_node/exclude_same.rb +24 -0
  80. data/lib/dcmgr/scheduler/host_node/find_first.rb +12 -0
  81. data/lib/dcmgr/scheduler/host_node/least_usage.rb +28 -0
  82. data/lib/dcmgr/scheduler/host_node/per_instance.rb +18 -0
  83. data/lib/dcmgr/scheduler/host_node/specify_node.rb +26 -0
  84. data/lib/dcmgr/scheduler/network/flat_single.rb +23 -0
  85. data/lib/dcmgr/scheduler/network/nat_one_to_one.rb +23 -0
  86. data/lib/dcmgr/scheduler/network/per_instance.rb +39 -0
  87. data/lib/dcmgr/scheduler/network/vif_template.rb +19 -0
  88. data/lib/dcmgr/scheduler/storage_node/find_first.rb +13 -0
  89. data/lib/dcmgr/scheduler/storage_node/least_usage.rb +23 -0
  90. data/lib/dcmgr/storage_service.rb +39 -40
  91. data/lib/dcmgr/tags.rb +3 -3
  92. data/lib/dcmgr/version.rb +1 -1
  93. data/lib/dcmgr/vnet.rb +105 -0
  94. data/lib/dcmgr/vnet/factories.rb +141 -0
  95. data/lib/dcmgr/vnet/isolators/by_securitygroup.rb +21 -0
  96. data/lib/dcmgr/vnet/isolators/dummy.rb +17 -0
  97. data/lib/dcmgr/vnet/netfilter/cache.rb +51 -0
  98. data/lib/dcmgr/vnet/netfilter/chain.rb +66 -0
  99. data/lib/dcmgr/vnet/netfilter/controller.rb +193 -0
  100. data/lib/dcmgr/vnet/netfilter/ebtables_rule.rb +53 -0
  101. data/lib/dcmgr/vnet/netfilter/iptables_rule.rb +45 -0
  102. data/lib/dcmgr/vnet/netfilter/task_manager.rb +459 -0
  103. data/lib/dcmgr/vnet/tasks/accept_all_dns.rb +19 -0
  104. data/lib/dcmgr/vnet/tasks/accept_arp_broadcast.rb +24 -0
  105. data/lib/dcmgr/vnet/tasks/accept_arp_from_friends.rb +34 -0
  106. data/lib/dcmgr/vnet/tasks/accept_arp_from_gateway.rb +21 -0
  107. data/lib/dcmgr/vnet/tasks/accept_arp_to_host.rb +30 -0
  108. data/lib/dcmgr/vnet/tasks/accept_ip_from_friends.rb +26 -0
  109. data/lib/dcmgr/vnet/tasks/accept_ip_from_gateway.rb +23 -0
  110. data/lib/dcmgr/vnet/tasks/accept_ip_to_anywhere.rb +18 -0
  111. data/lib/dcmgr/vnet/tasks/accept_related_established.rb +45 -0
  112. data/lib/dcmgr/vnet/tasks/accept_wakame_dhcp_only.rb +33 -0
  113. data/lib/dcmgr/vnet/tasks/accept_wakame_dns_only.rb +33 -0
  114. data/lib/dcmgr/vnet/tasks/debug_iptables.rb +21 -0
  115. data/lib/dcmgr/vnet/tasks/drop_arp_forwarding.rb +27 -0
  116. data/lib/dcmgr/vnet/tasks/drop_arp_to_host.rb +24 -0
  117. data/lib/dcmgr/vnet/tasks/drop_ip_from_anywhere.rb +18 -0
  118. data/lib/dcmgr/vnet/tasks/drop_ip_spoofing.rb +34 -0
  119. data/lib/dcmgr/vnet/tasks/drop_mac_spoofing.rb +33 -0
  120. data/lib/dcmgr/vnet/tasks/exclude_from_nat.rb +47 -0
  121. data/lib/dcmgr/vnet/tasks/security_group.rb +37 -0
  122. data/lib/dcmgr/vnet/tasks/static_nat.rb +54 -0
  123. data/lib/dcmgr/vnet/tasks/translate_metadata_address.rb +32 -0
  124. data/web/metadata/config.ru +1 -1
  125. metadata +174 -89
  126. data/lib/dcmgr/cli/group.rb +0 -101
  127. data/lib/dcmgr/endpoints/core_api_mock.rb +0 -865
  128. data/lib/dcmgr/models/host_pool.rb +0 -122
  129. data/lib/dcmgr/models/instance_netfilter_group.rb +0 -16
  130. data/lib/dcmgr/models/netfilter_group.rb +0 -89
  131. data/lib/dcmgr/models/netfilter_rule.rb +0 -21
  132. data/lib/dcmgr/scheduler/find_last.rb +0 -16
  133. data/lib/dcmgr/scheduler/find_random.rb +0 -16
  134. data/lib/dcmgr/stm/instance.rb +0 -25
  135. data/lib/dcmgr/stm/snapshot_context.rb +0 -33
  136. data/lib/dcmgr/stm/volume_context.rb +0 -65
@@ -3,34 +3,24 @@
3
3
  module Dcmgr::Drivers
4
4
 
5
5
  class IIJGIOStorage < SnapshotStorage
6
-
7
- def download(keyname, filename, path)
6
+ include Dcmgr::Logger
7
+ include Dcmgr::Helpers::SnapshotStorageHelper
8
+
9
+ def download(filename)
8
10
  cmd = "get %s %s %s"
9
- args = [@bucket, keyname, File.join(path, filename)]
11
+ args = [@bucket, key(filename), self.snapshot(filename)]
10
12
  execute(cmd, args)
11
13
  end
12
14
 
13
- def upload(keyname, file)
15
+ def upload(filename)
14
16
  cmd = "put %s %s %s"
15
- args = [@bucket, keyname, file]
17
+ args = [@bucket, key(filename), self.snapshot(filename)]
16
18
  execute(cmd, args)
17
19
  end
18
20
 
19
- def delete(keyname)
21
+ def delete(filename)
20
22
  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]
23
+ args = [@bucket, key(filename)]
34
24
  execute(cmd, args)
35
25
  end
36
26
  end
@@ -0,0 +1,41 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr
4
+ module Drivers
5
+ class IscsiTarget
6
+ attr_reader :node
7
+
8
+ def create(ctx)
9
+ raise NotImplmenetedError
10
+ end
11
+
12
+ def delete(ctx)
13
+ raise NotImplmenetedError
14
+ end
15
+
16
+ # Register target information to the target device.
17
+ # @param [Hash] volume hash data
18
+ def register(volume)
19
+ # TODO: uncomment here once all drivers were updated.
20
+ #raise NotImplmenetedError
21
+ end
22
+
23
+ def self.select_iscsi_target(iscsi_target, node)
24
+ raise ArgumentError unless node.is_a?(Isono::Node)
25
+ case iscsi_target
26
+ when "linux_iscsi"
27
+ bs = Dcmgr::Drivers::LinuxIscsi.new
28
+ when "sun_iscsi"
29
+ bs = Dcmgr::Drivers::SunIscsi.new
30
+ when "comstar"
31
+ bs = Dcmgr::Drivers::Comstar.new
32
+ else
33
+ raise "Unknown iscsi_target type: #{iscsi_target}"
34
+ end
35
+ # for bs.node readable accessor.
36
+ bs.instance_variable_set(:@node, node)
37
+ bs
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,51 +1,105 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'net/telnet'
4
+
1
5
  module Dcmgr
2
6
  module Drivers
3
7
  class Kvm < Hypervisor
4
8
  include Dcmgr::Logger
5
9
  include Dcmgr::Helpers::CliHelper
6
- include Dcmgr::Rpc::KvmHelper
7
10
  include Dcmgr::Helpers::NicHelper
8
11
 
12
+ # 0x0-2 are reserved by KVM.
13
+ # 0=Host bridge
14
+ # 1=ISA bridge
15
+ # 2=VGA
16
+ KVM_NIC_PCI_ADDR_OFFSET=0x10
17
+
9
18
  def run_instance(hc)
19
+
20
+ # tcp listen ports for KVM monitor and VNC console
21
+ monitor_port = pick_tcp_listen_port
22
+ vnc_port = pick_tcp_listen_port
23
+ File.open(File.expand_path('monitor.port', hc.inst_data_dir), "w") { |f|
24
+ f.write(monitor_port)
25
+ }
26
+ File.open(File.expand_path('vnc.port', hc.inst_data_dir), "w") { |f|
27
+ f.write(vnc_port)
28
+ }
29
+
10
30
  # run vm
11
31
  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],
32
+ cmd = ["kvm -m %d -smp %d -name vdc-%s -vnc :%d",
33
+ "-cpu host",
34
+ "-pidfile %s",
35
+ "-daemonize",
36
+ "-monitor telnet:127.0.0.1:%d,server,nowait",
37
+ "-no-shutdown",
38
+ ]
39
+ args=[inst[:memory_size],
40
+ inst[:cpu_cores],
15
41
  inst[:uuid],
16
- inst[:runtime_config][:vnc_port],
17
- hc.os_devpath,
42
+ vnc_port - 5900, # KVM -vnc offsets 5900
18
43
  File.expand_path('kvm.pid', hc.inst_data_dir),
19
- inst[:runtime_config][:telnet_port]
44
+ monitor_port
20
45
  ]
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
46
 
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]])
47
+ cmd << "-drive file=%s,media=disk,boot=on,index=0,cache=none,if=#{drive_model(hc)}"
48
+ args << hc.os_devpath
49
+ cmd << "-drive file=%s,media=disk,index=1,cache=none,if=#{drive_model(hc)}"
50
+ args << hc.metadata_img_path
51
+
52
+ vifs = inst[:vif]
53
+ if !vifs.empty?
54
+ vifs.sort {|a, b| a[:device_index] <=> b[:device_index] }.each { |vif|
55
+ cmd << "-net nic,vlan=#{vif[:device_index].to_i},macaddr=%s,model=#{nic_model(hc)},addr=%x -net tap,vlan=#{vif[:device_index].to_i},ifname=%s,script=no,downscript=no"
56
+ args << vif[:mac_addr].unpack('A2'*6).join(':')
57
+ args << (KVM_NIC_PCI_ADDR_OFFSET + vif[:device_index].to_i)
58
+ args << vif[:uuid]
59
+ }
31
60
  end
61
+ sh(cmd.join(' '), args)
62
+
63
+ vifs.each { |vif|
64
+ if vif[:ipv4]
65
+ sh("/sbin/ip link set %s up", [vif[:uuid]])
66
+ sh("/usr/sbin/brctl addif %s %s", [vif[:ipv4][:network][:link_interface], vif[:uuid]])
67
+ end
68
+ }
32
69
 
33
70
  sleep 1
34
71
  end
35
72
 
36
73
  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}")
74
+ begin
75
+ connect_monitor(hc) { |t|
76
+ t.cmd("quit")
77
+ }
78
+ rescue Errno::ECONNRESET => e
79
+ # succssfully terminated the process
80
+ rescue => e
81
+ kvm_pid = File.read(File.expand_path('kvm.pid', hc.inst_data_dir))
82
+ if kvm_pid.nil? || kvm_pid == ''
83
+ kvm_pid=`pgrep -u root -f vdc-#{hc.inst_id}`
84
+ end
85
+ if kvm_pid.to_s =~ /^\d+$/
86
+ sh("/bin/kill -9 #{kvm_pid}") rescue logger.error($!)
87
+ else
88
+ logger.error("Can not find the KVM process. Skipping: #{hc.inst_id}")
89
+ end
42
90
  end
43
91
  end
44
92
 
45
93
  def reboot_instance(hc)
46
94
  inst = hc.inst
47
- connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
95
+ connect_monitor(hc) { |t|
48
96
  t.cmd("system_reset")
97
+ # When the guest initiate halt/poweroff the KVM might become
98
+ # "paused" status. At that time, "system_reset" command does
99
+ # not work as it is an ACPI signal. The "cont" command allows
100
+ # to bring the status back to running in this case.
101
+ # It has no effect if the status is kept running already.
102
+ t.cmd('cont')
49
103
  }
50
104
  end
51
105
 
@@ -61,12 +115,12 @@ module Dcmgr
61
115
  inst = hc.inst
62
116
 
63
117
  sddev = File.expand_path(File.readlink(hc.os_devpath), '/dev/disk/by-path')
64
- connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
118
+ connect_monitor(hc) { |t|
65
119
  # success message:
66
120
  # OK domain 0, bus 0, slot 4, function 0
67
121
  # error message:
68
122
  # failed to add file=/dev/xxxx,if=virtio
69
- c = t.cmd("pci_add auto storage file=#{sddev},if=scsi")
123
+ c = t.cmd("pci_add auto storage file=#{sddev},if=#{drive_model(hc)},cache=off")
70
124
  # Note: pci_parse_devaddr() called in "pci_add" uses strtoul()
71
125
  # with base 16 so that the input is expected in hex. however
72
126
  # at the result display, void pci_device_hot_add_print() uses
@@ -96,8 +150,9 @@ module Dcmgr
96
150
  vol = hc.vol
97
151
  pci_devaddr = vol[:guest_device_name]
98
152
 
99
- connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
153
+ connect_monitor(hc) { |t|
100
154
  t.cmd("pci_del #{pci_devaddr}")
155
+
101
156
  #
102
157
  # Bus 0, device 4, function 0:
103
158
  # SCSI controller: PCI device 1af4:1001
@@ -105,14 +160,92 @@ module Dcmgr
105
160
  # BAR0: I/O at 0x1000 [0x103f].
106
161
  # BAR1: 32 bit memory at 0x08000000 [0x08000fff].
107
162
  # id ""
108
- c = t.cmd("info pci")
109
163
  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(':')}"
164
+ pass=false
165
+ tryagain do
166
+ sleep 1
167
+ pass = t.shell_result("info pci").split(/\n/).grep(/\s+Bus\s+#{pci_devaddr[1].to_i(16)}, device\s+#{pci_devaddr[2].to_i(16)}, function/).empty?
112
168
  end
169
+ raise "Detached disk device still be attached in qemu-kvm: #{pci_devaddr.join(':')}" if pass == false
113
170
  }
114
171
  end
115
172
 
173
+ private
174
+ # Establish telnet connection to KVM monitor console
175
+ def connect_monitor(hc, &blk)
176
+ port = File.read(File.expand_path('monitor.port', hc.inst_data_dir)).to_i
177
+ logger.debug("monitor port number: #{port}")
178
+ begin
179
+ telnet = ::Net::Telnet.new("Host" => "localhost",
180
+ "Port"=>port.to_s,
181
+ "Prompt" => /\n\(qemu\) \z/,
182
+ "Timeout" => 60,
183
+ "Waittime" => 0.2)
184
+
185
+ # Add helper method for parsing response from qemu monitor shell.
186
+ telnet.instance_eval {
187
+ def shell_result(cmdstr)
188
+ ret = ""
189
+ hit = false
190
+ self.cmd(cmdstr).split("\n(qemu) ").each { |i|
191
+ i.split("\n").each { |i2|
192
+
193
+ if i2 =~ /#{cmdstr}/
194
+ hit = true
195
+ next
196
+ end
197
+ ret += ("\n" + i2) if hit
198
+ }
199
+ }
200
+ ret.sub(/^\n/, '')
201
+ end
202
+ }
203
+
204
+ blk.call(telnet)
205
+ ensure
206
+ telnet.close
207
+ end
208
+ end
209
+
210
+ TCP_PORT_MAX=65535
211
+ PORT_OFFSET=9000
212
+ # Randomly choose unused local tcp port number.
213
+ def pick_tcp_listen_port
214
+ # Support only for Linux netstat output.
215
+ l=`/bin/netstat -nlt`.split("\n")
216
+ # take out two header lines.
217
+ l.shift
218
+ l.shift
219
+
220
+ listen_ports = {}
221
+
222
+ l.each { |n|
223
+ m = n.split(/\s+/)
224
+ if m[0] == 'tcp'
225
+ ip, port = m[3].split(':')
226
+ listen_ports[port.to_i]=ip
227
+ elsif m[0] == 'tcp6'
228
+ ary = m[3].split(':')
229
+ port = ary.pop
230
+ listen_ports[port.to_i]=ary.join(':')
231
+ end
232
+ }
233
+
234
+
235
+ begin
236
+ new_port = (PORT_OFFSET + rand(TCP_PORT_MAX - PORT_OFFSET))
237
+ end until(!listen_ports.has_key?(new_port))
238
+ new_port
239
+ end
240
+
241
+ def drive_model(hc)
242
+ hc.inst[:image][:features][:virtio] ? 'virtio' : 'scsi'
243
+ end
244
+
245
+ def nic_model(hc)
246
+ hc.inst[:image][:features][:virtio] ? 'virtio' : 'e1000'
247
+ end
248
+
116
249
  end
117
250
  end
118
251
  end
@@ -0,0 +1,60 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr
4
+ module Drivers
5
+ class LinuxIscsi < IscsiTarget
6
+ include Dcmgr::Logger
7
+ include Dcmgr::Helpers::CliHelper
8
+
9
+ IQN_PREFIX="iqn.2010-09.jp.wakame".freeze
10
+
11
+ def create(ctx)
12
+ @volume = ctx.volume
13
+ @volume_id = ctx.volume_id
14
+ @node = ctx.node
15
+
16
+ vol_path = File.join(@volume[:storage_node][:export_path], @volume[:account_id], @volume[:uuid])
17
+
18
+ @volume[:transport_information] = iscsi = {}
19
+ iscsi[:iqn] = "#{IQN_PREFIX}:#{@volume[:account_id]}.#{@volume[:uuid]}"
20
+ iscsi[:tid] = pick_next_tid
21
+ iscsi[:lun] = 1
22
+ iscsi[:backing_store] = vol_path
23
+
24
+ register(@volume)
25
+
26
+ opt = { :iqn => iscsi[:iqn], :lun => iscsi[:lun], :tid => iscsi[:tid], :backing_store => iscsi[:backing_store] }
27
+ end
28
+
29
+ def delete(ctx)
30
+ @volume = ctx.volume
31
+ sh("/usr/sbin/tgt-admin --delete #{@volume[:transport_information][:iqn]}")
32
+ end
33
+
34
+ def register(volume)
35
+ tinfo = volume[:transport_information]
36
+
37
+ # register target
38
+ sh("/usr/sbin/tgtadm --lld iscsi --op new --mode=target --tid=%s --targetname %s", [tinfo[:tid], tinfo[:iqn]])
39
+ # register logical unit
40
+ sh("/usr/sbin/tgtadm --lld iscsi --op new --mode=logicalunit --tid=%s --lun=%s -b %s",
41
+ [tinfo[:tid], tinfo[:lun], tinfo[:backing_store]])
42
+ # bind target
43
+ sh("/usr/sbin/tgtadm --lld iscsi --op bind --mode=target --tid=%s --initiator-address=%s",
44
+ [tinfo[:tid], node.manifest.config.initiator_address])
45
+ end
46
+
47
+ private
48
+ def pick_next_tid
49
+ # $ sudo /usr/sbin/tgtadm --lld iscsi --op show --mode target | grep '^Target '
50
+ # Target 1: iqn.2010-09.jp.wakame:a-shpoolxx.vol-dw55bba8
51
+ last_target = `/usr/sbin/tgtadm --lld iscsi --op show --mode target | grep ^Target`.split("\n").last
52
+ tid = if last_target.nil?
53
+ 1
54
+ else
55
+ last_target.split(':').first.split(' ')[1].to_i + 1
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Drivers
4
+ class LocalStorage < SnapshotStorage
5
+ include Dcmgr::Logger
6
+ include Dcmgr::Helpers::CliHelper
7
+
8
+ def download(filename)
9
+ from = File.join(@volume_snaphost_path, filename)
10
+ to = self.snapshot(filename)
11
+
12
+ logger.debug("copying #{from} to #{to}")
13
+ sh("/bin/cp -p %s %s", [from, to])
14
+ end
15
+
16
+ def upload(filename)
17
+ sh("/bin/mv %s %s", [self.snapshot(filename), File.join(@volume_snaphost_path, filename)])
18
+ end
19
+
20
+ def delete(filename)
21
+ sh("rm -f %s", [File.join(@volume_snaphost_path, filename)])
22
+ end
23
+ end
24
+ end
@@ -1,165 +1,207 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'erb'
4
+
1
5
  module Dcmgr
2
6
  module Drivers
3
7
  class Lxc < Hypervisor
4
8
  include Dcmgr::Logger
5
9
  include Dcmgr::Helpers::CliHelper
6
10
 
7
- def create_config
8
- # create config file i-xxxxxxxx.log
9
- inst_id = @inst[:uuid]
10
- vnic = @inst[:instance_nics].first
11
- mac_addr = vnic[:mac_addr].unpack('A2'*6).join(':')
12
-
13
- config_name = "#{@inst_data_dir}/config.#{inst_id}"
14
- # check config file
15
- if File.exist?(config_name)
16
- sh("rm #{config_name}")
17
- end
18
-
19
- config = File.open(config_name, 'w')
20
- config.puts "lxc.utsname = #{inst_id}"
21
- config.puts "lxc.tty = 4"
22
- config.puts "lxc.pts = 1024"
23
- config.puts "lxc.network.type = veth"
24
- config.puts "lxc.network.veth.pair = #{vnic[:uuid]}"
25
- config.puts "lxc.network.flags = up"
26
- config.puts "lxc.network.link = #{@bridge_if}"
27
- config.puts "lxc.network.hwaddr = #{mac_addr}"
28
- config.puts "lxc.rootfs = #{@inst_data_dir}/rootfs"
29
- config.puts "lxc.mount = #{@inst_data_dir}/fstab"
30
- config.puts "lxc.cgroup.devices.deny = a"
31
- config.puts "lxc.cgroup.devices.allow = c 1:3 rwm"
32
- config.puts "lxc.cgroup.devices.allow = c 1:5 rwm"
33
- config.puts "lxc.cgroup.devices.allow = c 5:1 rwm"
34
- config.puts "lxc.cgroup.devices.allow = c 5:0 rwm"
35
- config.puts "lxc.cgroup.devices.allow = c 4:0 rwm"
36
- config.puts "lxc.cgroup.devices.allow = c 4:1 rwm"
37
- config.puts "lxc.cgroup.devices.allow = c 1:9 rwm"
38
- config.puts "lxc.cgroup.devices.allow = c 1:8 rwm"
39
- config.puts "lxc.cgroup.devices.allow = c 136:* rwm"
40
- config.puts "lxc.cgroup.devices.allow = c 5:2 rwm"
41
- config.puts "lxc.cgroup.devices.allow = c 254:0 rwm"
42
- config.puts "lxc.cgroup.devices.allow = c 10:232 rwm"
43
- config.puts "lxc.cgroup.devices.allow = c 10:200 rwm"
44
- unless @inst[:volume].nil?
45
- @inst[:volume].each { |volid, v|
46
- vol_id = volid
47
- vol = v
48
- unless v[:guest_device_name].nil?
49
- config.puts "lxc.cgroup.devices.allow = b #{v[:guest_device_name]} rwm"
50
- else
51
- @os_devpath = v[:host_device_name] unless v[:host_device_name].nil?
52
- sddev = File.expand_path(File.readlink(@os_devpath), '/dev/disk/by-path')
53
- # find major number and minor number to device file
54
- stat = File.stat(sddev)
55
- config.puts "lxc.cgroup.devices.allow = b #{stat.rdev_major}:#{stat.rdev_minor} rwm"
56
- end
57
- }
58
- end
59
- config.close
60
- config_name
61
- end
62
-
63
- def create_fstab
64
- config_name = "#{@inst_data_dir}/fstab"
65
- config = File.open(config_name, "w")
66
- config.puts "proc #{@inst_data_dir}/rootfs/proc proc nodev,noexec,nosuid 0 0"
67
- config.puts "devpts #{@inst_data_dir}/rootfs/dev/pts devpts defaults 0 0"
68
- config.puts "sysfs #{@inst_data_dir}/rootfs/sys sysfs defaults 0 0"
69
- config.close
70
- end
71
-
72
- def setup_container
73
- sh("echo \"127.0.0.1 localhost #{@inst_id}\" > #{@inst_data_dir}/rootfs/etc/hosts")
74
- sh("echo \"#{@inst_id}\" > #{@inst_data_dir}/rootfs/etc/hostname")
75
- end
76
-
77
- def run_instance(hc)
11
+ def run_instance(ctx)
78
12
  # run lxc
79
- @inst = hc.inst
80
- @bridge_if = hc.bridge_if
81
- @inst_data_dir = hc.inst_data_dir
82
- @os_devpath = hc.os_devpath
13
+ @os_devpath = ctx.os_devpath
83
14
  if @os_devpath.nil?
84
- if @inst[:image][:boot_dev_type] == 1
85
- @inst[:volume].each{|volid, v|
86
- @os_devpath = v[:host_device_name] if v[:boot_dev] == 1
15
+ if ctx.inst[:image][:boot_dev_type] == 1
16
+ ctx.inst[:volume].each{ |vol_id, vol|
17
+ @os_devpath = vol[:host_device_name] if vol[:boot_dev] == 1
87
18
  }
88
19
  else
89
- @os_devpath = "#{@inst_data_dir}/#{hc.inst_id}"
20
+ @os_devpath = "#{ctx.inst_data_dir}/#{ctx.inst_id}"
90
21
  end
91
22
  end
92
23
  # check mount point
93
- mount_point = "#{@inst_data_dir}/rootfs"
94
- unless File.exist?(mount_point)
95
- sh("mkdir #{mount_point}")
96
- end
24
+ mount_point = "#{ctx.inst_data_dir}/rootfs"
25
+ Dir.mkdir(mount_point) unless File.exists?(mount_point)
97
26
 
98
27
  cmd = "mount %s %s"
99
28
  args = [@os_devpath, mount_point]
100
- if @inst[:image][:boot_dev_type] == 2
29
+ if ctx.inst[:image][:boot_dev_type] == 2
101
30
  cmd += " -o loop"
102
31
  end
103
32
  sh(cmd, args)
104
33
 
105
- config_name = create_config
106
- create_fstab
107
- setup_container
108
-
109
- sh("lxc-create -f %s -n %s", [config_name, @inst[:uuid]])
110
- sh("sudo lxc-start -n %s -d -l DEBUG -o %s/%s.log", [@inst[:uuid], @inst_data_dir, @inst[:uuid]])
34
+ # metadata drive
35
+ metadata_path = "#{ctx.inst_data_dir}/rootfs/metadata"
36
+ Dir.mkdir(metadata_path) unless File.exists?(metadata_path)
37
+ sh("mount -t vfat -o loop -o ro #{ctx.metadata_img_path} #{metadata_path}")
38
+
39
+ config_path = create_config(ctx)
40
+ create_fstab(ctx)
41
+ setup_container(ctx)
42
+ mount_cgroup
43
+
44
+ # Ubuntu 10.04.3 LTS
45
+ # Linux ubuntu 2.6.38-10-generic #46~lucid1-Ubuntu SMP Wed Jul 6 18:40:11 UTC 2011 i686 GNU/Linux
46
+ # Linux ubuntu 2.6.38-8-server #42-Ubuntu SMP Mon Apr 11 03:49:04 UTC 2011 x86_64 GNU/Linux
47
+ # lxc 0.7.4-0ubuntu7
48
+ #
49
+ # Ubuntu-10.04.3 on Virtualbox-4.0.12 r72916 on Windows-7
50
+ # Ubuntu-10.10
51
+ #
52
+ # > lxc-start 1311803515.629 ERROR lxc_start - inherited fd 3 on pipe:[58281]
53
+ # > lxc-start 1311803515.629 ERROR lxc_start - inherited fd 4 on pipe:[58281]
54
+ # > lxc-start 1311803515.629 ERROR lxc_start - inherited fd 6 on socket:[58286]
55
+ #
56
+ # http://comments.gmane.org/gmane.linux.kernel.containers.lxc.general/912
57
+ # http://comments.gmane.org/gmane.linux.kernel.containers.lxc.general/1400
58
+ lxc_version = `lxc-version`.chomp.split(': ').last
59
+ logger.debug("lxc-version: #{lxc_version}")
60
+
61
+ sh("lxc-create -f %s -n %s", [config_path, ctx.inst[:uuid]])
62
+ sh("lxc-start -n %s -d -l DEBUG -o %s/%s.log 3<&- 4<&- 6<&-", [ctx.inst[:uuid], ctx.inst_data_dir, ctx.inst[:uuid]])
111
63
  end
112
64
 
113
- def terminate_instance(hc)
114
- sh("lxc-stop -n #{hc.inst_id}")
115
- sh("lxc-destroy -n #{hc.inst_id}")
116
- sh("umount #{hc.inst_data_dir}/rootfs")
65
+ def terminate_instance(ctx)
66
+ sh("lxc-stop -n #{ctx.inst_id}")
67
+ sh("lxc-destroy -n #{ctx.inst_id}")
68
+ sh("umount #{ctx.inst_data_dir}/rootfs/metadata")
69
+ sh("umount #{ctx.inst_data_dir}/rootfs")
117
70
  end
118
71
 
119
- def reboot_instance(hc)
120
- inst = hc.inst
121
- terminate_instance(hc)
122
- run_instance(hc)
72
+ def reboot_instance(ctx)
73
+ sh("lxc-stop -n #{ctx.inst[:uuid]}")
74
+ sh("lxc-start -n %s -d -l DEBUG -o %s/%s.log 3<&- 4<&- 6<&-", [ctx.inst[:uuid], ctx.inst_data_dir, ctx.inst[:uuid]])
123
75
  end
124
76
 
125
- def attach_volume_to_guest(hc)
126
- inst_id = hc.inst_id
127
- sddev = File.expand_path(File.readlink(hc.os_devpath), '/dev/disk/by-path')
77
+ def attach_volume_to_guest(ctx)
78
+ sddev = File.expand_path(File.readlink(ctx.os_devpath), '/dev/disk/by-path')
128
79
 
129
80
  # find major number and minor number to device file
130
81
  stat = File.stat(sddev)
131
82
  devnum = [stat.rdev_major,stat.rdev_minor].join(':')
132
-
133
- sh("echo \"b #{devnum} rwm\" > /cgroup/#{inst_id}/devices.allow")
134
- sh("mknod #{hc.inst_data_dir}/rootfs#{sddev} -m 660 b #{stat.rdev_major} #{stat.rdev_minor}")
135
-
136
- config_name = "#{hc.inst_data_dir}/config.#{inst_id}"
137
- config = File.open(config_name, 'r')
138
- data = config.readlines
139
- config.close
140
- config = File.open(config_name, 'w')
141
- config.write data
142
- config.puts "lxc.cgroup.devices.allow = b #{devnum} rwm"
143
- config.close
83
+
84
+ sh("echo \"b #{devnum} rwm\" > /cgroup/#{ctx.inst_id}/devices.allow")
85
+ logger.debug("Makinging new block device: #{ctx.inst_data_dir}/rootfs#{sddev}")
86
+ sh("mknod #{ctx.inst_data_dir}/rootfs#{sddev} -m 660 b #{stat.rdev_major} #{stat.rdev_minor}")
87
+
88
+ config_path = "#{ctx.inst_data_dir}/config.#{ctx.inst_id}"
89
+ File.open(config_path, 'a+') { |f|
90
+ f.puts "lxc.cgroup.devices.allow = b #{devnum} rwm"
91
+ }
92
+
144
93
  devnum
145
94
  end
146
95
 
147
- def detach_volume_from_guest(hc)
148
- inst_id = hc.inst_id
149
- vol = hc.vol
96
+ def detach_volume_from_guest(ctx)
97
+ vol = ctx.vol
150
98
  sddev = File.expand_path(File.readlink(vol[:host_device_name]), '/dev/disk/by-path')
151
99
  devnum = vol[:guest_device_name]
152
100
 
153
- sh("echo \"b #{devnum} rwm\" > /cgroup/#{inst_id}/devices.deny")
154
- sh("rm -rf #{hc.inst_data_dir}/rootfs#{sddev}")
101
+ sh("echo \"b #{devnum} rwm\" > /cgroup/#{ctx.inst_id}/devices.deny")
102
+ logger.debug("Deleting block device: #{ctx.inst_data_dir}/rootfs#{sddev}")
103
+ sh("rm #{ctx.inst_data_dir}/rootfs#{sddev}")
104
+
105
+ config_path = "#{ctx.inst_data_dir}/config.#{ctx.inst_id}"
106
+ config_body = File.open(config_path, 'r') { |f|
107
+ f.readlines.select {|line| line != "lxc.cgroup.devices.allow = b #{devnum} rwm\n" }
108
+ }
109
+ File.open(config_path, 'w') { |f|
110
+ f.write config_body
111
+ }
112
+ end
113
+
114
+ private
115
+ def create_config(ctx)
116
+ # create config file i-xxxxxxxx.log
117
+
118
+ config_path = "#{ctx.inst_data_dir}/config.#{ctx.inst_id}"
119
+ # check config file
120
+ if File.exist?(config_path)
121
+ sh("rm #{config_path}")
122
+ end
123
+
124
+ vifs = ctx.inst[:vif]
125
+
126
+ File.open(config_path, 'w') { |f|
127
+ f.puts "lxc.utsname = #{ctx.inst_id}"
128
+ f.puts ""
129
+ if !vifs.empty?
130
+ vifs.sort {|a, b| a[:device_index] <=> b[:device_index] }.each { |vif|
131
+ f.puts "lxc.network.type = veth"
132
+ if vif[:ipv4]
133
+ f.puts "lxc.network.link = #{vif[:ipv4][:network][:link_interface]}"
134
+ end
135
+ f.puts "lxc.network.veth.pair = #{vif[:uuid]}"
136
+ f.puts "lxc.network.hwaddr = #{vif[:mac_addr].unpack('A2'*6).join(':')}"
137
+ f.puts "lxc.network.flags = up"
138
+ }
139
+ end
140
+ f.puts ""
141
+ f.puts "lxc.tty = 4"
142
+ f.puts "lxc.pts = 1024"
143
+ f.puts "lxc.rootfs = #{ctx.inst_data_dir}/rootfs"
144
+ f.puts "lxc.mount = #{ctx.inst_data_dir}/fstab"
145
+ f.puts ""
146
+ f.puts "lxc.cgroup.devices.deny = a"
147
+ f.puts "# /dev/null and zero"
148
+ f.puts "lxc.cgroup.devices.allow = c 1:3 rwm"
149
+ f.puts "lxc.cgroup.devices.allow = c 1:5 rwm"
150
+ f.puts "# consoles"
151
+ f.puts "lxc.cgroup.devices.allow = c 5:1 rwm"
152
+ f.puts "lxc.cgroup.devices.allow = c 5:0 rwm"
153
+ f.puts "lxc.cgroup.devices.allow = c 4:0 rwm"
154
+ f.puts "lxc.cgroup.devices.allow = c 4:1 rwm"
155
+ f.puts "# /dev/{,u}random"
156
+ f.puts "lxc.cgroup.devices.allow = c 1:9 rwm"
157
+ f.puts "lxc.cgroup.devices.allow = c 1:8 rwm"
158
+ f.puts "lxc.cgroup.devices.allow = c 136:* rwm"
159
+ f.puts "lxc.cgroup.devices.allow = c 5:2 rwm"
160
+ f.puts "#rtc"
161
+ f.puts "lxc.cgroup.devices.allow = c 254:0 rwm"
162
+ f.puts "#kvm"
163
+ f.puts "#lxc.cgroup.devices.allow = c 10:232 rwm"
164
+ f.puts "#lxc.cgroup.devices.allow = c 10:200 rwm"
165
+
166
+ unless ctx.inst[:volume].nil?
167
+ ctx.inst[:volume].each { |vol_id, vol|
168
+ unless vol[:guest_device_name].nil?
169
+ f.puts "lxc.cgroup.devices.allow = b #{vol[:guest_device_name]} rwm"
170
+ else
171
+ @os_devpath = vol[:host_device_name] unless vol[:host_device_name].nil?
172
+ sddev = File.expand_path(File.readlink(@os_devpath), '/dev/disk/by-path')
173
+ # find major number and minor number to device file
174
+ stat = File.stat(sddev)
175
+ f.puts "lxc.cgroup.devices.allow = b #{stat.rdev_major}:#{stat.rdev_minor} rwm"
176
+ end
177
+ }
178
+ end
179
+ }
155
180
 
156
- config_name = "#{hc.inst_data_dir}/config.#{inst_id}"
157
- config = File.open(config_name, 'r')
158
- data = config.readlines.select {|f| f != "lxc.cgroup.devices.allow = b #{devnum} rwm\n" }
159
- config.close
160
- config = File.open(config_name, 'w+')
161
- config.write data
162
- config.close
181
+ config_path
182
+ end
183
+
184
+ def create_fstab(ctx)
185
+ config_path = "#{ctx.inst_data_dir}/fstab"
186
+ File.open(config_path, "w") { |f|
187
+ f.puts "proc #{ctx.inst_data_dir}/rootfs/proc proc nodev,noexec,nosuid 0 0"
188
+ f.puts "devpts #{ctx.inst_data_dir}/rootfs/dev/pts devpts defaults 0 0"
189
+ f.puts "sysfs #{ctx.inst_data_dir}/rootfs/sys sysfs defaults 0 0"
190
+ }
191
+ end
192
+
193
+ def setup_container(ctx)
194
+ sh("echo \"127.0.0.1 localhost #{ctx.inst_id}\" > #{ctx.inst_data_dir}/rootfs/etc/hosts")
195
+ sh("echo \"#{ctx.inst_id}\" > #{ctx.inst_data_dir}/rootfs/etc/hostname")
196
+ end
197
+
198
+ def mount_cgroup
199
+ `mount -t cgroup | egrep -q cgroup`
200
+ if $?.exitstatus != 0
201
+ mount_point = "/cgroup"
202
+ Dir.mkdir(mount_point) unless File.exists?(mount_point)
203
+ sh("mount none -t cgroup #{mount_point}")
204
+ end
163
205
  end
164
206
 
165
207
  end