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,167 @@
1
+ module Dcmgr
2
+ module Drivers
3
+ class Lxc < Hypervisor
4
+ include Dcmgr::Logger
5
+ include Dcmgr::Helpers::CliHelper
6
+
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)
78
+ # 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
83
+ 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
87
+ }
88
+ else
89
+ @os_devpath = "#{@inst_data_dir}/#{hc.inst_id}"
90
+ end
91
+ end
92
+ # check mount point
93
+ mount_point = "#{@inst_data_dir}/rootfs"
94
+ unless File.exist?(mount_point)
95
+ sh("mkdir #{mount_point}")
96
+ end
97
+
98
+ cmd = "mount %s %s"
99
+ args = [@os_devpath, mount_point]
100
+ if @inst[:image][:boot_dev_type] == 2
101
+ cmd += " -o loop"
102
+ end
103
+ sh(cmd, args)
104
+
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]])
111
+ end
112
+
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")
117
+ end
118
+
119
+ def reboot_instance(hc)
120
+ inst = hc.inst
121
+ terminate_instance(hc)
122
+ run_instance(hc)
123
+ end
124
+
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')
128
+
129
+ # find major number and minor number to device file
130
+ stat = File.stat(sddev)
131
+ 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
144
+ devnum
145
+ end
146
+
147
+ def detach_volume_from_guest(hc)
148
+ inst_id = hc.inst_id
149
+ vol = hc.vol
150
+ sddev = File.expand_path(File.readlink(vol[:host_device_name]), '/dev/disk/by-path')
151
+ devnum = vol[:guest_device_name]
152
+
153
+ sh("echo \"b #{devnum} rwm\" > /cgroup/#{inst_id}/devices.deny")
154
+ sh("rm -rf #{hc.inst_data_dir}/rootfs#{sddev}")
155
+
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
163
+ end
164
+
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Drivers
4
+
5
+ class S3Storage < SnapshotStorage
6
+
7
+ include Dcmgr::Logger
8
+
9
+ def download(keyname, filename, path)
10
+ cmd = "get %s %s %s"
11
+ args = [@bucket, keyname, File.join(path, filename)]
12
+ execute(cmd, args)
13
+ end
14
+
15
+ def upload(keyname, file)
16
+ cmd = "put %s %s %s"
17
+ args = [@bucket, keyname, file]
18
+ execute(cmd, args)
19
+ end
20
+
21
+ def delete(keyname)
22
+ cmd = "rm %s %s"
23
+ args = [@bucket, keyname]
24
+ execute(cmd, args)
25
+ end
26
+
27
+ def check(keyname)
28
+ cmd = "test %s %s"
29
+ args = [@bucket, keyname]
30
+ execute(cmd, args)
31
+ end
32
+
33
+ def list
34
+ cmd = "ls %s"
35
+ args = [@bucket]
36
+ execute(cmd, args)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rexml/document'
4
+
5
+ module Dcmgr::Drivers
6
+ class SnapshotStorage
7
+ include Dcmgr::Helpers::CliHelper
8
+
9
+ def initialize(bucket)
10
+ @env = []
11
+ @bucket = bucket
12
+ end
13
+
14
+ def setenv(key, value)
15
+ @env.push("#{key}=#{value}")
16
+ end
17
+
18
+ def download
19
+ end
20
+
21
+ def upload
22
+ end
23
+
24
+ def delete
25
+ end
26
+
27
+ def check
28
+ end
29
+
30
+ def execute(cmd, args)
31
+ script_root_path = File.join(File.expand_path('../../../../',__FILE__), 'script')
32
+ script = File.join(script_root_path, 'storage_service')
33
+ cmd = "/usr/bin/env #{@env.join(' ')} %s " + cmd
34
+ args = [script] + args
35
+ res = sh(cmd, args)
36
+
37
+ if res[:stdout] != ''
38
+ doc = REXML::Document.new res[:stdout]
39
+ code = REXML::XPath.match( doc, "//Error/Code/text()" ).to_s
40
+ message = REXML::XPath.match( doc, "//Error/Message/text()" ).to_s
41
+ bucket_name = REXML::XPath.match( doc, "//Error/BucketName/text()" ).to_s
42
+ request_id = REXML::XPath.match( doc, "//Error/RequestId/text()" ).to_s
43
+ host_id = REXML::XPath.match( doc, "//Error/HostId/text()" ).to_s
44
+ error_message = ["Snapshot execute error: ",cmd, code, message, bucket_name, request_id, host_id].join(',')
45
+ raise error_message
46
+ else
47
+ res
48
+ end
49
+ end
50
+ end
51
+ end
@@ -11,25 +11,40 @@ require 'dcmgr/endpoints/errors'
11
11
 
12
12
  module Dcmgr
13
13
  module Endpoints
14
+ # HTTP Header constants for request credentials.
15
+ HTTP_X_VDC_REQUESTER_TOKEN='HTTP_X_VDC_REQUESTER_TOKEN'.freeze
16
+ HTTP_X_VDC_ACCOUNT_UUID='HTTP_X_VDC_ACCOUNT_UUID'.freeze
17
+
18
+ RACK_FRONTEND_SYSTEM_ID='dcmgr.frotend_system.id'
19
+
14
20
  class CoreAPI < Sinatra::Base
15
21
  include Dcmgr::Logger
16
22
  register Sinatra::Rabbit
17
23
  register Sinatra::SequelTransaction
18
24
 
25
+ use Dcmgr::Rack::RequestLogger
26
+
19
27
  disable :sessions
20
28
  disable :show_exceptions
21
29
 
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
30
  before do
29
31
  @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']]
32
+ if request.env[HTTP_X_VDC_ACCOUNT_UUID].to_s == ''
33
+ raise InvalidRequestCredentials
34
+ else
35
+ begin
36
+ # find or create account entry.
37
+ @account = Models::Account[request.env[HTTP_X_VDC_ACCOUNT_UUID]] || \
38
+ Models::Account.create(:uuid=>Models::Account.trim_uuid(request.env[HTTP_X_VDC_ACCOUNT_UUID]))
39
+ rescue => e
40
+ logger.error(e)
41
+ raise InvalidRequestCredentials, "#{e.message}"
42
+ end
43
+ raise InvalidRequestCredentials if @account.nil?
44
+ end
45
+
46
+ @requester_token = request.env[HTTP_X_VDC_REQUESTER_TOKEN]
47
+ #@frontend = Models::FrontendSystem[request.env[RACK_FRONTEND_SYSTEM_ID]]
33
48
 
34
49
  #raise InvalidRequestCredentials if !(@account && @frontend)
35
50
  raise DisabledAccount if @account.disable?
@@ -85,12 +100,12 @@ module Dcmgr
85
100
  case mime.to_s
86
101
  when 'application/yaml', 'text/yaml'
87
102
  content_type 'yaml'
88
- res.to_yaml
103
+ body res.to_yaml
89
104
  when 'application/xml', 'text/xml'
90
105
  raise NotImplementedError
91
106
  else
92
107
  content_type 'json'
93
- res.to_json
108
+ body res.to_json
94
109
  end
95
110
  end
96
111
 
@@ -98,11 +113,12 @@ module Dcmgr
98
113
  # when matches the Exception class exactly. I expect to match
99
114
  # whole subclasses of APIError so that override handle_exception!().
100
115
  def handle_exception!(boom)
101
- logger.error(boom)
102
116
  if boom.kind_of?(APIError)
103
117
  @env['sinatra.error'] = boom
104
- error(boom.status_code, boom.class.to_s)
118
+ Dcmgr::Logger.create('API Error').error("#{request.path_info} -> #{boom.class.to_s}: #{boom.message} (#{boom.backtrace.first})")
119
+ error(boom.status_code, response_to({:error=>boom.class.to_s, :message=>boom.message, :code=>boom.error_code}))
105
120
  else
121
+ logger.error(boom)
106
122
  super
107
123
  end
108
124
  end
@@ -110,7 +126,8 @@ module Dcmgr
110
126
  def create_volume_from_snapshot(account_id, snapshot_id)
111
127
  vs = find_by_uuid(:VolumeSnapshot, snapshot_id)
112
128
  raise UnknownVolumeSnapshot if vs.nil?
113
- raise InvalidRequestCredentials unless vs.state.to_s == 'available'
129
+ raise InvalidVolumeState unless vs.state.to_s == 'available'
130
+
114
131
  vs.create_volume(account_id)
115
132
  end
116
133
 
@@ -123,124 +140,48 @@ module Dcmgr
123
140
  end
124
141
  end
125
142
 
126
- collection :accounts do
127
- operation :index do
128
- control do
129
- end
130
- end
131
-
132
- operation :show do
133
- control do
134
- a = find_account(params[:id])
135
- response_to(a.to_hash)
136
- end
137
- end
138
-
139
- operation :create do
140
- description 'Register a new account'
141
- control do
142
- a = Models::Account.create()
143
- response_to(a.to_hash)
144
- end
145
- end
146
-
147
- operation :destroy do
148
- description 'Unregister the account.'
149
- # Associated resources all have to be destroied prior to
150
- # removing the account.
151
- #param :id, :string, :required
152
- control do
153
- a = find_account(params[:id])
154
- a.destroy
155
-
156
- response_to([a.canonical_uuid])
157
- end
158
- end
159
-
160
- operation :enable, :method=>:get, :member=>true do
161
- description 'Enable the account for all operations'
162
- control do
163
- a = find_account(params[:id])
164
- a.enabled = Models::Account::ENABLED
165
- a.save
166
-
167
- respond_to { |f|
168
- f.json { {} }
169
- }
170
- end
171
- end
172
-
173
- operation :disable, :method=>:get, :member=>true do
174
- description 'Disable the account for all operations'
175
- control do
176
- a = find_account(params[:id])
177
- a.enabled = Models::Account::DISABLED
178
- a.save
179
-
180
- respond_to { |f|
181
- f.json { {} }
182
- }
183
- end
143
+ def select_index(model_class, data)
144
+ if model_class.is_a?(Symbol)
145
+ model_class = Models.const_get(model_class)
184
146
  end
185
147
 
186
- operation :add_tag, :method=>:get, :member=>true do
187
- description 'Add a tag belongs to the account'
188
- #param :tag_name, :string, :required
189
- control do
190
- a = find_account(params[:id])
191
-
192
- tag_class = Models::Tags.find_tag_class(params[:tag_name])
193
- raise "UnknownTagClass: #{params[:tag_name]}" if tag_class.nil?
148
+ start = data[:start].to_i
149
+ start = start < 1 ? 0 : start
150
+ limit = data[:limit].to_i
151
+ limit = limit < 1 ? nil : limit
194
152
 
195
- a.add_tag(tag_class.new(:name=>params[:name]))
196
- end
153
+ if %w(Dcmgr::Models::InstanceSpec).member?(model_class.to_s)
154
+ total_ds = model_class.where(:account_id=>[@account.canonical_uuid,
155
+ Models::Account::SystemAccount::SharedPoolAccount.uuid,
156
+ ])
157
+ else
158
+ total_ds = model_class.where(:account_id=>@account.canonical_uuid)
197
159
  end
198
-
199
- operation :remove_tag, :method=>:get, :member=>true do
200
- description 'Unlink the associated tag of the account'
201
- #param :tag_id, :string, :required
202
- control do
203
- a = find_account(params[:id])
204
- t = a.tags_dataset.filter(:uuid=>params[:tag_id]).first
205
- if t
206
- a.remove_tag(t)
207
- else
208
- raise "Unknown or disassociated tag for #{a.cuuid}: #{params[:tag_id]}"
209
- end
210
- end
160
+
161
+ if %w(Dcmgr::Models::Instance Dcmgr::Models::Volume Dcmgr::Models::VolumeSnapshot).member?(model_class.to_s)
162
+ total_ds = total_ds.alives_and_recent_termed
211
163
  end
212
- end
213
-
214
- collection :tags do
215
- operation :create do
216
- description 'Register new tag to the account'
217
- #param :tag_name, :string, :required
218
- #param :type_id, :fixnum, :optional
219
- #param :account_id, :string, :optional
220
- control do
221
- tag_class = Models::Tag.find_tag_class(params[:tag_name])
222
-
223
- tag_class.create
224
-
225
- end
164
+ if %w(Dcmgr::Models::Image).member?(model_class.to_s)
165
+ total_ds = total_ds.or(:is_public=>true)
226
166
  end
227
167
 
228
- operation :show do
229
- #param :account_id, :string, :optional
230
- control do
231
- end
232
- end
168
+ partial_ds = total_ds.dup.order(:id.desc)
169
+ partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
233
170
 
234
- operation :destroy do
235
- description 'Create a new user'
236
- control do
237
- end
238
- end
239
-
240
- operation :update do
241
- control do
171
+ results = partial_ds.all.map {|i|
172
+ if %w(Dcmgr::Models::Image).member?(model_class.to_s)
173
+ i.to_api_document(@account.canonical_uuid)
174
+ else
175
+ i.to_api_document
242
176
  end
243
- end
177
+ }
178
+
179
+ res = [{
180
+ :owner_total => total_ds.count,
181
+ :start => start,
182
+ :limit => limit,
183
+ :results=> results
184
+ }]
244
185
  end
245
186
 
246
187
  # Endpoint to handle VM instance.
@@ -250,22 +191,8 @@ module Dcmgr
250
191
  # params start, fixnum, optional
251
192
  # params limit, fixnum, optional
252
193
  control do
253
- start = params[:start].to_i
254
- start = start < 1 ? 0 : start
255
- limit = params[:limit].to_i
256
- limit = limit < 1 ? nil : limit
257
-
258
- total_ds = Models::Instance.where(:account_id=>@account.canonical_uuid)
259
- partial_ds = total_ds.dup.order(:id)
260
- partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
261
-
262
- res = [{
263
- :owner_total => total_ds.count,
264
- :start => start,
265
- :limit => limit,
266
- :results=> partial_ds.all.map {|i| i.to_api_document }
267
- }]
268
-
194
+ res = select_index(:Instance, {:start => params[:start],
195
+ :limit => params[:limit]})
269
196
  response_to(res)
270
197
  end
271
198
  end
@@ -284,8 +211,8 @@ module Dcmgr
284
211
  control do
285
212
  Models::Instance.lock!
286
213
 
287
- wmi = find_by_uuid(:Image, params[:image_id])
288
- spec = find_by_uuid(:InstanceSpec, (params[:instance_spec_id] || 'is-kpf0pasc'))
214
+ wmi = Models::Image[params[:image_id]] || raise(InvalidImageID)
215
+ spec = Models::InstanceSpec[params[:instance_spec_id]] || raise(InvalidInstanceSpec)
289
216
 
290
217
  # look up params[:host_id] in following order:
291
218
  # 1. assume the host pool name.
@@ -369,7 +296,7 @@ module Dcmgr
369
296
  if ssh_key_pair.nil?
370
297
  raise UnknownSshKeyPair, "#{params[:ssh_key]}"
371
298
  else
372
- i.ssh_key_pair_id = ssh_key_pair.canonical_uuid
299
+ i.set_ssh_key_pair(ssh_key_pair)
373
300
  end
374
301
  end
375
302
 
@@ -392,8 +319,10 @@ module Dcmgr
392
319
  vol.boot_dev = 1
393
320
  vol.instance = inst
394
321
  vol.save
322
+ commit_transaction
395
323
  res = Dcmgr.messaging.submit("kvm-handle.#{hostnode.node_id}", 'run_vol_store', inst.canonical_uuid, vol.canonical_uuid)
396
324
  when Models::Image::BOOT_DEV_LOCAL
325
+ commit_transaction
397
326
  res = Dcmgr.messaging.submit("kvm-handle.#{hostnode.node_id}", 'run_local_store', inst.canonical_uuid)
398
327
  else
399
328
  raise "Unknown boot type"
@@ -416,7 +345,6 @@ module Dcmgr
416
345
  operation :destroy do
417
346
  description 'Shutdown the instance'
418
347
  control do
419
- Models::Instance.lock!
420
348
  i = find_by_uuid(:Instance, params[:id])
421
349
  if examine_owner(i)
422
350
  else
@@ -430,8 +358,9 @@ module Dcmgr
430
358
  operation :reboot, :method=>:put, :member=>true do
431
359
  description 'Reboots the instance'
432
360
  control do
433
- Models::Instance.lock!
434
361
  i = find_by_uuid(:Instance, params[:id])
362
+ Dcmgr.messaging.submit("kvm-handle.#{i.host_pool.node_id}", 'reboot', i.canonical_uuid)
363
+ response_to({})
435
364
  end
436
365
  end
437
366
  end
@@ -448,22 +377,8 @@ module Dcmgr
448
377
  operation :index do
449
378
  description 'Show list of machine images'
450
379
  control do
451
- start = params[:start].to_i
452
- start = start < 1 ? 0 : start
453
- limit = params[:limit].to_i
454
- limit = limit < 1 ? nil : limit
455
-
456
- total_ds = Models::Image.where(:account_id=>@account.canonical_uuid)
457
- partial_ds = total_ds.dup.order(:id)
458
- partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
459
-
460
- res = [{
461
- :owner_total => total_ds.count,
462
- :start => start,
463
- :limit => limit,
464
- :results=> partial_ds.all.map {|i| i.to_hash }
465
- }]
466
-
380
+ res = select_index(:Image, {:start => params[:start],
381
+ :limit => params[:limit]})
467
382
  response_to(res)
468
383
  end
469
384
  end
@@ -472,11 +387,10 @@ module Dcmgr
472
387
  description "Show a machine image details."
473
388
  control do
474
389
  i = find_by_uuid(:Image, params[:id])
475
- # TODO: add visibility by account check
476
- unless examine_owner(i)
390
+ if !(examine_owner(i) || i.is_public)
477
391
  raise OperationNotPermitted
478
392
  end
479
- response_to(i.to_hash)
393
+ response_to(i.to_api_document(@account.canonical_uuid))
480
394
  end
481
395
  end
482
396
 
@@ -499,22 +413,8 @@ module Dcmgr
499
413
  operation :index do
500
414
  description 'Show list of host pools'
501
415
  control do
502
- start = params[:start].to_i
503
- start = start < 1 ? 0 : start
504
- limit = params[:limit].to_i
505
- limit = limit < 1 ? nil : limit
506
-
507
- total_ds = Models::HostPool.where(:account_id=>@account.canonical_uuid)
508
- partial_ds = total_ds.dup.order(:id)
509
- partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
510
-
511
- res = [{
512
- :owner_total => total_ds.count,
513
- :start => start,
514
- :limit => limit,
515
- :results=> partial_ds.all.map {|i| i.to_hash }
516
- }]
517
-
416
+ res = select_index(:HostPool, {:start => params[:start],
417
+ :limit => params[:limit]})
518
418
  response_to(res)
519
419
  end
520
420
  end
@@ -526,7 +426,7 @@ module Dcmgr
526
426
  hp = find_by_uuid(:HostPool, params[:id])
527
427
  raise OperationNotPermitted unless examine_owner(hp)
528
428
 
529
- response_to(hp.to_hash)
429
+ response_to(hp.to_api_document)
530
430
  end
531
431
  end
532
432
  end
@@ -537,20 +437,8 @@ module Dcmgr
537
437
  # params start, fixnum, optional
538
438
  # params limit, fixnum, optional
539
439
  control do
540
- start = params[:start].to_i
541
- start = start < 1 ? 0 : start
542
- limit = params[:limit].to_i
543
- limit = limit < 1 ? nil : limit
544
-
545
- total_v = Models::Volume.where(:account_id => @account.canonical_uuid)
546
- partial_v = total_v.dup.order(:id)
547
- partial_v = partial_v.limit(limit, start) if limit.is_a?(Integer)
548
- res = [{
549
- :owner_total => total_v.count,
550
- :start => start,
551
- :limit => limit,
552
- :results => partial_v.all.map { |v| v.to_api_document}
553
- }]
440
+ res = select_index(:Volume, {:start => params[:start],
441
+ :limit => params[:limit]})
554
442
  response_to(res)
555
443
  end
556
444
  end
@@ -576,10 +464,14 @@ module Dcmgr
576
464
  if params[:snapshot_id]
577
465
  v = create_volume_from_snapshot(@account.canonical_uuid, params[:snapshot_id])
578
466
  sp = v.storage_pool
467
+ vs = find_by_uuid(:VolumeSnapshot, params[:snapshot_id])
468
+ repository_address = Dcmgr::StorageService.repository_address(vs.destination_key)
579
469
  elsif params[:volume_size]
580
- if !(Dcmgr.conf.create_volume_max_size.to_i >= params[:volume_size].to_i) ||
581
- !(params[:volume_size].to_i >= Dcmgr.conf.create_volume_min_size.to_i)
582
- raise InvalidVolumeSize
470
+ if Dcmgr.conf.create_volume_min_size.to_i > params[:volume_size].to_i
471
+ raise InvalidVolumeSize, "(>#{Dcmgr.conf.create_volume_min_size.to_i})"
472
+ end
473
+ if Dcmgr.conf.create_volume_max_size.to_i < params[:volume_size].to_i
474
+ raise InvalidVolumeSize, "Requested Size is(<#{Dcmgr.conf.create_volume_max_size.to_i})"
583
475
  end
584
476
  if params[:storage_pool_id]
585
477
  sp = find_by_uuid(:StoragePool, params[:storage_pool_id])
@@ -599,7 +491,8 @@ module Dcmgr
599
491
  raise UndefinedRequiredParameter
600
492
  end
601
493
 
602
- res = Dcmgr.messaging.submit("zfs-handle.#{sp.values[:node_id]}", 'create_volume', v.canonical_uuid)
494
+ commit_transaction
495
+ res = Dcmgr.messaging.submit("zfs-handle.#{sp.values[:node_id]}", 'create_volume', v.canonical_uuid, repository_address)
603
496
  response_to(v.to_api_document)
604
497
  end
605
498
  end
@@ -608,9 +501,12 @@ module Dcmgr
608
501
  description 'Delete the volume'
609
502
  # params id, string, required
610
503
  control do
611
- Models::Volume.lock!
612
504
  volume_id = params[:id]
613
505
  raise UndefinedVolumeID if volume_id.nil?
506
+
507
+ vol = find_by_uuid(:Volume, volume_id)
508
+ raise UnknownVolume if vol.nil?
509
+ raise InvalidVolumeState unless vol.state == "available"
614
510
 
615
511
  begin
616
512
  v = Models::Volume.delete_volume(@account.canonical_uuid, volume_id)
@@ -621,6 +517,7 @@ module Dcmgr
621
517
  raise UnknownVolume if v.nil?
622
518
  sp = v.storage_pool
623
519
 
520
+ commit_transaction
624
521
  res = Dcmgr.messaging.submit("zfs-handle.#{sp.values[:node_id]}", 'delete_volume', v.canonical_uuid)
625
522
  response_to([v.canonical_uuid])
626
523
  end
@@ -644,6 +541,7 @@ module Dcmgr
644
541
 
645
542
  v.instance = i
646
543
  v.save
544
+ commit_transaction
647
545
  res = Dcmgr.messaging.submit("kvm-handle.#{i.host_pool.node_id}", 'attach', i.canonical_uuid, v.canonical_uuid)
648
546
 
649
547
  response_to(v.to_api_document)
@@ -663,46 +561,39 @@ module Dcmgr
663
561
  raise DetachVolumeFailure, "boot device can not be detached" if v.boot_dev == 1
664
562
  i = v.instance
665
563
  raise InvalidInstanceState unless i.live? && i.state == 'running'
564
+ commit_transaction
666
565
  res = Dcmgr.messaging.submit("kvm-handle.#{i.host_pool.node_id}", 'detach', i.canonical_uuid, v.canonical_uuid)
667
566
  response_to(v.to_api_document)
668
567
  end
669
568
  end
670
569
 
671
- operation :status, :method =>:get, :member =>true do
672
- description 'Show the status'
673
- control do
674
- vl = [{ :id => 1, :uuid => 'vol-xxxxxxx', :status => 1 },
675
- { :id => 2, :uuid => 'vol-xxxxxxx', :status => 0 },
676
- { :id => 3, :uuid => 'vol-xxxxxxx', :status => 3 },
677
- { :id => 4, :uuid => 'vol-xxxxxxx', :status => 2 },
678
- { :id => 5, :uuid => 'vol-xxxxxxx', :status => 4 }]
679
- respond_to {|f|
680
- f.json { vl.to_json}
681
- }
682
- end
683
- end
684
570
  end
685
-
571
+
572
+ get '/api/volume_snapshots/upload_destination' do
573
+ c = StorageService::snapshot_repository_config.dup
574
+ tmp = c['local']
575
+ c.delete('local')
576
+ results = {}
577
+ results = c.collect {|item| {
578
+ :destination_id => item[0],
579
+ :destination_name => item[1]["display_name"]
580
+ }
581
+ }
582
+ results.unshift({
583
+ :destination_id => 'local',
584
+ :destination_name => tmp['display_name']
585
+ })
586
+ response_to([{:results => results}])
587
+ end
588
+
686
589
  collection :volume_snapshots do
687
590
  operation :index do
688
591
  description 'Show lists of the volume_snapshots'
689
592
  # params start, fixnum, optional
690
593
  # params limit, fixnum, optional
691
594
  control do
692
- start = params[:start].to_i
693
- start = start < 1 ? 0 : start
694
- limit = params[:limit].to_i
695
- limit = limit < 1 ? nil : limit
696
-
697
- total_vs = Models::VolumeSnapshot.where(:account_id => @account.canonical_uuid)
698
- partial_vs = total_vs.dup.order(:id)
699
- partial_vs = partial_vs.limit(limit, start) if limit.is_a?(Integer)
700
- res = [{
701
- :owner_total => total_vs.count,
702
- :start => start,
703
- :limit => limit,
704
- :results => partial_vs.all.map { |vs| vs.to_api_document}
705
- }]
595
+ res = select_index(:VolumeSnapshot, {:start => params[:start],
596
+ :limit => params[:limit]})
706
597
  response_to(res)
707
598
  end
708
599
  end
@@ -728,12 +619,15 @@ module Dcmgr
728
619
 
729
620
  v = find_by_uuid(:Volume, params[:volume_id])
730
621
  raise UnknownVolume if v.nil?
731
- raise InvalidRequestCredentials unless v.state == "available"
732
-
622
+ raise InvalidVolumeState unless v.ready_to_take_snapshot?
733
623
  vs = v.create_snapshot(@account.canonical_uuid)
734
624
  sp = vs.storage_pool
735
-
736
- res = Dcmgr.messaging.submit("zfs-handle.#{sp.node_id}", 'create_snapshot', vs.canonical_uuid)
625
+ destination_key = Dcmgr::StorageService.destination_key(@account.canonical_uuid, params[:destination], sp.snapshot_base_path, vs.snapshot_filename)
626
+ vs.update_destination_key(@account.canonical_uuid, destination_key)
627
+ commit_transaction
628
+
629
+ repository_address = Dcmgr::StorageService.repository_address(destination_key)
630
+ res = Dcmgr.messaging.submit("zfs-handle.#{sp.node_id}", 'create_snapshot', vs.canonical_uuid, repository_address)
737
631
  response_to(vs.to_api_document)
738
632
  end
739
633
  end
@@ -745,7 +639,13 @@ module Dcmgr
745
639
  Models::VolumeSnapshot.lock!
746
640
  snapshot_id = params[:id]
747
641
  raise UndefindVolumeSnapshotID if snapshot_id.nil?
748
-
642
+
643
+ v = find_by_uuid(:VolumeSnapshot, snapshot_id)
644
+ raise UnknownVolumeSnapshot if v.nil?
645
+ raise InvalidVolumeState unless v.state == "available"
646
+
647
+ destination_key = v.destination_key
648
+
749
649
  begin
750
650
  vs = Models::VolumeSnapshot.delete_snapshot(@account.canonical_uuid, snapshot_id)
751
651
  rescue Models::VolumeSnapshot::RequestError => e
@@ -755,46 +655,22 @@ module Dcmgr
755
655
  raise UnknownVolumeSnapshot if vs.nil?
756
656
  sp = vs.storage_pool
757
657
 
758
- res = Dcmgr.messaging.submit("zfs-handle.#{sp.node_id}", 'delete_snapshot', vs.canonical_uuid)
658
+ commit_transaction
659
+
660
+ repository_address = Dcmgr::StorageService.repository_address(destination_key)
661
+ res = Dcmgr.messaging.submit("zfs-handle.#{sp.node_id}", 'delete_snapshot', vs.canonical_uuid, repository_address)
759
662
  response_to([vs.canonical_uuid])
760
663
  end
761
664
  end
762
665
 
763
- operation :status, :method =>:get, :member =>true do
764
- description 'Show the status'
765
- control do
766
- vs = [{ :id => 1, :uuid => 'snap-xxxxxxx', :status => 1 },
767
- { :id => 2, :uuid => 'snap-xxxxxxx', :status => 0 },
768
- { :id => 3, :uuid => 'snap-xxxxxxx', :status => 3 },
769
- { :id => 4, :uuid => 'snap-xxxxxxx', :status => 2 },
770
- { :id => 5, :uuid => 'snap-xxxxxxx', :status => 4 }]
771
- respond_to {|f|
772
- f.json { vs.to_json}
773
- }
774
- end
775
- end
776
666
  end
777
667
 
778
668
  collection :netfilter_groups do
779
669
  description 'Show lists of the netfilter_groups'
780
670
  operation :index do
781
671
  control do
782
- start = params[:start].to_i
783
- start = start < 1 ? 0 : start
784
- limit = params[:limit].to_i
785
- limit = limit < 1 ? nil : limit
786
-
787
- total_ds = Models::NetfilterGroup.where(:account_id=>@account.canonical_uuid)
788
- partial_ds = total_ds.dup.order(:id)
789
- partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
790
-
791
- res = [{
792
- :owner_total => total_ds.count,
793
- :start => start,
794
- :limit => limit,
795
- :results=> partial_ds.all.map {|i| i.to_hash }
796
- }]
797
-
672
+ res = select_index(:NetfilterGroup, {:start => params[:start],
673
+ :limit => params[:limit]})
798
674
  response_to(res)
799
675
  end
800
676
  end
@@ -805,7 +681,7 @@ module Dcmgr
805
681
  g = find_by_uuid(:NetfilterGroup, params[:id])
806
682
  raise OperationNotPermitted unless examine_owner(g)
807
683
 
808
- response_to(g.to_hash)
684
+ response_to(g.to_api_document)
809
685
  end
810
686
  end
811
687
 
@@ -826,7 +702,7 @@ module Dcmgr
826
702
  raise DuplicatedNetfilterGroup unless g.nil?
827
703
 
828
704
  g = Models::NetfilterGroup.create_group(@account.canonical_uuid, params)
829
- response_to(g.to_hash)
705
+ response_to(g.to_api_document)
830
706
  end
831
707
  end
832
708
 
@@ -849,10 +725,11 @@ module Dcmgr
849
725
  g.save
850
726
  g.rebuild_rule
851
727
 
728
+ commit_transaction
852
729
  # refresh netfilter_rules
853
730
  Dcmgr.messaging.event_publish('hva/netfilter_updated', :args=>[g.canonical_uuid])
854
731
 
855
- response_to(g.to_hash)
732
+ response_to(g.to_api_document)
856
733
  end
857
734
  end
858
735
 
@@ -865,9 +742,16 @@ module Dcmgr
865
742
  g = find_by_uuid(:NetfilterGroup, params[:id])
866
743
 
867
744
  raise UnknownNetfilterGroup if g.nil?
868
- raise NetfilterGroupNotPermitted if g.account_id != @account.canonical_uuid
745
+ raise OperationNotPermitted unless examine_owner(g)
746
+
747
+ # raise OperationNotPermitted if g.instances.size > 0
748
+ begin
749
+ g.destroy
750
+ rescue => e
751
+ # logger.error(e)
752
+ raise OperationNotPermitted
753
+ end
869
754
 
870
- g.destroy
871
755
  response_to([g.canonical_uuid])
872
756
  end
873
757
  end
@@ -905,22 +789,8 @@ module Dcmgr
905
789
  # params start, fixnum, optional
906
790
  # params limit, fixnum, optional
907
791
  control do
908
- start = params[:start].to_i
909
- start = start < 1 ? 0 : start
910
- limit = params[:limit].to_i
911
- limit = limit < 1 ? nil : limit
912
-
913
- total_ds = Models::StoragePool.where(:account_id=>@account.canonical_uuid)
914
- partial_ds = total_ds.dup.order(:id)
915
- partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
916
-
917
- res = [{
918
- :owner_total => total_ds.count,
919
- :start => start,
920
- :limit => limit,
921
- :results=> partial_ds.all.map {|sp| sp.to_hash }
922
- }]
923
-
792
+ res = select_index(:StoragePool, {:start => params[:start],
793
+ :limit => params[:limit]})
924
794
  response_to(res)
925
795
  end
926
796
  end
@@ -933,7 +803,7 @@ module Dcmgr
933
803
  raise UndefinedStoragePoolID if pool_id.nil?
934
804
  vs = find_by_uuid(:StoragePool, pool_id)
935
805
  raise UnknownStoragePool if vs.nil?
936
- response_to(vs.to_hash)
806
+ response_to(vs.to_api_document)
937
807
  end
938
808
  end
939
809
  end
@@ -944,23 +814,8 @@ module Dcmgr
944
814
  # params start, fixnum, optional
945
815
  # params limit, fixnum, optional
946
816
  control do
947
- start = params[:start].to_i
948
- start = start < 1 ? 0 : start
949
- limit = params[:limit].to_i
950
- limit = limit < 1 ? nil : limit
951
-
952
- total_ds = Models::SshKeyPair.where(:account_id=>@account.canonical_uuid)
953
- partial_ds = total_ds.dup.order(:id)
954
- partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
955
-
956
- res = [{
957
- :owner_total => total_ds.count,
958
- :filter_total => total_ds.count,
959
- :start => start,
960
- :limit => limit,
961
- :results=> partial_ds.all.map {|i| i.to_hash }
962
- }]
963
-
817
+ res = select_index(:SshKeyPair, {:start => params[:start],
818
+ :limit => params[:limit]})
964
819
  response_to(res)
965
820
  end
966
821
  end
@@ -972,7 +827,7 @@ module Dcmgr
972
827
  control do
973
828
  ssh = find_by_uuid(:SshKeyPair, params[:id])
974
829
 
975
- response_to(ssh.to_hash)
830
+ response_to(ssh.to_api_document)
976
831
  end
977
832
  end
978
833
 
@@ -987,16 +842,27 @@ module Dcmgr
987
842
  savedata = {
988
843
  :name=>params[:name],
989
844
  :account_id=>@account.canonical_uuid,
990
- :public_key=>keydata[:public_key]
845
+ :public_key=>keydata[:public_key],
846
+ :finger_print => keydata[:finger_print],
991
847
  }
992
848
  if params[:download_once] != 'true'
993
849
  savedata[:private_key]=keydata[:private_key]
994
850
  end
995
- ssh = Models::SshKeyPair.create(savedata)
851
+
852
+ if !Models::SshKeyPair.filter(:account_id=>@account.canonical_uuid,
853
+ :name => params[:name]).empty?
854
+ raise DuplicateSshKeyName, params[:name]
855
+ end
856
+
857
+ begin
858
+ ssh = Models::SshKeyPair.create(savedata)
859
+ rescue => e
860
+ raise DatabaseError, e.message
861
+ end
996
862
 
997
863
  # include private_key data in response even if
998
864
  # it's not going to be stored on DB.
999
- response_to(ssh.to_hash.merge(:private_key=>keydata[:private_key]))
865
+ response_to(ssh.to_api_document.merge(:private_key=>keydata[:private_key]))
1000
866
  end
1001
867
  end
1002
868
 
@@ -1025,23 +891,8 @@ module Dcmgr
1025
891
  # params start, fixnum, optional
1026
892
  # params limit, fixnum, optional
1027
893
  control do
1028
- start = params[:start].to_i
1029
- start = start < 1 ? 0 : start
1030
- limit = params[:limit].to_i
1031
- limit = limit < 1 ? nil : limit
1032
-
1033
- total_ds = Models::Network.where(:account_id=>@account.canonical_uuid)
1034
- partial_ds = total_ds.dup.order(:id)
1035
- partial_ds = partial_ds.limit(limit, start) if limit.is_a?(Integer)
1036
-
1037
- res = [{
1038
- :owner_total => total_ds.count,
1039
- :filter_total => total_ds.count,
1040
- :start => start,
1041
- :limit => limit,
1042
- :results=> partial_ds.all.map {|i| i.to_hash }
1043
- }]
1044
-
894
+ res = select_index(:Network, {:start => params[:start],
895
+ :limit => params[:limit]})
1045
896
  response_to(res)
1046
897
  end
1047
898
  end
@@ -1053,7 +904,7 @@ module Dcmgr
1053
904
  nw = find_by_uuid(:Network, params[:id])
1054
905
  examine_owner(nw) || raise(OperationNotPermitted)
1055
906
 
1056
- response_to(nw.to_hash)
907
+ response_to(nw.to_api_document)
1057
908
  end
1058
909
  end
1059
910
 
@@ -1073,7 +924,7 @@ module Dcmgr
1073
924
  }
1074
925
  nw = Models::Network.create(savedata)
1075
926
 
1076
- response_to(nw.to_hash)
927
+ response_to(nw.to_api_document)
1077
928
  end
1078
929
  end
1079
930
 
@@ -1160,6 +1011,19 @@ module Dcmgr
1160
1011
  end
1161
1012
  end
1162
1013
  end
1014
+
1015
+ collection :instance_specs do
1016
+ operation :index do
1017
+ description 'Show list of instance template'
1018
+ # params start, fixnum, optional
1019
+ # params limit, fixnum, optional
1020
+ control do
1021
+ res = select_index(:InstanceSpec, {:start => params[:start],
1022
+ :limit => params[:limit]})
1023
+ response_to(res)
1024
+ end
1025
+ end
1026
+ end
1163
1027
 
1164
1028
  end
1165
1029
  end