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
@@ -241,6 +241,43 @@ module Dcmgr
241
241
  end
242
242
 
243
243
  collection :instances do
244
+ operation :index do
245
+ description 'Show list of instances'
246
+ control do
247
+ start = params[:start].to_i
248
+ start = start < 1 ? 0 : start
249
+ limit = params[:limit].to_i
250
+ limit = limit < 1 ? 10 : limit
251
+
252
+ partial_ds = (1..30).collect { |i| {
253
+ :id => "i-123456" + ('%02d' % i).to_s,
254
+ :image_id => 'wmi-12345678',
255
+ :cpu_cores => 1,
256
+ :memory_size => 256,
257
+ :network => [{
258
+ :ipaddr => '192.168.0.%d' % i,
259
+ }],
260
+ :state => 'running',
261
+ :status => 'running'
262
+ }
263
+ }
264
+
265
+ total = partial_ds.count
266
+ partial_ds = pagenate(partial_ds,params[:start],params[:limit])
267
+
268
+ res = [{
269
+ :owner_total => total,
270
+ :start => start,
271
+ :limit => limit,
272
+ :results=> partial_ds
273
+ }]
274
+
275
+ respond_to { |f|
276
+ f.json {res.to_json}
277
+ }
278
+ end
279
+ end
280
+
244
281
  operation :create do
245
282
  description 'Runs a new instance'
246
283
  # param :image_id, :required
@@ -267,11 +304,23 @@ module Dcmgr
267
304
  end
268
305
 
269
306
  operation :show do
270
- #param :account_id, :string, :optional
271
307
  control do
272
- i = Modles::Instance[params[:id]]
308
+ i = {
309
+ :id => params[:id],
310
+ :image_id => 'wmi-12345678',
311
+ :cpu_cores => 1,
312
+ :memory_size => 256,
313
+ :network => [{
314
+ :ipaddr => '192.168.0.1',
315
+ }],
316
+ :state => 'running',
317
+ :status => 'running',
318
+ :ssh_key_pair => nil,
319
+ :netfilter_group => {},
320
+ :created_at => "Wed Oct 27 16:58:24 +0900 2010",
321
+ }
273
322
  respond_to { |f|
274
- f.json { i.to_hash_document.to_json }
323
+ f.json { i.to_json }
275
324
  }
276
325
  end
277
326
  end
@@ -2,14 +2,31 @@
2
2
 
3
3
  module Dcmgr
4
4
  module Endpoints
5
- def self.define_error(class_name, status_code, &blk)
5
+ def self.define_error(class_name, status_code, error_code, &blk)
6
6
  c = Class.new(APIError)
7
7
  c.status_code(status_code)
8
+ c.error_code(error_code)
8
9
  c.instance_eval(&blk) if blk
10
+ self.set_error_code_type(error_code, c)
9
11
  self.const_set(class_name.to_sym, c)
10
12
  end
11
13
 
14
+ @error_code_map = {}
15
+ def self.set_error_code_type(error_code, klass)
16
+ raise TypeError unless klass < APIError
17
+ if @error_code_map.has_key?(error_code)
18
+ if @error_code[error_code] == klass
19
+ else
20
+ raise "Duplicate Error Code Registration: #{klass}, code=#{error_code}"
21
+ end
22
+ else
23
+ @error_code_map[error_code]=klass
24
+ end
25
+ end
26
+
12
27
  class APIError < StandardError
28
+
29
+ # HTTP status code of the error.
13
30
  def self.status_code(code=nil)
14
31
  if code
15
32
  @status_code = code
@@ -17,43 +34,67 @@ module Dcmgr
17
34
  @status_code || raise("@status_code for the class is not set")
18
35
  end
19
36
 
37
+ # Internal error code of the error.
38
+ def self.error_code(code=nil)
39
+ if code
40
+ @error_code = code
41
+ end
42
+ @error_code || raise("@error_code for the class is not set")
43
+ end
44
+
20
45
  def status_code
21
46
  self.class.status_code
22
47
  end
48
+
49
+ def error_code
50
+ self.class.error_code
51
+ end
23
52
  end
24
53
 
25
- define_error(:UnknownUUIDResource, 404)
26
- define_error(:UnknownMember, 400)
27
- define_error(:InvalidCredentialHeaders, 400)
28
- define_error(:InvalidRequestCredentials, 400)
29
- define_error(:DisabledAccount, 403)
30
- define_error(:OperationNotPermitted, 403)
31
- define_error(:UndefinedVolumeSize, 400)
32
- define_error(:StoragePoolNotPermitted, 403)
33
- define_error(:UnknownStoragePool, 404)
34
- define_error(:OutOfDiskSpace, 400)
35
- define_error(:DatabaseError, 400)
36
- define_error(:UndefinedVolumeID, 400)
37
- define_error(:InvalidDeleteRequest, 400)
38
- define_error(:UnknownVolume, 404)
39
- define_error(:UnknownHostPool, 404)
40
- define_error(:UnknownInstance, 404)
41
- define_error(:UndefindVolumeSnapshotID, 400)
42
- define_error(:UnknownVolumeSnapshot, 404)
43
- define_error(:UndefinedRequiredParameter, 400)
44
- define_error(:InvalidVolumeSize, 400)
45
- define_error(:OutOfHostCapacity, 400)
46
- define_error(:UnknownSshKeyPair, 404)
47
- define_error(:UndefinedStoragePoolID, 400)
48
- define_error(:DetachVolumeFailure, 400)
49
- define_error(:AttachVolumeFailure, 400)
50
- define_error(:InvalidInstanceState, 400)
51
- define_error(:DuplicateHostname, 400)
54
+ define_error(:UnknownUUIDResource, 404, '100')
55
+ define_error(:UnknownMember, 400, '101')
56
+ define_error(:InvalidCredentialHeaders, 400, '102')
57
+ define_error(:InvalidRequestCredentials, 400, '103')
58
+ define_error(:DisabledAccount, 403, '104')
59
+ define_error(:OperationNotPermitted, 403, '105')
60
+ define_error(:UndefinedVolumeSize, 400, '106')
61
+ define_error(:StoragePoolNotPermitted, 403, '107')
62
+ define_error(:UnknownStoragePool, 404, '108')
63
+ define_error(:OutOfDiskSpace, 400, '109')
64
+ define_error(:DatabaseError, 400, '110')
65
+ define_error(:UndefinedVolumeID, 400, '111')
66
+ define_error(:InvalidDeleteRequest, 400, '112')
67
+ define_error(:UnknownVolume, 404, '113')
68
+ define_error(:UnknownHostPool, 404, '114')
69
+ define_error(:UnknownInstance, 404, '115')
70
+ define_error(:UndefindVolumeSnapshotID, 400, '116')
71
+ define_error(:UnknownVolumeSnapshot, 404, '117')
72
+ define_error(:UndefinedRequiredParameter, 400, '118')
73
+ define_error(:InvalidVolumeSize, 400, '119')
74
+ define_error(:OutOfHostCapacity, 400, '120')
75
+ define_error(:UnknownSshKeyPair, 404, '121')
76
+ define_error(:UndefinedStoragePoolID, 400, '122')
77
+ define_error(:DetachVolumeFailure, 400, '123')
78
+ define_error(:AttachVolumeFailure, 400, '124')
79
+ define_error(:InvalidInstanceState, 400, '125')
80
+ define_error(:DuplicateHostname, 400, '126')
81
+ define_error(:UnknownImageID, 404, '127')
82
+ define_error(:UnknownInstanceSpec, 404, '128')
83
+ define_error(:UnknownNetworkID, 404, '129')
84
+ define_error(:OutOfNetworkCapacity, 400, '130')
85
+ define_error(:InvalidVolumeSnapshotState, 400, '131')
86
+
52
87
 
53
88
  # netfilter_group
54
- define_error(:UndefinedNetfilterGroup, 400)
55
- define_error(:UnknownNetfilterGroup, 400)
56
- define_error(:NetfilterGroupNotPermitted, 400)
57
- define_error(:DuplicatedNetfilterGroup, 400)
89
+ define_error(:UndefinedNetfilterGroup, 400, '132')
90
+ define_error(:UnknownNetfilterGroup, 400, '133')
91
+ define_error(:NetfilterGroupNotPermitted, 400, '134')
92
+ define_error(:DuplicatedNetfilterGroup, 400, '135')
93
+
94
+ define_error(:DuplicateSshKeyName, 400, '136')
95
+ define_error(:InvalidImageID, 400, '137')
96
+ define_error(:InvalidInstanceSpec, 400, '138')
97
+ define_error(:UndefinedInstanceID, 404, '139')
98
+ define_error(:InvalidVolumeState, 400, '140')
58
99
  end
59
100
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'extlib'
4
4
  require 'sinatra/base'
5
+ require 'sinatra/sequel_transaction'
5
6
  require 'yaml'
6
7
  require 'json'
7
8
 
@@ -21,29 +22,25 @@ module Dcmgr
21
22
  module Endpoints
22
23
  class Metadata < Sinatra::Base
23
24
  include Dcmgr::Logger
25
+ register Sinatra::SequelTransaction
24
26
 
25
27
  disable :sessions
26
28
  disable :show_exceptions
27
29
 
28
- LATEST_PROVIDER_VER_ID='2010-11-01'
30
+ LATEST_PROVIDER_VER_ID='2011-05-19'
29
31
 
30
32
  get '/' do
31
33
  ''
32
34
  end
33
35
 
36
+ get '/:version/meta-data/:data' do
37
+ get_data(params)
38
+ end
39
+
34
40
  get '/:version/metadata.*' do
35
41
  #get %r!\A/(\d{4}-\d{2}-\d{2})/metadata.(\w+)\Z! do
36
- v = params[:version]
42
+ v = parse_version params[:version]
37
43
  ext = params[:splat][0]
38
- v = case v
39
- when 'latest'
40
- LATEST_PROVIDER_VER_ID
41
- when /\A\d{4}-\d{2}-\d{2}\Z/
42
- v
43
- else
44
- raise "Invalid syntax in the version"
45
- end
46
- v = v.gsub(/-/, '')
47
44
 
48
45
  hash_doc = begin
49
46
  self.class.find_const("Provider_#{v}").new.document(request.ip)
@@ -68,7 +65,47 @@ module Dcmgr
68
65
  end
69
66
  end
70
67
 
71
- private
68
+ private
69
+ def get_data(params)
70
+ v = parse_version params[:version]
71
+
72
+ get_method = params[:data].gsub(/-/,'_')
73
+
74
+ provider = begin
75
+ self.class.find_const("Provider_#{v}").new
76
+ rescue NameError => e
77
+ raise e if e.is_a? NoMethodError
78
+ logger.error("ERROR: Unsupported metadata version: #{v}")
79
+ logger.error(e)
80
+ error(404, "Unsupported metadata version: #{v}")
81
+ rescue UnknownSourceIpError => e
82
+ error(404, "Unknown source IP: #{e.message}")
83
+ end
84
+
85
+ result = begin
86
+ provider.method(get_method).call(request.ip)
87
+ rescue NameError => e
88
+ raise e if e.is_a? NoMethodError
89
+ logger.error("ERROR: Unknown metadata: #{get_method}")
90
+ logger.error(e)
91
+ error(404, "Unknown metadata: #{get_method}")
92
+ end
93
+
94
+ result
95
+ end
96
+
97
+ def parse_version(v)
98
+ ret = case v
99
+ when 'latest'
100
+ LATEST_PROVIDER_VER_ID
101
+ when /\A\d{4}-\d{2}-\d{2}\Z/
102
+ v
103
+ else
104
+ raise "Invalid syntax in the version"
105
+ end
106
+ ret.gsub(/-/, '')
107
+ end
108
+
72
109
  def shell_dump(hash)
73
110
  # TODO: values to be shell escaped
74
111
  hash.map {|k,v|
@@ -100,11 +137,38 @@ module Dcmgr
100
137
  # }]
101
138
  # }
102
139
  def document(src_ip)
140
+ inst = get_instance_from_ip(src_ip)
141
+ ret = {
142
+ :instance_id=>inst.canonical_uuid,
143
+ :cpu_cores=>inst.cpu_cores,
144
+ :memory_size=>inst.memory_size,
145
+ :state => inst.state,
146
+ :user_data=>inst.user_data.to_s,
147
+ }
148
+ # IP/network values
149
+ ret[:network] = inst.nic.map { |nic|
150
+ {:ip=>nic.ip.ipv4,
151
+ :name=>nic.ip.network.name,
152
+ }
153
+ }
154
+ ret[:volume] = inst.volume.map { |v|
155
+ }
156
+ ret
157
+ end
158
+
159
+ def get_instance_from_ip(src_ip)
103
160
  ip = Models::IpLease.find(:ipv4=>src_ip)
104
161
  if ip.nil? || ip.instance_nic.nil?
105
162
  raise UnknownSourceIpError, src_ip
106
163
  end
107
- inst = ip.instance_nic.instance
164
+ ip.instance_nic.instance
165
+ end
166
+ end
167
+
168
+ #This version implements compatibility with amazon EC2
169
+ class Provider_20110519 < Provider_20101101
170
+ def document(src_ip)
171
+ inst = get_instance_from_ip(src_ip)
108
172
  ret = {
109
173
  :instance_id=>inst.canonical_uuid,
110
174
  :cpu_cores=>inst.cpu_cores,
@@ -114,16 +178,99 @@ module Dcmgr
114
178
  }
115
179
  # IP/network values
116
180
  ret[:network] = inst.nic.map { |nic|
117
- {:ip=>nic.ip.ipv4,
118
- :name=>nic.ip.network.name,
181
+ nic.ip.map { |ip|
182
+ {:ip=>ip.ipv4,
183
+ :uuid=>ip.network.canonical_uuid,
184
+ }
119
185
  }
120
186
  }
121
187
  ret[:volume] = inst.volume.map { |v|
122
188
  }
123
189
  ret
124
190
  end
125
- end
126
191
 
192
+ # EC2 Functions not implemented yet
193
+ # http://169.254.169.254/latest/meta-data/ami-launch-index
194
+ # http://169.254.169.254/latest/meta-data/ami-manifest-path
195
+ # http://169.254.169.254/latest/meta-data/ancestor-ami-ids
196
+ # http://169.254.169.254/latest/meta-data/block-device-mapping
197
+ # http://169.254.169.254/latest/meta-data/instance-type/instance-action
198
+ # http://169.254.169.254/latest/meta-data/instance-type
199
+ # http://169.254.169.254/latest/meta-data/kernel-id
200
+ # http://169.254.169.254/latest/meta-data/placement/availability-zone
201
+ # http://169.254.169.254/latest/meta-data/product-codes
202
+ # http://169.254.169.254/latest/meta-data/placement
203
+ # http://169.254.169.254/latest/meta-data/profile
204
+ # http://169.254.169.254/latest/meta-data/public-hostname
205
+ # http://169.254.169.254/latest/meta-data/ramdisk-id
206
+ # http://169.254.169.254/latest/meta-data/reservation-id
207
+ def wmi_id(src_ip)
208
+ get_instance_from_ip(src_ip).image.cuuid
209
+ end
210
+ alias ami_id wmi_id
211
+
212
+ def mac(src_ip)
213
+ get_instance_from_ip(src_ip).nic.map { |nic|
214
+ nic.pretty_mac_addr
215
+ }.join("\n")
216
+ end
217
+
218
+ def network(src_ip)
219
+ get_instance_from_ip(src_ip).nic.map { |nic|
220
+ nic.ip.map { |ip|
221
+ ip.network.cuuid
222
+ }
223
+ }.join("\n")
224
+ end
225
+
226
+ def instance_id(src_ip)
227
+ get_instance_from_ip(src_ip).cuuid
228
+ end
229
+
230
+ def local_hostname(src_ip)
231
+ get_instance_from_ip(src_ip).hostname
232
+ end
233
+
234
+ def local_ipv4(src_ip)
235
+ get_instance_from_ip(src_ip).nic.map { |nic|
236
+ nic.ip.map { |ip|
237
+ unless ip.is_natted?
238
+ ip.ipv4
239
+ else
240
+ nil
241
+ end
242
+ }.compact
243
+ }.join("\n")
244
+ end
245
+
246
+ def public_ipv4(src_ip)
247
+ get_instance_from_ip(src_ip).nic.map { |nic|
248
+ nic.ip.map { |ip|
249
+ if ip.is_natted?
250
+ ip.ipv4
251
+ else
252
+ nil
253
+ end
254
+ }.compact
255
+ }.join("\n")
256
+ end
257
+
258
+ def public_keys(src_ip)
259
+ i = get_instance_from_ip(src_ip)
260
+ # ssh_key_data is possible to be nil.
261
+ i.ssh_key_data.nil? ? '' : i.ssh_key_data[:public_key]
262
+ end
263
+
264
+ def security_groups(src_ip)
265
+ get_instance_from_ip(src_ip).netfilter_groups.map { |grp|
266
+ grp.name
267
+ }.join("\n")
268
+ end
269
+
270
+ def user_data(src_ip)
271
+ get_instance_from_ip(src_ip).user_data
272
+ end
273
+ end
127
274
  end
128
275
  end
129
276
  end
@@ -71,7 +71,7 @@ module Dcmgr
71
71
  raise CommandError.new("Unexpected exit code=#{stat.exitstatus} (expected=#{opts[:expect_exitcode]})", \
72
72
  outbuf, errbuf)
73
73
  end
74
- true
74
+ {:stdout => outbuf, :stderr => errbuf}
75
75
  end
76
76
  end
77
77
 
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr
4
+ module Helpers
5
+ module NicHelper
6
+ def find_nic(ifindex = 2)
7
+ ifindex_map = {}
8
+ Dir.glob("/sys/class/net/*/ifindex").each do |ifindex_path|
9
+ device_name = File.split(File.split(ifindex_path).first)[1]
10
+ ifindex_num = File.readlines(ifindex_path).first.strip
11
+ ifindex_map[ifindex_num] = device_name
12
+ end
13
+ #p ifindex_map
14
+ ifindex_map[ifindex.to_s]
15
+ end
16
+
17
+ def nic_state(if_name = 'eth0')
18
+ operstate_path = "/sys/class/net/#{if_name}/operstate"
19
+ if File.exists?(operstate_path)
20
+ File.readlines(operstate_path).first.strip
21
+ end
22
+ end
23
+
24
+ def valid_nic?(nic)
25
+ ifindex_path = "/sys/class/net/#{nic}/ifindex"
26
+ if FileTest.exist?(ifindex_path)
27
+ true
28
+ else
29
+ logger.warn("#{nic}: error fetching interface information: Device not found")
30
+ false
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end