Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 370f2042

History | View | Annotate | Download (37.5 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 b459a848 Andrea Spadaccini
# pylint: disable=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 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
152 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
153 4e5a68f8 Oleksiy Mishchenko

154 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
155 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
156 4e5a68f8 Oleksiy Mishchenko

157 4e5a68f8 Oleksiy Mishchenko
  """
158 7e950d31 Iustin Pop
  @staticmethod
159 7e950d31 Iustin Pop
  def GET():
160 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
161 4e5a68f8 Oleksiy Mishchenko

162 4e5a68f8 Oleksiy Mishchenko
    """
163 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
164 4e5a68f8 Oleksiy Mishchenko
165 4e5a68f8 Oleksiy Mishchenko
166 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
167 b58a4d16 Michael Hanselmann
  """/2/info resource.
168 4e5a68f8 Oleksiy Mishchenko

169 4e5a68f8 Oleksiy Mishchenko
  """
170 7e950d31 Iustin Pop
  @staticmethod
171 7e950d31 Iustin Pop
  def GET():
172 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
173 4e5a68f8 Oleksiy Mishchenko

174 4e5a68f8 Oleksiy Mishchenko
    """
175 59b4eeef Iustin Pop
    client = baserlib.GetClient()
176 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
177 4e5a68f8 Oleksiy Mishchenko
178 4e5a68f8 Oleksiy Mishchenko
179 7eac4a4d Michael Hanselmann
class R_2_features(baserlib.R_Generic):
180 7eac4a4d Michael Hanselmann
  """/2/features resource.
181 7eac4a4d Michael Hanselmann

182 7eac4a4d Michael Hanselmann
  """
183 7eac4a4d Michael Hanselmann
  @staticmethod
184 7eac4a4d Michael Hanselmann
  def GET():
185 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
186 7eac4a4d Michael Hanselmann

187 7eac4a4d Michael Hanselmann
    """
188 b4fcee5b Michael Hanselmann
    return list(ALL_FEATURES)
189 7eac4a4d Michael Hanselmann
190 7eac4a4d Michael Hanselmann
191 4e5a68f8 Oleksiy Mishchenko
class R_2_os(baserlib.R_Generic):
192 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
193 4e5a68f8 Oleksiy Mishchenko

194 4e5a68f8 Oleksiy Mishchenko
  """
195 7e950d31 Iustin Pop
  @staticmethod
196 7e950d31 Iustin Pop
  def GET():
197 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
198 4e5a68f8 Oleksiy Mishchenko

199 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
200 4e5a68f8 Oleksiy Mishchenko

201 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
202 4e5a68f8 Oleksiy Mishchenko

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

224 508e9b20 Michael Hanselmann
  """
225 7e950d31 Iustin Pop
  @staticmethod
226 7e950d31 Iustin Pop
  def PUT():
227 508e9b20 Michael Hanselmann
    """Redistribute configuration to all nodes.
228 508e9b20 Michael Hanselmann

229 508e9b20 Michael Hanselmann
    """
230 d1240007 Iustin Pop
    return baserlib.SubmitJob([opcodes.OpClusterRedistConf()])
231 508e9b20 Michael Hanselmann
232 508e9b20 Michael Hanselmann
233 62e999a5 Michael Hanselmann
class R_2_cluster_modify(baserlib.R_Generic):
234 62e999a5 Michael Hanselmann
  """/2/modify resource.
235 62e999a5 Michael Hanselmann

236 62e999a5 Michael Hanselmann
  """
237 62e999a5 Michael Hanselmann
  def PUT(self):
238 62e999a5 Michael Hanselmann
    """Modifies cluster parameters.
239 62e999a5 Michael Hanselmann

240 62e999a5 Michael Hanselmann
    @return: a job id
241 62e999a5 Michael Hanselmann

242 62e999a5 Michael Hanselmann
    """
243 a6682fdc Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpClusterSetParams, self.request_body,
244 62e999a5 Michael Hanselmann
                             None)
245 62e999a5 Michael Hanselmann
246 62e999a5 Michael Hanselmann
    return baserlib.SubmitJob([op])
247 62e999a5 Michael Hanselmann
248 62e999a5 Michael Hanselmann
249 10b207d4 Oleksiy Mishchenko
class R_2_jobs(baserlib.R_Generic):
250 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
251 10b207d4 Oleksiy Mishchenko

252 10b207d4 Oleksiy Mishchenko
  """
253 e987f166 Michael Hanselmann
  def GET(self):
254 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
255 10b207d4 Oleksiy Mishchenko

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

258 10b207d4 Oleksiy Mishchenko
    """
259 e987f166 Michael Hanselmann
    client = baserlib.GetClient()
260 e987f166 Michael Hanselmann
261 e987f166 Michael Hanselmann
    if self.useBulk():
262 bd7b2070 Michael Hanselmann
      bulkdata = client.QueryJobs(None, J_FIELDS_BULK)
263 bd7b2070 Michael Hanselmann
      return baserlib.MapBulkFields(bulkdata, J_FIELDS_BULK)
264 e987f166 Michael Hanselmann
    else:
265 e987f166 Michael Hanselmann
      jobdata = map(compat.fst, client.QueryJobs(None, ["id"]))
266 e987f166 Michael Hanselmann
      return baserlib.BuildUriList(jobdata, "/2/jobs/%s",
267 e987f166 Michael Hanselmann
                                   uri_fields=("id", "uri"))
268 10b207d4 Oleksiy Mishchenko
269 10b207d4 Oleksiy Mishchenko
270 10b207d4 Oleksiy Mishchenko
class R_2_jobs_id(baserlib.R_Generic):
271 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
272 10b207d4 Oleksiy Mishchenko

273 10b207d4 Oleksiy Mishchenko
  """
274 10b207d4 Oleksiy Mishchenko
  def GET(self):
275 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
276 10b207d4 Oleksiy Mishchenko

277 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
278 c41eea6e Iustin Pop
        The result includes:
279 c41eea6e Iustin Pop
            - id: job ID as a number
280 c41eea6e Iustin Pop
            - status: current job status as a string
281 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
282 c41eea6e Iustin Pop
              opcodes in the job
283 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
284 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
285 38206f3c Iustin Pop

286 10b207d4 Oleksiy Mishchenko
    """
287 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
288 e987f166 Michael Hanselmann
    result = baserlib.GetClient().QueryJobs([job_id, ], J_FIELDS)[0]
289 ee69c97f Iustin Pop
    if result is None:
290 ee69c97f Iustin Pop
      raise http.HttpNotFound()
291 e987f166 Michael Hanselmann
    return baserlib.MapFields(J_FIELDS, result)
292 10b207d4 Oleksiy Mishchenko
293 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
294 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
295 c7f5f338 Oleksiy Mishchenko

296 c7f5f338 Oleksiy Mishchenko
    """
297 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
298 59b4eeef Iustin Pop
    result = baserlib.GetClient().CancelJob(job_id)
299 c7f5f338 Oleksiy Mishchenko
    return result
300 c7f5f338 Oleksiy Mishchenko
301 10b207d4 Oleksiy Mishchenko
302 793a8f7c Michael Hanselmann
class R_2_jobs_id_wait(baserlib.R_Generic):
303 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
304 793a8f7c Michael Hanselmann

305 793a8f7c Michael Hanselmann
  """
306 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
307 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
308 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
309 793a8f7c Michael Hanselmann
310 793a8f7c Michael Hanselmann
  def GET(self):
311 793a8f7c Michael Hanselmann
    """Waits for job changes.
312 793a8f7c Michael Hanselmann

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

354 10b207d4 Oleksiy Mishchenko
  """
355 10b207d4 Oleksiy Mishchenko
  def GET(self):
356 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
357 38206f3c Iustin Pop

358 10b207d4 Oleksiy Mishchenko
    """
359 59b4eeef Iustin Pop
    client = baserlib.GetClient()
360 38206f3c Iustin Pop
361 3d103742 Iustin Pop
    if self.useBulk():
362 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
363 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
364 9031ee8e Iustin Pop
    else:
365 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
366 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
367 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
368 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
369 441e7cfd Oleksiy Mishchenko
370 441e7cfd Oleksiy Mishchenko
371 4e5a68f8 Oleksiy Mishchenko
class R_2_nodes_name(baserlib.R_Generic):
372 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name] resource.
373 028c6b76 Oleksiy Mishchenko

374 028c6b76 Oleksiy Mishchenko
  """
375 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
376 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
377 4e5a68f8 Oleksiy Mishchenko

378 4e5a68f8 Oleksiy Mishchenko
    """
379 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
380 59b4eeef Iustin Pop
    client = baserlib.GetClient()
381 e8ebbd2b Michael Hanselmann
382 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
383 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
384 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
385 4e5a68f8 Oleksiy Mishchenko
386 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
387 028c6b76 Oleksiy Mishchenko
388 028c6b76 Oleksiy Mishchenko
389 64dae8fc Michael Hanselmann
class R_2_nodes_name_role(baserlib.R_Generic):
390 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
391 64dae8fc Michael Hanselmann

392 64dae8fc Michael Hanselmann
  """
393 64dae8fc Michael Hanselmann
  def GET(self):
394 64dae8fc Michael Hanselmann
    """Returns the current node role.
395 64dae8fc Michael Hanselmann

396 64dae8fc Michael Hanselmann
    @return: Node role
397 64dae8fc Michael Hanselmann

398 64dae8fc Michael Hanselmann
    """
399 64dae8fc Michael Hanselmann
    node_name = self.items[0]
400 64dae8fc Michael Hanselmann
    client = baserlib.GetClient()
401 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
402 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
403 64dae8fc Michael Hanselmann
404 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
405 64dae8fc Michael Hanselmann
406 64dae8fc Michael Hanselmann
  def PUT(self):
407 64dae8fc Michael Hanselmann
    """Sets the node role.
408 64dae8fc Michael Hanselmann

409 64dae8fc Michael Hanselmann
    @return: a job id
410 64dae8fc Michael Hanselmann

411 64dae8fc Michael Hanselmann
    """
412 627ad739 Michael Hanselmann
    if not isinstance(self.request_body, basestring):
413 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a string")
414 64dae8fc Michael Hanselmann
415 64dae8fc Michael Hanselmann
    node_name = self.items[0]
416 627ad739 Michael Hanselmann
    role = self.request_body
417 64dae8fc Michael Hanselmann
418 8de8e68d Michael Hanselmann
    auto_promote = bool(self._checkIntVariable("auto-promote"))
419 8de8e68d Michael Hanselmann
420 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
421 64dae8fc Michael Hanselmann
      candidate = False
422 64dae8fc Michael Hanselmann
      offline = False
423 64dae8fc Michael Hanselmann
      drained = False
424 64dae8fc Michael Hanselmann
425 64dae8fc Michael Hanselmann
    elif role == _NR_MASTER_CANDIATE:
426 64dae8fc Michael Hanselmann
      candidate = True
427 64dae8fc Michael Hanselmann
      offline = drained = None
428 64dae8fc Michael Hanselmann
429 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
430 64dae8fc Michael Hanselmann
      drained = True
431 64dae8fc Michael Hanselmann
      candidate = offline = None
432 64dae8fc Michael Hanselmann
433 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
434 64dae8fc Michael Hanselmann
      offline = True
435 64dae8fc Michael Hanselmann
      candidate = drained = None
436 64dae8fc Michael Hanselmann
437 64dae8fc Michael Hanselmann
    else:
438 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
439 64dae8fc Michael Hanselmann
440 f13973c4 Iustin Pop
    op = opcodes.OpNodeSetParams(node_name=node_name,
441 64dae8fc Michael Hanselmann
                                 master_candidate=candidate,
442 64dae8fc Michael Hanselmann
                                 offline=offline,
443 64dae8fc Michael Hanselmann
                                 drained=drained,
444 8de8e68d Michael Hanselmann
                                 auto_promote=auto_promote,
445 64dae8fc Michael Hanselmann
                                 force=bool(self.useForce()))
446 64dae8fc Michael Hanselmann
447 64dae8fc Michael Hanselmann
    return baserlib.SubmitJob([op])
448 64dae8fc Michael Hanselmann
449 64dae8fc Michael Hanselmann
450 73452f12 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.R_Generic):
451 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
452 73452f12 Michael Hanselmann

453 73452f12 Michael Hanselmann
  """
454 73452f12 Michael Hanselmann
  def POST(self):
455 de40437a Michael Hanselmann
    """Evacuate all instances off a node.
456 73452f12 Michael Hanselmann

457 73452f12 Michael Hanselmann
    """
458 de40437a Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeEvacuate, self.request_body, {
459 de40437a Michael Hanselmann
      "node_name": self.items[0],
460 de40437a Michael Hanselmann
      "dry_run": self.dryRun(),
461 de40437a Michael Hanselmann
      })
462 941b9309 Iustin Pop
463 de40437a Michael Hanselmann
    return baserlib.SubmitJob([op])
464 73452f12 Michael Hanselmann
465 73452f12 Michael Hanselmann
466 1c482bab Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.R_Generic):
467 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
468 1c482bab Michael Hanselmann

469 1c482bab Michael Hanselmann
  """
470 1c482bab Michael Hanselmann
  def POST(self):
471 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
472 1c482bab Michael Hanselmann

473 1c482bab Michael Hanselmann
    """
474 1c482bab Michael Hanselmann
    node_name = self.items[0]
475 1c482bab Michael Hanselmann
476 b7a1c816 Michael Hanselmann
    if self.queryargs:
477 b7a1c816 Michael Hanselmann
      # Support old-style requests
478 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs and "mode" in self.queryargs:
479 b7a1c816 Michael Hanselmann
        raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
480 b7a1c816 Michael Hanselmann
                                  " be passed")
481 b7a1c816 Michael Hanselmann
482 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs:
483 b7a1c816 Michael Hanselmann
        if self._checkIntVariable("live", default=1):
484 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_LIVE
485 b7a1c816 Michael Hanselmann
        else:
486 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_NONLIVE
487 52194140 Iustin Pop
      else:
488 b7a1c816 Michael Hanselmann
        mode = self._checkStringVariable("mode", default=None)
489 b7a1c816 Michael Hanselmann
490 b7a1c816 Michael Hanselmann
      data = {
491 b7a1c816 Michael Hanselmann
        "mode": mode,
492 b7a1c816 Michael Hanselmann
        }
493 52194140 Iustin Pop
    else:
494 b7a1c816 Michael Hanselmann
      data = self.request_body
495 52194140 Iustin Pop
496 b7a1c816 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeMigrate, data, {
497 b7a1c816 Michael Hanselmann
      "node_name": node_name,
498 b7a1c816 Michael Hanselmann
      })
499 1c482bab Michael Hanselmann
500 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
501 1c482bab Michael Hanselmann
502 1c482bab Michael Hanselmann
503 94497dd1 Michael Hanselmann
class R_2_nodes_name_modify(baserlib.R_Generic):
504 94497dd1 Michael Hanselmann
  """/2/nodes/[node_name]/modify resource.
505 94497dd1 Michael Hanselmann

506 94497dd1 Michael Hanselmann
  """
507 94497dd1 Michael Hanselmann
  def POST(self):
508 94497dd1 Michael Hanselmann
    """Changes parameters of a node.
509 94497dd1 Michael Hanselmann

510 94497dd1 Michael Hanselmann
    @return: a job id
511 94497dd1 Michael Hanselmann

512 94497dd1 Michael Hanselmann
    """
513 94497dd1 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
514 94497dd1 Michael Hanselmann
515 94497dd1 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeSetParams, self.request_body, {
516 370f2042 Guido Trotter
      "node_name": self.items[0],
517 94497dd1 Michael Hanselmann
      })
518 94497dd1 Michael Hanselmann
519 94497dd1 Michael Hanselmann
    return baserlib.SubmitJob([op])
520 94497dd1 Michael Hanselmann
521 94497dd1 Michael Hanselmann
522 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
523 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
524 7a95a954 Michael Hanselmann

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

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

581 723f4565 Michael Hanselmann
  """
582 723f4565 Michael Hanselmann
  def PUT(self):
583 723f4565 Michael Hanselmann
    node_name = self.items[0]
584 723f4565 Michael Hanselmann
585 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
586 723f4565 Michael Hanselmann
    if not storage_type:
587 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
588 723f4565 Michael Hanselmann
                                " parameter")
589 723f4565 Michael Hanselmann
590 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
591 723f4565 Michael Hanselmann
    if not name:
592 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
593 723f4565 Michael Hanselmann
                                " parameter")
594 723f4565 Michael Hanselmann
595 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
596 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
597 723f4565 Michael Hanselmann
                                     name=name)
598 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
599 723f4565 Michael Hanselmann
600 723f4565 Michael Hanselmann
601 90e99856 Adeodato Simo
def _ParseCreateGroupRequest(data, dry_run):
602 90e99856 Adeodato Simo
  """Parses a request for creating a node group.
603 90e99856 Adeodato Simo

604 fabf1731 Iustin Pop
  @rtype: L{opcodes.OpGroupAdd}
605 90e99856 Adeodato Simo
  @return: Group creation opcode
606 90e99856 Adeodato Simo

607 90e99856 Adeodato Simo
  """
608 527fbde8 Michael Hanselmann
  override = {
609 527fbde8 Michael Hanselmann
    "dry_run": dry_run,
610 527fbde8 Michael Hanselmann
    }
611 90e99856 Adeodato Simo
612 527fbde8 Michael Hanselmann
  rename = {
613 527fbde8 Michael Hanselmann
    "name": "group_name",
614 527fbde8 Michael Hanselmann
    }
615 527fbde8 Michael Hanselmann
616 527fbde8 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupAdd, data, override,
617 527fbde8 Michael Hanselmann
                             rename=rename)
618 90e99856 Adeodato Simo
619 90e99856 Adeodato Simo
620 0897dc97 Adeodato Simo
class R_2_groups(baserlib.R_Generic):
621 0897dc97 Adeodato Simo
  """/2/groups resource.
622 0897dc97 Adeodato Simo

623 0897dc97 Adeodato Simo
  """
624 0897dc97 Adeodato Simo
  def GET(self):
625 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
626 0897dc97 Adeodato Simo

627 0897dc97 Adeodato Simo
    """
628 0897dc97 Adeodato Simo
    client = baserlib.GetClient()
629 0897dc97 Adeodato Simo
630 0897dc97 Adeodato Simo
    if self.useBulk():
631 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
632 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
633 0897dc97 Adeodato Simo
    else:
634 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
635 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
636 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
637 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
638 0897dc97 Adeodato Simo
639 0dbaa9ca Adeodato Simo
  def POST(self):
640 0dbaa9ca Adeodato Simo
    """Create a node group.
641 0dbaa9ca Adeodato Simo

642 0dbaa9ca Adeodato Simo
    @return: a job id
643 0dbaa9ca Adeodato Simo

644 0dbaa9ca Adeodato Simo
    """
645 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
646 90e99856 Adeodato Simo
    op = _ParseCreateGroupRequest(self.request_body, self.dryRun())
647 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
648 0dbaa9ca Adeodato Simo
649 0897dc97 Adeodato Simo
650 0897dc97 Adeodato Simo
class R_2_groups_name(baserlib.R_Generic):
651 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name] resource.
652 0897dc97 Adeodato Simo

653 0897dc97 Adeodato Simo
  """
654 0897dc97 Adeodato Simo
  def GET(self):
655 0897dc97 Adeodato Simo
    """Send information about a node group.
656 0897dc97 Adeodato Simo

657 0897dc97 Adeodato Simo
    """
658 0897dc97 Adeodato Simo
    group_name = self.items[0]
659 0897dc97 Adeodato Simo
    client = baserlib.GetClient()
660 0897dc97 Adeodato Simo
661 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
662 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
663 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
664 0897dc97 Adeodato Simo
665 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
666 0897dc97 Adeodato Simo
667 0dbaa9ca Adeodato Simo
  def DELETE(self):
668 0dbaa9ca Adeodato Simo
    """Delete a node group.
669 0dbaa9ca Adeodato Simo

670 0dbaa9ca Adeodato Simo
    """
671 4d1baa51 Iustin Pop
    op = opcodes.OpGroupRemove(group_name=self.items[0],
672 0dbaa9ca Adeodato Simo
                               dry_run=bool(self.dryRun()))
673 0dbaa9ca Adeodato Simo
674 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
675 0dbaa9ca Adeodato Simo
676 0dbaa9ca Adeodato Simo
677 f18fab7d Adeodato Simo
def _ParseModifyGroupRequest(name, data):
678 f18fab7d Adeodato Simo
  """Parses a request for modifying a node group.
679 f18fab7d Adeodato Simo

680 7cbf74f0 Iustin Pop
  @rtype: L{opcodes.OpGroupSetParams}
681 f18fab7d Adeodato Simo
  @return: Group modify opcode
682 f18fab7d Adeodato Simo

683 f18fab7d Adeodato Simo
  """
684 df340fae Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupSetParams, data, {
685 df340fae Michael Hanselmann
    "group_name": name,
686 df340fae Michael Hanselmann
    })
687 df340fae Michael Hanselmann
688 f18fab7d Adeodato Simo
689 f18fab7d Adeodato Simo
class R_2_groups_name_modify(baserlib.R_Generic):
690 f18fab7d Adeodato Simo
  """/2/groups/[group_name]/modify resource.
691 f18fab7d Adeodato Simo

692 f18fab7d Adeodato Simo
  """
693 f18fab7d Adeodato Simo
  def PUT(self):
694 f18fab7d Adeodato Simo
    """Changes some parameters of node group.
695 f18fab7d Adeodato Simo

696 f18fab7d Adeodato Simo
    @return: a job id
697 f18fab7d Adeodato Simo

698 f18fab7d Adeodato Simo
    """
699 f18fab7d Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
700 f18fab7d Adeodato Simo
701 f18fab7d Adeodato Simo
    op = _ParseModifyGroupRequest(self.items[0], self.request_body)
702 f18fab7d Adeodato Simo
703 f18fab7d Adeodato Simo
    return baserlib.SubmitJob([op])
704 f18fab7d Adeodato Simo
705 f18fab7d Adeodato Simo
706 0dbaa9ca Adeodato Simo
def _ParseRenameGroupRequest(name, data, dry_run):
707 0dbaa9ca Adeodato Simo
  """Parses a request for renaming a node group.
708 0dbaa9ca Adeodato Simo

709 0dbaa9ca Adeodato Simo
  @type name: string
710 0dbaa9ca Adeodato Simo
  @param name: name of the node group to rename
711 0dbaa9ca Adeodato Simo
  @type data: dict
712 0dbaa9ca Adeodato Simo
  @param data: the body received by the rename request
713 0dbaa9ca Adeodato Simo
  @type dry_run: bool
714 0dbaa9ca Adeodato Simo
  @param dry_run: whether to perform a dry run
715 0dbaa9ca Adeodato Simo

716 a8173e82 Iustin Pop
  @rtype: L{opcodes.OpGroupRename}
717 0dbaa9ca Adeodato Simo
  @return: Node group rename opcode
718 0dbaa9ca Adeodato Simo

719 0dbaa9ca Adeodato Simo
  """
720 8a08be3b Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupRename, data, {
721 8a08be3b Michael Hanselmann
    "group_name": name,
722 8a08be3b Michael Hanselmann
    "dry_run": dry_run,
723 8a08be3b Michael Hanselmann
    })
724 0dbaa9ca Adeodato Simo
725 0dbaa9ca Adeodato Simo
726 0dbaa9ca Adeodato Simo
class R_2_groups_name_rename(baserlib.R_Generic):
727 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/rename resource.
728 0dbaa9ca Adeodato Simo

729 0dbaa9ca Adeodato Simo
  """
730 0dbaa9ca Adeodato Simo
  def PUT(self):
731 0dbaa9ca Adeodato Simo
    """Changes the name of a node group.
732 0dbaa9ca Adeodato Simo

733 0dbaa9ca Adeodato Simo
    @return: a job id
734 0dbaa9ca Adeodato Simo

735 0dbaa9ca Adeodato Simo
    """
736 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
737 0dbaa9ca Adeodato Simo
    op = _ParseRenameGroupRequest(self.items[0], self.request_body,
738 0dbaa9ca Adeodato Simo
                                  self.dryRun())
739 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
740 0897dc97 Adeodato Simo
741 0897dc97 Adeodato Simo
742 4245446f Adeodato Simo
class R_2_groups_name_assign_nodes(baserlib.R_Generic):
743 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/assign-nodes resource.
744 4245446f Adeodato Simo

745 4245446f Adeodato Simo
  """
746 4245446f Adeodato Simo
  def PUT(self):
747 4245446f Adeodato Simo
    """Assigns nodes to a group.
748 4245446f Adeodato Simo

749 4245446f Adeodato Simo
    @return: a job id
750 4245446f Adeodato Simo

751 4245446f Adeodato Simo
    """
752 934704ae Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpGroupAssignNodes, self.request_body, {
753 4245446f Adeodato Simo
      "group_name": self.items[0],
754 4245446f Adeodato Simo
      "dry_run": self.dryRun(),
755 4245446f Adeodato Simo
      "force": self.useForce(),
756 4245446f Adeodato Simo
      })
757 4245446f Adeodato Simo
758 4245446f Adeodato Simo
    return baserlib.SubmitJob([op])
759 4245446f Adeodato Simo
760 4245446f Adeodato Simo
761 6395cebb Michael Hanselmann
def _ParseInstanceCreateRequestVersion1(data, dry_run):
762 6395cebb Michael Hanselmann
  """Parses an instance creation request version 1.
763 6395cebb Michael Hanselmann

764 e1530b10 Iustin Pop
  @rtype: L{opcodes.OpInstanceCreate}
765 6395cebb Michael Hanselmann
  @return: Instance creation opcode
766 6395cebb Michael Hanselmann

767 6395cebb Michael Hanselmann
  """
768 526a662a Michael Hanselmann
  override = {
769 526a662a Michael Hanselmann
    "dry_run": dry_run,
770 526a662a Michael Hanselmann
    }
771 6395cebb Michael Hanselmann
772 526a662a Michael Hanselmann
  rename = {
773 526a662a Michael Hanselmann
    "os": "os_type",
774 526a662a Michael Hanselmann
    "name": "instance_name",
775 526a662a Michael Hanselmann
    }
776 526a662a Michael Hanselmann
777 526a662a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceCreate, data, override,
778 526a662a Michael Hanselmann
                             rename=rename)
779 6395cebb Michael Hanselmann
780 6395cebb Michael Hanselmann
781 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
782 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
783 441e7cfd Oleksiy Mishchenko

784 441e7cfd Oleksiy Mishchenko
  """
785 441e7cfd Oleksiy Mishchenko
  def GET(self):
786 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
787 441e7cfd Oleksiy Mishchenko

788 441e7cfd Oleksiy Mishchenko
    """
789 59b4eeef Iustin Pop
    client = baserlib.GetClient()
790 441e7cfd Oleksiy Mishchenko
791 3d103742 Iustin Pop
    use_locking = self.useLocking()
792 3d103742 Iustin Pop
    if self.useBulk():
793 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
794 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
795 441e7cfd Oleksiy Mishchenko
    else:
796 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
797 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
798 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
799 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
800 441e7cfd Oleksiy Mishchenko
801 d975f482 Michael Hanselmann
  def POST(self):
802 d975f482 Michael Hanselmann
    """Create an instance.
803 d975f482 Michael Hanselmann

804 d975f482 Michael Hanselmann
    @return: a job id
805 d975f482 Michael Hanselmann

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

831 028c6b76 Oleksiy Mishchenko
  """
832 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
833 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
834 4e5a68f8 Oleksiy Mishchenko

835 4e5a68f8 Oleksiy Mishchenko
    """
836 59b4eeef Iustin Pop
    client = baserlib.GetClient()
837 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
838 e8ebbd2b Michael Hanselmann
839 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
840 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
841 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
842 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
843 4e5a68f8 Oleksiy Mishchenko
844 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
845 028c6b76 Oleksiy Mishchenko
846 6e99c5a0 Iustin Pop
  def DELETE(self):
847 6e99c5a0 Iustin Pop
    """Delete an instance.
848 6e99c5a0 Iustin Pop

849 6e99c5a0 Iustin Pop
    """
850 3cd2d4b1 Iustin Pop
    op = opcodes.OpInstanceRemove(instance_name=self.items[0],
851 6f59b964 Iustin Pop
                                  ignore_failures=False,
852 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
853 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
854 6e99c5a0 Iustin Pop
855 028c6b76 Oleksiy Mishchenko
856 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
857 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
858 d8260842 Michael Hanselmann

859 d8260842 Michael Hanselmann
  """
860 d8260842 Michael Hanselmann
  def GET(self):
861 d8260842 Michael Hanselmann
    """Request detailed instance information.
862 d8260842 Michael Hanselmann

863 d8260842 Michael Hanselmann
    """
864 d8260842 Michael Hanselmann
    instance_name = self.items[0]
865 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
866 d8260842 Michael Hanselmann
867 dc28c4e4 Iustin Pop
    op = opcodes.OpInstanceQueryData(instances=[instance_name],
868 d8260842 Michael Hanselmann
                                     static=static)
869 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
870 d8260842 Michael Hanselmann
871 d8260842 Michael Hanselmann
872 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
873 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
874 2276aa29 Oleksiy Mishchenko

875 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
876 2276aa29 Oleksiy Mishchenko

877 2276aa29 Oleksiy Mishchenko
  """
878 21f04e5e Oleksiy Mishchenko
  def POST(self):
879 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
880 2276aa29 Oleksiy Mishchenko

881 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
882 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
883 0c55c24b Oleksiy Mishchenko

884 2276aa29 Oleksiy Mishchenko
    """
885 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
886 d0c8c01d Iustin Pop
    reboot_type = self.queryargs.get("type",
887 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
888 d0c8c01d Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable("ignore_secondaries"))
889 90ab1a95 Iustin Pop
    op = opcodes.OpInstanceReboot(instance_name=instance_name,
890 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
891 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
892 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
893 2276aa29 Oleksiy Mishchenko
894 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
895 2276aa29 Oleksiy Mishchenko
896 2276aa29 Oleksiy Mishchenko
897 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
898 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
899 0c55c24b Oleksiy Mishchenko

900 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
901 0c55c24b Oleksiy Mishchenko

902 0c55c24b Oleksiy Mishchenko
  """
903 21f04e5e Oleksiy Mishchenko
  def PUT(self):
904 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
905 0c55c24b Oleksiy Mishchenko

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

909 0c55c24b Oleksiy Mishchenko
    """
910 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
911 d0c8c01d Iustin Pop
    force_startup = bool(self._checkIntVariable("force"))
912 d0c8c01d Iustin Pop
    no_remember = bool(self._checkIntVariable("no_remember"))
913 c873d91c Iustin Pop
    op = opcodes.OpInstanceStartup(instance_name=instance_name,
914 6f59b964 Iustin Pop
                                   force=force_startup,
915 2ba39b8f Iustin Pop
                                   dry_run=bool(self.dryRun()),
916 2ba39b8f Iustin Pop
                                   no_remember=no_remember)
917 0c55c24b Oleksiy Mishchenko
918 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
919 0c55c24b Oleksiy Mishchenko
920 0c55c24b Oleksiy Mishchenko
921 6aac5aef Iustin Pop
def _ParseShutdownInstanceRequest(name, data, dry_run, no_remember):
922 7fa310f6 René Nussbaumer
  """Parses a request for an instance shutdown.
923 7fa310f6 René Nussbaumer

924 7fa310f6 René Nussbaumer
  @rtype: L{opcodes.OpInstanceShutdown}
925 7fa310f6 René Nussbaumer
  @return: Instance shutdown opcode
926 7fa310f6 René Nussbaumer

927 7fa310f6 René Nussbaumer
  """
928 7fa310f6 René Nussbaumer
  return baserlib.FillOpcode(opcodes.OpInstanceShutdown, data, {
929 7fa310f6 René Nussbaumer
    "instance_name": name,
930 7fa310f6 René Nussbaumer
    "dry_run": dry_run,
931 6aac5aef Iustin Pop
    "no_remember": no_remember,
932 7fa310f6 René Nussbaumer
    })
933 7fa310f6 René Nussbaumer
934 7fa310f6 René Nussbaumer
935 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
936 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
937 0c55c24b Oleksiy Mishchenko

938 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
939 0c55c24b Oleksiy Mishchenko

940 0c55c24b Oleksiy Mishchenko
  """
941 21f04e5e Oleksiy Mishchenko
  def PUT(self):
942 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
943 0c55c24b Oleksiy Mishchenko

944 7fa310f6 René Nussbaumer
    @return: a job id
945 7fa310f6 René Nussbaumer

946 0c55c24b Oleksiy Mishchenko
    """
947 d0c8c01d Iustin Pop
    no_remember = bool(self._checkIntVariable("no_remember"))
948 7fa310f6 René Nussbaumer
    op = _ParseShutdownInstanceRequest(self.items[0], self.request_body,
949 6aac5aef Iustin Pop
                                       bool(self.dryRun()), no_remember)
950 0c55c24b Oleksiy Mishchenko
951 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
952 0c55c24b Oleksiy Mishchenko
953 0c55c24b Oleksiy Mishchenko
954 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
955 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
956 c744425f Michael Hanselmann

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

981 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
982 e5b7c4ca Iustin Pop

983 e5b7c4ca Iustin Pop
  """
984 e5b7c4ca Iustin Pop
  def POST(self):
985 e5b7c4ca Iustin Pop
    """Reinstall an instance.
986 e5b7c4ca Iustin Pop

987 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
988 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
989 e5b7c4ca Iustin Pop
    automatically.
990 e5b7c4ca Iustin Pop

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

1014 d1c172de Michael Hanselmann
  @rtype: L{opcodes.OpInstanceReplaceDisks}
1015 d1c172de Michael Hanselmann
  @return: Instance export opcode
1016 d1c172de Michael Hanselmann

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

1041 4c98b915 Michael Hanselmann
  """
1042 4c98b915 Michael Hanselmann
  def POST(self):
1043 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1044 4c98b915 Michael Hanselmann

1045 4c98b915 Michael Hanselmann
    """
1046 d1c172de Michael Hanselmann
    op = _ParseInstanceReplaceDisksRequest(self.items[0], self.request_body)
1047 4c98b915 Michael Hanselmann
1048 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
1049 4c98b915 Michael Hanselmann
1050 4c98b915 Michael Hanselmann
1051 2197b66f René Nussbaumer
class R_2_instances_name_activate_disks(baserlib.R_Generic):
1052 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1053 2197b66f René Nussbaumer

1054 2197b66f René Nussbaumer
  """
1055 2197b66f René Nussbaumer
  def PUT(self):
1056 2197b66f René Nussbaumer
    """Activate disks for an instance.
1057 2197b66f René Nussbaumer

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

1060 2197b66f René Nussbaumer
    """
1061 2197b66f René Nussbaumer
    instance_name = self.items[0]
1062 d0c8c01d Iustin Pop
    ignore_size = bool(self._checkIntVariable("ignore_size"))
1063 2197b66f René Nussbaumer
1064 83f5d475 Iustin Pop
    op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
1065 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
1066 2197b66f René Nussbaumer
1067 2197b66f René Nussbaumer
    return baserlib.SubmitJob([op])
1068 2197b66f René Nussbaumer
1069 2197b66f René Nussbaumer
1070 0a37de5f René Nussbaumer
class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
1071 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1072 0a37de5f René Nussbaumer

1073 0a37de5f René Nussbaumer
  """
1074 0a37de5f René Nussbaumer
  def PUT(self):
1075 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1076 0a37de5f René Nussbaumer

1077 0a37de5f René Nussbaumer
    """
1078 0a37de5f René Nussbaumer
    instance_name = self.items[0]
1079 0a37de5f René Nussbaumer
1080 e176281f Iustin Pop
    op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name)
1081 0a37de5f René Nussbaumer
1082 0a37de5f René Nussbaumer
    return baserlib.SubmitJob([op])
1083 0a37de5f René Nussbaumer
1084 0a37de5f René Nussbaumer
1085 ebeb600f Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.R_Generic):
1086 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1087 ebeb600f Michael Hanselmann

1088 ebeb600f Michael Hanselmann
  """
1089 ebeb600f Michael Hanselmann
  def PUT(self):
1090 ebeb600f Michael Hanselmann
    """Prepares an export for an instance.
1091 ebeb600f Michael Hanselmann

1092 ebeb600f Michael Hanselmann
    @return: a job id
1093 ebeb600f Michael Hanselmann

1094 ebeb600f Michael Hanselmann
    """
1095 ebeb600f Michael Hanselmann
    instance_name = self.items[0]
1096 ebeb600f Michael Hanselmann
    mode = self._checkStringVariable("mode")
1097 ebeb600f Michael Hanselmann
1098 71910715 Iustin Pop
    op = opcodes.OpBackupPrepare(instance_name=instance_name,
1099 ebeb600f Michael Hanselmann
                                 mode=mode)
1100 ebeb600f Michael Hanselmann
1101 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1102 ebeb600f Michael Hanselmann
1103 ebeb600f Michael Hanselmann
1104 ebeb600f Michael Hanselmann
def _ParseExportInstanceRequest(name, data):
1105 ebeb600f Michael Hanselmann
  """Parses a request for an instance export.
1106 ebeb600f Michael Hanselmann

1107 4ff922a2 Iustin Pop
  @rtype: L{opcodes.OpBackupExport}
1108 ebeb600f Michael Hanselmann
  @return: Instance export opcode
1109 ebeb600f Michael Hanselmann

1110 ebeb600f Michael Hanselmann
  """
1111 07ce3e70 Michael Hanselmann
  # Rename "destination" to "target_node"
1112 07ce3e70 Michael Hanselmann
  try:
1113 07ce3e70 Michael Hanselmann
    data["target_node"] = data.pop("destination")
1114 07ce3e70 Michael Hanselmann
  except KeyError:
1115 07ce3e70 Michael Hanselmann
    pass
1116 07ce3e70 Michael Hanselmann
1117 07ce3e70 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpBackupExport, data, {
1118 07ce3e70 Michael Hanselmann
    "instance_name": name,
1119 07ce3e70 Michael Hanselmann
    })
1120 ebeb600f Michael Hanselmann
1121 ebeb600f Michael Hanselmann
1122 ebeb600f Michael Hanselmann
class R_2_instances_name_export(baserlib.R_Generic):
1123 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1124 ebeb600f Michael Hanselmann

1125 ebeb600f Michael Hanselmann
  """
1126 ebeb600f Michael Hanselmann
  def PUT(self):
1127 ebeb600f Michael Hanselmann
    """Exports an instance.
1128 ebeb600f Michael Hanselmann

1129 ebeb600f Michael Hanselmann
    @return: a job id
1130 ebeb600f Michael Hanselmann

1131 ebeb600f Michael Hanselmann
    """
1132 ebeb600f Michael Hanselmann
    if not isinstance(self.request_body, dict):
1133 ebeb600f Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
1134 ebeb600f Michael Hanselmann
1135 ebeb600f Michael Hanselmann
    op = _ParseExportInstanceRequest(self.items[0], self.request_body)
1136 ebeb600f Michael Hanselmann
1137 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1138 ebeb600f Michael Hanselmann
1139 ebeb600f Michael Hanselmann
1140 5823e0d2 Michael Hanselmann
def _ParseMigrateInstanceRequest(name, data):
1141 5823e0d2 Michael Hanselmann
  """Parses a request for an instance migration.
1142 5823e0d2 Michael Hanselmann

1143 75c866c2 Iustin Pop
  @rtype: L{opcodes.OpInstanceMigrate}
1144 5823e0d2 Michael Hanselmann
  @return: Instance migration opcode
1145 5823e0d2 Michael Hanselmann

1146 5823e0d2 Michael Hanselmann
  """
1147 c1a27c9a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceMigrate, data, {
1148 c1a27c9a Michael Hanselmann
    "instance_name": name,
1149 c1a27c9a Michael Hanselmann
    })
1150 5823e0d2 Michael Hanselmann
1151 5823e0d2 Michael Hanselmann
1152 5823e0d2 Michael Hanselmann
class R_2_instances_name_migrate(baserlib.R_Generic):
1153 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1154 5823e0d2 Michael Hanselmann

1155 5823e0d2 Michael Hanselmann
  """
1156 5823e0d2 Michael Hanselmann
  def PUT(self):
1157 5823e0d2 Michael Hanselmann
    """Migrates an instance.
1158 5823e0d2 Michael Hanselmann

1159 5823e0d2 Michael Hanselmann
    @return: a job id
1160 5823e0d2 Michael Hanselmann

1161 5823e0d2 Michael Hanselmann
    """
1162 5823e0d2 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1163 5823e0d2 Michael Hanselmann
1164 5823e0d2 Michael Hanselmann
    op = _ParseMigrateInstanceRequest(self.items[0], self.request_body)
1165 5823e0d2 Michael Hanselmann
1166 5823e0d2 Michael Hanselmann
    return baserlib.SubmitJob([op])
1167 5823e0d2 Michael Hanselmann
1168 5823e0d2 Michael Hanselmann
1169 c0a146a1 Michael Hanselmann
class R_2_instances_name_failover(baserlib.R_Generic):
1170 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1171 c0a146a1 Michael Hanselmann

1172 c0a146a1 Michael Hanselmann
  """
1173 c0a146a1 Michael Hanselmann
  def PUT(self):
1174 c0a146a1 Michael Hanselmann
    """Does a failover of an instance.
1175 c0a146a1 Michael Hanselmann

1176 c0a146a1 Michael Hanselmann
    @return: a job id
1177 c0a146a1 Michael Hanselmann

1178 c0a146a1 Michael Hanselmann
    """
1179 c0a146a1 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1180 c0a146a1 Michael Hanselmann
1181 c0a146a1 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpInstanceFailover, self.request_body, {
1182 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1183 c0a146a1 Michael Hanselmann
      })
1184 c0a146a1 Michael Hanselmann
1185 c0a146a1 Michael Hanselmann
    return baserlib.SubmitJob([op])
1186 c0a146a1 Michael Hanselmann
1187 c0a146a1 Michael Hanselmann
1188 d56e7dc7 Michael Hanselmann
def _ParseRenameInstanceRequest(name, data):
1189 d56e7dc7 Michael Hanselmann
  """Parses a request for renaming an instance.
1190 d56e7dc7 Michael Hanselmann

1191 5659e2e2 Iustin Pop
  @rtype: L{opcodes.OpInstanceRename}
1192 d56e7dc7 Michael Hanselmann
  @return: Instance rename opcode
1193 d56e7dc7 Michael Hanselmann

1194 d56e7dc7 Michael Hanselmann
  """
1195 88bc199a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceRename, data, {
1196 88bc199a Michael Hanselmann
    "instance_name": name,
1197 88bc199a Michael Hanselmann
    })
1198 d56e7dc7 Michael Hanselmann
1199 d56e7dc7 Michael Hanselmann
1200 d56e7dc7 Michael Hanselmann
class R_2_instances_name_rename(baserlib.R_Generic):
1201 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1202 d56e7dc7 Michael Hanselmann

1203 d56e7dc7 Michael Hanselmann
  """
1204 d56e7dc7 Michael Hanselmann
  def PUT(self):
1205 d56e7dc7 Michael Hanselmann
    """Changes the name of an instance.
1206 d56e7dc7 Michael Hanselmann

1207 d56e7dc7 Michael Hanselmann
    @return: a job id
1208 d56e7dc7 Michael Hanselmann

1209 d56e7dc7 Michael Hanselmann
    """
1210 d56e7dc7 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1211 d56e7dc7 Michael Hanselmann
1212 d56e7dc7 Michael Hanselmann
    op = _ParseRenameInstanceRequest(self.items[0], self.request_body)
1213 d56e7dc7 Michael Hanselmann
1214 d56e7dc7 Michael Hanselmann
    return baserlib.SubmitJob([op])
1215 d56e7dc7 Michael Hanselmann
1216 d56e7dc7 Michael Hanselmann
1217 3882937a Michael Hanselmann
def _ParseModifyInstanceRequest(name, data):
1218 3882937a Michael Hanselmann
  """Parses a request for modifying an instance.
1219 3882937a Michael Hanselmann

1220 9a3cc7ae Iustin Pop
  @rtype: L{opcodes.OpInstanceSetParams}
1221 3882937a Michael Hanselmann
  @return: Instance modify opcode
1222 3882937a Michael Hanselmann

1223 3882937a Michael Hanselmann
  """
1224 ee5549c7 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceSetParams, data, {
1225 ee5549c7 Michael Hanselmann
    "instance_name": name,
1226 ee5549c7 Michael Hanselmann
    })
1227 3882937a Michael Hanselmann
1228 3882937a Michael Hanselmann
1229 3882937a Michael Hanselmann
class R_2_instances_name_modify(baserlib.R_Generic):
1230 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1231 3882937a Michael Hanselmann

1232 3882937a Michael Hanselmann
  """
1233 3882937a Michael Hanselmann
  def PUT(self):
1234 3882937a Michael Hanselmann
    """Changes some parameters of an instance.
1235 3882937a Michael Hanselmann

1236 3882937a Michael Hanselmann
    @return: a job id
1237 3882937a Michael Hanselmann

1238 3882937a Michael Hanselmann
    """
1239 3882937a Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1240 3882937a Michael Hanselmann
1241 3882937a Michael Hanselmann
    op = _ParseModifyInstanceRequest(self.items[0], self.request_body)
1242 3882937a Michael Hanselmann
1243 3882937a Michael Hanselmann
    return baserlib.SubmitJob([op])
1244 3882937a Michael Hanselmann
1245 3882937a Michael Hanselmann
1246 e23881ed Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.R_Generic):
1247 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1248 e23881ed Michael Hanselmann

1249 e23881ed Michael Hanselmann
  """
1250 e23881ed Michael Hanselmann
  def POST(self):
1251 e23881ed Michael Hanselmann
    """Increases the size of an instance disk.
1252 e23881ed Michael Hanselmann

1253 e23881ed Michael Hanselmann
    @return: a job id
1254 e23881ed Michael Hanselmann

1255 e23881ed Michael Hanselmann
    """
1256 60472d29 Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpInstanceGrowDisk, self.request_body, {
1257 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1258 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1259 e23881ed Michael Hanselmann
      })
1260 e23881ed Michael Hanselmann
1261 e23881ed Michael Hanselmann
    return baserlib.SubmitJob([op])
1262 e23881ed Michael Hanselmann
1263 e23881ed Michael Hanselmann
1264 b82d4c5e Michael Hanselmann
class R_2_instances_name_console(baserlib.R_Generic):
1265 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1266 b82d4c5e Michael Hanselmann

1267 b82d4c5e Michael Hanselmann
  """
1268 b82d4c5e Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1269 b82d4c5e Michael Hanselmann
1270 b82d4c5e Michael Hanselmann
  def GET(self):
1271 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1272 b82d4c5e Michael Hanselmann

1273 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1274 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1275 b82d4c5e Michael Hanselmann

1276 b82d4c5e Michael Hanselmann
    """
1277 b82d4c5e Michael Hanselmann
    client = baserlib.GetClient()
1278 b82d4c5e Michael Hanselmann
1279 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1280 b82d4c5e Michael Hanselmann
1281 b82d4c5e Michael Hanselmann
    if console is None:
1282 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1283 b82d4c5e Michael Hanselmann
1284 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1285 b82d4c5e Michael Hanselmann
    return console
1286 b82d4c5e Michael Hanselmann
1287 b82d4c5e Michael Hanselmann
1288 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1289 208a6cff Michael Hanselmann
  """
1290 208a6cff Michael Hanselmann

1291 208a6cff Michael Hanselmann
  """
1292 208a6cff Michael Hanselmann
  try:
1293 208a6cff Michael Hanselmann
    fields = args["fields"]
1294 208a6cff Michael Hanselmann
  except KeyError:
1295 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1296 208a6cff Michael Hanselmann
1297 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1298 208a6cff Michael Hanselmann
1299 208a6cff Michael Hanselmann
1300 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1301 208a6cff Michael Hanselmann
  """
1302 208a6cff Michael Hanselmann

1303 208a6cff Michael Hanselmann
  """
1304 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1305 208a6cff Michael Hanselmann
1306 208a6cff Michael Hanselmann
1307 208a6cff Michael Hanselmann
class R_2_query(baserlib.R_Generic):
1308 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1309 208a6cff Michael Hanselmann

1310 208a6cff Michael Hanselmann
  """
1311 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1312 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1313 208a6cff Michael Hanselmann
1314 208a6cff Michael Hanselmann
  def _Query(self, fields, filter_):
1315 208a6cff Michael Hanselmann
    return baserlib.GetClient().Query(self.items[0], fields, filter_).ToDict()
1316 208a6cff Michael Hanselmann
1317 208a6cff Michael Hanselmann
  def GET(self):
1318 208a6cff Michael Hanselmann
    """Returns resource information.
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
    return self._Query(_GetQueryFields(self.queryargs), None)
1324 208a6cff Michael Hanselmann
1325 208a6cff Michael Hanselmann
  def PUT(self):
1326 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1327 208a6cff Michael Hanselmann

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

1330 208a6cff Michael Hanselmann
    """
1331 208a6cff Michael Hanselmann
    body = self.request_body
1332 208a6cff Michael Hanselmann
1333 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1334 208a6cff Michael Hanselmann
1335 208a6cff Michael Hanselmann
    try:
1336 208a6cff Michael Hanselmann
      fields = body["fields"]
1337 208a6cff Michael Hanselmann
    except KeyError:
1338 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1339 208a6cff Michael Hanselmann
1340 208a6cff Michael Hanselmann
    return self._Query(fields, self.request_body.get("filter", None))
1341 208a6cff Michael Hanselmann
1342 208a6cff Michael Hanselmann
1343 208a6cff Michael Hanselmann
class R_2_query_fields(baserlib.R_Generic):
1344 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1345 208a6cff Michael Hanselmann

1346 208a6cff Michael Hanselmann
  """
1347 208a6cff Michael Hanselmann
  def GET(self):
1348 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1349 208a6cff Michael Hanselmann

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

1352 208a6cff Michael Hanselmann
    """
1353 208a6cff Michael Hanselmann
    try:
1354 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1355 208a6cff Michael Hanselmann
    except KeyError:
1356 208a6cff Michael Hanselmann
      fields = None
1357 208a6cff Michael Hanselmann
    else:
1358 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1359 208a6cff Michael Hanselmann
1360 208a6cff Michael Hanselmann
    return baserlib.GetClient().QueryFields(self.items[0], fields).ToDict()
1361 208a6cff Michael Hanselmann
1362 208a6cff Michael Hanselmann
1363 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
1364 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1365 441e7cfd Oleksiy Mishchenko

1366 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1367 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1368 441e7cfd Oleksiy Mishchenko

1369 441e7cfd Oleksiy Mishchenko
  """
1370 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1371 18cb43a2 Oleksiy Mishchenko
1372 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
1373 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1374 18cb43a2 Oleksiy Mishchenko

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

1377 18cb43a2 Oleksiy Mishchenko
    """
1378 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
1379 18cb43a2 Oleksiy Mishchenko
1380 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1381 5313eed7 Michael Hanselmann
      self.name = None
1382 18cb43a2 Oleksiy Mishchenko
    else:
1383 5313eed7 Michael Hanselmann
      self.name = items[0]
1384 441e7cfd Oleksiy Mishchenko
1385 441e7cfd Oleksiy Mishchenko
  def GET(self):
1386 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1387 441e7cfd Oleksiy Mishchenko

1388 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1389 441e7cfd Oleksiy Mishchenko

1390 441e7cfd Oleksiy Mishchenko
    """
1391 b459a848 Andrea Spadaccini
    # pylint: disable=W0212
1392 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
1393 441e7cfd Oleksiy Mishchenko
1394 21f04e5e Oleksiy Mishchenko
  def PUT(self):
1395 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1396 441e7cfd Oleksiy Mishchenko

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

1400 441e7cfd Oleksiy Mishchenko
    """
1401 b459a848 Andrea Spadaccini
    # pylint: disable=W0212
1402 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1403 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
1404 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
1405 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
1406 d0c8c01d Iustin Pop
                              self.queryargs["tag"], name=self.name,
1407 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
1408 15fd9fd5 Oleksiy Mishchenko
1409 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
1410 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1411 15fd9fd5 Oleksiy Mishchenko

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

1416 15fd9fd5 Oleksiy Mishchenko
    """
1417 b459a848 Andrea Spadaccini
    # pylint: disable=W0212
1418 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1419 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
1420 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
1421 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
1422 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
1423 d0c8c01d Iustin Pop
                                 self.queryargs["tag"],
1424 6f59b964 Iustin Pop
                                 name=self.name,
1425 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
1426 18cb43a2 Oleksiy Mishchenko
1427 18cb43a2 Oleksiy Mishchenko
1428 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1429 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1430 18cb43a2 Oleksiy Mishchenko

1431 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1432 18cb43a2 Oleksiy Mishchenko

1433 18cb43a2 Oleksiy Mishchenko
  """
1434 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1435 18cb43a2 Oleksiy Mishchenko
1436 18cb43a2 Oleksiy Mishchenko
1437 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1438 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1439 18cb43a2 Oleksiy Mishchenko

1440 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1441 18cb43a2 Oleksiy Mishchenko

1442 18cb43a2 Oleksiy Mishchenko
  """
1443 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1444 18cb43a2 Oleksiy Mishchenko
1445 18cb43a2 Oleksiy Mishchenko
1446 414ebaf1 Michael Hanselmann
class R_2_groups_name_tags(_R_Tags):
1447 414ebaf1 Michael Hanselmann
  """ /2/groups/[group_name]/tags resource.
1448 414ebaf1 Michael Hanselmann

1449 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1450 414ebaf1 Michael Hanselmann

1451 414ebaf1 Michael Hanselmann
  """
1452 414ebaf1 Michael Hanselmann
  TAG_LEVEL = constants.TAG_NODEGROUP
1453 414ebaf1 Michael Hanselmann
1454 414ebaf1 Michael Hanselmann
1455 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1456 b58a4d16 Michael Hanselmann
  """ /2/tags resource.
1457 18cb43a2 Oleksiy Mishchenko

1458 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1459 18cb43a2 Oleksiy Mishchenko

1460 18cb43a2 Oleksiy Mishchenko
  """
1461 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER