Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ d8260842

History | View | Annotate | Download (19.6 kB)

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

24 10b207d4 Oleksiy Mishchenko
"""
25 10b207d4 Oleksiy Mishchenko
26 59b4eeef Iustin Pop
from ganeti import opcodes
27 15fd9fd5 Oleksiy Mishchenko
from ganeti import http
28 15fd9fd5 Oleksiy Mishchenko
from ganeti import constants
29 59b4eeef Iustin Pop
from ganeti import cli
30 8381fa2d Michael Hanselmann
from ganeti import rapi
31 38206f3c Iustin Pop
from ganeti.rapi import baserlib
32 10b207d4 Oleksiy Mishchenko
33 4e5a68f8 Oleksiy Mishchenko
34 9031ee8e Iustin Pop
I_FIELDS = ["name", "admin_state", "os",
35 9031ee8e Iustin Pop
            "pnode", "snodes",
36 9031ee8e Iustin Pop
            "disk_template",
37 495cfdf0 Guido Trotter
            "nic.ips", "nic.macs", "nic.modes", "nic.links",
38 a8b16c4e Tim Boring
            "network_port",
39 024e157f Iustin Pop
            "disk.sizes", "disk_usage",
40 a5b9d725 Iustin Pop
            "beparams", "hvparams",
41 9031ee8e Iustin Pop
            "oper_state", "oper_ram", "status",
42 9031ee8e Iustin Pop
            "tags"]
43 9031ee8e Iustin Pop
44 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
45 9031ee8e Iustin Pop
            "dtotal", "dfree",
46 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
47 0105bad3 Iustin Pop
            "pinst_cnt", "sinst_cnt", "tags",
48 0105bad3 Iustin Pop
            "ctotal", "cnodes", "csockets",
49 0105bad3 Iustin Pop
            ]
50 4e5a68f8 Oleksiy Mishchenko
51 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
52 64dae8fc Michael Hanselmann
_NR_MASTER_CANDIATE = "master-candidate"
53 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
54 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
55 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
56 64dae8fc Michael Hanselmann
57 64dae8fc Michael Hanselmann
_NR_MAP = {
58 64dae8fc Michael Hanselmann
  "M": _NR_MASTER,
59 64dae8fc Michael Hanselmann
  "C": _NR_MASTER_CANDIATE,
60 64dae8fc Michael Hanselmann
  "D": _NR_DRAINED,
61 64dae8fc Michael Hanselmann
  "O": _NR_OFFLINE,
62 64dae8fc Michael Hanselmann
  "R": _NR_REGULAR,
63 64dae8fc Michael Hanselmann
  }
64 64dae8fc Michael Hanselmann
65 4e5a68f8 Oleksiy Mishchenko
66 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
67 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
68 4e5a68f8 Oleksiy Mishchenko

69 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
70 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
71 4e5a68f8 Oleksiy Mishchenko

72 4e5a68f8 Oleksiy Mishchenko
  """
73 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
74 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
75 4e5a68f8 Oleksiy Mishchenko

76 4e5a68f8 Oleksiy Mishchenko
    """
77 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
78 4e5a68f8 Oleksiy Mishchenko
79 4e5a68f8 Oleksiy Mishchenko
80 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
81 4e5a68f8 Oleksiy Mishchenko
  """Cluster info.
82 4e5a68f8 Oleksiy Mishchenko

83 4e5a68f8 Oleksiy Mishchenko
  """
84 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
85 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
86 4e5a68f8 Oleksiy Mishchenko

87 4e5a68f8 Oleksiy Mishchenko
    """
88 59b4eeef Iustin Pop
    client = baserlib.GetClient()
89 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
90 4e5a68f8 Oleksiy Mishchenko
91 4e5a68f8 Oleksiy Mishchenko
92 4e5a68f8 Oleksiy Mishchenko
class R_2_os(baserlib.R_Generic):
93 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
94 4e5a68f8 Oleksiy Mishchenko

95 4e5a68f8 Oleksiy Mishchenko
  """
96 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
97 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
98 4e5a68f8 Oleksiy Mishchenko

99 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
100 4e5a68f8 Oleksiy Mishchenko

101 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
102 4e5a68f8 Oleksiy Mishchenko

103 4e5a68f8 Oleksiy Mishchenko
    """
104 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
105 59b4eeef Iustin Pop
    op = opcodes.OpDiagnoseOS(output_fields=["name", "valid"], names=[])
106 59b4eeef Iustin Pop
    job_id = baserlib.SubmitJob([op], cl)
107 59b4eeef Iustin Pop
    # we use custom feedback function, instead of print we log the status
108 59b4eeef Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
109 59b4eeef Iustin Pop
    diagnose_data = result[0]
110 4e5a68f8 Oleksiy Mishchenko
111 4e5a68f8 Oleksiy Mishchenko
    if not isinstance(diagnose_data, list):
112 59b4eeef Iustin Pop
      raise http.HttpBadGateway(message="Can't get OS list")
113 4e5a68f8 Oleksiy Mishchenko
114 4e5a68f8 Oleksiy Mishchenko
    return [row[0] for row in diagnose_data if row[1]]
115 51ee2f49 Oleksiy Mishchenko
116 10b207d4 Oleksiy Mishchenko
117 10b207d4 Oleksiy Mishchenko
class R_2_jobs(baserlib.R_Generic):
118 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
119 10b207d4 Oleksiy Mishchenko

120 10b207d4 Oleksiy Mishchenko
  """
121 10b207d4 Oleksiy Mishchenko
  def GET(self):
122 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
123 10b207d4 Oleksiy Mishchenko

124 c41eea6e Iustin Pop
    @return: a dictionary with jobs id and uri.
125 38206f3c Iustin Pop

126 10b207d4 Oleksiy Mishchenko
    """
127 10b207d4 Oleksiy Mishchenko
    fields = ["id"]
128 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
129 10b207d4 Oleksiy Mishchenko
    # Convert the list of lists to the list of ids
130 59b4eeef Iustin Pop
    result = [job_id for [job_id] in cl.QueryJobs(None, fields)]
131 9031ee8e Iustin Pop
    return baserlib.BuildUriList(result, "/2/jobs/%s",
132 9031ee8e Iustin Pop
                                 uri_fields=("id", "uri"))
133 10b207d4 Oleksiy Mishchenko
134 10b207d4 Oleksiy Mishchenko
135 10b207d4 Oleksiy Mishchenko
class R_2_jobs_id(baserlib.R_Generic):
136 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
137 10b207d4 Oleksiy Mishchenko

138 10b207d4 Oleksiy Mishchenko
  """
139 10b207d4 Oleksiy Mishchenko
  def GET(self):
140 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
141 10b207d4 Oleksiy Mishchenko

142 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
143 c41eea6e Iustin Pop
        The result includes:
144 c41eea6e Iustin Pop
            - id: job ID as a number
145 c41eea6e Iustin Pop
            - status: current job status as a string
146 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
147 c41eea6e Iustin Pop
              opcodes in the job
148 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
149 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
150 38206f3c Iustin Pop

151 10b207d4 Oleksiy Mishchenko
    """
152 ee69c97f Iustin Pop
    fields = ["id", "ops", "status", "summary",
153 ee69c97f Iustin Pop
              "opstatus", "opresult", "oplog",
154 ee69c97f Iustin Pop
              "received_ts", "start_ts", "end_ts",
155 ee69c97f Iustin Pop
              ]
156 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
157 59b4eeef Iustin Pop
    result = baserlib.GetClient().QueryJobs([job_id, ], fields)[0]
158 ee69c97f Iustin Pop
    if result is None:
159 ee69c97f Iustin Pop
      raise http.HttpNotFound()
160 10b207d4 Oleksiy Mishchenko
    return baserlib.MapFields(fields, result)
161 10b207d4 Oleksiy Mishchenko
162 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
163 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
164 c7f5f338 Oleksiy Mishchenko

165 c7f5f338 Oleksiy Mishchenko
    """
166 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
167 59b4eeef Iustin Pop
    result = baserlib.GetClient().CancelJob(job_id)
168 c7f5f338 Oleksiy Mishchenko
    return result
169 c7f5f338 Oleksiy Mishchenko
170 10b207d4 Oleksiy Mishchenko
171 10b207d4 Oleksiy Mishchenko
class R_2_nodes(baserlib.R_Generic):
172 10b207d4 Oleksiy Mishchenko
  """/2/nodes resource.
173 10b207d4 Oleksiy Mishchenko

174 10b207d4 Oleksiy Mishchenko
  """
175 10b207d4 Oleksiy Mishchenko
  def GET(self):
176 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
177 38206f3c Iustin Pop

178 10b207d4 Oleksiy Mishchenko
    """
179 59b4eeef Iustin Pop
    client = baserlib.GetClient()
180 38206f3c Iustin Pop
181 3d103742 Iustin Pop
    if self.useBulk():
182 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
183 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
184 9031ee8e Iustin Pop
    else:
185 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
186 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
187 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
188 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
189 441e7cfd Oleksiy Mishchenko
190 441e7cfd Oleksiy Mishchenko
191 4e5a68f8 Oleksiy Mishchenko
class R_2_nodes_name(baserlib.R_Generic):
192 4e5a68f8 Oleksiy Mishchenko
  """/2/nodes/[node_name] resources.
193 028c6b76 Oleksiy Mishchenko

194 028c6b76 Oleksiy Mishchenko
  """
195 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
196 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
197 4e5a68f8 Oleksiy Mishchenko

198 4e5a68f8 Oleksiy Mishchenko
    """
199 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
200 59b4eeef Iustin Pop
    client = baserlib.GetClient()
201 9031ee8e Iustin Pop
    result = client.QueryNodes(names=[node_name], fields=N_FIELDS,
202 3d103742 Iustin Pop
                               use_locking=self.useLocking())
203 4e5a68f8 Oleksiy Mishchenko
204 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
205 028c6b76 Oleksiy Mishchenko
206 028c6b76 Oleksiy Mishchenko
207 64dae8fc Michael Hanselmann
class R_2_nodes_name_role(baserlib.R_Generic):
208 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
209 64dae8fc Michael Hanselmann

210 64dae8fc Michael Hanselmann
  """
211 64dae8fc Michael Hanselmann
  def GET(self):
212 64dae8fc Michael Hanselmann
    """Returns the current node role.
213 64dae8fc Michael Hanselmann

214 64dae8fc Michael Hanselmann
    @return: Node role
215 64dae8fc Michael Hanselmann

216 64dae8fc Michael Hanselmann
    """
217 64dae8fc Michael Hanselmann
    node_name = self.items[0]
218 64dae8fc Michael Hanselmann
    client = baserlib.GetClient()
219 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
220 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
221 64dae8fc Michael Hanselmann
222 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
223 64dae8fc Michael Hanselmann
224 64dae8fc Michael Hanselmann
  def PUT(self):
225 64dae8fc Michael Hanselmann
    """Sets the node role.
226 64dae8fc Michael Hanselmann

227 64dae8fc Michael Hanselmann
    @return: a job id
228 64dae8fc Michael Hanselmann

229 64dae8fc Michael Hanselmann
    """
230 64dae8fc Michael Hanselmann
    if not isinstance(self.req.request_body, basestring):
231 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a string")
232 64dae8fc Michael Hanselmann
233 64dae8fc Michael Hanselmann
    node_name = self.items[0]
234 64dae8fc Michael Hanselmann
    role = self.req.request_body
235 64dae8fc Michael Hanselmann
236 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
237 64dae8fc Michael Hanselmann
      candidate = False
238 64dae8fc Michael Hanselmann
      offline = False
239 64dae8fc Michael Hanselmann
      drained = False
240 64dae8fc Michael Hanselmann
241 64dae8fc Michael Hanselmann
    elif role == _NR_MASTER_CANDIATE:
242 64dae8fc Michael Hanselmann
      candidate = True
243 64dae8fc Michael Hanselmann
      offline = drained = None
244 64dae8fc Michael Hanselmann
245 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
246 64dae8fc Michael Hanselmann
      drained = True
247 64dae8fc Michael Hanselmann
      candidate = offline = None
248 64dae8fc Michael Hanselmann
249 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
250 64dae8fc Michael Hanselmann
      offline = True
251 64dae8fc Michael Hanselmann
      candidate = drained = None
252 64dae8fc Michael Hanselmann
253 64dae8fc Michael Hanselmann
    else:
254 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
255 64dae8fc Michael Hanselmann
256 64dae8fc Michael Hanselmann
    op = opcodes.OpSetNodeParams(node_name=node_name,
257 64dae8fc Michael Hanselmann
                                 master_candidate=candidate,
258 64dae8fc Michael Hanselmann
                                 offline=offline,
259 64dae8fc Michael Hanselmann
                                 drained=drained,
260 64dae8fc Michael Hanselmann
                                 force=bool(self.useForce()))
261 64dae8fc Michael Hanselmann
262 64dae8fc Michael Hanselmann
    return baserlib.SubmitJob([op])
263 64dae8fc Michael Hanselmann
264 64dae8fc Michael Hanselmann
265 73452f12 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.R_Generic):
266 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
267 73452f12 Michael Hanselmann

268 73452f12 Michael Hanselmann
  """
269 73452f12 Michael Hanselmann
  def POST(self):
270 73452f12 Michael Hanselmann
    """Evacuate all secondary instances off a node.
271 73452f12 Michael Hanselmann

272 73452f12 Michael Hanselmann
    """
273 73452f12 Michael Hanselmann
    node_name = self.items[0]
274 73452f12 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
275 73452f12 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
276 73452f12 Michael Hanselmann
277 73452f12 Michael Hanselmann
    op = opcodes.OpEvacuateNode(node_name=node_name,
278 73452f12 Michael Hanselmann
                                remote_node=remote_node,
279 73452f12 Michael Hanselmann
                                iallocator=iallocator)
280 73452f12 Michael Hanselmann
281 73452f12 Michael Hanselmann
    return baserlib.SubmitJob([op])
282 73452f12 Michael Hanselmann
283 73452f12 Michael Hanselmann
284 1c482bab Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.R_Generic):
285 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
286 1c482bab Michael Hanselmann

287 1c482bab Michael Hanselmann
  """
288 1c482bab Michael Hanselmann
  def POST(self):
289 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
290 1c482bab Michael Hanselmann

291 1c482bab Michael Hanselmann
    """
292 1c482bab Michael Hanselmann
    node_name = self.items[0]
293 1c482bab Michael Hanselmann
    live = bool(self._checkIntVariable("live", default=1))
294 1c482bab Michael Hanselmann
295 1c482bab Michael Hanselmann
    op = opcodes.OpMigrateNode(node_name=node_name, live=live)
296 1c482bab Michael Hanselmann
297 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
298 1c482bab Michael Hanselmann
299 1c482bab Michael Hanselmann
300 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
301 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/storage ressource.
302 7a95a954 Michael Hanselmann

303 7a95a954 Michael Hanselmann
  """
304 7a95a954 Michael Hanselmann
  # LUQueryNodeStorage acquires locks, hence restricting access to GET
305 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
306 7a95a954 Michael Hanselmann
307 7a95a954 Michael Hanselmann
  def GET(self):
308 7a95a954 Michael Hanselmann
    node_name = self.items[0]
309 7a95a954 Michael Hanselmann
310 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
311 7a95a954 Michael Hanselmann
    if not storage_type:
312 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
313 7a95a954 Michael Hanselmann
                                " parameter")
314 7a95a954 Michael Hanselmann
315 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
316 7a95a954 Michael Hanselmann
    if not output_fields:
317 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
318 7a95a954 Michael Hanselmann
                                " parameter")
319 7a95a954 Michael Hanselmann
320 7a95a954 Michael Hanselmann
    op = opcodes.OpQueryNodeStorage(nodes=[node_name],
321 7a95a954 Michael Hanselmann
                                    storage_type=storage_type,
322 7a95a954 Michael Hanselmann
                                    output_fields=output_fields.split(","))
323 7a95a954 Michael Hanselmann
    return baserlib.SubmitJob([op])
324 7a95a954 Michael Hanselmann
325 7a95a954 Michael Hanselmann
326 1e82bc80 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.R_Generic):
327 1e82bc80 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify ressource.
328 1e82bc80 Michael Hanselmann

329 1e82bc80 Michael Hanselmann
  """
330 1e82bc80 Michael Hanselmann
  def PUT(self):
331 1e82bc80 Michael Hanselmann
    node_name = self.items[0]
332 1e82bc80 Michael Hanselmann
333 1e82bc80 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
334 1e82bc80 Michael Hanselmann
    if not storage_type:
335 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
336 1e82bc80 Michael Hanselmann
                                " parameter")
337 1e82bc80 Michael Hanselmann
338 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
339 1e82bc80 Michael Hanselmann
    if not name:
340 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
341 1e82bc80 Michael Hanselmann
                                " parameter")
342 1e82bc80 Michael Hanselmann
343 1e82bc80 Michael Hanselmann
    changes = {}
344 1e82bc80 Michael Hanselmann
345 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
346 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
347 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
348 1e82bc80 Michael Hanselmann
349 1e82bc80 Michael Hanselmann
    op = opcodes.OpModifyNodeStorage(node_name=node_name,
350 1e82bc80 Michael Hanselmann
                                     storage_type=storage_type,
351 1e82bc80 Michael Hanselmann
                                     name=name,
352 1e82bc80 Michael Hanselmann
                                     changes=changes)
353 1e82bc80 Michael Hanselmann
    return baserlib.SubmitJob([op])
354 1e82bc80 Michael Hanselmann
355 1e82bc80 Michael Hanselmann
356 723f4565 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.R_Generic):
357 723f4565 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair ressource.
358 723f4565 Michael Hanselmann

359 723f4565 Michael Hanselmann
  """
360 723f4565 Michael Hanselmann
  def PUT(self):
361 723f4565 Michael Hanselmann
    node_name = self.items[0]
362 723f4565 Michael Hanselmann
363 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
364 723f4565 Michael Hanselmann
    if not storage_type:
365 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
366 723f4565 Michael Hanselmann
                                " parameter")
367 723f4565 Michael Hanselmann
368 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
369 723f4565 Michael Hanselmann
    if not name:
370 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
371 723f4565 Michael Hanselmann
                                " parameter")
372 723f4565 Michael Hanselmann
373 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
374 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
375 723f4565 Michael Hanselmann
                                     name=name)
376 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
377 723f4565 Michael Hanselmann
378 723f4565 Michael Hanselmann
379 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
380 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
381 441e7cfd Oleksiy Mishchenko

382 441e7cfd Oleksiy Mishchenko
  """
383 441e7cfd Oleksiy Mishchenko
  def GET(self):
384 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
385 441e7cfd Oleksiy Mishchenko

386 441e7cfd Oleksiy Mishchenko
    """
387 59b4eeef Iustin Pop
    client = baserlib.GetClient()
388 441e7cfd Oleksiy Mishchenko
389 3d103742 Iustin Pop
    use_locking = self.useLocking()
390 3d103742 Iustin Pop
    if self.useBulk():
391 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
392 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
393 441e7cfd Oleksiy Mishchenko
    else:
394 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
395 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
396 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
397 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
398 441e7cfd Oleksiy Mishchenko
399 21f04e5e Oleksiy Mishchenko
  def POST(self):
400 2f7635f4 Oleksiy Mishchenko
    """Create an instance.
401 2f7635f4 Oleksiy Mishchenko

402 5fcc718f Iustin Pop
    @return: a job id
403 2f7635f4 Oleksiy Mishchenko

404 2f7635f4 Oleksiy Mishchenko
    """
405 6e99c5a0 Iustin Pop
    if not isinstance(self.req.request_body, dict):
406 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
407 6e99c5a0 Iustin Pop
408 6e99c5a0 Iustin Pop
    beparams = baserlib.MakeParamsDict(self.req.request_body,
409 6e99c5a0 Iustin Pop
                                       constants.BES_PARAMETERS)
410 6e99c5a0 Iustin Pop
    hvparams = baserlib.MakeParamsDict(self.req.request_body,
411 6e99c5a0 Iustin Pop
                                       constants.HVS_PARAMETERS)
412 6e99c5a0 Iustin Pop
    fn = self.getBodyParameter
413 6e99c5a0 Iustin Pop
414 6e99c5a0 Iustin Pop
    # disk processing
415 6e99c5a0 Iustin Pop
    disk_data = fn('disks')
416 6e99c5a0 Iustin Pop
    if not isinstance(disk_data, list):
417 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("The 'disks' parameter should be a list")
418 6e99c5a0 Iustin Pop
    disks = []
419 6e99c5a0 Iustin Pop
    for idx, d in enumerate(disk_data):
420 6e99c5a0 Iustin Pop
      if not isinstance(d, int):
421 6e99c5a0 Iustin Pop
        raise http.HttpBadRequest("Disk %d specification wrong: should"
422 6e99c5a0 Iustin Pop
                                  " be an integer")
423 6e99c5a0 Iustin Pop
      disks.append({"size": d})
424 6e99c5a0 Iustin Pop
    # nic processing (one nic only)
425 495cfdf0 Guido Trotter
    nics = [{"mac": fn("mac", constants.VALUE_AUTO)}]
426 495cfdf0 Guido Trotter
    if fn("ip", None) is not None:
427 495cfdf0 Guido Trotter
      nics[0]["ip"] = fn("ip")
428 495cfdf0 Guido Trotter
    if fn("mode", None) is not None:
429 495cfdf0 Guido Trotter
      nics[0]["mode"] = fn("mode")
430 495cfdf0 Guido Trotter
    if fn("link", None) is not None:
431 495cfdf0 Guido Trotter
      nics[0]["link"] = fn("link")
432 495cfdf0 Guido Trotter
    if fn("bridge", None) is not None:
433 495cfdf0 Guido Trotter
       nics[0]["bridge"] = fn("bridge")
434 2f7635f4 Oleksiy Mishchenko
435 59b4eeef Iustin Pop
    op = opcodes.OpCreateInstance(
436 59b4eeef Iustin Pop
      mode=constants.INSTANCE_CREATE,
437 59b4eeef Iustin Pop
      instance_name=fn('name'),
438 59b4eeef Iustin Pop
      disks=disks,
439 59b4eeef Iustin Pop
      disk_template=fn('disk_template'),
440 59b4eeef Iustin Pop
      os_type=fn('os'),
441 59b4eeef Iustin Pop
      pnode=fn('pnode', None),
442 59b4eeef Iustin Pop
      snode=fn('snode', None),
443 59b4eeef Iustin Pop
      iallocator=fn('iallocator', None),
444 59b4eeef Iustin Pop
      nics=nics,
445 59b4eeef Iustin Pop
      start=fn('start', True),
446 59b4eeef Iustin Pop
      ip_check=fn('ip_check', True),
447 59b4eeef Iustin Pop
      wait_for_sync=True,
448 59b4eeef Iustin Pop
      hypervisor=fn('hypervisor', None),
449 59b4eeef Iustin Pop
      hvparams=hvparams,
450 59b4eeef Iustin Pop
      beparams=beparams,
451 59b4eeef Iustin Pop
      file_storage_dir=fn('file_storage_dir', None),
452 59b4eeef Iustin Pop
      file_driver=fn('file_driver', 'loop'),
453 6f59b964 Iustin Pop
      dry_run=bool(self.dryRun()),
454 59b4eeef Iustin Pop
      )
455 59b4eeef Iustin Pop
456 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
457 2f7635f4 Oleksiy Mishchenko
458 441e7cfd Oleksiy Mishchenko
459 4e5a68f8 Oleksiy Mishchenko
class R_2_instances_name(baserlib.R_Generic):
460 4e5a68f8 Oleksiy Mishchenko
  """/2/instances/[instance_name] resources.
461 028c6b76 Oleksiy Mishchenko

462 028c6b76 Oleksiy Mishchenko
  """
463 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
464 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
465 4e5a68f8 Oleksiy Mishchenko

466 4e5a68f8 Oleksiy Mishchenko
    """
467 59b4eeef Iustin Pop
    client = baserlib.GetClient()
468 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
469 9031ee8e Iustin Pop
    result = client.QueryInstances(names=[instance_name], fields=I_FIELDS,
470 3d103742 Iustin Pop
                                   use_locking=self.useLocking())
471 4e5a68f8 Oleksiy Mishchenko
472 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
473 028c6b76 Oleksiy Mishchenko
474 6e99c5a0 Iustin Pop
  def DELETE(self):
475 6e99c5a0 Iustin Pop
    """Delete an instance.
476 6e99c5a0 Iustin Pop

477 6e99c5a0 Iustin Pop
    """
478 59b4eeef Iustin Pop
    op = opcodes.OpRemoveInstance(instance_name=self.items[0],
479 6f59b964 Iustin Pop
                                  ignore_failures=False,
480 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
481 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
482 6e99c5a0 Iustin Pop
483 028c6b76 Oleksiy Mishchenko
484 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
485 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
486 d8260842 Michael Hanselmann

487 d8260842 Michael Hanselmann
  """
488 d8260842 Michael Hanselmann
  def GET(self):
489 d8260842 Michael Hanselmann
    """Request detailed instance information.
490 d8260842 Michael Hanselmann

491 d8260842 Michael Hanselmann
    """
492 d8260842 Michael Hanselmann
    instance_name = self.items[0]
493 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
494 d8260842 Michael Hanselmann
495 d8260842 Michael Hanselmann
    op = opcodes.OpQueryInstanceData(instances=[instance_name],
496 d8260842 Michael Hanselmann
                                     static=static)
497 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
498 d8260842 Michael Hanselmann
499 d8260842 Michael Hanselmann
500 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
501 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
502 2276aa29 Oleksiy Mishchenko

503 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
504 2276aa29 Oleksiy Mishchenko

505 2276aa29 Oleksiy Mishchenko
  """
506 21f04e5e Oleksiy Mishchenko
  def POST(self):
507 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
508 2276aa29 Oleksiy Mishchenko

509 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
510 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
511 0c55c24b Oleksiy Mishchenko

512 2276aa29 Oleksiy Mishchenko
    """
513 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
514 0c55c24b Oleksiy Mishchenko
    reboot_type = self.queryargs.get('type',
515 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
516 0c55c24b Oleksiy Mishchenko
    ignore_secondaries = bool(self.queryargs.get('ignore_secondaries',
517 0c55c24b Oleksiy Mishchenko
                                                 [False])[0])
518 59b4eeef Iustin Pop
    op = opcodes.OpRebootInstance(instance_name=instance_name,
519 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
520 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
521 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
522 2276aa29 Oleksiy Mishchenko
523 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
524 2276aa29 Oleksiy Mishchenko
525 2276aa29 Oleksiy Mishchenko
526 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
527 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
528 0c55c24b Oleksiy Mishchenko

529 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
530 0c55c24b Oleksiy Mishchenko

531 0c55c24b Oleksiy Mishchenko
  """
532 21f04e5e Oleksiy Mishchenko
  def PUT(self):
533 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
534 0c55c24b Oleksiy Mishchenko

535 c41eea6e Iustin Pop
    The URI takes force=[False|True] parameter to start the instance
536 c41eea6e Iustin Pop
    if even if secondary disks are failing.
537 0c55c24b Oleksiy Mishchenko

538 0c55c24b Oleksiy Mishchenko
    """
539 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
540 0c55c24b Oleksiy Mishchenko
    force_startup = bool(self.queryargs.get('force', [False])[0])
541 59b4eeef Iustin Pop
    op = opcodes.OpStartupInstance(instance_name=instance_name,
542 6f59b964 Iustin Pop
                                   force=force_startup,
543 6f59b964 Iustin Pop
                                   dry_run=bool(self.dryRun()))
544 0c55c24b Oleksiy Mishchenko
545 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
546 0c55c24b Oleksiy Mishchenko
547 0c55c24b Oleksiy Mishchenko
548 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
549 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
550 0c55c24b Oleksiy Mishchenko

551 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
552 0c55c24b Oleksiy Mishchenko

553 0c55c24b Oleksiy Mishchenko
  """
554 21f04e5e Oleksiy Mishchenko
  def PUT(self):
555 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
556 0c55c24b Oleksiy Mishchenko

557 0c55c24b Oleksiy Mishchenko
    """
558 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
559 6f59b964 Iustin Pop
    op = opcodes.OpShutdownInstance(instance_name=instance_name,
560 6f59b964 Iustin Pop
                                    dry_run=bool(self.dryRun()))
561 0c55c24b Oleksiy Mishchenko
562 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
563 0c55c24b Oleksiy Mishchenko
564 0c55c24b Oleksiy Mishchenko
565 e5b7c4ca Iustin Pop
class R_2_instances_name_reinstall(baserlib.R_Generic):
566 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
567 e5b7c4ca Iustin Pop

568 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
569 e5b7c4ca Iustin Pop

570 e5b7c4ca Iustin Pop
  """
571 e5b7c4ca Iustin Pop
  def POST(self):
572 e5b7c4ca Iustin Pop
    """Reinstall an instance.
573 e5b7c4ca Iustin Pop

574 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
575 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
576 e5b7c4ca Iustin Pop
    automatically.
577 e5b7c4ca Iustin Pop

578 e5b7c4ca Iustin Pop
    """
579 e5b7c4ca Iustin Pop
    instance_name = self.items[0]
580 e5b7c4ca Iustin Pop
    ostype = self._checkStringVariable('os')
581 e5b7c4ca Iustin Pop
    nostartup = self._checkIntVariable('nostartup')
582 e5b7c4ca Iustin Pop
    ops = [
583 e5b7c4ca Iustin Pop
      opcodes.OpShutdownInstance(instance_name=instance_name),
584 e5b7c4ca Iustin Pop
      opcodes.OpReinstallInstance(instance_name=instance_name, os_type=ostype),
585 e5b7c4ca Iustin Pop
      ]
586 e5b7c4ca Iustin Pop
    if not nostartup:
587 e5b7c4ca Iustin Pop
      ops.append(opcodes.OpStartupInstance(instance_name=instance_name,
588 e5b7c4ca Iustin Pop
                                           force=False))
589 e5b7c4ca Iustin Pop
    return baserlib.SubmitJob(ops)
590 e5b7c4ca Iustin Pop
591 e5b7c4ca Iustin Pop
592 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
593 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
594 4c98b915 Michael Hanselmann

595 4c98b915 Michael Hanselmann
  """
596 4c98b915 Michael Hanselmann
  def POST(self):
597 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
598 4c98b915 Michael Hanselmann

599 4c98b915 Michael Hanselmann
    """
600 4c98b915 Michael Hanselmann
    instance_name = self.items[0]
601 4c98b915 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
602 4c98b915 Michael Hanselmann
    mode = self._checkStringVariable("mode", default=None)
603 4c98b915 Michael Hanselmann
    raw_disks = self._checkStringVariable("disks", default=None)
604 4c98b915 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
605 4c98b915 Michael Hanselmann
606 4c98b915 Michael Hanselmann
    if raw_disks:
607 4c98b915 Michael Hanselmann
      try:
608 4c98b915 Michael Hanselmann
        disks = [int(part) for part in raw_disks.split(",")]
609 4c98b915 Michael Hanselmann
      except ValueError, err:
610 4c98b915 Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
611 4c98b915 Michael Hanselmann
    else:
612 4c98b915 Michael Hanselmann
      disks = []
613 4c98b915 Michael Hanselmann
614 4c98b915 Michael Hanselmann
    op = opcodes.OpReplaceDisks(instance_name=instance_name,
615 4c98b915 Michael Hanselmann
                                remote_node=remote_node,
616 4c98b915 Michael Hanselmann
                                mode=mode,
617 4c98b915 Michael Hanselmann
                                disks=disks,
618 4c98b915 Michael Hanselmann
                                iallocator=iallocator)
619 4c98b915 Michael Hanselmann
620 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
621 4c98b915 Michael Hanselmann
622 4c98b915 Michael Hanselmann
623 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
624 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
625 441e7cfd Oleksiy Mishchenko

626 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
627 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
628 441e7cfd Oleksiy Mishchenko

629 441e7cfd Oleksiy Mishchenko
  """
630 7a6b9510 Iustin Pop
  TAG_LEVEL = None
631 18cb43a2 Oleksiy Mishchenko
632 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
633 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
634 18cb43a2 Oleksiy Mishchenko

635 18cb43a2 Oleksiy Mishchenko
    We have to override the default to sort out cluster naming case.
636 18cb43a2 Oleksiy Mishchenko

637 18cb43a2 Oleksiy Mishchenko
    """
638 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
639 18cb43a2 Oleksiy Mishchenko
640 18cb43a2 Oleksiy Mishchenko
    if self.TAG_LEVEL != constants.TAG_CLUSTER:
641 18cb43a2 Oleksiy Mishchenko
      self.name = items[0]
642 18cb43a2 Oleksiy Mishchenko
    else:
643 18cb43a2 Oleksiy Mishchenko
      self.name = ""
644 441e7cfd Oleksiy Mishchenko
645 441e7cfd Oleksiy Mishchenko
  def GET(self):
646 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
647 441e7cfd Oleksiy Mishchenko

648 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
649 441e7cfd Oleksiy Mishchenko

650 441e7cfd Oleksiy Mishchenko
    """
651 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
652 441e7cfd Oleksiy Mishchenko
653 21f04e5e Oleksiy Mishchenko
  def PUT(self):
654 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
655 441e7cfd Oleksiy Mishchenko

656 c41eea6e Iustin Pop
    The request as a list of strings should be PUT to this URI. And
657 c41eea6e Iustin Pop
    you'll have back a job id.
658 441e7cfd Oleksiy Mishchenko

659 441e7cfd Oleksiy Mishchenko
    """
660 6e99c5a0 Iustin Pop
    if 'tag' not in self.queryargs:
661 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
662 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
663 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
664 6f59b964 Iustin Pop
                              self.queryargs['tag'], name=self.name,
665 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
666 15fd9fd5 Oleksiy Mishchenko
667 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
668 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
669 15fd9fd5 Oleksiy Mishchenko

670 18cb43a2 Oleksiy Mishchenko
    In order to delete a set of tags, the DELETE
671 c41eea6e Iustin Pop
    request should be addressed to URI like:
672 18cb43a2 Oleksiy Mishchenko
    /tags?tag=[tag]&tag=[tag]
673 15fd9fd5 Oleksiy Mishchenko

674 15fd9fd5 Oleksiy Mishchenko
    """
675 15fd9fd5 Oleksiy Mishchenko
    if 'tag' not in self.queryargs:
676 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
677 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
678 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
679 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
680 15fd9fd5 Oleksiy Mishchenko
                                 self.queryargs['tag'],
681 6f59b964 Iustin Pop
                                 name=self.name,
682 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
683 18cb43a2 Oleksiy Mishchenko
684 18cb43a2 Oleksiy Mishchenko
685 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
686 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
687 18cb43a2 Oleksiy Mishchenko

688 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
689 18cb43a2 Oleksiy Mishchenko

690 18cb43a2 Oleksiy Mishchenko
  """
691 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
692 18cb43a2 Oleksiy Mishchenko
693 18cb43a2 Oleksiy Mishchenko
694 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
695 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
696 18cb43a2 Oleksiy Mishchenko

697 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
698 18cb43a2 Oleksiy Mishchenko

699 18cb43a2 Oleksiy Mishchenko
  """
700 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
701 18cb43a2 Oleksiy Mishchenko
702 18cb43a2 Oleksiy Mishchenko
703 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
704 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/tags resource.
705 18cb43a2 Oleksiy Mishchenko

706 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
707 18cb43a2 Oleksiy Mishchenko

708 18cb43a2 Oleksiy Mishchenko
  """
709 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER