1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Remote API version 2 baserlib.library.
23
24 """
25
26
27
28
29
30 from ganeti import opcodes
31 from ganeti import http
32 from ganeti import constants
33 from ganeti import cli
34 from ganeti.rapi import baserlib
35
36
37 I_FIELDS = ["name", "admin_state", "os",
38 "pnode", "snodes",
39 "disk_template",
40 "nic.ips", "nic.macs", "nic.bridges",
41 "network_port",
42 "disk.sizes", "disk_usage",
43 "beparams", "hvparams",
44 "oper_state", "oper_ram", "status",
45 "tags"]
46
47 N_FIELDS = ["name", "offline", "master_candidate", "drained",
48 "dtotal", "dfree",
49 "mtotal", "mnode", "mfree",
50 "pinst_cnt", "sinst_cnt", "tags",
51 "ctotal", "cnodes", "csockets",
52 "pip", "sip", "serial_no", "role",
53 "pinst_list", "sinst_list",
54 ]
55
56
58 """/version resource.
59
60 This resource should be used to determine the remote API version and
61 to adapt clients accordingly.
62
63 """
64 DOC_URI = "/version"
65
71
72
74 """Cluster info.
75
76 """
77 DOC_URI = "/2/info"
78
80 """Returns cluster information.
81
82 Example::
83
84 {
85 "config_version": 2000000,
86 "name": "cluster",
87 "software_version": "2.0.0~beta2",
88 "os_api_version": 10,
89 "export_version": 0,
90 "candidate_pool_size": 10,
91 "enabled_hypervisors": [
92 "fake"
93 ],
94 "hvparams": {
95 "fake": {}
96 },
97 "default_hypervisor": "fake",
98 "master": "node1.example.com",
99 "architecture": [
100 "64bit",
101 "x86_64"
102 ],
103 "protocol_version": 20,
104 "beparams": {
105 "default": {
106 "auto_balance": true,
107 "vcpus": 1,
108 "memory": 128
109 }
110 }
111 }
112
113 """
114 client = baserlib.GetClient()
115 return client.QueryClusterInfo()
116
117
118 -class R_2_os(baserlib.R_Generic):
119 """/2/os resource.
120
121 """
122 DOC_URI = "/2/os"
123
125 """Return a list of all OSes.
126
127 Can return error 500 in case of a problem.
128
129 Example: ["debian-etch"]
130
131 """
132 cl = baserlib.GetClient()
133 op = opcodes.OpDiagnoseOS(output_fields=["name", "valid"], names=[])
134 job_id = baserlib.SubmitJob([op], cl)
135
136 result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
137 diagnose_data = result[0]
138
139 if not isinstance(diagnose_data, list):
140 raise http.HttpBadGateway(message="Can't get OS list")
141
142 return [row[0] for row in diagnose_data if row[1]]
143
144
146 """/2/jobs resource.
147
148 """
149 DOC_URI = "/2/jobs"
150
152 """Returns a dictionary of jobs.
153
154 @return: a dictionary with jobs id and uri.
155
156 """
157 fields = ["id"]
158 cl = baserlib.GetClient()
159
160 result = [job_id for [job_id] in cl.QueryJobs(None, fields)]
161 return baserlib.BuildUriList(result, "/2/jobs/%s",
162 uri_fields=("id", "uri"))
163
164
166 """/2/jobs/[job_id] resource.
167
168 """
169 DOC_URI = "/2/jobs/[job_id]"
170
172 """Returns a job status.
173
174 @return: a dictionary with job parameters.
175 The result includes:
176 - id: job ID as a number
177 - status: current job status as a string
178 - ops: involved OpCodes as a list of dictionaries for each
179 opcodes in the job
180 - opstatus: OpCodes status as a list
181 - opresult: OpCodes results as a list of lists
182
183 """
184 fields = ["id", "ops", "status", "summary",
185 "opstatus", "opresult", "oplog",
186 "received_ts", "start_ts", "end_ts",
187 ]
188 job_id = self.items[0]
189 result = baserlib.GetClient().QueryJobs([job_id, ], fields)[0]
190 if result is None:
191 raise http.HttpNotFound()
192 return baserlib.MapFields(fields, result)
193
195 """Cancel not-yet-started job.
196
197 """
198 job_id = self.items[0]
199 result = baserlib.GetClient().CancelJob(job_id)
200 return result
201
202
204 """/2/nodes resource.
205
206 """
207 DOC_URI = "/2/nodes"
208
210 """Returns a list of all nodes.
211
212 Example::
213
214 [
215 {
216 "id": "node1.example.com",
217 "uri": "\/instances\/node1.example.com"
218 },
219 {
220 "id": "node2.example.com",
221 "uri": "\/instances\/node2.example.com"
222 }
223 ]
224
225 If the optional 'bulk' argument is provided and set to 'true'
226 value (i.e '?bulk=1'), the output contains detailed
227 information about nodes as a list.
228
229 Example::
230
231 [
232 {
233 "pinst_cnt": 1,
234 "mfree": 31280,
235 "mtotal": 32763,
236 "name": "www.example.com",
237 "tags": [],
238 "mnode": 512,
239 "dtotal": 5246208,
240 "sinst_cnt": 2,
241 "dfree": 5171712,
242 "offline": false
243 },
244 ...
245 ]
246
247 @return: a dictionary with 'name' and 'uri' keys for each of them
248
249 """
250 client = baserlib.GetClient()
251
252 if self.useBulk():
253 bulkdata = client.QueryNodes([], N_FIELDS, False)
254 return baserlib.MapBulkFields(bulkdata, N_FIELDS)
255 else:
256 nodesdata = client.QueryNodes([], ["name"], False)
257 nodeslist = [row[0] for row in nodesdata]
258 return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
259 uri_fields=("id", "uri"))
260
261
263 """/2/nodes/[node_name] resources.
264
265 """
266 DOC_URI = "/nodes/[node_name]"
267
278
279
281 """/2/instances resource.
282
283 """
284 DOC_URI = "/2/instances"
285
287 """Returns a list of all available instances.
288
289
290 Example::
291
292 [
293 {
294 "name": "web.example.com",
295 "uri": "\/instances\/web.example.com"
296 },
297 {
298 "name": "mail.example.com",
299 "uri": "\/instances\/mail.example.com"
300 }
301 ]
302
303 If the optional 'bulk' argument is provided and set to 'true'
304 value (i.e '?bulk=1'), the output contains detailed
305 information about instances as a list.
306
307 Example::
308
309 [
310 {
311 "status": "running",
312 "disk_usage": 20480,
313 "nic.bridges": [
314 "xen-br0"
315 ],
316 "name": "web.example.com",
317 "tags": ["tag1", "tag2"],
318 "beparams": {
319 "vcpus": 2,
320 "memory": 512
321 },
322 "disk.sizes": [
323 20480
324 ],
325 "pnode": "node1.example.com",
326 "nic.macs": ["01:23:45:67:89:01"],
327 "snodes": ["node2.example.com"],
328 "disk_template": "drbd",
329 "admin_state": true,
330 "os": "debian-etch",
331 "oper_state": true
332 },
333 ...
334 ]
335
336 @return: a dictionary with 'name' and 'uri' keys for each of them.
337
338 """
339 client = baserlib.GetClient()
340
341 use_locking = self.useLocking()
342 if self.useBulk():
343 bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
344 return baserlib.MapBulkFields(bulkdata, I_FIELDS)
345 else:
346 instancesdata = client.QueryInstances([], ["name"], use_locking)
347 instanceslist = [row[0] for row in instancesdata]
348 return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
349 uri_fields=("id", "uri"))
350
352 """Create an instance.
353
354 @return: a job id
355
356 """
357 if not isinstance(self.req.request_body, dict):
358 raise http.HttpBadRequest("Invalid body contents, not a dictionary")
359
360 beparams = baserlib.MakeParamsDict(self.req.request_body,
361 constants.BES_PARAMETERS)
362 hvparams = baserlib.MakeParamsDict(self.req.request_body,
363 constants.HVS_PARAMETERS)
364 fn = self.getBodyParameter
365
366
367 disk_data = fn('disks')
368 if not isinstance(disk_data, list):
369 raise http.HttpBadRequest("The 'disks' parameter should be a list")
370 disks = []
371 for idx, d in enumerate(disk_data):
372 if not isinstance(d, int):
373 raise http.HttpBadRequest("Disk %d specification wrong: should"
374 " be an integer")
375 disks.append({"size": d})
376
377 nics = [{"mac": fn("mac", constants.VALUE_AUTO),
378 "ip": fn("ip", None),
379 "bridge": fn("bridge", None)}]
380
381 op = opcodes.OpCreateInstance(
382 mode=constants.INSTANCE_CREATE,
383 instance_name=fn('name'),
384 disks=disks,
385 disk_template=fn('disk_template'),
386 os_type=fn('os'),
387 pnode=fn('pnode', None),
388 snode=fn('snode', None),
389 iallocator=fn('iallocator', None),
390 nics=nics,
391 start=fn('start', True),
392 ip_check=fn('ip_check', True),
393 wait_for_sync=True,
394 hypervisor=fn('hypervisor', None),
395 hvparams=hvparams,
396 beparams=beparams,
397 file_storage_dir=fn('file_storage_dir', None),
398 file_driver=fn('file_driver', 'loop'),
399 )
400
401 return baserlib.SubmitJob([op])
402
403
405 """/2/instances/[instance_name] resources.
406
407 """
408 DOC_URI = "/2/instances/[instance_name]"
409
420
428
429
431 """/2/instances/[instance_name]/reboot resource.
432
433 Implements an instance reboot.
434
435 """
436
437 DOC_URI = "/2/instances/[instance_name]/reboot"
438
440 """Reboot an instance.
441
442 The URI takes type=[hard|soft|full] and
443 ignore_secondaries=[False|True] parameters.
444
445 """
446 instance_name = self.items[0]
447 reboot_type = self.queryargs.get('type',
448 [constants.INSTANCE_REBOOT_HARD])[0]
449 ignore_secondaries = bool(self._checkIntVariable('ignore_secondaries'))
450 op = opcodes.OpRebootInstance(instance_name=instance_name,
451 reboot_type=reboot_type,
452 ignore_secondaries=ignore_secondaries)
453
454 return baserlib.SubmitJob([op])
455
456
458 """/2/instances/[instance_name]/startup resource.
459
460 Implements an instance startup.
461
462 """
463
464 DOC_URI = "/2/instances/[instance_name]/startup"
465
467 """Startup an instance.
468
469 The URI takes force=[False|True] parameter to start the instance
470 if even if secondary disks are failing.
471
472 """
473 instance_name = self.items[0]
474 force_startup = bool(self._checkIntVariable('force'))
475 op = opcodes.OpStartupInstance(instance_name=instance_name,
476 force=force_startup)
477
478 return baserlib.SubmitJob([op])
479
480
482 """/2/instances/[instance_name]/shutdown resource.
483
484 Implements an instance shutdown.
485
486 """
487
488 DOC_URI = "/2/instances/[instance_name]/shutdown"
489
498
499
501 """/2/instances/[instance_name]/reinstall resource.
502
503 Implements an instance reinstall.
504
505 """
506
507 DOC_URI = "/2/instances/[instance_name]/reinstall"
508
510 """Reinstall an instance.
511
512 The URI takes os=name and nostartup=[0|1] optional
513 parameters. By default, the instance will be started
514 automatically.
515
516 """
517 instance_name = self.items[0]
518 ostype = self._checkStringVariable('os')
519 nostartup = self._checkIntVariable('nostartup')
520 ops = [
521 opcodes.OpShutdownInstance(instance_name=instance_name),
522 opcodes.OpReinstallInstance(instance_name=instance_name, os_type=ostype),
523 ]
524 if not nostartup:
525 ops.append(opcodes.OpStartupInstance(instance_name=instance_name,
526 force=False))
527 return baserlib.SubmitJob(ops)
528
529
588
589
598
599
608
609
618