Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ f6f91001

History | View | Annotate | Download (9.7 kB)

1
#
2
#
3

    
4
# Copyright (C) 2006, 2007, 2008 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Remote API version 2 baserlib.library.
23

24
"""
25

    
26
import ganeti.opcodes
27
from ganeti import http
28
from ganeti import luxi
29
from ganeti import constants
30
from ganeti.rapi import baserlib
31

    
32
from ganeti.rapi.rlib1 import I_FIELDS, N_FIELDS
33

    
34

    
35
class R_2_jobs(baserlib.R_Generic):
36
  """/2/jobs resource.
37

38
  """
39
  DOC_URI = "/2/jobs"
40

    
41
  def GET(self):
42
    """Returns a dictionary of jobs.
43

44
    @return: a dictionary with jobs id and uri.
45

46
    """
47
    fields = ["id"]
48
    # Convert the list of lists to the list of ids
49
    result = [job_id for [job_id] in luxi.Client().QueryJobs(None, fields)]
50
    return baserlib.BuildUriList(result, "/2/jobs/%s", uri_fields=("id", "uri"))
51

    
52

    
53
class R_2_jobs_id(baserlib.R_Generic):
54
  """/2/jobs/[job_id] resource.
55

56
  """
57
  DOC_URI = "/2/jobs/[job_id]"
58

    
59
  def GET(self):
60
    """Returns a job status.
61

62
    @return: a dictionary with job parameters.
63
        The result includes:
64
            - id: job ID as a number
65
            - status: current job status as a string
66
            - ops: involved OpCodes as a list of dictionaries for each
67
              opcodes in the job
68
            - opstatus: OpCodes status as a list
69
            - opresult: OpCodes results as a list of lists
70

71
    """
72
    fields = ["id", "ops", "status", "opstatus", "opresult"]
73
    job_id = self.items[0]
74
    result = luxi.Client().QueryJobs([job_id, ], fields)[0]
75
    return baserlib.MapFields(fields, result)
76

    
77
  def DELETE(self):
78
    """Cancel not-yet-started job.
79

80
    """
81
    job_id = self.items[0]
82
    result = luxi.Client().CancelJob(job_id)
83
    return result
84

    
85

    
86
class R_2_nodes(baserlib.R_Generic):
87
  """/2/nodes resource.
88

89
  """
90
  DOC_URI = "/2/nodes"
91

    
92
  def GET(self):
93
    """Returns a list of all nodes.
94

95
    Example::
96

97
      [
98
        {
99
          "id": "node1.example.com",
100
          "uri": "\/instances\/node1.example.com"
101
        },
102
        {
103
          "id": "node2.example.com",
104
          "uri": "\/instances\/node2.example.com"
105
        }
106
      ]
107

108
    If the optional 'bulk' argument is provided and set to 'true'
109
    value (i.e '?bulk=1'), the output contains detailed
110
    information about nodes as a list.
111

112
    Example::
113

114
      [
115
        {
116
          "pinst_cnt": 1,
117
          "mfree": 31280,
118
          "mtotal": 32763,
119
          "name": "www.example.com",
120
          "tags": [],
121
          "mnode": 512,
122
          "dtotal": 5246208,
123
          "sinst_cnt": 2,
124
          "dfree": 5171712
125
        },
126
        ...
127
      ]
128

129
    @return: a dictionary with 'name' and 'uri' keys for each of them
130

131
    """
132
    client = luxi.Client()
133
    nodesdata = client.QueryNodes([], ["name"])
134
    nodeslist = [row[0] for row in nodesdata]
135

    
136
    if 'bulk' in self.queryargs:
137
      bulkdata = client.QueryNodes(nodeslist, N_FIELDS)
138
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
139

    
140
    return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
141
                                 uri_fields=("id", "uri"))
142

    
143

    
144
class R_nodes(R_2_nodes):
145
  """/nodes resource
146

147
  """
148
  # TODO: Temporary resource will be deprecated
149
  DOC_URI = "/nodes"
150

    
151

    
152
class R_2_instances(baserlib.R_Generic):
153
  """/2/instances resource.
154

155
  """
156
  DOC_URI = "/2/instances"
157

    
158
  def GET(self):
159
    """Returns a list of all available instances.
160

161

162
    Example::
163

164
      [
165
        {
166
          "name": "web.example.com",
167
          "uri": "\/instances\/web.example.com"
168
        },
169
        {
170
          "name": "mail.example.com",
171
          "uri": "\/instances\/mail.example.com"
172
        }
173
      ]
174

175
    If the optional 'bulk' argument is provided and set to 'true'
176
    value (i.e '?bulk=1'), the output contains detailed
177
    information about instances as a list.
178

179
    Example::
180

181
      [
182
        {
183
           "status": "running",
184
           "bridge": "xen-br0",
185
           "name": "web.example.com",
186
           "tags": ["tag1", "tag2"],
187
           "admin_ram": 512,
188
           "sda_size": 20480,
189
           "pnode": "node1.example.com",
190
           "mac": "01:23:45:67:89:01",
191
           "sdb_size": 4096,
192
           "snodes": ["node2.example.com"],
193
           "disk_template": "drbd",
194
           "ip": null,
195
           "admin_state": true,
196
           "os": "debian-etch",
197
           "vcpus": 2,
198
           "oper_state": true
199
        },
200
        ...
201
      ]
202

203
    @returns: a dictionary with 'name' and 'uri' keys for each of them.
204

205
    """
206
    client = luxi.Client()
207
    instancesdata = client.QueryInstances([], ["name"])
208
    instanceslist = [row[0] for row in instancesdata]
209

    
210

    
211
    if 'bulk' in self.queryargs:
212
      bulkdata = client.QueryInstances(instanceslist, I_FIELDS)
213
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
214

    
215
    else:
216
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
217
                                   uri_fields=("id", "uri"))
218

    
219
  def POST(self):
220
    """Create an instance.
221

222
    @returns: a job id
223

224
    """
225
    opts = self.req.request_post_data
226

    
227
    beparams = baserlib.MakeParamsDict(opts, constants.BES_PARAMETERS)
228
    hvparams = baserlib.MakeParamsDict(opts, constants.HVS_PARAMETERS)
229

    
230
    op = ganeti.opcodes.OpCreateInstance(
231
        instance_name=opts.get('name'),
232
        disk_size=opts.get('size', 20 * 1024),
233
        swap_size=opts.get('swap', 4 * 1024),
234
        disk_template=opts.get('disk_template', None),
235
        mode=constants.INSTANCE_CREATE,
236
        os_type=opts.get('os'),
237
        pnode=opts.get('pnode'),
238
        snode=opts.get('snode'),
239
        ip=opts.get('ip', 'none'),
240
        bridge=opts.get('bridge', None),
241
        start=opts.get('start', True),
242
        ip_check=opts.get('ip_check', True),
243
        wait_for_sync=opts.get('wait_for_sync', True),
244
        mac=opts.get('mac', 'auto'),
245
        hypervisor=opts.get('hypervisor', None),
246
        hvparams=hvparams,
247
        beparams=beparams,
248
        iallocator=opts.get('iallocator', None),
249
        file_storage_dir=opts.get('file_storage_dir', None),
250
        file_driver=opts.get('file_driver', 'loop'),
251
        )
252

    
253
    job_id = ganeti.cli.SendJob([op])
254
    return job_id
255

    
256

    
257
class R_instances(R_2_instances):
258
  """/instances resource.
259

260
  """
261
  # TODO: Temporary resource will be deprecated
262
  DOC_URI = "/instances"
263

    
264

    
265
class R_2_instances_name_reboot(baserlib.R_Generic):
266
  """/2/instances/[instance_name]/reboot resource.
267

268
  Implements an instance reboot.
269

270
  """
271

    
272
  DOC_URI = "/2/instances/[instance_name]/reboot"
273

    
274
  def POST(self):
275
    """Reboot an instance.
276

277
    The URI takes type=[hard|soft|full] and
278
    ignore_secondaries=[False|True] parameters.
279

280
    """
281
    instance_name = self.items[0]
282
    reboot_type = self.queryargs.get('type',
283
                                     [constants.INSTANCE_REBOOT_HARD])[0]
284
    ignore_secondaries = bool(self.queryargs.get('ignore_secondaries',
285
                                                 [False])[0])
286
    op = ganeti.opcodes.OpRebootInstance(
287
        instance_name=instance_name,
288
        reboot_type=reboot_type,
289
        ignore_secondaries=ignore_secondaries)
290

    
291
    job_id = ganeti.cli.SendJob([op])
292

    
293
    return job_id
294

    
295

    
296
class R_2_instances_name_startup(baserlib.R_Generic):
297
  """/2/instances/[instance_name]/startup resource.
298

299
  Implements an instance startup.
300

301
  """
302

    
303
  DOC_URI = "/2/instances/[instance_name]/startup"
304

    
305
  def PUT(self):
306
    """Startup an instance.
307

308
    The URI takes force=[False|True] parameter to start the instance
309
    if even if secondary disks are failing.
310

311
    """
312
    instance_name = self.items[0]
313
    force_startup = bool(self.queryargs.get('force', [False])[0])
314
    op = ganeti.opcodes.OpStartupInstance(instance_name=instance_name,
315
                                          force=force_startup)
316

    
317
    job_id = ganeti.cli.SendJob([op])
318

    
319
    return job_id
320

    
321

    
322
class R_2_instances_name_shutdown(baserlib.R_Generic):
323
  """/2/instances/[instance_name]/shutdown resource.
324

325
  Implements an instance shutdown.
326

327
  """
328

    
329
  DOC_URI = "/2/instances/[instance_name]/shutdown"
330

    
331
  def PUT(self):
332
    """Shutdown an instance.
333

334
    """
335
    instance_name = self.items[0]
336
    op = ganeti.opcodes.OpShutdownInstance(instance_name=instance_name)
337

    
338
    job_id = ganeti.cli.SendJob([op])
339

    
340
    return job_id
341

    
342

    
343
class R_2_instances_name_tags(baserlib.R_Generic):
344
  """/2/instances/[instance_name]/tags resource.
345

346
  Manages per-instance tags.
347

348
  """
349
  DOC_URI = "/2/instances/[instance_name]/tags"
350

    
351
  def GET(self):
352
    """Returns a list of instance tags.
353

354
    Example: ["tag1", "tag2", "tag3"]
355

356
    """
357
    return baserlib._Tags_GET(constants.TAG_INSTANCE, name=self.items[0])
358

    
359
  def PUT(self):
360
    """Add a set of tags to the instance.
361

362
    The request as a list of strings should be PUT to this URI. And
363
    you'll have back a job id.
364

365
    """
366
    return baserlib._Tags_PUT(constants.TAG_INSTANCE,
367
                              self.req.request_post_data, name=self.items[0])
368

    
369
  def DELETE(self):
370
    """Delete a tag.
371

372
    In order to delete a set of tags from a instance, the DELETE
373
    request should be addressed to URI like:
374
    /2/instances/[instance_name]/tags?tag=[tag]&tag=[tag]
375

376
    """
377
    if 'tag' not in self.queryargs:
378
      # no we not gonna delete all tags from an instance
379
      raise http.HttpNotImplemented()
380
    return baserlib._Tags_DELETE(constants.TAG_INSTANCE,
381
                                 self.queryargs['tag'],
382
                                 name=self.items[0])