Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 0f945c65

History | View | Annotate | Download (37.2 kB)

1 10b207d4 Oleksiy Mishchenko
#
2 10b207d4 Oleksiy Mishchenko
#
3 10b207d4 Oleksiy Mishchenko
4 4ff922a2 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 f3c1a70c Michael Hanselmann
"""Remote API resource implementations.
23 10b207d4 Oleksiy Mishchenko

24 f3c1a70c Michael Hanselmann
PUT or POST?
25 f3c1a70c Michael Hanselmann
============
26 88394aa7 René Nussbaumer

27 f3c1a70c Michael Hanselmann
According to RFC2616 the main difference between PUT and POST is that
28 f3c1a70c Michael Hanselmann
POST can create new resources but PUT can only create the resource the
29 f3c1a70c Michael Hanselmann
URI was pointing to on the PUT request.
30 88394aa7 René Nussbaumer

31 d91a933f Michael Hanselmann
In the context of this module POST on ``/2/instances`` to change an existing
32 f3c1a70c Michael Hanselmann
entity is legitimate, while PUT would not be. PUT creates a new entity (e.g. a
33 f3c1a70c Michael Hanselmann
new instance) with a name specified in the request.
34 88394aa7 René Nussbaumer

35 140ff718 Michael Hanselmann
Quoting from RFC2616, section 9.6::
36 f3c1a70c Michael Hanselmann

37 f3c1a70c Michael Hanselmann
  The fundamental difference between the POST and PUT requests is reflected in
38 f3c1a70c Michael Hanselmann
  the different meaning of the Request-URI. The URI in a POST request
39 f3c1a70c Michael Hanselmann
  identifies the resource that will handle the enclosed entity. That resource
40 f3c1a70c Michael Hanselmann
  might be a data-accepting process, a gateway to some other protocol, or a
41 f3c1a70c Michael Hanselmann
  separate entity that accepts annotations. In contrast, the URI in a PUT
42 f3c1a70c Michael Hanselmann
  request identifies the entity enclosed with the request -- the user agent
43 f3c1a70c Michael Hanselmann
  knows what URI is intended and the server MUST NOT attempt to apply the
44 f3c1a70c Michael Hanselmann
  request to some other resource. If the server desires that the request be
45 f3c1a70c Michael Hanselmann
  applied to a different URI, it MUST send a 301 (Moved Permanently) response;
46 f3c1a70c Michael Hanselmann
  the user agent MAY then make its own decision regarding whether or not to
47 f3c1a70c Michael Hanselmann
  redirect the request.
48 f3c1a70c Michael Hanselmann

49 f3c1a70c Michael Hanselmann
So when adding new methods, if they are operating on the URI entity itself,
50 f3c1a70c Michael Hanselmann
PUT should be prefered over POST.
51 88394aa7 René Nussbaumer

52 10b207d4 Oleksiy Mishchenko
"""
53 10b207d4 Oleksiy Mishchenko
54 fe267188 Iustin Pop
# pylint: disable-msg=C0103
55 fe267188 Iustin Pop
56 fe267188 Iustin Pop
# C0103: Invalid name, since the R_* names are not conforming
57 fe267188 Iustin Pop
58 59b4eeef Iustin Pop
from ganeti import opcodes
59 15fd9fd5 Oleksiy Mishchenko
from ganeti import http
60 15fd9fd5 Oleksiy Mishchenko
from ganeti import constants
61 59b4eeef Iustin Pop
from ganeti import cli
62 8381fa2d Michael Hanselmann
from ganeti import rapi
63 d1c172de Michael Hanselmann
from ganeti import ht
64 e987f166 Michael Hanselmann
from ganeti import compat
65 38206f3c Iustin Pop
from ganeti.rapi import baserlib
66 10b207d4 Oleksiy Mishchenko
67 4e5a68f8 Oleksiy Mishchenko
68 7118a0df Iustin Pop
_COMMON_FIELDS = ["ctime", "mtime", "uuid", "serial_no", "tags"]
69 9031ee8e Iustin Pop
I_FIELDS = ["name", "admin_state", "os",
70 9031ee8e Iustin Pop
            "pnode", "snodes",
71 9031ee8e Iustin Pop
            "disk_template",
72 82e186f8 Michael Hanselmann
            "nic.ips", "nic.macs", "nic.modes", "nic.links", "nic.bridges",
73 a8b16c4e Tim Boring
            "network_port",
74 024e157f Iustin Pop
            "disk.sizes", "disk_usage",
75 a5b9d725 Iustin Pop
            "beparams", "hvparams",
76 4ea3de4e Balazs Lecz
            "oper_state", "oper_ram", "oper_vcpus", "status",
77 90224407 Iustin Pop
            "custom_hvparams", "custom_beparams", "custom_nicparams",
78 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
79 9031ee8e Iustin Pop
80 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
81 9031ee8e Iustin Pop
            "dtotal", "dfree",
82 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
83 7118a0df Iustin Pop
            "pinst_cnt", "sinst_cnt",
84 0105bad3 Iustin Pop
            "ctotal", "cnodes", "csockets",
85 7118a0df Iustin Pop
            "pip", "sip", "role",
86 93962b80 Iustin Pop
            "pinst_list", "sinst_list",
87 c190e817 Iustin Pop
            "master_capable", "vm_capable",
88 fd254195 Iustin Pop
            "group.uuid",
89 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
90 4e5a68f8 Oleksiy Mishchenko
91 f4e86448 Michael Hanselmann
G_FIELDS = [
92 f4e86448 Michael Hanselmann
  "alloc_policy",
93 f4e86448 Michael Hanselmann
  "name",
94 f4e86448 Michael Hanselmann
  "node_cnt",
95 f4e86448 Michael Hanselmann
  "node_list",
96 f4e86448 Michael Hanselmann
  ] + _COMMON_FIELDS
97 0897dc97 Adeodato Simo
98 bd7b2070 Michael Hanselmann
J_FIELDS_BULK = [
99 e987f166 Michael Hanselmann
  "id", "ops", "status", "summary",
100 bd7b2070 Michael Hanselmann
  "opstatus",
101 e987f166 Michael Hanselmann
  "received_ts", "start_ts", "end_ts",
102 e987f166 Michael Hanselmann
  ]
103 e987f166 Michael Hanselmann
104 bd7b2070 Michael Hanselmann
J_FIELDS = J_FIELDS_BULK + [
105 bd7b2070 Michael Hanselmann
  "oplog",
106 bd7b2070 Michael Hanselmann
  "opresult",
107 bd7b2070 Michael Hanselmann
  ]
108 bd7b2070 Michael Hanselmann
109 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
110 64dae8fc Michael Hanselmann
_NR_MASTER_CANDIATE = "master-candidate"
111 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
112 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
113 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
114 64dae8fc Michael Hanselmann
115 64dae8fc Michael Hanselmann
_NR_MAP = {
116 1e28e3b8 Michael Hanselmann
  constants.NR_MASTER: _NR_MASTER,
117 1e28e3b8 Michael Hanselmann
  constants.NR_MCANDIDATE: _NR_MASTER_CANDIATE,
118 1e28e3b8 Michael Hanselmann
  constants.NR_DRAINED: _NR_DRAINED,
119 1e28e3b8 Michael Hanselmann
  constants.NR_OFFLINE: _NR_OFFLINE,
120 1e28e3b8 Michael Hanselmann
  constants.NR_REGULAR: _NR_REGULAR,
121 64dae8fc Michael Hanselmann
  }
122 64dae8fc Michael Hanselmann
123 1e28e3b8 Michael Hanselmann
assert frozenset(_NR_MAP.keys()) == constants.NR_ALL
124 1e28e3b8 Michael Hanselmann
125 d975f482 Michael Hanselmann
# Request data version field
126 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
127 d975f482 Michael Hanselmann
128 6395cebb Michael Hanselmann
# Feature string for instance creation request data version 1
129 6395cebb Michael Hanselmann
_INST_CREATE_REQV1 = "instance-create-reqv1"
130 6395cebb Michael Hanselmann
131 c744425f Michael Hanselmann
# Feature string for instance reinstall request version 1
132 c744425f Michael Hanselmann
_INST_REINSTALL_REQV1 = "instance-reinstall-reqv1"
133 c744425f Michael Hanselmann
134 b7a1c816 Michael Hanselmann
# Feature string for node migration version 1
135 b7a1c816 Michael Hanselmann
_NODE_MIGRATE_REQV1 = "node-migrate-reqv1"
136 b7a1c816 Michael Hanselmann
137 de40437a Michael Hanselmann
# Feature string for node evacuation with LU-generated jobs
138 de40437a Michael Hanselmann
_NODE_EVAC_RES1 = "node-evac-res1"
139 de40437a Michael Hanselmann
140 b4fcee5b Michael Hanselmann
ALL_FEATURES = frozenset([
141 b4fcee5b Michael Hanselmann
  _INST_CREATE_REQV1,
142 b4fcee5b Michael Hanselmann
  _INST_REINSTALL_REQV1,
143 b4fcee5b Michael Hanselmann
  _NODE_MIGRATE_REQV1,
144 b4fcee5b Michael Hanselmann
  _NODE_EVAC_RES1,
145 b4fcee5b Michael Hanselmann
  ])
146 b4fcee5b Michael Hanselmann
147 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
148 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
149 793a8f7c Michael Hanselmann
150 4e5a68f8 Oleksiy Mishchenko
151 0f945c65 Michael Hanselmann
class R_root(baserlib.R_Generic):
152 0f945c65 Michael Hanselmann
  """/ resource.
153 0f945c65 Michael Hanselmann

154 0f945c65 Michael Hanselmann
  """
155 0f945c65 Michael Hanselmann
  @staticmethod
156 0f945c65 Michael Hanselmann
  def GET():
157 0f945c65 Michael Hanselmann
    """Supported for legacy reasons.
158 0f945c65 Michael Hanselmann

159 0f945c65 Michael Hanselmann
    """
160 0f945c65 Michael Hanselmann
    return None
161 0f945c65 Michael Hanselmann
162 0f945c65 Michael Hanselmann
163 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
164 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
165 4e5a68f8 Oleksiy Mishchenko

166 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
167 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
168 4e5a68f8 Oleksiy Mishchenko

169 4e5a68f8 Oleksiy Mishchenko
  """
170 7e950d31 Iustin Pop
  @staticmethod
171 7e950d31 Iustin Pop
  def GET():
172 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
173 4e5a68f8 Oleksiy Mishchenko

174 4e5a68f8 Oleksiy Mishchenko
    """
175 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
176 4e5a68f8 Oleksiy Mishchenko
177 4e5a68f8 Oleksiy Mishchenko
178 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
179 b58a4d16 Michael Hanselmann
  """/2/info resource.
180 4e5a68f8 Oleksiy Mishchenko

181 4e5a68f8 Oleksiy Mishchenko
  """
182 7e950d31 Iustin Pop
  @staticmethod
183 7e950d31 Iustin Pop
  def GET():
184 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
185 4e5a68f8 Oleksiy Mishchenko

186 4e5a68f8 Oleksiy Mishchenko
    """
187 59b4eeef Iustin Pop
    client = baserlib.GetClient()
188 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
189 4e5a68f8 Oleksiy Mishchenko
190 4e5a68f8 Oleksiy Mishchenko
191 7eac4a4d Michael Hanselmann
class R_2_features(baserlib.R_Generic):
192 7eac4a4d Michael Hanselmann
  """/2/features resource.
193 7eac4a4d Michael Hanselmann

194 7eac4a4d Michael Hanselmann
  """
195 7eac4a4d Michael Hanselmann
  @staticmethod
196 7eac4a4d Michael Hanselmann
  def GET():
197 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
198 7eac4a4d Michael Hanselmann

199 7eac4a4d Michael Hanselmann
    """
200 b4fcee5b Michael Hanselmann
    return list(ALL_FEATURES)
201 7eac4a4d Michael Hanselmann
202 7eac4a4d Michael Hanselmann
203 4e5a68f8 Oleksiy Mishchenko
class R_2_os(baserlib.R_Generic):
204 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
205 4e5a68f8 Oleksiy Mishchenko

206 4e5a68f8 Oleksiy Mishchenko
  """
207 7e950d31 Iustin Pop
  @staticmethod
208 7e950d31 Iustin Pop
  def GET():
209 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
210 4e5a68f8 Oleksiy Mishchenko

211 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
212 4e5a68f8 Oleksiy Mishchenko

213 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
214 4e5a68f8 Oleksiy Mishchenko

215 4e5a68f8 Oleksiy Mishchenko
    """
216 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
217 da2d02e7 Iustin Pop
    op = opcodes.OpOsDiagnose(output_fields=["name", "variants"], names=[])
218 59b4eeef Iustin Pop
    job_id = baserlib.SubmitJob([op], cl)
219 59b4eeef Iustin Pop
    # we use custom feedback function, instead of print we log the status
220 59b4eeef Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
221 59b4eeef Iustin Pop
    diagnose_data = result[0]
222 4e5a68f8 Oleksiy Mishchenko
223 4e5a68f8 Oleksiy Mishchenko
    if not isinstance(diagnose_data, list):
224 59b4eeef Iustin Pop
      raise http.HttpBadGateway(message="Can't get OS list")
225 4e5a68f8 Oleksiy Mishchenko
226 e3ac208c Guido Trotter
    os_names = []
227 d22dfef7 Iustin Pop
    for (name, variants) in diagnose_data:
228 d22dfef7 Iustin Pop
      os_names.extend(cli.CalculateOSNames(name, variants))
229 e3ac208c Guido Trotter
230 e3ac208c Guido Trotter
    return os_names
231 51ee2f49 Oleksiy Mishchenko
232 10b207d4 Oleksiy Mishchenko
233 508e9b20 Michael Hanselmann
class R_2_redist_config(baserlib.R_Generic):
234 508e9b20 Michael Hanselmann
  """/2/redistribute-config resource.
235 508e9b20 Michael Hanselmann

236 508e9b20 Michael Hanselmann
  """
237 7e950d31 Iustin Pop
  @staticmethod
238 7e950d31 Iustin Pop
  def PUT():
239 508e9b20 Michael Hanselmann
    """Redistribute configuration to all nodes.
240 508e9b20 Michael Hanselmann

241 508e9b20 Michael Hanselmann
    """
242 d1240007 Iustin Pop
    return baserlib.SubmitJob([opcodes.OpClusterRedistConf()])
243 508e9b20 Michael Hanselmann
244 508e9b20 Michael Hanselmann
245 62e999a5 Michael Hanselmann
class R_2_cluster_modify(baserlib.R_Generic):
246 62e999a5 Michael Hanselmann
  """/2/modify resource.
247 62e999a5 Michael Hanselmann

248 62e999a5 Michael Hanselmann
  """
249 62e999a5 Michael Hanselmann
  def PUT(self):
250 62e999a5 Michael Hanselmann
    """Modifies cluster parameters.
251 62e999a5 Michael Hanselmann

252 62e999a5 Michael Hanselmann
    @return: a job id
253 62e999a5 Michael Hanselmann

254 62e999a5 Michael Hanselmann
    """
255 a6682fdc Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpClusterSetParams, self.request_body,
256 62e999a5 Michael Hanselmann
                             None)
257 62e999a5 Michael Hanselmann
258 62e999a5 Michael Hanselmann
    return baserlib.SubmitJob([op])
259 62e999a5 Michael Hanselmann
260 62e999a5 Michael Hanselmann
261 10b207d4 Oleksiy Mishchenko
class R_2_jobs(baserlib.R_Generic):
262 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
263 10b207d4 Oleksiy Mishchenko

264 10b207d4 Oleksiy Mishchenko
  """
265 e987f166 Michael Hanselmann
  def GET(self):
266 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
267 10b207d4 Oleksiy Mishchenko

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

270 10b207d4 Oleksiy Mishchenko
    """
271 e987f166 Michael Hanselmann
    client = baserlib.GetClient()
272 e987f166 Michael Hanselmann
273 e987f166 Michael Hanselmann
    if self.useBulk():
274 bd7b2070 Michael Hanselmann
      bulkdata = client.QueryJobs(None, J_FIELDS_BULK)
275 bd7b2070 Michael Hanselmann
      return baserlib.MapBulkFields(bulkdata, J_FIELDS_BULK)
276 e987f166 Michael Hanselmann
    else:
277 e987f166 Michael Hanselmann
      jobdata = map(compat.fst, client.QueryJobs(None, ["id"]))
278 e987f166 Michael Hanselmann
      return baserlib.BuildUriList(jobdata, "/2/jobs/%s",
279 e987f166 Michael Hanselmann
                                   uri_fields=("id", "uri"))
280 10b207d4 Oleksiy Mishchenko
281 10b207d4 Oleksiy Mishchenko
282 10b207d4 Oleksiy Mishchenko
class R_2_jobs_id(baserlib.R_Generic):
283 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
284 10b207d4 Oleksiy Mishchenko

285 10b207d4 Oleksiy Mishchenko
  """
286 10b207d4 Oleksiy Mishchenko
  def GET(self):
287 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
288 10b207d4 Oleksiy Mishchenko

289 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
290 c41eea6e Iustin Pop
        The result includes:
291 c41eea6e Iustin Pop
            - id: job ID as a number
292 c41eea6e Iustin Pop
            - status: current job status as a string
293 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
294 c41eea6e Iustin Pop
              opcodes in the job
295 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
296 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
297 38206f3c Iustin Pop

298 10b207d4 Oleksiy Mishchenko
    """
299 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
300 e987f166 Michael Hanselmann
    result = baserlib.GetClient().QueryJobs([job_id, ], J_FIELDS)[0]
301 ee69c97f Iustin Pop
    if result is None:
302 ee69c97f Iustin Pop
      raise http.HttpNotFound()
303 e987f166 Michael Hanselmann
    return baserlib.MapFields(J_FIELDS, result)
304 10b207d4 Oleksiy Mishchenko
305 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
306 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
307 c7f5f338 Oleksiy Mishchenko

308 c7f5f338 Oleksiy Mishchenko
    """
309 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
310 59b4eeef Iustin Pop
    result = baserlib.GetClient().CancelJob(job_id)
311 c7f5f338 Oleksiy Mishchenko
    return result
312 c7f5f338 Oleksiy Mishchenko
313 10b207d4 Oleksiy Mishchenko
314 793a8f7c Michael Hanselmann
class R_2_jobs_id_wait(baserlib.R_Generic):
315 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
316 793a8f7c Michael Hanselmann

317 793a8f7c Michael Hanselmann
  """
318 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
319 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
320 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
321 793a8f7c Michael Hanselmann
322 793a8f7c Michael Hanselmann
  def GET(self):
323 793a8f7c Michael Hanselmann
    """Waits for job changes.
324 793a8f7c Michael Hanselmann

325 793a8f7c Michael Hanselmann
    """
326 793a8f7c Michael Hanselmann
    job_id = self.items[0]
327 793a8f7c Michael Hanselmann
328 793a8f7c Michael Hanselmann
    fields = self.getBodyParameter("fields")
329 793a8f7c Michael Hanselmann
    prev_job_info = self.getBodyParameter("previous_job_info", None)
330 793a8f7c Michael Hanselmann
    prev_log_serial = self.getBodyParameter("previous_log_serial", None)
331 793a8f7c Michael Hanselmann
332 793a8f7c Michael Hanselmann
    if not isinstance(fields, list):
333 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'fields' parameter should be a list")
334 793a8f7c Michael Hanselmann
335 793a8f7c Michael Hanselmann
    if not (prev_job_info is None or isinstance(prev_job_info, list)):
336 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_job_info' parameter should"
337 793a8f7c Michael Hanselmann
                                " be a list")
338 793a8f7c Michael Hanselmann
339 793a8f7c Michael Hanselmann
    if not (prev_log_serial is None or
340 793a8f7c Michael Hanselmann
            isinstance(prev_log_serial, (int, long))):
341 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_log_serial' parameter should"
342 793a8f7c Michael Hanselmann
                                " be a number")
343 793a8f7c Michael Hanselmann
344 793a8f7c Michael Hanselmann
    client = baserlib.GetClient()
345 793a8f7c Michael Hanselmann
    result = client.WaitForJobChangeOnce(job_id, fields,
346 793a8f7c Michael Hanselmann
                                         prev_job_info, prev_log_serial,
347 793a8f7c Michael Hanselmann
                                         timeout=_WFJC_TIMEOUT)
348 793a8f7c Michael Hanselmann
    if not result:
349 793a8f7c Michael Hanselmann
      raise http.HttpNotFound()
350 793a8f7c Michael Hanselmann
351 793a8f7c Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
352 793a8f7c Michael Hanselmann
      # No changes
353 793a8f7c Michael Hanselmann
      return None
354 793a8f7c Michael Hanselmann
355 793a8f7c Michael Hanselmann
    (job_info, log_entries) = result
356 793a8f7c Michael Hanselmann
357 793a8f7c Michael Hanselmann
    return {
358 793a8f7c Michael Hanselmann
      "job_info": job_info,
359 793a8f7c Michael Hanselmann
      "log_entries": log_entries,
360 793a8f7c Michael Hanselmann
      }
361 793a8f7c Michael Hanselmann
362 793a8f7c Michael Hanselmann
363 10b207d4 Oleksiy Mishchenko
class R_2_nodes(baserlib.R_Generic):
364 10b207d4 Oleksiy Mishchenko
  """/2/nodes resource.
365 10b207d4 Oleksiy Mishchenko

366 10b207d4 Oleksiy Mishchenko
  """
367 10b207d4 Oleksiy Mishchenko
  def GET(self):
368 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
369 38206f3c Iustin Pop

370 10b207d4 Oleksiy Mishchenko
    """
371 59b4eeef Iustin Pop
    client = baserlib.GetClient()
372 38206f3c Iustin Pop
373 3d103742 Iustin Pop
    if self.useBulk():
374 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
375 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
376 9031ee8e Iustin Pop
    else:
377 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
378 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
379 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
380 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
381 441e7cfd Oleksiy Mishchenko
382 441e7cfd Oleksiy Mishchenko
383 4e5a68f8 Oleksiy Mishchenko
class R_2_nodes_name(baserlib.R_Generic):
384 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name] resource.
385 028c6b76 Oleksiy Mishchenko

386 028c6b76 Oleksiy Mishchenko
  """
387 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
388 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
389 4e5a68f8 Oleksiy Mishchenko

390 4e5a68f8 Oleksiy Mishchenko
    """
391 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
392 59b4eeef Iustin Pop
    client = baserlib.GetClient()
393 e8ebbd2b Michael Hanselmann
394 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
395 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
396 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
397 4e5a68f8 Oleksiy Mishchenko
398 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
399 028c6b76 Oleksiy Mishchenko
400 028c6b76 Oleksiy Mishchenko
401 64dae8fc Michael Hanselmann
class R_2_nodes_name_role(baserlib.R_Generic):
402 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
403 64dae8fc Michael Hanselmann

404 64dae8fc Michael Hanselmann
  """
405 64dae8fc Michael Hanselmann
  def GET(self):
406 64dae8fc Michael Hanselmann
    """Returns the current node role.
407 64dae8fc Michael Hanselmann

408 64dae8fc Michael Hanselmann
    @return: Node role
409 64dae8fc Michael Hanselmann

410 64dae8fc Michael Hanselmann
    """
411 64dae8fc Michael Hanselmann
    node_name = self.items[0]
412 64dae8fc Michael Hanselmann
    client = baserlib.GetClient()
413 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
414 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
415 64dae8fc Michael Hanselmann
416 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
417 64dae8fc Michael Hanselmann
418 64dae8fc Michael Hanselmann
  def PUT(self):
419 64dae8fc Michael Hanselmann
    """Sets the node role.
420 64dae8fc Michael Hanselmann

421 64dae8fc Michael Hanselmann
    @return: a job id
422 64dae8fc Michael Hanselmann

423 64dae8fc Michael Hanselmann
    """
424 627ad739 Michael Hanselmann
    if not isinstance(self.request_body, basestring):
425 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a string")
426 64dae8fc Michael Hanselmann
427 64dae8fc Michael Hanselmann
    node_name = self.items[0]
428 627ad739 Michael Hanselmann
    role = self.request_body
429 64dae8fc Michael Hanselmann
430 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
431 64dae8fc Michael Hanselmann
      candidate = False
432 64dae8fc Michael Hanselmann
      offline = False
433 64dae8fc Michael Hanselmann
      drained = False
434 64dae8fc Michael Hanselmann
435 64dae8fc Michael Hanselmann
    elif role == _NR_MASTER_CANDIATE:
436 64dae8fc Michael Hanselmann
      candidate = True
437 64dae8fc Michael Hanselmann
      offline = drained = None
438 64dae8fc Michael Hanselmann
439 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
440 64dae8fc Michael Hanselmann
      drained = True
441 64dae8fc Michael Hanselmann
      candidate = offline = None
442 64dae8fc Michael Hanselmann
443 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
444 64dae8fc Michael Hanselmann
      offline = True
445 64dae8fc Michael Hanselmann
      candidate = drained = None
446 64dae8fc Michael Hanselmann
447 64dae8fc Michael Hanselmann
    else:
448 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
449 64dae8fc Michael Hanselmann
450 f13973c4 Iustin Pop
    op = opcodes.OpNodeSetParams(node_name=node_name,
451 64dae8fc Michael Hanselmann
                                 master_candidate=candidate,
452 64dae8fc Michael Hanselmann
                                 offline=offline,
453 64dae8fc Michael Hanselmann
                                 drained=drained,
454 64dae8fc Michael Hanselmann
                                 force=bool(self.useForce()))
455 64dae8fc Michael Hanselmann
456 64dae8fc Michael Hanselmann
    return baserlib.SubmitJob([op])
457 64dae8fc Michael Hanselmann
458 64dae8fc Michael Hanselmann
459 73452f12 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.R_Generic):
460 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
461 73452f12 Michael Hanselmann

462 73452f12 Michael Hanselmann
  """
463 73452f12 Michael Hanselmann
  def POST(self):
464 de40437a Michael Hanselmann
    """Evacuate all instances off a node.
465 73452f12 Michael Hanselmann

466 73452f12 Michael Hanselmann
    """
467 de40437a Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeEvacuate, self.request_body, {
468 de40437a Michael Hanselmann
      "node_name": self.items[0],
469 de40437a Michael Hanselmann
      "dry_run": self.dryRun(),
470 de40437a Michael Hanselmann
      })
471 941b9309 Iustin Pop
472 de40437a Michael Hanselmann
    return baserlib.SubmitJob([op])
473 73452f12 Michael Hanselmann
474 73452f12 Michael Hanselmann
475 1c482bab Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.R_Generic):
476 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
477 1c482bab Michael Hanselmann

478 1c482bab Michael Hanselmann
  """
479 1c482bab Michael Hanselmann
  def POST(self):
480 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
481 1c482bab Michael Hanselmann

482 1c482bab Michael Hanselmann
    """
483 1c482bab Michael Hanselmann
    node_name = self.items[0]
484 1c482bab Michael Hanselmann
485 b7a1c816 Michael Hanselmann
    if self.queryargs:
486 b7a1c816 Michael Hanselmann
      # Support old-style requests
487 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs and "mode" in self.queryargs:
488 b7a1c816 Michael Hanselmann
        raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
489 b7a1c816 Michael Hanselmann
                                  " be passed")
490 b7a1c816 Michael Hanselmann
491 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs:
492 b7a1c816 Michael Hanselmann
        if self._checkIntVariable("live", default=1):
493 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_LIVE
494 b7a1c816 Michael Hanselmann
        else:
495 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_NONLIVE
496 52194140 Iustin Pop
      else:
497 b7a1c816 Michael Hanselmann
        mode = self._checkStringVariable("mode", default=None)
498 b7a1c816 Michael Hanselmann
499 b7a1c816 Michael Hanselmann
      data = {
500 b7a1c816 Michael Hanselmann
        "mode": mode,
501 b7a1c816 Michael Hanselmann
        }
502 52194140 Iustin Pop
    else:
503 b7a1c816 Michael Hanselmann
      data = self.request_body
504 52194140 Iustin Pop
505 b7a1c816 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeMigrate, data, {
506 b7a1c816 Michael Hanselmann
      "node_name": node_name,
507 b7a1c816 Michael Hanselmann
      })
508 1c482bab Michael Hanselmann
509 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
510 1c482bab Michael Hanselmann
511 1c482bab Michael Hanselmann
512 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
513 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
514 7a95a954 Michael Hanselmann

515 7a95a954 Michael Hanselmann
  """
516 ad8d0595 Iustin Pop
  # LUNodeQueryStorage acquires locks, hence restricting access to GET
517 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
518 7a95a954 Michael Hanselmann
519 7a95a954 Michael Hanselmann
  def GET(self):
520 7a95a954 Michael Hanselmann
    node_name = self.items[0]
521 7a95a954 Michael Hanselmann
522 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
523 7a95a954 Michael Hanselmann
    if not storage_type:
524 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
525 7a95a954 Michael Hanselmann
                                " parameter")
526 7a95a954 Michael Hanselmann
527 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
528 7a95a954 Michael Hanselmann
    if not output_fields:
529 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
530 7a95a954 Michael Hanselmann
                                " parameter")
531 7a95a954 Michael Hanselmann
532 ad8d0595 Iustin Pop
    op = opcodes.OpNodeQueryStorage(nodes=[node_name],
533 7a95a954 Michael Hanselmann
                                    storage_type=storage_type,
534 7a95a954 Michael Hanselmann
                                    output_fields=output_fields.split(","))
535 7a95a954 Michael Hanselmann
    return baserlib.SubmitJob([op])
536 7a95a954 Michael Hanselmann
537 7a95a954 Michael Hanselmann
538 1e82bc80 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.R_Generic):
539 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify resource.
540 1e82bc80 Michael Hanselmann

541 1e82bc80 Michael Hanselmann
  """
542 1e82bc80 Michael Hanselmann
  def PUT(self):
543 1e82bc80 Michael Hanselmann
    node_name = self.items[0]
544 1e82bc80 Michael Hanselmann
545 1e82bc80 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
546 1e82bc80 Michael Hanselmann
    if not storage_type:
547 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
548 1e82bc80 Michael Hanselmann
                                " parameter")
549 1e82bc80 Michael Hanselmann
550 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
551 1e82bc80 Michael Hanselmann
    if not name:
552 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
553 1e82bc80 Michael Hanselmann
                                " parameter")
554 1e82bc80 Michael Hanselmann
555 1e82bc80 Michael Hanselmann
    changes = {}
556 1e82bc80 Michael Hanselmann
557 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
558 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
559 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
560 1e82bc80 Michael Hanselmann
561 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
562 1e82bc80 Michael Hanselmann
                                     storage_type=storage_type,
563 1e82bc80 Michael Hanselmann
                                     name=name,
564 1e82bc80 Michael Hanselmann
                                     changes=changes)
565 1e82bc80 Michael Hanselmann
    return baserlib.SubmitJob([op])
566 1e82bc80 Michael Hanselmann
567 1e82bc80 Michael Hanselmann
568 723f4565 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.R_Generic):
569 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair resource.
570 723f4565 Michael Hanselmann

571 723f4565 Michael Hanselmann
  """
572 723f4565 Michael Hanselmann
  def PUT(self):
573 723f4565 Michael Hanselmann
    node_name = self.items[0]
574 723f4565 Michael Hanselmann
575 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
576 723f4565 Michael Hanselmann
    if not storage_type:
577 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
578 723f4565 Michael Hanselmann
                                " parameter")
579 723f4565 Michael Hanselmann
580 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
581 723f4565 Michael Hanselmann
    if not name:
582 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
583 723f4565 Michael Hanselmann
                                " parameter")
584 723f4565 Michael Hanselmann
585 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
586 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
587 723f4565 Michael Hanselmann
                                     name=name)
588 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
589 723f4565 Michael Hanselmann
590 723f4565 Michael Hanselmann
591 90e99856 Adeodato Simo
def _ParseCreateGroupRequest(data, dry_run):
592 90e99856 Adeodato Simo
  """Parses a request for creating a node group.
593 90e99856 Adeodato Simo

594 fabf1731 Iustin Pop
  @rtype: L{opcodes.OpGroupAdd}
595 90e99856 Adeodato Simo
  @return: Group creation opcode
596 90e99856 Adeodato Simo

597 90e99856 Adeodato Simo
  """
598 527fbde8 Michael Hanselmann
  override = {
599 527fbde8 Michael Hanselmann
    "dry_run": dry_run,
600 527fbde8 Michael Hanselmann
    }
601 90e99856 Adeodato Simo
602 527fbde8 Michael Hanselmann
  rename = {
603 527fbde8 Michael Hanselmann
    "name": "group_name",
604 527fbde8 Michael Hanselmann
    }
605 527fbde8 Michael Hanselmann
606 527fbde8 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupAdd, data, override,
607 527fbde8 Michael Hanselmann
                             rename=rename)
608 90e99856 Adeodato Simo
609 90e99856 Adeodato Simo
610 0897dc97 Adeodato Simo
class R_2_groups(baserlib.R_Generic):
611 0897dc97 Adeodato Simo
  """/2/groups resource.
612 0897dc97 Adeodato Simo

613 0897dc97 Adeodato Simo
  """
614 0897dc97 Adeodato Simo
  def GET(self):
615 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
616 0897dc97 Adeodato Simo

617 0897dc97 Adeodato Simo
    """
618 0897dc97 Adeodato Simo
    client = baserlib.GetClient()
619 0897dc97 Adeodato Simo
620 0897dc97 Adeodato Simo
    if self.useBulk():
621 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
622 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
623 0897dc97 Adeodato Simo
    else:
624 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
625 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
626 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
627 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
628 0897dc97 Adeodato Simo
629 0dbaa9ca Adeodato Simo
  def POST(self):
630 0dbaa9ca Adeodato Simo
    """Create a node group.
631 0dbaa9ca Adeodato Simo

632 0dbaa9ca Adeodato Simo
    @return: a job id
633 0dbaa9ca Adeodato Simo

634 0dbaa9ca Adeodato Simo
    """
635 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
636 90e99856 Adeodato Simo
    op = _ParseCreateGroupRequest(self.request_body, self.dryRun())
637 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
638 0dbaa9ca Adeodato Simo
639 0897dc97 Adeodato Simo
640 0897dc97 Adeodato Simo
class R_2_groups_name(baserlib.R_Generic):
641 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name] resource.
642 0897dc97 Adeodato Simo

643 0897dc97 Adeodato Simo
  """
644 0897dc97 Adeodato Simo
  def GET(self):
645 0897dc97 Adeodato Simo
    """Send information about a node group.
646 0897dc97 Adeodato Simo

647 0897dc97 Adeodato Simo
    """
648 0897dc97 Adeodato Simo
    group_name = self.items[0]
649 0897dc97 Adeodato Simo
    client = baserlib.GetClient()
650 0897dc97 Adeodato Simo
651 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
652 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
653 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
654 0897dc97 Adeodato Simo
655 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
656 0897dc97 Adeodato Simo
657 0dbaa9ca Adeodato Simo
  def DELETE(self):
658 0dbaa9ca Adeodato Simo
    """Delete a node group.
659 0dbaa9ca Adeodato Simo

660 0dbaa9ca Adeodato Simo
    """
661 4d1baa51 Iustin Pop
    op = opcodes.OpGroupRemove(group_name=self.items[0],
662 0dbaa9ca Adeodato Simo
                               dry_run=bool(self.dryRun()))
663 0dbaa9ca Adeodato Simo
664 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
665 0dbaa9ca Adeodato Simo
666 0dbaa9ca Adeodato Simo
667 f18fab7d Adeodato Simo
def _ParseModifyGroupRequest(name, data):
668 f18fab7d Adeodato Simo
  """Parses a request for modifying a node group.
669 f18fab7d Adeodato Simo

670 7cbf74f0 Iustin Pop
  @rtype: L{opcodes.OpGroupSetParams}
671 f18fab7d Adeodato Simo
  @return: Group modify opcode
672 f18fab7d Adeodato Simo

673 f18fab7d Adeodato Simo
  """
674 df340fae Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupSetParams, data, {
675 df340fae Michael Hanselmann
    "group_name": name,
676 df340fae Michael Hanselmann
    })
677 df340fae Michael Hanselmann
678 f18fab7d Adeodato Simo
679 f18fab7d Adeodato Simo
class R_2_groups_name_modify(baserlib.R_Generic):
680 f18fab7d Adeodato Simo
  """/2/groups/[group_name]/modify resource.
681 f18fab7d Adeodato Simo

682 f18fab7d Adeodato Simo
  """
683 f18fab7d Adeodato Simo
  def PUT(self):
684 f18fab7d Adeodato Simo
    """Changes some parameters of node group.
685 f18fab7d Adeodato Simo

686 f18fab7d Adeodato Simo
    @return: a job id
687 f18fab7d Adeodato Simo

688 f18fab7d Adeodato Simo
    """
689 f18fab7d Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
690 f18fab7d Adeodato Simo
691 f18fab7d Adeodato Simo
    op = _ParseModifyGroupRequest(self.items[0], self.request_body)
692 f18fab7d Adeodato Simo
693 f18fab7d Adeodato Simo
    return baserlib.SubmitJob([op])
694 f18fab7d Adeodato Simo
695 f18fab7d Adeodato Simo
696 0dbaa9ca Adeodato Simo
def _ParseRenameGroupRequest(name, data, dry_run):
697 0dbaa9ca Adeodato Simo
  """Parses a request for renaming a node group.
698 0dbaa9ca Adeodato Simo

699 0dbaa9ca Adeodato Simo
  @type name: string
700 0dbaa9ca Adeodato Simo
  @param name: name of the node group to rename
701 0dbaa9ca Adeodato Simo
  @type data: dict
702 0dbaa9ca Adeodato Simo
  @param data: the body received by the rename request
703 0dbaa9ca Adeodato Simo
  @type dry_run: bool
704 0dbaa9ca Adeodato Simo
  @param dry_run: whether to perform a dry run
705 0dbaa9ca Adeodato Simo

706 a8173e82 Iustin Pop
  @rtype: L{opcodes.OpGroupRename}
707 0dbaa9ca Adeodato Simo
  @return: Node group rename opcode
708 0dbaa9ca Adeodato Simo

709 0dbaa9ca Adeodato Simo
  """
710 8a08be3b Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupRename, data, {
711 8a08be3b Michael Hanselmann
    "group_name": name,
712 8a08be3b Michael Hanselmann
    "dry_run": dry_run,
713 8a08be3b Michael Hanselmann
    })
714 0dbaa9ca Adeodato Simo
715 0dbaa9ca Adeodato Simo
716 0dbaa9ca Adeodato Simo
class R_2_groups_name_rename(baserlib.R_Generic):
717 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/rename resource.
718 0dbaa9ca Adeodato Simo

719 0dbaa9ca Adeodato Simo
  """
720 0dbaa9ca Adeodato Simo
  def PUT(self):
721 0dbaa9ca Adeodato Simo
    """Changes the name of a node group.
722 0dbaa9ca Adeodato Simo

723 0dbaa9ca Adeodato Simo
    @return: a job id
724 0dbaa9ca Adeodato Simo

725 0dbaa9ca Adeodato Simo
    """
726 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
727 0dbaa9ca Adeodato Simo
    op = _ParseRenameGroupRequest(self.items[0], self.request_body,
728 0dbaa9ca Adeodato Simo
                                  self.dryRun())
729 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
730 0897dc97 Adeodato Simo
731 0897dc97 Adeodato Simo
732 4245446f Adeodato Simo
class R_2_groups_name_assign_nodes(baserlib.R_Generic):
733 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/assign-nodes resource.
734 4245446f Adeodato Simo

735 4245446f Adeodato Simo
  """
736 4245446f Adeodato Simo
  def PUT(self):
737 4245446f Adeodato Simo
    """Assigns nodes to a group.
738 4245446f Adeodato Simo

739 4245446f Adeodato Simo
    @return: a job id
740 4245446f Adeodato Simo

741 4245446f Adeodato Simo
    """
742 934704ae Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpGroupAssignNodes, self.request_body, {
743 4245446f Adeodato Simo
      "group_name": self.items[0],
744 4245446f Adeodato Simo
      "dry_run": self.dryRun(),
745 4245446f Adeodato Simo
      "force": self.useForce(),
746 4245446f Adeodato Simo
      })
747 4245446f Adeodato Simo
748 4245446f Adeodato Simo
    return baserlib.SubmitJob([op])
749 4245446f Adeodato Simo
750 4245446f Adeodato Simo
751 6395cebb Michael Hanselmann
def _ParseInstanceCreateRequestVersion1(data, dry_run):
752 6395cebb Michael Hanselmann
  """Parses an instance creation request version 1.
753 6395cebb Michael Hanselmann

754 e1530b10 Iustin Pop
  @rtype: L{opcodes.OpInstanceCreate}
755 6395cebb Michael Hanselmann
  @return: Instance creation opcode
756 6395cebb Michael Hanselmann

757 6395cebb Michael Hanselmann
  """
758 526a662a Michael Hanselmann
  override = {
759 526a662a Michael Hanselmann
    "dry_run": dry_run,
760 526a662a Michael Hanselmann
    }
761 6395cebb Michael Hanselmann
762 526a662a Michael Hanselmann
  rename = {
763 526a662a Michael Hanselmann
    "os": "os_type",
764 526a662a Michael Hanselmann
    "name": "instance_name",
765 526a662a Michael Hanselmann
    }
766 526a662a Michael Hanselmann
767 526a662a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceCreate, data, override,
768 526a662a Michael Hanselmann
                             rename=rename)
769 6395cebb Michael Hanselmann
770 6395cebb Michael Hanselmann
771 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
772 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
773 441e7cfd Oleksiy Mishchenko

774 441e7cfd Oleksiy Mishchenko
  """
775 441e7cfd Oleksiy Mishchenko
  def GET(self):
776 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
777 441e7cfd Oleksiy Mishchenko

778 441e7cfd Oleksiy Mishchenko
    """
779 59b4eeef Iustin Pop
    client = baserlib.GetClient()
780 441e7cfd Oleksiy Mishchenko
781 3d103742 Iustin Pop
    use_locking = self.useLocking()
782 3d103742 Iustin Pop
    if self.useBulk():
783 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
784 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
785 441e7cfd Oleksiy Mishchenko
    else:
786 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
787 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
788 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
789 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
790 441e7cfd Oleksiy Mishchenko
791 d975f482 Michael Hanselmann
  def POST(self):
792 d975f482 Michael Hanselmann
    """Create an instance.
793 d975f482 Michael Hanselmann

794 d975f482 Michael Hanselmann
    @return: a job id
795 d975f482 Michael Hanselmann

796 d975f482 Michael Hanselmann
    """
797 1c54156d Luca Bigliardi
    if not isinstance(self.request_body, dict):
798 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
799 d975f482 Michael Hanselmann
800 d975f482 Michael Hanselmann
    # Default to request data version 0
801 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
802 d975f482 Michael Hanselmann
803 d975f482 Michael Hanselmann
    if data_version == 0:
804 3fd7f652 Michael Hanselmann
      raise http.HttpBadRequest("Instance creation request version 0 is no"
805 3fd7f652 Michael Hanselmann
                                " longer supported")
806 6395cebb Michael Hanselmann
    elif data_version == 1:
807 4b163794 Michael Hanselmann
      data = self.request_body.copy()
808 4b163794 Michael Hanselmann
      # Remove "__version__"
809 4b163794 Michael Hanselmann
      data.pop(_REQ_DATA_VERSION, None)
810 4b163794 Michael Hanselmann
      op = _ParseInstanceCreateRequestVersion1(data, self.dryRun())
811 d975f482 Michael Hanselmann
    else:
812 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
813 12eff9b9 Michael Hanselmann
                                data_version)
814 d975f482 Michael Hanselmann
815 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
816 2f7635f4 Oleksiy Mishchenko
817 441e7cfd Oleksiy Mishchenko
818 4e5a68f8 Oleksiy Mishchenko
class R_2_instances_name(baserlib.R_Generic):
819 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name] resource.
820 028c6b76 Oleksiy Mishchenko

821 028c6b76 Oleksiy Mishchenko
  """
822 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
823 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
824 4e5a68f8 Oleksiy Mishchenko

825 4e5a68f8 Oleksiy Mishchenko
    """
826 59b4eeef Iustin Pop
    client = baserlib.GetClient()
827 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
828 e8ebbd2b Michael Hanselmann
829 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
830 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
831 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
832 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
833 4e5a68f8 Oleksiy Mishchenko
834 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
835 028c6b76 Oleksiy Mishchenko
836 6e99c5a0 Iustin Pop
  def DELETE(self):
837 6e99c5a0 Iustin Pop
    """Delete an instance.
838 6e99c5a0 Iustin Pop

839 6e99c5a0 Iustin Pop
    """
840 3cd2d4b1 Iustin Pop
    op = opcodes.OpInstanceRemove(instance_name=self.items[0],
841 6f59b964 Iustin Pop
                                  ignore_failures=False,
842 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
843 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
844 6e99c5a0 Iustin Pop
845 028c6b76 Oleksiy Mishchenko
846 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
847 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
848 d8260842 Michael Hanselmann

849 d8260842 Michael Hanselmann
  """
850 d8260842 Michael Hanselmann
  def GET(self):
851 d8260842 Michael Hanselmann
    """Request detailed instance information.
852 d8260842 Michael Hanselmann

853 d8260842 Michael Hanselmann
    """
854 d8260842 Michael Hanselmann
    instance_name = self.items[0]
855 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
856 d8260842 Michael Hanselmann
857 dc28c4e4 Iustin Pop
    op = opcodes.OpInstanceQueryData(instances=[instance_name],
858 d8260842 Michael Hanselmann
                                     static=static)
859 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
860 d8260842 Michael Hanselmann
861 d8260842 Michael Hanselmann
862 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
863 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
864 2276aa29 Oleksiy Mishchenko

865 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
866 2276aa29 Oleksiy Mishchenko

867 2276aa29 Oleksiy Mishchenko
  """
868 21f04e5e Oleksiy Mishchenko
  def POST(self):
869 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
870 2276aa29 Oleksiy Mishchenko

871 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
872 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
873 0c55c24b Oleksiy Mishchenko

874 2276aa29 Oleksiy Mishchenko
    """
875 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
876 d0c8c01d Iustin Pop
    reboot_type = self.queryargs.get("type",
877 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
878 d0c8c01d Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable("ignore_secondaries"))
879 90ab1a95 Iustin Pop
    op = opcodes.OpInstanceReboot(instance_name=instance_name,
880 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
881 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
882 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
883 2276aa29 Oleksiy Mishchenko
884 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
885 2276aa29 Oleksiy Mishchenko
886 2276aa29 Oleksiy Mishchenko
887 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
888 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
889 0c55c24b Oleksiy Mishchenko

890 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
891 0c55c24b Oleksiy Mishchenko

892 0c55c24b Oleksiy Mishchenko
  """
893 21f04e5e Oleksiy Mishchenko
  def PUT(self):
894 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
895 0c55c24b Oleksiy Mishchenko

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

899 0c55c24b Oleksiy Mishchenko
    """
900 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
901 d0c8c01d Iustin Pop
    force_startup = bool(self._checkIntVariable("force"))
902 d0c8c01d Iustin Pop
    no_remember = bool(self._checkIntVariable("no_remember"))
903 c873d91c Iustin Pop
    op = opcodes.OpInstanceStartup(instance_name=instance_name,
904 6f59b964 Iustin Pop
                                   force=force_startup,
905 2ba39b8f Iustin Pop
                                   dry_run=bool(self.dryRun()),
906 2ba39b8f Iustin Pop
                                   no_remember=no_remember)
907 0c55c24b Oleksiy Mishchenko
908 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
909 0c55c24b Oleksiy Mishchenko
910 0c55c24b Oleksiy Mishchenko
911 6aac5aef Iustin Pop
def _ParseShutdownInstanceRequest(name, data, dry_run, no_remember):
912 7fa310f6 René Nussbaumer
  """Parses a request for an instance shutdown.
913 7fa310f6 René Nussbaumer

914 7fa310f6 René Nussbaumer
  @rtype: L{opcodes.OpInstanceShutdown}
915 7fa310f6 René Nussbaumer
  @return: Instance shutdown opcode
916 7fa310f6 René Nussbaumer

917 7fa310f6 René Nussbaumer
  """
918 7fa310f6 René Nussbaumer
  return baserlib.FillOpcode(opcodes.OpInstanceShutdown, data, {
919 7fa310f6 René Nussbaumer
    "instance_name": name,
920 7fa310f6 René Nussbaumer
    "dry_run": dry_run,
921 6aac5aef Iustin Pop
    "no_remember": no_remember,
922 7fa310f6 René Nussbaumer
    })
923 7fa310f6 René Nussbaumer
924 7fa310f6 René Nussbaumer
925 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
926 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
927 0c55c24b Oleksiy Mishchenko

928 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
929 0c55c24b Oleksiy Mishchenko

930 0c55c24b Oleksiy Mishchenko
  """
931 21f04e5e Oleksiy Mishchenko
  def PUT(self):
932 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
933 0c55c24b Oleksiy Mishchenko

934 7fa310f6 René Nussbaumer
    @return: a job id
935 7fa310f6 René Nussbaumer

936 0c55c24b Oleksiy Mishchenko
    """
937 7fa310f6 René Nussbaumer
    baserlib.CheckType(self.request_body, dict, "Body contents")
938 7fa310f6 René Nussbaumer
939 d0c8c01d Iustin Pop
    no_remember = bool(self._checkIntVariable("no_remember"))
940 7fa310f6 René Nussbaumer
    op = _ParseShutdownInstanceRequest(self.items[0], self.request_body,
941 6aac5aef Iustin Pop
                                       bool(self.dryRun()), no_remember)
942 0c55c24b Oleksiy Mishchenko
943 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
944 0c55c24b Oleksiy Mishchenko
945 0c55c24b Oleksiy Mishchenko
946 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
947 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
948 c744425f Michael Hanselmann

949 c744425f Michael Hanselmann
  """
950 c744425f Michael Hanselmann
  if not isinstance(data, dict):
951 c744425f Michael Hanselmann
    raise http.HttpBadRequest("Invalid body contents, not a dictionary")
952 c744425f Michael Hanselmann
953 bd0807fe Guido Trotter
  ostype = baserlib.CheckParameter(data, "os", default=None)
954 c744425f Michael Hanselmann
  start = baserlib.CheckParameter(data, "start", exptype=bool,
955 c744425f Michael Hanselmann
                                  default=True)
956 c744425f Michael Hanselmann
  osparams = baserlib.CheckParameter(data, "osparams", default=None)
957 c744425f Michael Hanselmann
958 c744425f Michael Hanselmann
  ops = [
959 ee3e37a7 Iustin Pop
    opcodes.OpInstanceShutdown(instance_name=name),
960 5073fd8f Iustin Pop
    opcodes.OpInstanceReinstall(instance_name=name, os_type=ostype,
961 c744425f Michael Hanselmann
                                osparams=osparams),
962 c744425f Michael Hanselmann
    ]
963 c744425f Michael Hanselmann
964 c744425f Michael Hanselmann
  if start:
965 c873d91c Iustin Pop
    ops.append(opcodes.OpInstanceStartup(instance_name=name, force=False))
966 c744425f Michael Hanselmann
967 c744425f Michael Hanselmann
  return ops
968 c744425f Michael Hanselmann
969 c744425f Michael Hanselmann
970 e5b7c4ca Iustin Pop
class R_2_instances_name_reinstall(baserlib.R_Generic):
971 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
972 e5b7c4ca Iustin Pop

973 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
974 e5b7c4ca Iustin Pop

975 e5b7c4ca Iustin Pop
  """
976 e5b7c4ca Iustin Pop
  def POST(self):
977 e5b7c4ca Iustin Pop
    """Reinstall an instance.
978 e5b7c4ca Iustin Pop

979 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
980 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
981 e5b7c4ca Iustin Pop
    automatically.
982 e5b7c4ca Iustin Pop

983 e5b7c4ca Iustin Pop
    """
984 c744425f Michael Hanselmann
    if self.request_body:
985 c744425f Michael Hanselmann
      if self.queryargs:
986 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
987 c744425f Michael Hanselmann
988 c744425f Michael Hanselmann
      body = self.request_body
989 bd0807fe Guido Trotter
    elif self.queryargs:
990 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
991 c744425f Michael Hanselmann
      body = {
992 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
993 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
994 c744425f Michael Hanselmann
        }
995 bd0807fe Guido Trotter
    else:
996 bd0807fe Guido Trotter
      body = {}
997 c744425f Michael Hanselmann
998 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
999 c744425f Michael Hanselmann
1000 e5b7c4ca Iustin Pop
    return baserlib.SubmitJob(ops)
1001 e5b7c4ca Iustin Pop
1002 e5b7c4ca Iustin Pop
1003 d1c172de Michael Hanselmann
def _ParseInstanceReplaceDisksRequest(name, data):
1004 d1c172de Michael Hanselmann
  """Parses a request for an instance export.
1005 d1c172de Michael Hanselmann

1006 d1c172de Michael Hanselmann
  @rtype: L{opcodes.OpInstanceReplaceDisks}
1007 d1c172de Michael Hanselmann
  @return: Instance export opcode
1008 d1c172de Michael Hanselmann

1009 d1c172de Michael Hanselmann
  """
1010 d1c172de Michael Hanselmann
  override = {
1011 d1c172de Michael Hanselmann
    "instance_name": name,
1012 d1c172de Michael Hanselmann
    }
1013 d1c172de Michael Hanselmann
1014 d1c172de Michael Hanselmann
  # Parse disks
1015 d1c172de Michael Hanselmann
  try:
1016 d1c172de Michael Hanselmann
    raw_disks = data["disks"]
1017 d1c172de Michael Hanselmann
  except KeyError:
1018 d1c172de Michael Hanselmann
    pass
1019 d1c172de Michael Hanselmann
  else:
1020 d1c172de Michael Hanselmann
    if not ht.TListOf(ht.TInt)(raw_disks): # pylint: disable-msg=E1102
1021 d1c172de Michael Hanselmann
      # Backwards compatibility for strings of the format "1, 2, 3"
1022 d1c172de Michael Hanselmann
      try:
1023 d1c172de Michael Hanselmann
        data["disks"] = [int(part) for part in raw_disks.split(",")]
1024 d1c172de Michael Hanselmann
      except (TypeError, ValueError), err:
1025 d1c172de Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
1026 d1c172de Michael Hanselmann
1027 d1c172de Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceReplaceDisks, data, override)
1028 d1c172de Michael Hanselmann
1029 d1c172de Michael Hanselmann
1030 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
1031 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
1032 4c98b915 Michael Hanselmann

1033 4c98b915 Michael Hanselmann
  """
1034 4c98b915 Michael Hanselmann
  def POST(self):
1035 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1036 4c98b915 Michael Hanselmann

1037 4c98b915 Michael Hanselmann
    """
1038 d1c172de Michael Hanselmann
    op = _ParseInstanceReplaceDisksRequest(self.items[0], self.request_body)
1039 4c98b915 Michael Hanselmann
1040 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
1041 4c98b915 Michael Hanselmann
1042 4c98b915 Michael Hanselmann
1043 2197b66f René Nussbaumer
class R_2_instances_name_activate_disks(baserlib.R_Generic):
1044 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1045 2197b66f René Nussbaumer

1046 2197b66f René Nussbaumer
  """
1047 2197b66f René Nussbaumer
  def PUT(self):
1048 2197b66f René Nussbaumer
    """Activate disks for an instance.
1049 2197b66f René Nussbaumer

1050 2197b66f René Nussbaumer
    The URI might contain ignore_size to ignore current recorded size.
1051 2197b66f René Nussbaumer

1052 2197b66f René Nussbaumer
    """
1053 2197b66f René Nussbaumer
    instance_name = self.items[0]
1054 d0c8c01d Iustin Pop
    ignore_size = bool(self._checkIntVariable("ignore_size"))
1055 2197b66f René Nussbaumer
1056 83f5d475 Iustin Pop
    op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
1057 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
1058 2197b66f René Nussbaumer
1059 2197b66f René Nussbaumer
    return baserlib.SubmitJob([op])
1060 2197b66f René Nussbaumer
1061 2197b66f René Nussbaumer
1062 0a37de5f René Nussbaumer
class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
1063 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1064 0a37de5f René Nussbaumer

1065 0a37de5f René Nussbaumer
  """
1066 0a37de5f René Nussbaumer
  def PUT(self):
1067 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1068 0a37de5f René Nussbaumer

1069 0a37de5f René Nussbaumer
    """
1070 0a37de5f René Nussbaumer
    instance_name = self.items[0]
1071 0a37de5f René Nussbaumer
1072 e176281f Iustin Pop
    op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name)
1073 0a37de5f René Nussbaumer
1074 0a37de5f René Nussbaumer
    return baserlib.SubmitJob([op])
1075 0a37de5f René Nussbaumer
1076 0a37de5f René Nussbaumer
1077 ebeb600f Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.R_Generic):
1078 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1079 ebeb600f Michael Hanselmann

1080 ebeb600f Michael Hanselmann
  """
1081 ebeb600f Michael Hanselmann
  def PUT(self):
1082 ebeb600f Michael Hanselmann
    """Prepares an export for an instance.
1083 ebeb600f Michael Hanselmann

1084 ebeb600f Michael Hanselmann
    @return: a job id
1085 ebeb600f Michael Hanselmann

1086 ebeb600f Michael Hanselmann
    """
1087 ebeb600f Michael Hanselmann
    instance_name = self.items[0]
1088 ebeb600f Michael Hanselmann
    mode = self._checkStringVariable("mode")
1089 ebeb600f Michael Hanselmann
1090 71910715 Iustin Pop
    op = opcodes.OpBackupPrepare(instance_name=instance_name,
1091 ebeb600f Michael Hanselmann
                                 mode=mode)
1092 ebeb600f Michael Hanselmann
1093 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1094 ebeb600f Michael Hanselmann
1095 ebeb600f Michael Hanselmann
1096 ebeb600f Michael Hanselmann
def _ParseExportInstanceRequest(name, data):
1097 ebeb600f Michael Hanselmann
  """Parses a request for an instance export.
1098 ebeb600f Michael Hanselmann

1099 4ff922a2 Iustin Pop
  @rtype: L{opcodes.OpBackupExport}
1100 ebeb600f Michael Hanselmann
  @return: Instance export opcode
1101 ebeb600f Michael Hanselmann

1102 ebeb600f Michael Hanselmann
  """
1103 07ce3e70 Michael Hanselmann
  # Rename "destination" to "target_node"
1104 07ce3e70 Michael Hanselmann
  try:
1105 07ce3e70 Michael Hanselmann
    data["target_node"] = data.pop("destination")
1106 07ce3e70 Michael Hanselmann
  except KeyError:
1107 07ce3e70 Michael Hanselmann
    pass
1108 07ce3e70 Michael Hanselmann
1109 07ce3e70 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpBackupExport, data, {
1110 07ce3e70 Michael Hanselmann
    "instance_name": name,
1111 07ce3e70 Michael Hanselmann
    })
1112 ebeb600f Michael Hanselmann
1113 ebeb600f Michael Hanselmann
1114 ebeb600f Michael Hanselmann
class R_2_instances_name_export(baserlib.R_Generic):
1115 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1116 ebeb600f Michael Hanselmann

1117 ebeb600f Michael Hanselmann
  """
1118 ebeb600f Michael Hanselmann
  def PUT(self):
1119 ebeb600f Michael Hanselmann
    """Exports an instance.
1120 ebeb600f Michael Hanselmann

1121 ebeb600f Michael Hanselmann
    @return: a job id
1122 ebeb600f Michael Hanselmann

1123 ebeb600f Michael Hanselmann
    """
1124 ebeb600f Michael Hanselmann
    if not isinstance(self.request_body, dict):
1125 ebeb600f Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
1126 ebeb600f Michael Hanselmann
1127 ebeb600f Michael Hanselmann
    op = _ParseExportInstanceRequest(self.items[0], self.request_body)
1128 ebeb600f Michael Hanselmann
1129 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1130 ebeb600f Michael Hanselmann
1131 ebeb600f Michael Hanselmann
1132 5823e0d2 Michael Hanselmann
def _ParseMigrateInstanceRequest(name, data):
1133 5823e0d2 Michael Hanselmann
  """Parses a request for an instance migration.
1134 5823e0d2 Michael Hanselmann

1135 75c866c2 Iustin Pop
  @rtype: L{opcodes.OpInstanceMigrate}
1136 5823e0d2 Michael Hanselmann
  @return: Instance migration opcode
1137 5823e0d2 Michael Hanselmann

1138 5823e0d2 Michael Hanselmann
  """
1139 c1a27c9a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceMigrate, data, {
1140 c1a27c9a Michael Hanselmann
    "instance_name": name,
1141 c1a27c9a Michael Hanselmann
    })
1142 5823e0d2 Michael Hanselmann
1143 5823e0d2 Michael Hanselmann
1144 5823e0d2 Michael Hanselmann
class R_2_instances_name_migrate(baserlib.R_Generic):
1145 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1146 5823e0d2 Michael Hanselmann

1147 5823e0d2 Michael Hanselmann
  """
1148 5823e0d2 Michael Hanselmann
  def PUT(self):
1149 5823e0d2 Michael Hanselmann
    """Migrates an instance.
1150 5823e0d2 Michael Hanselmann

1151 5823e0d2 Michael Hanselmann
    @return: a job id
1152 5823e0d2 Michael Hanselmann

1153 5823e0d2 Michael Hanselmann
    """
1154 5823e0d2 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1155 5823e0d2 Michael Hanselmann
1156 5823e0d2 Michael Hanselmann
    op = _ParseMigrateInstanceRequest(self.items[0], self.request_body)
1157 5823e0d2 Michael Hanselmann
1158 5823e0d2 Michael Hanselmann
    return baserlib.SubmitJob([op])
1159 5823e0d2 Michael Hanselmann
1160 5823e0d2 Michael Hanselmann
1161 c0a146a1 Michael Hanselmann
class R_2_instances_name_failover(baserlib.R_Generic):
1162 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1163 c0a146a1 Michael Hanselmann

1164 c0a146a1 Michael Hanselmann
  """
1165 c0a146a1 Michael Hanselmann
  def PUT(self):
1166 c0a146a1 Michael Hanselmann
    """Does a failover of an instance.
1167 c0a146a1 Michael Hanselmann

1168 c0a146a1 Michael Hanselmann
    @return: a job id
1169 c0a146a1 Michael Hanselmann

1170 c0a146a1 Michael Hanselmann
    """
1171 c0a146a1 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1172 c0a146a1 Michael Hanselmann
1173 c0a146a1 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpInstanceFailover, self.request_body, {
1174 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1175 c0a146a1 Michael Hanselmann
      })
1176 c0a146a1 Michael Hanselmann
1177 c0a146a1 Michael Hanselmann
    return baserlib.SubmitJob([op])
1178 c0a146a1 Michael Hanselmann
1179 c0a146a1 Michael Hanselmann
1180 d56e7dc7 Michael Hanselmann
def _ParseRenameInstanceRequest(name, data):
1181 d56e7dc7 Michael Hanselmann
  """Parses a request for renaming an instance.
1182 d56e7dc7 Michael Hanselmann

1183 5659e2e2 Iustin Pop
  @rtype: L{opcodes.OpInstanceRename}
1184 d56e7dc7 Michael Hanselmann
  @return: Instance rename opcode
1185 d56e7dc7 Michael Hanselmann

1186 d56e7dc7 Michael Hanselmann
  """
1187 88bc199a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceRename, data, {
1188 88bc199a Michael Hanselmann
    "instance_name": name,
1189 88bc199a Michael Hanselmann
    })
1190 d56e7dc7 Michael Hanselmann
1191 d56e7dc7 Michael Hanselmann
1192 d56e7dc7 Michael Hanselmann
class R_2_instances_name_rename(baserlib.R_Generic):
1193 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1194 d56e7dc7 Michael Hanselmann

1195 d56e7dc7 Michael Hanselmann
  """
1196 d56e7dc7 Michael Hanselmann
  def PUT(self):
1197 d56e7dc7 Michael Hanselmann
    """Changes the name of an instance.
1198 d56e7dc7 Michael Hanselmann

1199 d56e7dc7 Michael Hanselmann
    @return: a job id
1200 d56e7dc7 Michael Hanselmann

1201 d56e7dc7 Michael Hanselmann
    """
1202 d56e7dc7 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1203 d56e7dc7 Michael Hanselmann
1204 d56e7dc7 Michael Hanselmann
    op = _ParseRenameInstanceRequest(self.items[0], self.request_body)
1205 d56e7dc7 Michael Hanselmann
1206 d56e7dc7 Michael Hanselmann
    return baserlib.SubmitJob([op])
1207 d56e7dc7 Michael Hanselmann
1208 d56e7dc7 Michael Hanselmann
1209 3882937a Michael Hanselmann
def _ParseModifyInstanceRequest(name, data):
1210 3882937a Michael Hanselmann
  """Parses a request for modifying an instance.
1211 3882937a Michael Hanselmann

1212 9a3cc7ae Iustin Pop
  @rtype: L{opcodes.OpInstanceSetParams}
1213 3882937a Michael Hanselmann
  @return: Instance modify opcode
1214 3882937a Michael Hanselmann

1215 3882937a Michael Hanselmann
  """
1216 ee5549c7 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceSetParams, data, {
1217 ee5549c7 Michael Hanselmann
    "instance_name": name,
1218 ee5549c7 Michael Hanselmann
    })
1219 3882937a Michael Hanselmann
1220 3882937a Michael Hanselmann
1221 3882937a Michael Hanselmann
class R_2_instances_name_modify(baserlib.R_Generic):
1222 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1223 3882937a Michael Hanselmann

1224 3882937a Michael Hanselmann
  """
1225 3882937a Michael Hanselmann
  def PUT(self):
1226 3882937a Michael Hanselmann
    """Changes some parameters of an instance.
1227 3882937a Michael Hanselmann

1228 3882937a Michael Hanselmann
    @return: a job id
1229 3882937a Michael Hanselmann

1230 3882937a Michael Hanselmann
    """
1231 3882937a Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1232 3882937a Michael Hanselmann
1233 3882937a Michael Hanselmann
    op = _ParseModifyInstanceRequest(self.items[0], self.request_body)
1234 3882937a Michael Hanselmann
1235 3882937a Michael Hanselmann
    return baserlib.SubmitJob([op])
1236 3882937a Michael Hanselmann
1237 3882937a Michael Hanselmann
1238 e23881ed Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.R_Generic):
1239 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1240 e23881ed Michael Hanselmann

1241 e23881ed Michael Hanselmann
  """
1242 e23881ed Michael Hanselmann
  def POST(self):
1243 e23881ed Michael Hanselmann
    """Increases the size of an instance disk.
1244 e23881ed Michael Hanselmann

1245 e23881ed Michael Hanselmann
    @return: a job id
1246 e23881ed Michael Hanselmann

1247 e23881ed Michael Hanselmann
    """
1248 60472d29 Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpInstanceGrowDisk, self.request_body, {
1249 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1250 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1251 e23881ed Michael Hanselmann
      })
1252 e23881ed Michael Hanselmann
1253 e23881ed Michael Hanselmann
    return baserlib.SubmitJob([op])
1254 e23881ed Michael Hanselmann
1255 e23881ed Michael Hanselmann
1256 b82d4c5e Michael Hanselmann
class R_2_instances_name_console(baserlib.R_Generic):
1257 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1258 b82d4c5e Michael Hanselmann

1259 b82d4c5e Michael Hanselmann
  """
1260 b82d4c5e Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1261 b82d4c5e Michael Hanselmann
1262 b82d4c5e Michael Hanselmann
  def GET(self):
1263 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1264 b82d4c5e Michael Hanselmann

1265 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1266 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1267 b82d4c5e Michael Hanselmann

1268 b82d4c5e Michael Hanselmann
    """
1269 b82d4c5e Michael Hanselmann
    client = baserlib.GetClient()
1270 b82d4c5e Michael Hanselmann
1271 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1272 b82d4c5e Michael Hanselmann
1273 b82d4c5e Michael Hanselmann
    if console is None:
1274 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1275 b82d4c5e Michael Hanselmann
1276 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1277 b82d4c5e Michael Hanselmann
    return console
1278 b82d4c5e Michael Hanselmann
1279 b82d4c5e Michael Hanselmann
1280 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1281 208a6cff Michael Hanselmann
  """
1282 208a6cff Michael Hanselmann

1283 208a6cff Michael Hanselmann
  """
1284 208a6cff Michael Hanselmann
  try:
1285 208a6cff Michael Hanselmann
    fields = args["fields"]
1286 208a6cff Michael Hanselmann
  except KeyError:
1287 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1288 208a6cff Michael Hanselmann
1289 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1290 208a6cff Michael Hanselmann
1291 208a6cff Michael Hanselmann
1292 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1293 208a6cff Michael Hanselmann
  """
1294 208a6cff Michael Hanselmann

1295 208a6cff Michael Hanselmann
  """
1296 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1297 208a6cff Michael Hanselmann
1298 208a6cff Michael Hanselmann
1299 208a6cff Michael Hanselmann
class R_2_query(baserlib.R_Generic):
1300 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1301 208a6cff Michael Hanselmann

1302 208a6cff Michael Hanselmann
  """
1303 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1304 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1305 208a6cff Michael Hanselmann
1306 208a6cff Michael Hanselmann
  def _Query(self, fields, filter_):
1307 208a6cff Michael Hanselmann
    return baserlib.GetClient().Query(self.items[0], fields, filter_).ToDict()
1308 208a6cff Michael Hanselmann
1309 208a6cff Michael Hanselmann
  def GET(self):
1310 208a6cff Michael Hanselmann
    """Returns resource information.
1311 208a6cff Michael Hanselmann

1312 208a6cff Michael Hanselmann
    @return: Query result, see L{objects.QueryResponse}
1313 208a6cff Michael Hanselmann

1314 208a6cff Michael Hanselmann
    """
1315 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1316 208a6cff Michael Hanselmann
1317 208a6cff Michael Hanselmann
  def PUT(self):
1318 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1319 208a6cff Michael Hanselmann

1320 208a6cff Michael Hanselmann
    @return: Query result, see L{objects.QueryResponse}
1321 208a6cff Michael Hanselmann

1322 208a6cff Michael Hanselmann
    """
1323 208a6cff Michael Hanselmann
    body = self.request_body
1324 208a6cff Michael Hanselmann
1325 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1326 208a6cff Michael Hanselmann
1327 208a6cff Michael Hanselmann
    try:
1328 208a6cff Michael Hanselmann
      fields = body["fields"]
1329 208a6cff Michael Hanselmann
    except KeyError:
1330 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1331 208a6cff Michael Hanselmann
1332 208a6cff Michael Hanselmann
    return self._Query(fields, self.request_body.get("filter", None))
1333 208a6cff Michael Hanselmann
1334 208a6cff Michael Hanselmann
1335 208a6cff Michael Hanselmann
class R_2_query_fields(baserlib.R_Generic):
1336 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1337 208a6cff Michael Hanselmann

1338 208a6cff Michael Hanselmann
  """
1339 208a6cff Michael Hanselmann
  def GET(self):
1340 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1341 208a6cff Michael Hanselmann

1342 208a6cff Michael Hanselmann
    @return: List of serialized L{objects.QueryFieldDefinition}
1343 208a6cff Michael Hanselmann

1344 208a6cff Michael Hanselmann
    """
1345 208a6cff Michael Hanselmann
    try:
1346 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1347 208a6cff Michael Hanselmann
    except KeyError:
1348 208a6cff Michael Hanselmann
      fields = None
1349 208a6cff Michael Hanselmann
    else:
1350 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1351 208a6cff Michael Hanselmann
1352 208a6cff Michael Hanselmann
    return baserlib.GetClient().QueryFields(self.items[0], fields).ToDict()
1353 208a6cff Michael Hanselmann
1354 208a6cff Michael Hanselmann
1355 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
1356 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1357 441e7cfd Oleksiy Mishchenko

1358 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1359 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1360 441e7cfd Oleksiy Mishchenko

1361 441e7cfd Oleksiy Mishchenko
  """
1362 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1363 18cb43a2 Oleksiy Mishchenko
1364 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
1365 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1366 18cb43a2 Oleksiy Mishchenko

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

1369 18cb43a2 Oleksiy Mishchenko
    """
1370 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
1371 18cb43a2 Oleksiy Mishchenko
1372 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1373 5313eed7 Michael Hanselmann
      self.name = None
1374 18cb43a2 Oleksiy Mishchenko
    else:
1375 5313eed7 Michael Hanselmann
      self.name = items[0]
1376 441e7cfd Oleksiy Mishchenko
1377 441e7cfd Oleksiy Mishchenko
  def GET(self):
1378 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1379 441e7cfd Oleksiy Mishchenko

1380 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1381 441e7cfd Oleksiy Mishchenko

1382 441e7cfd Oleksiy Mishchenko
    """
1383 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1384 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
1385 441e7cfd Oleksiy Mishchenko
1386 21f04e5e Oleksiy Mishchenko
  def PUT(self):
1387 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1388 441e7cfd Oleksiy Mishchenko

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

1392 441e7cfd Oleksiy Mishchenko
    """
1393 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1394 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1395 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
1396 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
1397 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
1398 d0c8c01d Iustin Pop
                              self.queryargs["tag"], name=self.name,
1399 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
1400 15fd9fd5 Oleksiy Mishchenko
1401 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
1402 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1403 15fd9fd5 Oleksiy Mishchenko

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

1408 15fd9fd5 Oleksiy Mishchenko
    """
1409 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1410 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1411 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
1412 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
1413 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
1414 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
1415 d0c8c01d Iustin Pop
                                 self.queryargs["tag"],
1416 6f59b964 Iustin Pop
                                 name=self.name,
1417 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
1418 18cb43a2 Oleksiy Mishchenko
1419 18cb43a2 Oleksiy Mishchenko
1420 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1421 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1422 18cb43a2 Oleksiy Mishchenko

1423 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1424 18cb43a2 Oleksiy Mishchenko

1425 18cb43a2 Oleksiy Mishchenko
  """
1426 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1427 18cb43a2 Oleksiy Mishchenko
1428 18cb43a2 Oleksiy Mishchenko
1429 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1430 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1431 18cb43a2 Oleksiy Mishchenko

1432 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1433 18cb43a2 Oleksiy Mishchenko

1434 18cb43a2 Oleksiy Mishchenko
  """
1435 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1436 18cb43a2 Oleksiy Mishchenko
1437 18cb43a2 Oleksiy Mishchenko
1438 414ebaf1 Michael Hanselmann
class R_2_groups_name_tags(_R_Tags):
1439 414ebaf1 Michael Hanselmann
  """ /2/groups/[group_name]/tags resource.
1440 414ebaf1 Michael Hanselmann

1441 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1442 414ebaf1 Michael Hanselmann

1443 414ebaf1 Michael Hanselmann
  """
1444 414ebaf1 Michael Hanselmann
  TAG_LEVEL = constants.TAG_NODEGROUP
1445 414ebaf1 Michael Hanselmann
1446 414ebaf1 Michael Hanselmann
1447 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1448 b58a4d16 Michael Hanselmann
  """ /2/tags resource.
1449 18cb43a2 Oleksiy Mishchenko

1450 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1451 18cb43a2 Oleksiy Mishchenko

1452 18cb43a2 Oleksiy Mishchenko
  """
1453 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER