Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 028c6b76

History | View | Annotate | Download (9.6 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
    Returns:
45
      A dictionary with jobs id and uri.
46

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

    
53

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

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

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

63
    Returns:
64
      A dictionary with job parameters.
65

66
    The result includes:
67
      id - job ID as a number
68
      status - current job status as a string
69
      ops - involved OpCodes as a list of dictionaries for each opcodes in
70
        the job
71
      opstatus - OpCodes status as a list
72
      opresult - OpCodes results as a list of lists
73

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

    
80
  def DELETE(self):
81
    """Cancel not-yet-started job.
82

83
    """
84
    job_id = self.items[0]
85
    result = luxi.Client().CancelJob(job_id)
86
    return result
87

    
88

    
89
class R_2_nodes(baserlib.R_Generic):
90
  """/2/nodes resource.
91

92
  """
93
  DOC_URI = "/2/nodes"
94

    
95
  def GET(self):
96
    """Returns a list of all nodes.
97

98
    Returns:
99
      A dictionary with 'name' and 'uri' keys for each of them.
100

101
    Example: [
102
        {
103
          "id": "node1.example.com",
104
          "uri": "\/instances\/node1.example.com"
105
        },
106
        {
107
          "id": "node2.example.com",
108
          "uri": "\/instances\/node2.example.com"
109
        }]
110

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

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

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

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

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

    
142

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

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

    
150

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

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

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

160
    Returns:
161
       A dictionary with 'name' and 'uri' keys for each of them.
162

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

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

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

199
    """
200
    client = luxi.Client()
201
    instancesdata = client.QueryInstances([], ["name"])
202
    instanceslist = [row[0] for row in instancesdata]
203

    
204

    
205
    if 'bulk' in self.queryargs:
206
      bulkdata = client.QueryInstances(instanceslist, I_FIELDS)
207
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
208

    
209
    else:
210
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
211
                                   uri_fields=("id", "uri"))
212

    
213
  def POST(self):
214
    """Create an instance.
215

216
    Returns:
217
      A job id.
218

219
    """
220
    opts = self.req.request_post_data
221

    
222
    beparams = baserlib.MakeParamsDict(opts, constants.BES_PARAMETERS)
223
    hvparams = baserlib.MakeParamsDict(opts, constants.HVS_PARAMETERS)
224

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

    
248
    job_id = ganeti.cli.SendJob([op])
249
    return job_id
250

    
251

    
252
class R_instances(R_2_instances):
253
  """/instances resource.
254

255
  """
256
  # TODO: Temporary resource will be deprecated
257
  DOC_URI = "/instances"
258

    
259

    
260
class R_2_instances_name_reboot(baserlib.R_Generic):
261
  """/2/instances/[instance_name]/reboot resource.
262

263
  Implements an instance reboot.
264

265
  """
266

    
267
  DOC_URI = "/2/instances/[instance_name]/reboot"
268

    
269
  def POST(self):
270
    """Reboot an instance.
271

272
    The URI takes type=[hard|soft|full] and
273
    ignore_secondaries=[False|True] parameters.
274

275
    """
276
    instance_name = self.items[0]
277
    reboot_type = self.queryargs.get('type',
278
                                     [constants.INSTANCE_REBOOT_HARD])[0]
279
    ignore_secondaries = bool(self.queryargs.get('ignore_secondaries',
280
                                                 [False])[0])
281
    op = ganeti.opcodes.OpRebootInstance(
282
        instance_name=instance_name,
283
        reboot_type=reboot_type,
284
        ignore_secondaries=ignore_secondaries)
285

    
286
    job_id = ganeti.cli.SendJob([op])
287

    
288
    return job_id
289

    
290

    
291
class R_2_instances_name_startup(baserlib.R_Generic):
292
  """/2/instances/[instance_name]/startup resource.
293

294
  Implements an instance startup.
295

296
  """
297

    
298
  DOC_URI = "/2/instances/[instance_name]/startup"
299

    
300
  def PUT(self):
301
    """Startup an instance.
302

303
    The URI takes force=[False|True] parameter to start the instance if even if
304
    secondary disks are failing.
305

306
    """
307
    instance_name = self.items[0]
308
    force_startup = bool(self.queryargs.get('force', [False])[0])
309
    op = ganeti.opcodes.OpStartupInstance(instance_name=instance_name,
310
                                          force=force_startup)
311

    
312
    job_id = ganeti.cli.SendJob([op])
313

    
314
    return job_id
315

    
316

    
317
class R_2_instances_name_shutdown(baserlib.R_Generic):
318
  """/2/instances/[instance_name]/shutdown resource.
319

320
  Implements an instance shutdown.
321

322
  """
323

    
324
  DOC_URI = "/2/instances/[instance_name]/shutdown"
325

    
326
  def PUT(self):
327
    """Shutdown an instance.
328

329
    """
330
    instance_name = self.items[0]
331
    op = ganeti.opcodes.OpShutdownInstance(instance_name=instance_name)
332

    
333
    job_id = ganeti.cli.SendJob([op])
334

    
335
    return job_id
336

    
337

    
338
class R_2_instances_name_tags(baserlib.R_Generic):
339
  """/2/instances/[instance_name]/tags resource.
340

341
  Manages per-instance tags.
342

343
  """
344
  DOC_URI = "/2/instances/[instance_name]/tags"
345

    
346
  def GET(self):
347
    """Returns a list of instance tags.
348

349
    Example: ["tag1", "tag2", "tag3"]
350

351
    """
352
    return baserlib._Tags_GET(constants.TAG_INSTANCE, name=self.items[0])
353

    
354
  def PUT(self):
355
    """Add a set of tags to the instance.
356

357
    The request as a list of strings should be PUT to this URI. And you'll have
358
    back a job id.
359

360
    """
361
    return baserlib._Tags_PUT(constants.TAG_INSTANCE,
362
                               self.post_data, name=self.items[0])
363

    
364
  def DELETE(self):
365
    """Delete a tag.
366

367
    In order to delete a set of tags from a instance, DELETE request should be
368
    addressed to URI like: /2/instances/[instance_name]/tags?tag=[tag]&tag=[tag]
369

370
    """
371
    if 'tag' not in self.queryargs:
372
      # no we not gonna delete all tags from an instance
373
      raise http.HTTPNotImplemented()
374
    return baserlib._Tags_DELETE(constants.TAG_INSTANCE,
375
                                 self.queryargs['tag'],
376
                                 name=self.items[0])