Revision 441e7cfd

b/daemons/ganeti-rapi
22 22
"""
23 23

  
24 24
import glob
25
import logging
25 26
import optparse
26 27
import sys
27 28
import os
28 29
import signal
29 30

  
31
from ganeti import logger
30 32
from ganeti import constants
31 33
from ganeti import errors
32 34
from ganeti import http
33
from ganeti import rpc
34 35
from ganeti import ssconf
35 36
from ganeti import utils
36 37
from ganeti.rapi import connector
......
49 50

  
50 51
    """
51 52
    (HandlerClass, items, args) = self._resmap.getController(self.path)
52
    handler = HandlerClass(self, items, args)
53
    handler = HandlerClass(self, items, args, self.post_data)
53 54

  
54 55
    command = self.command.upper()
55 56
    try:
......
58 59
      raise http.HTTPBadRequest()
59 60

  
60 61
    try:
61
      result = fn()
62
      try:
63
        result = fn()
64
      except:
65
        logging.exception("Error while handling the %s request", command)
66
        raise
62 67

  
63 68
    except errors.OpPrereqError, err:
64 69
      # TODO: "Not found" is not always the correct error. Ganeti's core must
......
135 140
  if options.fork:
136 141
    utils.Daemonize(logfile=constants.LOG_RAPISERVER)
137 142

  
143
  logger.SetupLogging(constants.LOG_RAPISERVER, debug=options.debug,
144
                     stderr_logging=not options.fork)
145

  
138 146
  utils.WritePidFile(constants.RAPI_PID)
139 147

  
140 148
  log_fd = open(constants.LOG_RAPIACCESS, 'a')
......
155 163

  
156 164

  
157 165
if __name__ == '__main__':
166
  
158 167
  main()
b/lib/rapi/baserlib.py
26 26
import ganeti.cli
27 27
import ganeti.opcodes
28 28

  
29
from ganeti import luxi
30

  
29 31

  
30 32
def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
31 33
  """Builds a URI list as used by index resources.
......
89 91
  return list(tags)
90 92

  
91 93

  
94
def _Tags_POST(kind, tags, name=None):
95
  """Helper function to set tags.
96

  
97
  """
98
  if name is None:
99
    # Do not cause "missing parameter" error, which happens if a parameter
100
    # is None.
101
    name = ""
102
  cl = luxi.Client()
103
  return cl.SubmitJob([ganeti.opcodes.OpAddTags(kind=kind, name=name,
104
                                                tags=tags)])
105

  
106

  
92 107
def MapBulkFields(itemslist, fields):
93 108
  """Map value to field name in to one dictionary.
94 109

  
......
110 125
  """Generic class for resources.
111 126

  
112 127
  """
113
  def __init__(self, request, items, queryargs):
128
  def __init__(self, request, items, queryargs, post_data):
114 129
    """Generic resource constructor.
115 130

  
116 131
    Args:
......
122 137
    self.request = request
123 138
    self.items = items
124 139
    self.queryargs = queryargs
140
    self.post_data = post_data
b/lib/rapi/connector.py
137 137

  
138 138
  "/2/jobs": rlib2.R_2_jobs,
139 139
  "/2/nodes": rlib2.R_2_nodes,
140
  "/2/instances": rlib2.R_2_instances,
141
  re.compile(r'^/2/instances/([\w\._-]+)$'): rlib1.R_instances_name,
142
  re.compile(r'^/2/instances/([\w\._-]+)/tags$'): rlib2.R_2_instances_name_tags,
140 143
  re.compile(r'/2/jobs/(%s)$' % constants.JOB_ID_TEMPLATE): rlib2.R_2_jobs_id,
141 144
  })
b/lib/rapi/rlib2.py
129 129
      result = ganeti.cli.SubmitOpCode(op)
130 130
      return baserlib.MapBulkFields(result, N_FIELDS)
131 131

  
132
    return baserlib.BuildUriList(nodeslist, "/nodes/%s",
132
    return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
133 133
                                 uri_fields=("id", "uri"))
134

  
135

  
136
class R_2_instances(baserlib.R_Generic):
137
  """/2/instances resource.
138

  
139
  """
140
  DOC_URI = "/2/instances"
141

  
142

  
143
  def GET(self):
144
    """Returns a list of all available instances.
145

  
146
    Returns:
147
       A dictionary with 'name' and 'uri' keys for each of them.
148

  
149
    Example: [
150
        {
151
          "name": "web.example.com",
152
          "uri": "\/instances\/web.example.com"
153
        },
154
        {
155
          "name": "mail.example.com",
156
          "uri": "\/instances\/mail.example.com"
157
        }]
158

  
159
    If the optional 'bulk' argument is provided and set to 'true'
160
    value (i.e '?bulk=1'), the output contains detailed
161
    information about instances as a list.
162

  
163
    Example: [
164
        {
165
           "status": "running",
166
           "bridge": "xen-br0",
167
           "name": "web.example.com",
168
           "tags": ["tag1", "tag2"],
169
           "admin_ram": 512,
170
           "sda_size": 20480,
171
           "pnode": "node1.example.com",
172
           "mac": "01:23:45:67:89:01",
173
           "sdb_size": 4096,
174
           "snodes": ["node2.example.com"],
175
           "disk_template": "drbd",
176
           "ip": null,
177
           "admin_state": true,
178
           "os": "debian-etch",
179
           "vcpus": 2,
180
           "oper_state": true
181
        },
182
        ...
183
    ]
184

  
185
    """
186
    op = ganeti.opcodes.OpQueryInstances(output_fields=["name"], names=[])
187
    instanceslist = baserlib.ExtractField(ganeti.cli.SubmitOpCode(op), 0)
188

  
189
    if 'bulk' in self.queryargs:
190
      op = ganeti.opcodes.OpQueryInstances(output_fields=I_FIELDS,
191
                                           names=instanceslist)
192
      result = ganeti.cli.SubmitOpCode(op)
193
      return baserlib.MapBulkFields(result, I_FIELDS)
194

  
195

  
196
    else:
197
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
198
                                   uri_fields=("id", "uri"))
199

  
200

  
201
class R_2_instances_name_tags(baserlib.R_Generic):
202
  """/2/instances/[instance_name]/tags resource.
203

  
204
  Manages per-instance tags.
205

  
206
  """
207
  DOC_URI = "/2/instances/[instance_name]/tags"
208

  
209
  def GET(self):
210
    """Returns a list of instance tags.
211

  
212
    Example: ["tag1", "tag2", "tag3"]
213

  
214
    """
215
    return baserlib._Tags_GET(constants.TAG_INSTANCE, name=self.items[0])
216

  
217
  def POST(self):
218
    """Add a set of tags to the instance.
219

  
220
    The reqest as a list of strings should be POST to this URI. And you'll have
221
    back a job id.
222

  
223
    """
224
    return baserlib._Tags_POST(constants.TAG_INSTANCE,
225
                               self.post_data, name=self.items[0])
b/test/ganeti.rapi.resources_unittest.py
28 28
from ganeti import errors
29 29
from ganeti import http
30 30

  
31
from ganeti.rapi import connector
32
from ganeti.rapi import rlib1
31
from ganeti.rapi import connector 
32
from ganeti.rapi import rlib1 
33 33

  
34 34

  
35 35
class MapperTests(unittest.TestCase):
......
70 70
  """Testing for R_root class."""
71 71

  
72 72
  def setUp(self):
73
    self.root = connector.R_root(None, None, None)
73
    self.root = connector.R_root(None, None, None, None)
74 74

  
75 75
  def testGet(self):
76 76
    expected = [

Also available in: Unified diff