wakame-vdc-agents 10.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/LICENSE +202 -0
  2. data/NOTICE +1 -0
  3. data/Rakefile +142 -0
  4. data/bin/hva +972 -0
  5. data/bin/nsa +147 -0
  6. data/bin/sta +182 -0
  7. data/config/hva.conf.example +10 -0
  8. data/config/initializers/isono.rb +43 -0
  9. data/config/initializers/passenger.rb +6 -0
  10. data/config/initializers/sequel.rb +21 -0
  11. data/config/nsa.conf.example +9 -0
  12. data/config/path_resolver.rb +12 -0
  13. data/lib/dcmgr.rb +115 -0
  14. data/lib/dcmgr/endpoints/core_api.rb +1004 -0
  15. data/lib/dcmgr/endpoints/core_api_mock.rb +816 -0
  16. data/lib/dcmgr/endpoints/errors.rb +55 -0
  17. data/lib/dcmgr/endpoints/metadata.rb +129 -0
  18. data/lib/dcmgr/logger.rb +44 -0
  19. data/lib/dcmgr/models/account.rb +104 -0
  20. data/lib/dcmgr/models/account_resource.rb +16 -0
  21. data/lib/dcmgr/models/base.rb +69 -0
  22. data/lib/dcmgr/models/base_new.rb +371 -0
  23. data/lib/dcmgr/models/frontend_system.rb +38 -0
  24. data/lib/dcmgr/models/host_pool.rb +102 -0
  25. data/lib/dcmgr/models/image.rb +46 -0
  26. data/lib/dcmgr/models/instance.rb +255 -0
  27. data/lib/dcmgr/models/instance_netfilter_group.rb +16 -0
  28. data/lib/dcmgr/models/instance_nic.rb +68 -0
  29. data/lib/dcmgr/models/instance_spec.rb +21 -0
  30. data/lib/dcmgr/models/ip_lease.rb +42 -0
  31. data/lib/dcmgr/models/netfilter_group.rb +88 -0
  32. data/lib/dcmgr/models/netfilter_rule.rb +21 -0
  33. data/lib/dcmgr/models/network.rb +32 -0
  34. data/lib/dcmgr/models/physical_host.rb +67 -0
  35. data/lib/dcmgr/models/request_log.rb +25 -0
  36. data/lib/dcmgr/models/ssh_key_pair.rb +55 -0
  37. data/lib/dcmgr/models/storage_pool.rb +134 -0
  38. data/lib/dcmgr/models/tag.rb +126 -0
  39. data/lib/dcmgr/models/tag_mapping.rb +28 -0
  40. data/lib/dcmgr/models/volume.rb +130 -0
  41. data/lib/dcmgr/models/volume_snapshot.rb +47 -0
  42. data/lib/dcmgr/node_modules/hva_collector.rb +134 -0
  43. data/lib/dcmgr/node_modules/sta_collector.rb +72 -0
  44. data/lib/dcmgr/scheduler.rb +12 -0
  45. data/lib/dcmgr/scheduler/find_last.rb +16 -0
  46. data/lib/dcmgr/scheduler/find_random.rb +16 -0
  47. data/lib/dcmgr/stm/instance.rb +25 -0
  48. data/lib/dcmgr/stm/snapshot_context.rb +33 -0
  49. data/lib/dcmgr/stm/volume_context.rb +65 -0
  50. data/lib/dcmgr/web/base.rb +21 -0
  51. data/lib/sinatra/accept_media_types.rb +128 -0
  52. data/lib/sinatra/lazy_auth.rb +56 -0
  53. data/lib/sinatra/rabbit.rb +278 -0
  54. data/lib/sinatra/respond_to.rb +272 -0
  55. data/lib/sinatra/sequel_transaction.rb +27 -0
  56. data/lib/sinatra/static_assets.rb +83 -0
  57. data/lib/sinatra/url_for.rb +44 -0
  58. metadata +270 -0
@@ -0,0 +1,1004 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'sinatra/base'
4
+ require 'sinatra/rabbit'
5
+ require 'sinatra/sequel_transaction'
6
+
7
+ require 'json'
8
+ require 'extlib/hash'
9
+
10
+ require 'dcmgr/endpoints/errors'
11
+
12
+ module Dcmgr
13
+ module Endpoints
14
+ class CoreAPI < Sinatra::Base
15
+ include Dcmgr::Logger
16
+ register Sinatra::Rabbit
17
+ register Sinatra::SequelTransaction
18
+
19
+ disable :sessions
20
+ disable :show_exceptions
21
+
22
+ before do
23
+ request.env['dcmgr.frotend_system.id'] = 1
24
+ request.env['HTTP_X_VDC_REQUESTER_TOKEN']='u-xxxxxx'
25
+ request.env['HTTP_X_VDC_ACCOUNT_UUID']='a-00000000'
26
+ end
27
+
28
+ before do
29
+ @params = parsed_request_body if request.post?
30
+ @account = Models::Account[request.env['HTTP_X_VDC_ACCOUNT_UUID']]
31
+ @requester_token = request.env['HTTP_X_VDC_REQUESTER_TOKEN']
32
+ #@frontend = Models::FrontendSystem[request.env['dcmgr.frotend_system.id']]
33
+
34
+ #raise InvalidRequestCredentials if !(@account && @frontend)
35
+ raise DisabledAccount if @account.disable?
36
+ end
37
+
38
+ before do
39
+ Thread.current[Dcmgr::Models::BaseNew::LOCK_TABLES_KEY] = {}
40
+ end
41
+
42
+ def find_by_uuid(model_class, uuid)
43
+ if model_class.is_a?(Symbol)
44
+ model_class = Models.const_get(model_class)
45
+ end
46
+ model_class[uuid] || raise(UnknownUUIDResource, uuid.to_s)
47
+ end
48
+
49
+ def find_account(account_uuid)
50
+ find_by_uuid(:Account, account_uuid)
51
+ end
52
+
53
+ # Returns deserialized hash from HTTP body. Serialization fromat
54
+ # is guessed from content type header. The query string params
55
+ # is returned if none of content type header is in HTTP headers.
56
+ # This method is called only when the request method is POST.
57
+ def parsed_request_body
58
+ # @mime_types should be defined by sinatra/respond_to.rb plugin.
59
+ if @mime_types.nil?
60
+ # use query string as requested params if Content-Type
61
+ # header was not sent.
62
+ # ActiveResource library tells the one level nested hash which has
63
+ # {'something key'=>real_params} so that dummy key is assinged here.
64
+ hash = {:dummy=>@params}
65
+ else
66
+ mime = @mime_types.first
67
+ case mime.to_s
68
+ when 'application/json', 'text/json'
69
+ require 'json'
70
+ hash = JSON.load(request.body)
71
+ hash = hash.to_mash
72
+ when 'application/yaml', 'text/yaml'
73
+ require 'yaml'
74
+ hash = YAML.load(request.body)
75
+ hash = hash.to_mash
76
+ else
77
+ raise "Unsupported body document type: #{mime.to_s}"
78
+ end
79
+ end
80
+ return hash.values.first
81
+ end
82
+
83
+ def response_to(res)
84
+ mime = @mime_types.first unless @mime_types.nil?
85
+ case mime.to_s
86
+ when 'application/yaml', 'text/yaml'
87
+ content_type 'yaml'
88
+ res.to_yaml
89
+ when 'application/xml', 'text/xml'
90
+ raise NotImplementedError
91
+ else
92
+ content_type 'json'
93
+ res.to_json
94
+ end
95
+ end
96
+
97
+ # I am not going to use error(ex, &blk) hook since it works only
98
+ # when matches the Exception class exactly. I expect to match
99
+ # whole subclasses of APIError so that override handle_exception!().
100
+ def handle_exception!(boom)
101
+ logger.error(boom)
102
+ if boom.kind_of?(APIError)
103
+ @env['sinatra.error'] = boom
104
+ error(boom.status_code, boom.class.to_s)
105
+ else
106
+ super
107
+ end
108
+ end
109
+
110
+ def create_volume_from_snapshot(account_id, snapshot_id)
111
+ vs = find_by_uuid(:VolumeSnapshot, snapshot_id)
112
+ raise UnknownVolumeSnapshot if vs.nil?
113
+ vs.create_volume(account_id)
114
+ end
115
+
116
+ def examine_owner(account_resource)
117
+ if @account.canonical_uuid == account_resource.account_id ||
118
+ @account.canonical_uuid == 'a-00000000'
119
+ return true
120
+ else
121
+ return false
122
+ end
123
+ end
124
+
125
+ collection :accounts do
126
+ operation :index do
127
+ control do
128
+ end
129
+ end
130
+
131
+ operation :show do
132
+ control do
133
+ a = find_account(params[:id])
134
+ respond_to { |f|
135
+ f.json { a.to_hash_document.to_json }
136
+ }
137
+ end
138
+ end
139
+
140
+ operation :create do
141
+ description 'Register a new account'
142
+ control do
143
+ a = Models::Account.create()
144
+ respond_to { |f|
145
+ f.json { a.to_hash_document.to_json }
146
+ }
147
+ end
148
+ end
149
+
150
+ operation :destroy do
151
+ description 'Unregister the account.'
152
+ # Associated resources all have to be destroied prior to
153
+ # removing the account.
154
+ #param :id, :string, :required
155
+ control do
156
+ a = find_account(params[:id])
157
+ a.destroy
158
+
159
+ respond_to { |f|
160
+ f.json { {} }
161
+ }
162
+ end
163
+ end
164
+
165
+ operation :enable, :method=>:get, :member=>true do
166
+ description 'Enable the account for all operations'
167
+ control do
168
+ a = find_account(params[:id])
169
+ a.enabled = Models::Account::ENABLED
170
+ a.save
171
+
172
+ respond_to { |f|
173
+ f.json { {} }
174
+ }
175
+ end
176
+ end
177
+
178
+ operation :disable, :method=>:get, :member=>true do
179
+ description 'Disable the account for all operations'
180
+ control do
181
+ a = find_account(params[:id])
182
+ a.enabled = Models::Account::DISABLED
183
+ a.save
184
+
185
+ respond_to { |f|
186
+ f.json { {} }
187
+ }
188
+ end
189
+ end
190
+
191
+ operation :add_tag, :method=>:get, :member=>true do
192
+ description 'Add a tag belongs to the account'
193
+ #param :tag_name, :string, :required
194
+ control do
195
+ a = find_account(params[:id])
196
+
197
+ tag_class = Models::Tags.find_tag_class(params[:tag_name])
198
+ raise "UnknownTagClass: #{params[:tag_name]}" if tag_class.nil?
199
+
200
+ a.add_tag(tag_class.new(:name=>params[:name]))
201
+ end
202
+ end
203
+
204
+ operation :remove_tag, :method=>:get, :member=>true do
205
+ description 'Unlink the associated tag of the account'
206
+ #param :tag_id, :string, :required
207
+ control do
208
+ a = find_account(params[:id])
209
+ t = a.tags_dataset.filter(:uuid=>params[:tag_id]).first
210
+ if t
211
+ a.remove_tag(t)
212
+ else
213
+ raise "Unknown or disassociated tag for #{a.cuuid}: #{params[:tag_id]}"
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ collection :tags do
220
+ operation :create do
221
+ description 'Register new tag to the account'
222
+ #param :tag_name, :string, :required
223
+ #param :type_id, :fixnum, :optional
224
+ #param :account_id, :string, :optional
225
+ control do
226
+ tag_class = Models::Tag.find_tag_class(params[:tag_name])
227
+
228
+ tag_class.create
229
+
230
+ end
231
+ end
232
+
233
+ operation :show do
234
+ #param :account_id, :string, :optional
235
+ control do
236
+ end
237
+ end
238
+
239
+ operation :destroy do
240
+ description 'Create a new user'
241
+ control do
242
+ end
243
+ end
244
+
245
+ operation :update do
246
+ control do
247
+ end
248
+ end
249
+ end
250
+
251
+ # Endpoint to handle VM instance.
252
+ collection :instances do
253
+ operation :index do
254
+ description 'Show list of instances'
255
+ # params start, fixnum, optional
256
+ # params limit, fixnum, optional
257
+ control do
258
+ start = params[:start].to_i
259
+ start = start < 1 ? 0 : start
260
+ limit = params[:limit].to_i
261
+ limit = limit < 1 ? nil : limit
262
+
263
+ total_ds = Models::Instance.where(:account_id=>@account.canonical_uuid)
264
+ partial_ds = total_ds.dup.order(:id)
265
+ partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
266
+
267
+ res = [{
268
+ :owner_total => total_ds.count,
269
+ :start => start,
270
+ :limit => limit,
271
+ :results=> partial_ds.all.map {|i| i.to_api_document }
272
+ }]
273
+
274
+ respond_to { |f|
275
+ f.json {res.to_json}
276
+ }
277
+ end
278
+ end
279
+
280
+ operation :create do
281
+ description 'Runs a new VM instance'
282
+ # param :image_id, string, :required
283
+ # param :instance_spec_id, string, :required
284
+ # param :host_pool_id, string, :optional
285
+ # param :host_name, string, :optional
286
+ # param :user_data, string, :optional
287
+ # param :nf_group, array, :optional
288
+ # param :ssh_key, string, :optional
289
+ control do
290
+ Models::Instance.lock!
291
+
292
+ wmi = find_by_uuid(:Image, params[:image_id])
293
+ spec = find_by_uuid(:InstanceSpec, (params[:instance_spec_id] || 'is-kpf0pasc'))
294
+
295
+ if params[:host_pool_id]
296
+ hp = Models::HostPool[params[:host_pool_id]]
297
+ raise OutOfHostCapacity unless hp.check_capacity(spec)
298
+ else
299
+ # TODO: schedule a host pool owned by SharedPool account.
300
+ end
301
+
302
+ raise UnknownHostPool, "Could not find host pool: #{params[:host_pool_id]}" if hp.nil?
303
+
304
+ inst = hp.create_instance(@account, wmi, spec) do |i|
305
+ # TODO: do not use rand() to decide vnc port.
306
+ i.runtime_config = {:vnc_port=>rand(2000), :telnet_port=> (rand(2000) + 2000)}
307
+ i.user_data = params[:user_data] || ''
308
+
309
+ if params[:ssh_key]
310
+ ssh_key_pair = Models::SshKeyPair.find(:account_id=>@account.canonical_uuid,
311
+ :name=>params[:ssh_key])
312
+ if ssh_key_pair.nil?
313
+ raise UnknownSshKeyPair, "#{params[:ssh_key]}"
314
+ else
315
+ i.ssh_key_pair_id = ssh_key_pair.canonical_uuid
316
+ end
317
+ end
318
+ end
319
+
320
+ unless params[:nf_group].is_a?(Array)
321
+ params[:nf_group] = ['default']
322
+ end
323
+ inst.join_nfgroup_by_name(@account.canonical_uuid, params[:nf_group])
324
+
325
+ case wmi.boot_dev_type
326
+ when Models::Image::BOOT_DEV_SAN
327
+ # create new volume from snapshot.
328
+ snapshot_id = wmi.source[:snapshot_id]
329
+ vol = create_volume_from_snapshot(@account.canonical_uuid, snapshot_id)
330
+
331
+ vol.instance = inst
332
+ vol.save
333
+ res = Dcmgr.messaging.submit("kvm-handle.#{hp.node_id}", 'run_vol_store', inst.canonical_uuid, vol.canonical_uuid)
334
+ when Models::Image::BOOT_DEV_LOCAL
335
+ res = Dcmgr.messaging.submit("kvm-handle.#{hp.node_id}", 'run_local_store', inst.canonical_uuid)
336
+ else
337
+ raise "Unknown boot type"
338
+ end
339
+ respond_to { |f|
340
+ f.json { inst.to_api_document.to_json }
341
+ }
342
+ end
343
+ end
344
+
345
+ operation :show do
346
+ #param :account_id, :string, :optional
347
+ control do
348
+ i = find_by_uuid(:Instance, params[:id])
349
+ raise UnknownInstance if i.nil?
350
+
351
+ respond_to { |f|
352
+ f.json { i.to_api_document.to_json }
353
+ }
354
+ end
355
+ end
356
+
357
+ operation :destroy do
358
+ description 'Shutdown the instance'
359
+ control do
360
+ Models::Instance.lock!
361
+ i = find_by_uuid(:Instance, params[:id])
362
+ if examine_owner(i)
363
+ else
364
+ raise OperationNotPermitted
365
+ end
366
+ res = Dcmgr.messaging.submit("kvm-handle.#{i.host_pool.node_id}", 'terminate', i.canonical_uuid)
367
+ respond_to { |f|
368
+ f.json { i.canonical_uuid }
369
+ }
370
+ end
371
+ end
372
+
373
+ operation :reboot, :method=>:put, :member=>true do
374
+ description 'Reboots the instance'
375
+ control do
376
+ Models::Instance.lock!
377
+ i = find_by_uuid(:Instance, params[:id])
378
+ end
379
+ end
380
+ end
381
+
382
+ collection :images do
383
+ operation :create do
384
+ description 'Register new machine image'
385
+ control do
386
+ Models::Image.lock!
387
+ raise NotImplementedError
388
+ end
389
+ end
390
+
391
+ operation :index do
392
+ description 'Show list of machine images'
393
+ control do
394
+ start = params[:start].to_i
395
+ start = start < 1 ? 0 : start
396
+ limit = params[:limit].to_i
397
+ limit = limit < 1 ? nil : limit
398
+
399
+ total_ds = Models::Image.where(:account_id=>@account.canonical_uuid)
400
+ partial_ds = total_ds.dup.order(:id)
401
+ partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
402
+
403
+ res = [{
404
+ :owner_total => total_ds.count,
405
+ :start => start,
406
+ :limit => limit,
407
+ :results=> partial_ds.all.map {|i| i.to_hash }
408
+ }]
409
+
410
+ respond_to { |f|
411
+ f.json {res.to_json}
412
+ }
413
+ end
414
+ end
415
+
416
+ operation :show do
417
+ description "Show a machine image details."
418
+ control do
419
+ i = find_by_uuid(:Image, params[:id])
420
+ # TODO: add visibility by account check
421
+ unless examine_owner(i)
422
+ raise OperationNotPermitted
423
+ end
424
+ respond_to { |f|
425
+ f.json { i.to_hash.to_json }
426
+ }
427
+ end
428
+ end
429
+
430
+ operation :destroy do
431
+ description 'Delete a machine image'
432
+ control do
433
+ Models::Image.lock!
434
+ i = find_by_uuid(:Image, params[:id])
435
+ if examine_owner(i)
436
+ i.delete
437
+ else
438
+ raise OperationNotPermitted
439
+ end
440
+ end
441
+ end
442
+ end
443
+
444
+ collection :host_pools do
445
+ operation :index do
446
+ description 'Show list of host pools'
447
+ control do
448
+ start = params[:start].to_i
449
+ start = start < 1 ? 0 : start
450
+ limit = params[:limit].to_i
451
+ limit = limit < 1 ? nil : limit
452
+
453
+ total_ds = Models::HostPool.where(:account_id=>@account.canonical_uuid)
454
+ partial_ds = total_ds.dup.order(:id)
455
+ partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
456
+
457
+ res = [{
458
+ :owner_total => total_ds.count,
459
+ :start => start,
460
+ :limit => limit,
461
+ :results=> partial_ds.all.map {|i| i.to_hash }
462
+ }]
463
+
464
+ respond_to { |f|
465
+ f.json {res.to_json}
466
+ }
467
+ end
468
+ end
469
+
470
+ operation :show do
471
+ description 'Show status of the host'
472
+ #param :account_id, :string, :optional
473
+ control do
474
+ hp = find_by_uuid(:HostPool, params[:id])
475
+ raise OperationNotPermitted unless examine_owner(hp)
476
+
477
+ respond_to { |f|
478
+ f.json { hp.to_hash.to_json }
479
+ }
480
+ end
481
+ end
482
+ end
483
+
484
+ collection :volumes do
485
+ operation :index do
486
+ description 'Show lists of the volume'
487
+ # params start, fixnum, optional
488
+ # params limit, fixnum, optional
489
+ control do
490
+ start = params[:start].to_i
491
+ start = start < 1 ? 0 : start
492
+ limit = params[:limit].to_i
493
+ limit = limit < 1 ? nil : limit
494
+
495
+ total_v = Models::Volume.where(:account_id => @account.canonical_uuid)
496
+ partial_v = total_v.dup.order(:id)
497
+ partial_v = partial_v.limit(limit, start) if limit.is_a?(Integer)
498
+ res = [{
499
+ :owner_total => total_v.count,
500
+ :start => start,
501
+ :limit => limit,
502
+ :results => partial_v.all.map { |v| v.to_hash_document}
503
+ }]
504
+ respond_to { |f|
505
+ f.json { res.to_json}
506
+ }
507
+ end
508
+ end
509
+
510
+ operation :show do
511
+ description 'Show the volume status'
512
+ # params id, string, required
513
+ control do
514
+ volume_id = params[:id]
515
+ raise UndefinedVolumeID if volume_id.nil?
516
+ v = find_by_uuid(:Volume, volume_id)
517
+ respond_to { |f|
518
+ f.json { v.to_hash_document.to_json}
519
+ }
520
+ end
521
+ end
522
+
523
+ operation :create do
524
+ description 'Create the new volume'
525
+ # params volume_size, string, required
526
+ # params snapshot_id, string, optional
527
+ # params storage_pool_id, string, optional
528
+ control do
529
+ Models::Volume.lock!
530
+ if params[:snapshot_id]
531
+ v = create_volume_from_snapshot(@account.canonical_uuid, params[:snapshot_id])
532
+ sp = v.storage_pool
533
+ elsif params[:volume_size]
534
+ raise InvalidVolumeSize if !(Dcmgr.conf.create_volume_max_size.to_i >= params[:volume_size].to_i) || !(params[:volume_size\
535
+ ].to_i >= Dcmgr.conf.create_volume_min_size.to_i)
536
+ if params[:storage_pool_id]
537
+ sp = find_by_uuid(:StoragePool, params[:storage_pool_id])
538
+ raise StoragePoolNotPermitted if sp.account_id != @account.canonical_uuid
539
+ end
540
+ raise UnknownStoragePool if sp.nil?
541
+ begin
542
+ v = sp.create_volume(@account.canonical_uuid, params[:volume_size])
543
+ rescue Models::Volume::DiskError => e
544
+ logger.error(e)
545
+ raise OutOfDiskSpace
546
+ rescue Sequel::DatabaseError => e
547
+ logger.error(e)
548
+ raise DatabaseError
549
+ end
550
+ else
551
+ raise UndefinedRequiredParameter
552
+ end
553
+
554
+ res = Dcmgr.messaging.submit("zfs-handle.#{sp.values[:node_id]}", 'create_volume', v.canonical_uuid)
555
+ respond_to { |f|
556
+ f.json { v.to_hash_document.to_json}
557
+ }
558
+ end
559
+ end
560
+
561
+ operation :destroy do
562
+ description 'Delete the volume'
563
+ # params id, string, required
564
+ control do
565
+ Models::Volume.lock!
566
+ volume_id = params[:id]
567
+ raise UndefinedVolumeID if volume_id.nil?
568
+
569
+ begin
570
+ v = Models::Volume.delete_volume(@account.canonical_uuid, volume_id)
571
+ rescue Models::Volume::RequestError => e
572
+ logger.error(e)
573
+ raise InvalidDeleteRequest
574
+ end
575
+ raise UnknownVolume if v.nil?
576
+ sp = v.storage_pool
577
+
578
+ res = Dcmgr.messaging.submit("zfs-handle.#{sp.values[:node_id]}", 'delete_volume', v.canonical_uuid)
579
+ respond_to { |f|
580
+ f.json { v.to_hash_document.to_json}
581
+ }
582
+ end
583
+ end
584
+
585
+ operation :attach, :method =>:put, :member =>true do
586
+ description 'Attachd the volume'
587
+ # params id, string, required
588
+ # params instance_id, string, required
589
+ control do
590
+ raise UndefinedInstanceID if params[:instance_id].nil?
591
+ raise UndefinedVolumeID if params[:id].nil?
592
+
593
+ i = find_by_uuid(:Instance, params[:instance_id])
594
+ raise UnknownInstance if i.nil?
595
+
596
+ v = find_by_uuid(:Volume, params[:id])
597
+ raise UnknownVolume if v.nil?
598
+
599
+ v.instance = i
600
+ v.save
601
+ res = Dcmgr.messaging.submit("kvm-handle.#{i.host_pool.node_id}", 'attach', i.canonical_uuid, v.canonical_uuid)
602
+
603
+ respond_to { |f|
604
+ f.json { v.to_hash_document.to_json}
605
+ }
606
+ end
607
+ end
608
+
609
+ operation :detach, :method =>:put, :member =>true do
610
+ description 'Detachd the volume'
611
+ # params id, string, required
612
+ control do
613
+ raise UndefinedVolumeID if params[:id].nil?
614
+
615
+ v = find_by_uuid(:Volume, params[:id])
616
+ raise UnknownVolume if v.nil?
617
+ i = v.instance
618
+ res = Dcmgr.messaging.submit("kvm-handle.#{i.host_pool.node_id}", 'detach', i.canonical_uuid, v.canonical_uuid)
619
+ respond_to { |f|
620
+ f.json {v.to_hash_document.to_json}
621
+ }
622
+ end
623
+ end
624
+
625
+ operation :status, :method =>:get, :member =>true do
626
+ description 'Show the status'
627
+ control do
628
+ vl = [{ :id => 1, :uuid => 'vol-xxxxxxx', :status => 1 },
629
+ { :id => 2, :uuid => 'vol-xxxxxxx', :status => 0 },
630
+ { :id => 3, :uuid => 'vol-xxxxxxx', :status => 3 },
631
+ { :id => 4, :uuid => 'vol-xxxxxxx', :status => 2 },
632
+ { :id => 5, :uuid => 'vol-xxxxxxx', :status => 4 }]
633
+ respond_to {|f|
634
+ f.json { vl.to_json}
635
+ }
636
+ end
637
+ end
638
+ end
639
+
640
+ collection :volume_snapshots do
641
+ operation :index do
642
+ description 'Show lists of the volume_snapshots'
643
+ # params start, fixnum, optional
644
+ # params limit, fixnum, optional
645
+ control do
646
+ start = params[:start].to_i
647
+ start = start < 1 ? 0 : start
648
+ limit = params[:limit].to_i
649
+ limit = limit < 1 ? nil : limit
650
+
651
+ total_vs = Models::VolumeSnapshot.where(:account_id => @account.canonical_uuid)
652
+ partial_vs = total_vs.dup.order(:id)
653
+ partial_vs = partial_vs.limit(limit, start) if limit.is_a?(Integer)
654
+ res = [{
655
+ :owner_total => total_vs.count,
656
+ :start => start,
657
+ :limit => limit,
658
+ :results => partial_vs.all.map { |vs| vs.to_hash_document}
659
+ }]
660
+ respond_to { |f|
661
+ f.json { res.to_json}
662
+ }
663
+ end
664
+ end
665
+
666
+ operation :show do
667
+ description 'Show the volume status'
668
+ # params id, string, required
669
+ control do
670
+ snapshot_id = params[:id]
671
+ raise UndefinedVolumeSnapshotID if snapshot_id.nil?
672
+ vs = find_by_uuid(:VolumeSnapshot, snapshot_id)
673
+ respond_to { |f|
674
+ f.json { vs.to_hash_document.to_json}
675
+ }
676
+ end
677
+ end
678
+
679
+ operation :create do
680
+ description 'Create a new volume snapshot'
681
+ # params volume_id, string, required
682
+ # params storage_pool_id, string, optional
683
+ control do
684
+ Models::Volume.lock!
685
+ raise UndefinedVolumeID if params[:volume_id].nil?
686
+
687
+ v = find_by_uuid(:Volume, params[:volume_id])
688
+ raise UnknownVolume if v.nil?
689
+
690
+ vs = v.create_snapshot(@account.canonical_uuid)
691
+ sp = vs.storage_pool
692
+
693
+ res = Dcmgr.messaging.submit("zfs-handle.#{sp.node_id}", 'create_snapshot', vs.canonical_uuid)
694
+ respond_to { |f|
695
+ f.json { vs.to_hash_document.to_json}
696
+ }
697
+ end
698
+ end
699
+
700
+ operation :destroy do
701
+ description 'Delete the volume snapshot'
702
+ # params id, string, required
703
+ control do
704
+ Models::VolumeSnapshot.lock!
705
+ snapshot_id = params[:id]
706
+ raise UndefindVolumeSnapshotID if snapshot_id.nil?
707
+
708
+ vs = find_by_uuid(:VolumeSnapshot, snapshot_id)
709
+ raise UnknownVolumeSnapshot if vs.nil?
710
+ vs = vs.delete_snapshot
711
+ sp = vs.storage_pool
712
+
713
+ res = Dcmgr.messaging.submit("zfs-handle.#{sp.node_id}", 'delete_snapshot', vs.canonical_uuid)
714
+ respond_to { |f|
715
+ f.json { vs.to_hash_document.to_json }
716
+ }
717
+ end
718
+ end
719
+
720
+ operation :status, :method =>:get, :member =>true do
721
+ description 'Show the status'
722
+ control do
723
+ vs = [{ :id => 1, :uuid => 'snap-xxxxxxx', :status => 1 },
724
+ { :id => 2, :uuid => 'snap-xxxxxxx', :status => 0 },
725
+ { :id => 3, :uuid => 'snap-xxxxxxx', :status => 3 },
726
+ { :id => 4, :uuid => 'snap-xxxxxxx', :status => 2 },
727
+ { :id => 5, :uuid => 'snap-xxxxxxx', :status => 4 }]
728
+ respond_to {|f|
729
+ f.json { vs.to_json}
730
+ }
731
+ end
732
+ end
733
+ end
734
+
735
+ collection :netfilter_groups do
736
+ description 'Show lists of the netfilter_groups'
737
+ operation :index do
738
+ control do
739
+ start = params[:start].to_i
740
+ start = start < 1 ? 0 : start
741
+ limit = params[:limit].to_i
742
+ limit = limit < 1 ? nil : limit
743
+
744
+ total_ds = Models::NetfilterGroup.where(:account_id=>@account.canonical_uuid)
745
+ partial_ds = total_ds.dup.order(:id)
746
+ partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
747
+
748
+ res = [{
749
+ :owner_total => total_ds.count,
750
+ :start => start,
751
+ :limit => limit,
752
+ :results=> partial_ds.all.map {|i| i.to_hash }
753
+ }]
754
+
755
+ respond_to { |f|
756
+ f.json {res.to_json}
757
+ }
758
+ end
759
+ end
760
+
761
+ operation :show do
762
+ description 'Show the netfilter_groups'
763
+ control do
764
+ g = find_by_uuid(:NetfilterGroup, params[:id])
765
+ p params[:id]
766
+ raise OperationNotPermitted unless examine_owner(g)
767
+
768
+ respond_to { |f|
769
+ f.json { g.to_hash.to_json }
770
+ }
771
+ end
772
+ end
773
+
774
+ operation :create do
775
+ description 'Register a new netfilter_group'
776
+ # params name, string
777
+ # params description, string
778
+ # params rule, string
779
+ control do
780
+ Models::NetfilterGroup.lock!
781
+ raise UndefinedNetfilterGroup if params[:name].nil?
782
+
783
+ @name = params[:name]
784
+ # TODO: validate @name. @name can use [a-z] [A-Z] '_' '-'
785
+ # - invalidate? -> raise InvalidCharacterOfNetfilterGroupName
786
+
787
+ g = Models::NetfilterGroup.filter(:name => @name, :account_id => @account.canonical_uuid).first
788
+ raise DuplicatedNetfilterGroup unless g.nil?
789
+
790
+ g = Models::NetfilterGroup.create_group(@account.canonical_uuid, params)
791
+ respond_to { |f|
792
+ f.json { g.to_hash.to_json }
793
+ }
794
+ end
795
+ end
796
+
797
+ operation :update do
798
+ description "Update parameters for the netfilter group"
799
+ # params description, string
800
+ # params rule, string
801
+ control do
802
+ g = find_by_uuid(:NetfilterGroup, params[:id])
803
+
804
+ raise UnknownNetfilterGroup if g.nil?
805
+
806
+ if params[:description]
807
+ g.description = params[:description]
808
+ end
809
+ if params[:rule]
810
+ g.rule = params[:rule]
811
+ end
812
+
813
+ g.save
814
+ g.rebuild_rule
815
+
816
+ # refresh netfilter_rules
817
+ Dcmgr.messaging.event_publish('hva/netfilter_updated', :args=>[g.canonical_uuid])
818
+
819
+ respond_to { |f|
820
+ f.json { g.to_hash.to_json }
821
+ }
822
+ end
823
+ end
824
+
825
+ operation :destroy do
826
+ # params name, string
827
+ description "Delete the netfilter group"
828
+
829
+ control do
830
+ Models::NetfilterGroup.lock!
831
+ g = find_by_uuid(:NetfilterGroup, params[:id])
832
+
833
+ raise UnknownNetfilterGroup if g.nil?
834
+ raise NetfilterGroupNotPermitted if g.account_id != @account.canonical_uuid
835
+
836
+ respond_to { |f|
837
+ f.json { g.destroy_group.values.to_json }
838
+ }
839
+ end
840
+ end
841
+
842
+ end
843
+
844
+ collection :netfilter_rules do
845
+ operation :index do
846
+ control do
847
+ end
848
+ end
849
+
850
+ operation :show do
851
+ description 'Show lists of the netfilter_rules'
852
+ control do
853
+ rules = []
854
+ begin
855
+ @name = params[:id]
856
+ g = Models::NetfilterGroup.filter(:name => @name, :account_id => @account.canonical_uuid).first
857
+ raise UnknownNetfilterGroup if g.nil?
858
+
859
+ g.netfilter_rules.each { |rule|
860
+ rules << rule.values
861
+ }
862
+ end
863
+
864
+ respond_to { |f|
865
+ f.json { rules.to_json }
866
+ }
867
+ end
868
+ end
869
+ end
870
+
871
+ collection :storage_pools do
872
+ operation :index do
873
+ description 'Show lists of the storage_pools'
874
+ # params start, fixnum, optional
875
+ # params limit, fixnum, optional
876
+ control do
877
+ start = params[:start].to_i
878
+ start = start < 1 ? 0 : start
879
+ limit = params[:limit].to_i
880
+ limit = limit < 1 ? nil : limit
881
+
882
+ total_ds = Models::StoragePool.where(:account_id=>@account.canonical_uuid)
883
+ partial_ds = total_ds.dup.order(:id)
884
+ partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
885
+
886
+ res = [{
887
+ :owner_total => total_ds.count,
888
+ :start => start,
889
+ :limit => limit,
890
+ :results=> partial_ds.all.map {|sp| sp.to_hash_document }
891
+ }]
892
+
893
+ respond_to { |f|
894
+ f.json { res.to_json}
895
+ }
896
+ end
897
+ end
898
+
899
+ operation :show do
900
+ description 'Show the storage_pool status'
901
+ # params id, string, required
902
+ control do
903
+ pool_id = params[:id]
904
+ raise UndefinedStoragePoolID if pool_id.nil?
905
+ vs = find_by_uuid(:StoragePool, pool_id)
906
+ raise UnknownStoragePool if vs.nil?
907
+ respond_to { |f|
908
+ f.json { vs.to_hash_document.to_json}
909
+ }
910
+ end
911
+ end
912
+ end
913
+
914
+ collection :ssh_key_pairs do
915
+ description "List ssh key pairs in account"
916
+ operation :index do
917
+ # params start, fixnum, optional
918
+ # params limit, fixnum, optional
919
+ control do
920
+ start = params[:start].to_i
921
+ start = start < 1 ? 0 : start
922
+ limit = params[:limit].to_i
923
+ limit = limit < 1 ? nil : limit
924
+
925
+ total_ds = Models::SshKeyPair.where(:account_id=>@account.canonical_uuid)
926
+ partial_ds = total_ds.dup.order(:id)
927
+ partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
928
+
929
+ res = [{
930
+ :owner_total => total_ds.count,
931
+ :filter_total => total_ds.count,
932
+ :start => start,
933
+ :limit => limit,
934
+ :results=> partial_ds.all.map {|i| i.to_hash }
935
+ }]
936
+
937
+ respond_to { |f|
938
+ f.json {res.to_json}
939
+ }
940
+ end
941
+ end
942
+
943
+ operation :show do
944
+ description "Retrieve details about ssh key pair"
945
+ # params :id required
946
+ # params :format optional [openssh,putty]
947
+ control do
948
+ ssh = find_by_uuid(:SshKeyPair, params[:id])
949
+
950
+ respond_to { |f|
951
+ f.json {ssh.to_hash.to_json}
952
+ }
953
+ end
954
+ end
955
+
956
+ operation :create do
957
+ description "Create ssh key pair information"
958
+ # params :name required key name (<100 chars)
959
+ # params :download_once optional set true if you do not want
960
+ # to save private key info on database.
961
+ control do
962
+ Models::SshKeyPair.lock!
963
+ keydata = Models::SshKeyPair.generate_key_pair
964
+ savedata = {
965
+ :name=>params[:name],
966
+ :account_id=>@account.canonical_uuid,
967
+ :public_key=>keydata[:public_key]
968
+ }
969
+ if params[:download_once] != 'true'
970
+ savedata[:private_key]=keydata[:private_key]
971
+ end
972
+ ssh = Models::SshKeyPair.create(savedata)
973
+
974
+ respond_to { |f|
975
+ # include private_key data in response even if
976
+ # it's not going to be stored on DB.
977
+ f.json {ssh.to_hash.merge(:private_key=>keydata[:private_key]).to_json}
978
+ }
979
+ end
980
+ end
981
+
982
+ operation :destroy do
983
+ description "Remove ssh key pair information"
984
+ # params :id required
985
+ control do
986
+ Models::SshKeyPair.lock!
987
+ ssh = find_by_uuid(:SshKeyPair, params[:id])
988
+ if examine_owner(ssh)
989
+ ssh.destroy
990
+ else
991
+ raise OperationNotPermitted
992
+ end
993
+
994
+ respond_to { |f|
995
+ f.json {ssh.to_hash.to_json}
996
+ }
997
+ end
998
+ end
999
+
1000
+ end
1001
+
1002
+ end
1003
+ end
1004
+ end