Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 5e12acfe

History | View | Annotate | Download (35.6 kB)

1 10b207d4 Oleksiy Mishchenko
#
2 10b207d4 Oleksiy Mishchenko
#
3 10b207d4 Oleksiy Mishchenko
4 37e61a77 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 e5ff1a47 René Nussbaumer
from ganeti import objects
60 15fd9fd5 Oleksiy Mishchenko
from ganeti import http
61 15fd9fd5 Oleksiy Mishchenko
from ganeti import constants
62 59b4eeef Iustin Pop
from ganeti import cli
63 8381fa2d Michael Hanselmann
from ganeti import rapi
64 d1c172de Michael Hanselmann
from ganeti import ht
65 e987f166 Michael Hanselmann
from ganeti import compat
66 be1ddd09 Michael Hanselmann
from ganeti import ssconf
67 38206f3c Iustin Pop
from ganeti.rapi import baserlib
68 10b207d4 Oleksiy Mishchenko
69 4e5a68f8 Oleksiy Mishchenko
70 7118a0df Iustin Pop
_COMMON_FIELDS = ["ctime", "mtime", "uuid", "serial_no", "tags"]
71 9031ee8e Iustin Pop
I_FIELDS = ["name", "admin_state", "os",
72 9031ee8e Iustin Pop
            "pnode", "snodes",
73 9031ee8e Iustin Pop
            "disk_template",
74 82e186f8 Michael Hanselmann
            "nic.ips", "nic.macs", "nic.modes", "nic.links", "nic.bridges",
75 a8b16c4e Tim Boring
            "network_port",
76 024e157f Iustin Pop
            "disk.sizes", "disk_usage",
77 a5b9d725 Iustin Pop
            "beparams", "hvparams",
78 4ea3de4e Balazs Lecz
            "oper_state", "oper_ram", "oper_vcpus", "status",
79 90224407 Iustin Pop
            "custom_hvparams", "custom_beparams", "custom_nicparams",
80 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
81 9031ee8e Iustin Pop
82 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
83 9031ee8e Iustin Pop
            "dtotal", "dfree",
84 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
85 7118a0df Iustin Pop
            "pinst_cnt", "sinst_cnt",
86 0105bad3 Iustin Pop
            "ctotal", "cnodes", "csockets",
87 7118a0df Iustin Pop
            "pip", "sip", "role",
88 93962b80 Iustin Pop
            "pinst_list", "sinst_list",
89 c190e817 Iustin Pop
            "master_capable", "vm_capable",
90 37e61a77 Iustin Pop
            "ndparams",
91 fd254195 Iustin Pop
            "group.uuid",
92 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
93 4e5a68f8 Oleksiy Mishchenko
94 f4e86448 Michael Hanselmann
G_FIELDS = [
95 f4e86448 Michael Hanselmann
  "alloc_policy",
96 f4e86448 Michael Hanselmann
  "name",
97 f4e86448 Michael Hanselmann
  "node_cnt",
98 f4e86448 Michael Hanselmann
  "node_list",
99 edd49f9b Agata Murawska
  "ipolicy",
100 003306f9 Iustin Pop
  "custom_ipolicy",
101 003306f9 Iustin Pop
  "diskparams",
102 003306f9 Iustin Pop
  "custom_diskparams",
103 003306f9 Iustin Pop
  "ndparams",
104 003306f9 Iustin Pop
  "custom_ndparams",
105 f4e86448 Michael Hanselmann
  ] + _COMMON_FIELDS
106 0897dc97 Adeodato Simo
107 bd7b2070 Michael Hanselmann
J_FIELDS_BULK = [
108 e987f166 Michael Hanselmann
  "id", "ops", "status", "summary",
109 bd7b2070 Michael Hanselmann
  "opstatus",
110 e987f166 Michael Hanselmann
  "received_ts", "start_ts", "end_ts",
111 e987f166 Michael Hanselmann
  ]
112 e987f166 Michael Hanselmann
113 bd7b2070 Michael Hanselmann
J_FIELDS = J_FIELDS_BULK + [
114 bd7b2070 Michael Hanselmann
  "oplog",
115 bd7b2070 Michael Hanselmann
  "opresult",
116 bd7b2070 Michael Hanselmann
  ]
117 bd7b2070 Michael Hanselmann
118 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
119 51cc8637 Michael Hanselmann
_NR_MASTER_CANDIDATE = "master-candidate"
120 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
121 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
122 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
123 64dae8fc Michael Hanselmann
124 64dae8fc Michael Hanselmann
_NR_MAP = {
125 1e28e3b8 Michael Hanselmann
  constants.NR_MASTER: _NR_MASTER,
126 51cc8637 Michael Hanselmann
  constants.NR_MCANDIDATE: _NR_MASTER_CANDIDATE,
127 1e28e3b8 Michael Hanselmann
  constants.NR_DRAINED: _NR_DRAINED,
128 1e28e3b8 Michael Hanselmann
  constants.NR_OFFLINE: _NR_OFFLINE,
129 1e28e3b8 Michael Hanselmann
  constants.NR_REGULAR: _NR_REGULAR,
130 64dae8fc Michael Hanselmann
  }
131 64dae8fc Michael Hanselmann
132 1e28e3b8 Michael Hanselmann
assert frozenset(_NR_MAP.keys()) == constants.NR_ALL
133 1e28e3b8 Michael Hanselmann
134 d975f482 Michael Hanselmann
# Request data version field
135 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
136 d975f482 Michael Hanselmann
137 6395cebb Michael Hanselmann
# Feature string for instance creation request data version 1
138 6395cebb Michael Hanselmann
_INST_CREATE_REQV1 = "instance-create-reqv1"
139 6395cebb Michael Hanselmann
140 c744425f Michael Hanselmann
# Feature string for instance reinstall request version 1
141 c744425f Michael Hanselmann
_INST_REINSTALL_REQV1 = "instance-reinstall-reqv1"
142 c744425f Michael Hanselmann
143 b7a1c816 Michael Hanselmann
# Feature string for node migration version 1
144 b7a1c816 Michael Hanselmann
_NODE_MIGRATE_REQV1 = "node-migrate-reqv1"
145 b7a1c816 Michael Hanselmann
146 de40437a Michael Hanselmann
# Feature string for node evacuation with LU-generated jobs
147 de40437a Michael Hanselmann
_NODE_EVAC_RES1 = "node-evac-res1"
148 de40437a Michael Hanselmann
149 b4fcee5b Michael Hanselmann
ALL_FEATURES = frozenset([
150 b4fcee5b Michael Hanselmann
  _INST_CREATE_REQV1,
151 b4fcee5b Michael Hanselmann
  _INST_REINSTALL_REQV1,
152 b4fcee5b Michael Hanselmann
  _NODE_MIGRATE_REQV1,
153 b4fcee5b Michael Hanselmann
  _NODE_EVAC_RES1,
154 b4fcee5b Michael Hanselmann
  ])
155 b4fcee5b Michael Hanselmann
156 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
157 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
158 793a8f7c Michael Hanselmann
159 4e5a68f8 Oleksiy Mishchenko
160 28a45bfc René Nussbaumer
# FIXME: For compatibility we update the beparams/memory field. Needs to be
161 28a45bfc René Nussbaumer
#        removed in Ganeti 2.7
162 28a45bfc René Nussbaumer
def _UpdateBeparams(inst):
163 28a45bfc René Nussbaumer
  """Updates the beparams dict of inst to support the memory field.
164 28a45bfc René Nussbaumer

165 28a45bfc René Nussbaumer
  @param inst: Inst dict
166 28a45bfc René Nussbaumer
  @return: Updated inst dict
167 28a45bfc René Nussbaumer

168 28a45bfc René Nussbaumer
  """
169 28a45bfc René Nussbaumer
  beparams = inst["beparams"]
170 28a45bfc René Nussbaumer
  beparams[constants.BE_MEMORY] = beparams[constants.BE_MAXMEM]
171 28a45bfc René Nussbaumer
172 28a45bfc René Nussbaumer
  return inst
173 28a45bfc René Nussbaumer
174 28a45bfc René Nussbaumer
175 26ff6ee2 Michael Hanselmann
class R_root(baserlib.ResourceBase):
176 0f945c65 Michael Hanselmann
  """/ resource.
177 0f945c65 Michael Hanselmann

178 0f945c65 Michael Hanselmann
  """
179 0f945c65 Michael Hanselmann
  @staticmethod
180 0f945c65 Michael Hanselmann
  def GET():
181 0f945c65 Michael Hanselmann
    """Supported for legacy reasons.
182 0f945c65 Michael Hanselmann

183 0f945c65 Michael Hanselmann
    """
184 0f945c65 Michael Hanselmann
    return None
185 0f945c65 Michael Hanselmann
186 0f945c65 Michael Hanselmann
187 132cdb87 Michael Hanselmann
class R_2(R_root):
188 132cdb87 Michael Hanselmann
  """/2 resource.
189 132cdb87 Michael Hanselmann

190 132cdb87 Michael Hanselmann
  """
191 132cdb87 Michael Hanselmann
192 132cdb87 Michael Hanselmann
193 26ff6ee2 Michael Hanselmann
class R_version(baserlib.ResourceBase):
194 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
195 4e5a68f8 Oleksiy Mishchenko

196 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
197 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
198 4e5a68f8 Oleksiy Mishchenko

199 4e5a68f8 Oleksiy Mishchenko
  """
200 7e950d31 Iustin Pop
  @staticmethod
201 7e950d31 Iustin Pop
  def GET():
202 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
203 4e5a68f8 Oleksiy Mishchenko

204 4e5a68f8 Oleksiy Mishchenko
    """
205 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
206 4e5a68f8 Oleksiy Mishchenko
207 4e5a68f8 Oleksiy Mishchenko
208 f6ce0ba2 Michael Hanselmann
class R_2_info(baserlib.OpcodeResource):
209 b58a4d16 Michael Hanselmann
  """/2/info resource.
210 4e5a68f8 Oleksiy Mishchenko

211 4e5a68f8 Oleksiy Mishchenko
  """
212 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpClusterQuery
213 f6ce0ba2 Michael Hanselmann
214 be1ddd09 Michael Hanselmann
  def GET(self):
215 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
216 4e5a68f8 Oleksiy Mishchenko

217 4e5a68f8 Oleksiy Mishchenko
    """
218 a2160e57 Iustin Pop
    client = self.GetClient(query=True)
219 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
220 4e5a68f8 Oleksiy Mishchenko
221 4e5a68f8 Oleksiy Mishchenko
222 26ff6ee2 Michael Hanselmann
class R_2_features(baserlib.ResourceBase):
223 7eac4a4d Michael Hanselmann
  """/2/features resource.
224 7eac4a4d Michael Hanselmann

225 7eac4a4d Michael Hanselmann
  """
226 7eac4a4d Michael Hanselmann
  @staticmethod
227 7eac4a4d Michael Hanselmann
  def GET():
228 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
229 7eac4a4d Michael Hanselmann

230 7eac4a4d Michael Hanselmann
    """
231 b4fcee5b Michael Hanselmann
    return list(ALL_FEATURES)
232 7eac4a4d Michael Hanselmann
233 7eac4a4d Michael Hanselmann
234 f6ce0ba2 Michael Hanselmann
class R_2_os(baserlib.OpcodeResource):
235 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
236 4e5a68f8 Oleksiy Mishchenko

237 4e5a68f8 Oleksiy Mishchenko
  """
238 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpOsDiagnose
239 f6ce0ba2 Michael Hanselmann
240 be1ddd09 Michael Hanselmann
  def GET(self):
241 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
242 4e5a68f8 Oleksiy Mishchenko

243 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
244 4e5a68f8 Oleksiy Mishchenko

245 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
246 4e5a68f8 Oleksiy Mishchenko

247 4e5a68f8 Oleksiy Mishchenko
    """
248 be1ddd09 Michael Hanselmann
    cl = self.GetClient()
249 da2d02e7 Iustin Pop
    op = opcodes.OpOsDiagnose(output_fields=["name", "variants"], names=[])
250 be1ddd09 Michael Hanselmann
    job_id = self.SubmitJob([op], cl=cl)
251 59b4eeef Iustin Pop
    # we use custom feedback function, instead of print we log the status
252 59b4eeef Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
253 59b4eeef Iustin Pop
    diagnose_data = result[0]
254 4e5a68f8 Oleksiy Mishchenko
255 4e5a68f8 Oleksiy Mishchenko
    if not isinstance(diagnose_data, list):
256 59b4eeef Iustin Pop
      raise http.HttpBadGateway(message="Can't get OS list")
257 4e5a68f8 Oleksiy Mishchenko
258 e3ac208c Guido Trotter
    os_names = []
259 d22dfef7 Iustin Pop
    for (name, variants) in diagnose_data:
260 d22dfef7 Iustin Pop
      os_names.extend(cli.CalculateOSNames(name, variants))
261 e3ac208c Guido Trotter
262 e3ac208c Guido Trotter
    return os_names
263 51ee2f49 Oleksiy Mishchenko
264 10b207d4 Oleksiy Mishchenko
265 8fd625fc Michael Hanselmann
class R_2_redist_config(baserlib.OpcodeResource):
266 508e9b20 Michael Hanselmann
  """/2/redistribute-config resource.
267 508e9b20 Michael Hanselmann

268 508e9b20 Michael Hanselmann
  """
269 8fd625fc Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterRedistConf
270 508e9b20 Michael Hanselmann
271 508e9b20 Michael Hanselmann
272 50c7d82e Michael Hanselmann
class R_2_cluster_modify(baserlib.OpcodeResource):
273 62e999a5 Michael Hanselmann
  """/2/modify resource.
274 62e999a5 Michael Hanselmann

275 62e999a5 Michael Hanselmann
  """
276 50c7d82e Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterSetParams
277 62e999a5 Michael Hanselmann
278 62e999a5 Michael Hanselmann
279 26ff6ee2 Michael Hanselmann
class R_2_jobs(baserlib.ResourceBase):
280 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
281 10b207d4 Oleksiy Mishchenko

282 10b207d4 Oleksiy Mishchenko
  """
283 e987f166 Michael Hanselmann
  def GET(self):
284 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
285 10b207d4 Oleksiy Mishchenko

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

288 10b207d4 Oleksiy Mishchenko
    """
289 be1ddd09 Michael Hanselmann
    client = self.GetClient()
290 e987f166 Michael Hanselmann
291 e987f166 Michael Hanselmann
    if self.useBulk():
292 bd7b2070 Michael Hanselmann
      bulkdata = client.QueryJobs(None, J_FIELDS_BULK)
293 bd7b2070 Michael Hanselmann
      return baserlib.MapBulkFields(bulkdata, J_FIELDS_BULK)
294 e987f166 Michael Hanselmann
    else:
295 e987f166 Michael Hanselmann
      jobdata = map(compat.fst, client.QueryJobs(None, ["id"]))
296 e987f166 Michael Hanselmann
      return baserlib.BuildUriList(jobdata, "/2/jobs/%s",
297 e987f166 Michael Hanselmann
                                   uri_fields=("id", "uri"))
298 10b207d4 Oleksiy Mishchenko
299 10b207d4 Oleksiy Mishchenko
300 26ff6ee2 Michael Hanselmann
class R_2_jobs_id(baserlib.ResourceBase):
301 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
302 10b207d4 Oleksiy Mishchenko

303 10b207d4 Oleksiy Mishchenko
  """
304 10b207d4 Oleksiy Mishchenko
  def GET(self):
305 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
306 10b207d4 Oleksiy Mishchenko

307 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
308 c41eea6e Iustin Pop
        The result includes:
309 c41eea6e Iustin Pop
            - id: job ID as a number
310 c41eea6e Iustin Pop
            - status: current job status as a string
311 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
312 c41eea6e Iustin Pop
              opcodes in the job
313 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
314 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
315 38206f3c Iustin Pop

316 10b207d4 Oleksiy Mishchenko
    """
317 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
318 be1ddd09 Michael Hanselmann
    result = self.GetClient().QueryJobs([job_id, ], J_FIELDS)[0]
319 ee69c97f Iustin Pop
    if result is None:
320 ee69c97f Iustin Pop
      raise http.HttpNotFound()
321 e987f166 Michael Hanselmann
    return baserlib.MapFields(J_FIELDS, result)
322 10b207d4 Oleksiy Mishchenko
323 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
324 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
325 c7f5f338 Oleksiy Mishchenko

326 c7f5f338 Oleksiy Mishchenko
    """
327 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
328 be1ddd09 Michael Hanselmann
    result = self.GetClient().CancelJob(job_id)
329 c7f5f338 Oleksiy Mishchenko
    return result
330 c7f5f338 Oleksiy Mishchenko
331 10b207d4 Oleksiy Mishchenko
332 26ff6ee2 Michael Hanselmann
class R_2_jobs_id_wait(baserlib.ResourceBase):
333 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
334 793a8f7c Michael Hanselmann

335 793a8f7c Michael Hanselmann
  """
336 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
337 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
338 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
339 793a8f7c Michael Hanselmann
340 793a8f7c Michael Hanselmann
  def GET(self):
341 793a8f7c Michael Hanselmann
    """Waits for job changes.
342 793a8f7c Michael Hanselmann

343 793a8f7c Michael Hanselmann
    """
344 793a8f7c Michael Hanselmann
    job_id = self.items[0]
345 793a8f7c Michael Hanselmann
346 793a8f7c Michael Hanselmann
    fields = self.getBodyParameter("fields")
347 793a8f7c Michael Hanselmann
    prev_job_info = self.getBodyParameter("previous_job_info", None)
348 793a8f7c Michael Hanselmann
    prev_log_serial = self.getBodyParameter("previous_log_serial", None)
349 793a8f7c Michael Hanselmann
350 793a8f7c Michael Hanselmann
    if not isinstance(fields, list):
351 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'fields' parameter should be a list")
352 793a8f7c Michael Hanselmann
353 793a8f7c Michael Hanselmann
    if not (prev_job_info is None or isinstance(prev_job_info, list)):
354 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_job_info' parameter should"
355 793a8f7c Michael Hanselmann
                                " be a list")
356 793a8f7c Michael Hanselmann
357 793a8f7c Michael Hanselmann
    if not (prev_log_serial is None or
358 793a8f7c Michael Hanselmann
            isinstance(prev_log_serial, (int, long))):
359 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_log_serial' parameter should"
360 793a8f7c Michael Hanselmann
                                " be a number")
361 793a8f7c Michael Hanselmann
362 be1ddd09 Michael Hanselmann
    client = self.GetClient()
363 793a8f7c Michael Hanselmann
    result = client.WaitForJobChangeOnce(job_id, fields,
364 793a8f7c Michael Hanselmann
                                         prev_job_info, prev_log_serial,
365 793a8f7c Michael Hanselmann
                                         timeout=_WFJC_TIMEOUT)
366 793a8f7c Michael Hanselmann
    if not result:
367 793a8f7c Michael Hanselmann
      raise http.HttpNotFound()
368 793a8f7c Michael Hanselmann
369 793a8f7c Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
370 793a8f7c Michael Hanselmann
      # No changes
371 793a8f7c Michael Hanselmann
      return None
372 793a8f7c Michael Hanselmann
373 793a8f7c Michael Hanselmann
    (job_info, log_entries) = result
374 793a8f7c Michael Hanselmann
375 793a8f7c Michael Hanselmann
    return {
376 793a8f7c Michael Hanselmann
      "job_info": job_info,
377 793a8f7c Michael Hanselmann
      "log_entries": log_entries,
378 793a8f7c Michael Hanselmann
      }
379 793a8f7c Michael Hanselmann
380 793a8f7c Michael Hanselmann
381 f6ce0ba2 Michael Hanselmann
class R_2_nodes(baserlib.OpcodeResource):
382 10b207d4 Oleksiy Mishchenko
  """/2/nodes resource.
383 10b207d4 Oleksiy Mishchenko

384 10b207d4 Oleksiy Mishchenko
  """
385 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQuery
386 f6ce0ba2 Michael Hanselmann
387 10b207d4 Oleksiy Mishchenko
  def GET(self):
388 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
389 38206f3c Iustin Pop

390 10b207d4 Oleksiy Mishchenko
    """
391 9fbf0098 Iustin Pop
    client = self.GetClient(query=True)
392 38206f3c Iustin Pop
393 3d103742 Iustin Pop
    if self.useBulk():
394 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
395 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
396 9031ee8e Iustin Pop
    else:
397 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
398 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
399 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
400 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
401 441e7cfd Oleksiy Mishchenko
402 441e7cfd Oleksiy Mishchenko
403 f6ce0ba2 Michael Hanselmann
class R_2_nodes_name(baserlib.OpcodeResource):
404 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name] resource.
405 028c6b76 Oleksiy Mishchenko

406 028c6b76 Oleksiy Mishchenko
  """
407 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQuery
408 f6ce0ba2 Michael Hanselmann
409 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
410 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
411 4e5a68f8 Oleksiy Mishchenko

412 4e5a68f8 Oleksiy Mishchenko
    """
413 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
414 9fbf0098 Iustin Pop
    client = self.GetClient(query=True)
415 e8ebbd2b Michael Hanselmann
416 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
417 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
418 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
419 4e5a68f8 Oleksiy Mishchenko
420 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
421 028c6b76 Oleksiy Mishchenko
422 028c6b76 Oleksiy Mishchenko
423 42d4d8b9 Michael Hanselmann
class R_2_nodes_name_powercycle(baserlib.OpcodeResource):
424 42d4d8b9 Michael Hanselmann
  """/2/nodes/[node_name]/powercycle resource.
425 42d4d8b9 Michael Hanselmann

426 42d4d8b9 Michael Hanselmann
  """
427 42d4d8b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodePowercycle
428 42d4d8b9 Michael Hanselmann
429 42d4d8b9 Michael Hanselmann
  def GetPostOpInput(self):
430 42d4d8b9 Michael Hanselmann
    """Tries to powercycle a node.
431 42d4d8b9 Michael Hanselmann

432 42d4d8b9 Michael Hanselmann
    """
433 42d4d8b9 Michael Hanselmann
    return (self.request_body, {
434 42d4d8b9 Michael Hanselmann
      "node_name": self.items[0],
435 42d4d8b9 Michael Hanselmann
      "force": self.useForce(),
436 42d4d8b9 Michael Hanselmann
      })
437 42d4d8b9 Michael Hanselmann
438 42d4d8b9 Michael Hanselmann
439 51cc8637 Michael Hanselmann
class R_2_nodes_name_role(baserlib.OpcodeResource):
440 51cc8637 Michael Hanselmann
  """/2/nodes/[node_name]/role resource.
441 64dae8fc Michael Hanselmann

442 64dae8fc Michael Hanselmann
  """
443 51cc8637 Michael Hanselmann
  PUT_OPCODE = opcodes.OpNodeSetParams
444 51cc8637 Michael Hanselmann
445 64dae8fc Michael Hanselmann
  def GET(self):
446 64dae8fc Michael Hanselmann
    """Returns the current node role.
447 64dae8fc Michael Hanselmann

448 64dae8fc Michael Hanselmann
    @return: Node role
449 64dae8fc Michael Hanselmann

450 64dae8fc Michael Hanselmann
    """
451 64dae8fc Michael Hanselmann
    node_name = self.items[0]
452 9fbf0098 Iustin Pop
    client = self.GetClient(query=True)
453 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
454 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
455 64dae8fc Michael Hanselmann
456 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
457 64dae8fc Michael Hanselmann
458 51cc8637 Michael Hanselmann
  def GetPutOpInput(self):
459 64dae8fc Michael Hanselmann
    """Sets the node role.
460 64dae8fc Michael Hanselmann

461 64dae8fc Michael Hanselmann
    """
462 51cc8637 Michael Hanselmann
    baserlib.CheckType(self.request_body, basestring, "Body contents")
463 64dae8fc Michael Hanselmann
464 627ad739 Michael Hanselmann
    role = self.request_body
465 64dae8fc Michael Hanselmann
466 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
467 64dae8fc Michael Hanselmann
      candidate = False
468 64dae8fc Michael Hanselmann
      offline = False
469 64dae8fc Michael Hanselmann
      drained = False
470 64dae8fc Michael Hanselmann
471 51cc8637 Michael Hanselmann
    elif role == _NR_MASTER_CANDIDATE:
472 64dae8fc Michael Hanselmann
      candidate = True
473 64dae8fc Michael Hanselmann
      offline = drained = None
474 64dae8fc Michael Hanselmann
475 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
476 64dae8fc Michael Hanselmann
      drained = True
477 64dae8fc Michael Hanselmann
      candidate = offline = None
478 64dae8fc Michael Hanselmann
479 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
480 64dae8fc Michael Hanselmann
      offline = True
481 64dae8fc Michael Hanselmann
      candidate = drained = None
482 64dae8fc Michael Hanselmann
483 64dae8fc Michael Hanselmann
    else:
484 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
485 64dae8fc Michael Hanselmann
486 51cc8637 Michael Hanselmann
    assert len(self.items) == 1
487 64dae8fc Michael Hanselmann
488 51cc8637 Michael Hanselmann
    return ({}, {
489 51cc8637 Michael Hanselmann
      "node_name": self.items[0],
490 51cc8637 Michael Hanselmann
      "master_candidate": candidate,
491 51cc8637 Michael Hanselmann
      "offline": offline,
492 51cc8637 Michael Hanselmann
      "drained": drained,
493 51cc8637 Michael Hanselmann
      "force": self.useForce(),
494 682878d9 Guido Trotter
      "auto_promote": bool(self._checkIntVariable("auto-promote", default=0)),
495 51cc8637 Michael Hanselmann
      })
496 64dae8fc Michael Hanselmann
497 64dae8fc Michael Hanselmann
498 7fa91722 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.OpcodeResource):
499 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
500 73452f12 Michael Hanselmann

501 73452f12 Michael Hanselmann
  """
502 7fa91722 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodeEvacuate
503 7fa91722 Michael Hanselmann
504 7fa91722 Michael Hanselmann
  def GetPostOpInput(self):
505 de40437a Michael Hanselmann
    """Evacuate all instances off a node.
506 73452f12 Michael Hanselmann

507 73452f12 Michael Hanselmann
    """
508 7fa91722 Michael Hanselmann
    return (self.request_body, {
509 de40437a Michael Hanselmann
      "node_name": self.items[0],
510 de40437a Michael Hanselmann
      "dry_run": self.dryRun(),
511 de40437a Michael Hanselmann
      })
512 941b9309 Iustin Pop
513 73452f12 Michael Hanselmann
514 55168cc7 Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.OpcodeResource):
515 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
516 1c482bab Michael Hanselmann

517 1c482bab Michael Hanselmann
  """
518 55168cc7 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodeMigrate
519 55168cc7 Michael Hanselmann
520 55168cc7 Michael Hanselmann
  def GetPostOpInput(self):
521 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
522 1c482bab Michael Hanselmann

523 1c482bab Michael Hanselmann
    """
524 b7a1c816 Michael Hanselmann
    if self.queryargs:
525 b7a1c816 Michael Hanselmann
      # Support old-style requests
526 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs and "mode" in self.queryargs:
527 b7a1c816 Michael Hanselmann
        raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
528 b7a1c816 Michael Hanselmann
                                  " be passed")
529 b7a1c816 Michael Hanselmann
530 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs:
531 b7a1c816 Michael Hanselmann
        if self._checkIntVariable("live", default=1):
532 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_LIVE
533 b7a1c816 Michael Hanselmann
        else:
534 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_NONLIVE
535 52194140 Iustin Pop
      else:
536 b7a1c816 Michael Hanselmann
        mode = self._checkStringVariable("mode", default=None)
537 b7a1c816 Michael Hanselmann
538 b7a1c816 Michael Hanselmann
      data = {
539 b7a1c816 Michael Hanselmann
        "mode": mode,
540 b7a1c816 Michael Hanselmann
        }
541 52194140 Iustin Pop
    else:
542 b7a1c816 Michael Hanselmann
      data = self.request_body
543 52194140 Iustin Pop
544 55168cc7 Michael Hanselmann
    return (data, {
545 55168cc7 Michael Hanselmann
      "node_name": self.items[0],
546 b7a1c816 Michael Hanselmann
      })
547 1c482bab Michael Hanselmann
548 1c482bab Michael Hanselmann
549 682878d9 Guido Trotter
class R_2_nodes_name_modify(baserlib.OpcodeResource):
550 94497dd1 Michael Hanselmann
  """/2/nodes/[node_name]/modify resource.
551 94497dd1 Michael Hanselmann

552 94497dd1 Michael Hanselmann
  """
553 8b8f54dd Guido Trotter
  POST_OPCODE = opcodes.OpNodeSetParams
554 94497dd1 Michael Hanselmann
555 8b8f54dd Guido Trotter
  def GetPostOpInput(self):
556 682878d9 Guido Trotter
    """Changes parameters of a node.
557 94497dd1 Michael Hanselmann

558 94497dd1 Michael Hanselmann
    """
559 682878d9 Guido Trotter
    assert len(self.items) == 1
560 94497dd1 Michael Hanselmann
561 682878d9 Guido Trotter
    return (self.request_body, {
562 370f2042 Guido Trotter
      "node_name": self.items[0],
563 94497dd1 Michael Hanselmann
      })
564 94497dd1 Michael Hanselmann
565 94497dd1 Michael Hanselmann
566 eb08e09d Michael Hanselmann
class R_2_nodes_name_storage(baserlib.OpcodeResource):
567 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
568 7a95a954 Michael Hanselmann

569 7a95a954 Michael Hanselmann
  """
570 ad8d0595 Iustin Pop
  # LUNodeQueryStorage acquires locks, hence restricting access to GET
571 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
572 eb08e09d Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQueryStorage
573 7a95a954 Michael Hanselmann
574 eb08e09d Michael Hanselmann
  def GetGetOpInput(self):
575 eb08e09d Michael Hanselmann
    """List storage available on a node.
576 7a95a954 Michael Hanselmann

577 eb08e09d Michael Hanselmann
    """
578 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
579 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
580 eb08e09d Michael Hanselmann
581 7a95a954 Michael Hanselmann
    if not output_fields:
582 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
583 7a95a954 Michael Hanselmann
                                " parameter")
584 7a95a954 Michael Hanselmann
585 eb08e09d Michael Hanselmann
    return ({}, {
586 eb08e09d Michael Hanselmann
      "nodes": [self.items[0]],
587 eb08e09d Michael Hanselmann
      "storage_type": storage_type,
588 eb08e09d Michael Hanselmann
      "output_fields": output_fields.split(","),
589 eb08e09d Michael Hanselmann
      })
590 7a95a954 Michael Hanselmann
591 7a95a954 Michael Hanselmann
592 8d232068 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.OpcodeResource):
593 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify resource.
594 1e82bc80 Michael Hanselmann

595 1e82bc80 Michael Hanselmann
  """
596 8d232068 Michael Hanselmann
  PUT_OPCODE = opcodes.OpNodeModifyStorage
597 1e82bc80 Michael Hanselmann
598 8d232068 Michael Hanselmann
  def GetPutOpInput(self):
599 8d232068 Michael Hanselmann
    """Modifies a storage volume on a node.
600 1e82bc80 Michael Hanselmann

601 8d232068 Michael Hanselmann
    """
602 8d232068 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
603 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
604 8d232068 Michael Hanselmann
605 1e82bc80 Michael Hanselmann
    if not name:
606 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
607 1e82bc80 Michael Hanselmann
                                " parameter")
608 1e82bc80 Michael Hanselmann
609 1e82bc80 Michael Hanselmann
    changes = {}
610 1e82bc80 Michael Hanselmann
611 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
612 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
613 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
614 1e82bc80 Michael Hanselmann
615 8d232068 Michael Hanselmann
    return ({}, {
616 8d232068 Michael Hanselmann
      "node_name": self.items[0],
617 8d232068 Michael Hanselmann
      "storage_type": storage_type,
618 8d232068 Michael Hanselmann
      "name": name,
619 8d232068 Michael Hanselmann
      "changes": changes,
620 8d232068 Michael Hanselmann
      })
621 1e82bc80 Michael Hanselmann
622 1e82bc80 Michael Hanselmann
623 98270691 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.OpcodeResource):
624 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair resource.
625 723f4565 Michael Hanselmann

626 723f4565 Michael Hanselmann
  """
627 98270691 Michael Hanselmann
  PUT_OPCODE = opcodes.OpRepairNodeStorage
628 723f4565 Michael Hanselmann
629 98270691 Michael Hanselmann
  def GetPutOpInput(self):
630 98270691 Michael Hanselmann
    """Repairs a storage volume on a node.
631 723f4565 Michael Hanselmann

632 98270691 Michael Hanselmann
    """
633 98270691 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
634 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
635 723f4565 Michael Hanselmann
    if not name:
636 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
637 723f4565 Michael Hanselmann
                                " parameter")
638 723f4565 Michael Hanselmann
639 98270691 Michael Hanselmann
    return ({}, {
640 98270691 Michael Hanselmann
      "node_name": self.items[0],
641 98270691 Michael Hanselmann
      "storage_type": storage_type,
642 98270691 Michael Hanselmann
      "name": name,
643 98270691 Michael Hanselmann
      })
644 723f4565 Michael Hanselmann
645 723f4565 Michael Hanselmann
646 c91407bc Michael Hanselmann
class R_2_groups(baserlib.OpcodeResource):
647 c91407bc Michael Hanselmann
  """/2/groups resource.
648 90e99856 Adeodato Simo

649 90e99856 Adeodato Simo
  """
650 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpGroupQuery
651 c91407bc Michael Hanselmann
  POST_OPCODE = opcodes.OpGroupAdd
652 c91407bc Michael Hanselmann
  POST_RENAME = {
653 527fbde8 Michael Hanselmann
    "name": "group_name",
654 527fbde8 Michael Hanselmann
    }
655 527fbde8 Michael Hanselmann
656 c91407bc Michael Hanselmann
  def GetPostOpInput(self):
657 c91407bc Michael Hanselmann
    """Create a node group.
658 90e99856 Adeodato Simo

659 c91407bc Michael Hanselmann
    """
660 c91407bc Michael Hanselmann
    assert not self.items
661 c91407bc Michael Hanselmann
    return (self.request_body, {
662 c91407bc Michael Hanselmann
      "dry_run": self.dryRun(),
663 c91407bc Michael Hanselmann
      })
664 0897dc97 Adeodato Simo
665 0897dc97 Adeodato Simo
  def GET(self):
666 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
667 0897dc97 Adeodato Simo

668 0897dc97 Adeodato Simo
    """
669 9fbf0098 Iustin Pop
    client = self.GetClient(query=True)
670 0897dc97 Adeodato Simo
671 0897dc97 Adeodato Simo
    if self.useBulk():
672 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
673 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
674 0897dc97 Adeodato Simo
    else:
675 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
676 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
677 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
678 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
679 0897dc97 Adeodato Simo
680 0897dc97 Adeodato Simo
681 86f1f5d4 Michael Hanselmann
class R_2_groups_name(baserlib.OpcodeResource):
682 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name] resource.
683 0897dc97 Adeodato Simo

684 0897dc97 Adeodato Simo
  """
685 86f1f5d4 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpGroupRemove
686 86f1f5d4 Michael Hanselmann
687 0897dc97 Adeodato Simo
  def GET(self):
688 0897dc97 Adeodato Simo
    """Send information about a node group.
689 0897dc97 Adeodato Simo

690 0897dc97 Adeodato Simo
    """
691 0897dc97 Adeodato Simo
    group_name = self.items[0]
692 9fbf0098 Iustin Pop
    client = self.GetClient(query=True)
693 0897dc97 Adeodato Simo
694 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
695 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
696 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
697 0897dc97 Adeodato Simo
698 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
699 0897dc97 Adeodato Simo
700 86f1f5d4 Michael Hanselmann
  def GetDeleteOpInput(self):
701 0dbaa9ca Adeodato Simo
    """Delete a node group.
702 0dbaa9ca Adeodato Simo

703 0dbaa9ca Adeodato Simo
    """
704 86f1f5d4 Michael Hanselmann
    assert len(self.items) == 1
705 86f1f5d4 Michael Hanselmann
    return ({}, {
706 86f1f5d4 Michael Hanselmann
      "group_name": self.items[0],
707 86f1f5d4 Michael Hanselmann
      "dry_run": self.dryRun(),
708 86f1f5d4 Michael Hanselmann
      })
709 0dbaa9ca Adeodato Simo
710 0dbaa9ca Adeodato Simo
711 d5211458 Michael Hanselmann
class R_2_groups_name_modify(baserlib.OpcodeResource):
712 f18fab7d Adeodato Simo
  """/2/groups/[group_name]/modify resource.
713 f18fab7d Adeodato Simo

714 f18fab7d Adeodato Simo
  """
715 d5211458 Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupSetParams
716 f18fab7d Adeodato Simo
717 d5211458 Michael Hanselmann
  def GetPutOpInput(self):
718 d5211458 Michael Hanselmann
    """Changes some parameters of node group.
719 f18fab7d Adeodato Simo

720 f18fab7d Adeodato Simo
    """
721 d5211458 Michael Hanselmann
    assert self.items
722 d5211458 Michael Hanselmann
    return (self.request_body, {
723 d5211458 Michael Hanselmann
      "group_name": self.items[0],
724 d5211458 Michael Hanselmann
      })
725 f18fab7d Adeodato Simo
726 f18fab7d Adeodato Simo
727 cd0d4d5a Michael Hanselmann
class R_2_groups_name_rename(baserlib.OpcodeResource):
728 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/rename resource.
729 0dbaa9ca Adeodato Simo

730 0dbaa9ca Adeodato Simo
  """
731 cd0d4d5a Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupRename
732 0dbaa9ca Adeodato Simo
733 cd0d4d5a Michael Hanselmann
  def GetPutOpInput(self):
734 cd0d4d5a Michael Hanselmann
    """Changes the name of a node group.
735 0dbaa9ca Adeodato Simo

736 0dbaa9ca Adeodato Simo
    """
737 cd0d4d5a Michael Hanselmann
    assert len(self.items) == 1
738 cd0d4d5a Michael Hanselmann
    return (self.request_body, {
739 cd0d4d5a Michael Hanselmann
      "group_name": self.items[0],
740 cd0d4d5a Michael Hanselmann
      "dry_run": self.dryRun(),
741 cd0d4d5a Michael Hanselmann
      })
742 0897dc97 Adeodato Simo
743 0897dc97 Adeodato Simo
744 87fd3ec7 Michael Hanselmann
class R_2_groups_name_assign_nodes(baserlib.OpcodeResource):
745 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/assign-nodes resource.
746 4245446f Adeodato Simo

747 4245446f Adeodato Simo
  """
748 87fd3ec7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupAssignNodes
749 4245446f Adeodato Simo
750 87fd3ec7 Michael Hanselmann
  def GetPutOpInput(self):
751 87fd3ec7 Michael Hanselmann
    """Assigns nodes to a group.
752 4245446f Adeodato Simo

753 4245446f Adeodato Simo
    """
754 87fd3ec7 Michael Hanselmann
    assert len(self.items) == 1
755 87fd3ec7 Michael Hanselmann
    return (self.request_body, {
756 4245446f Adeodato Simo
      "group_name": self.items[0],
757 4245446f Adeodato Simo
      "dry_run": self.dryRun(),
758 4245446f Adeodato Simo
      "force": self.useForce(),
759 4245446f Adeodato Simo
      })
760 4245446f Adeodato Simo
761 4245446f Adeodato Simo
762 09a43b39 Michael Hanselmann
class R_2_instances(baserlib.OpcodeResource):
763 09a43b39 Michael Hanselmann
  """/2/instances resource.
764 6395cebb Michael Hanselmann

765 6395cebb Michael Hanselmann
  """
766 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQuery
767 09a43b39 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceCreate
768 09a43b39 Michael Hanselmann
  POST_RENAME = {
769 526a662a Michael Hanselmann
    "os": "os_type",
770 526a662a Michael Hanselmann
    "name": "instance_name",
771 526a662a Michael Hanselmann
    }
772 526a662a Michael Hanselmann
773 441e7cfd Oleksiy Mishchenko
  def GET(self):
774 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
775 441e7cfd Oleksiy Mishchenko

776 441e7cfd Oleksiy Mishchenko
    """
777 be1ddd09 Michael Hanselmann
    client = self.GetClient()
778 441e7cfd Oleksiy Mishchenko
779 3d103742 Iustin Pop
    use_locking = self.useLocking()
780 3d103742 Iustin Pop
    if self.useBulk():
781 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
782 28a45bfc René Nussbaumer
      return map(_UpdateBeparams, baserlib.MapBulkFields(bulkdata, I_FIELDS))
783 441e7cfd Oleksiy Mishchenko
    else:
784 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
785 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
786 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
787 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
788 441e7cfd Oleksiy Mishchenko
789 09a43b39 Michael Hanselmann
  def GetPostOpInput(self):
790 d975f482 Michael Hanselmann
    """Create an instance.
791 d975f482 Michael Hanselmann

792 d975f482 Michael Hanselmann
    @return: a job id
793 d975f482 Michael Hanselmann

794 d975f482 Michael Hanselmann
    """
795 09a43b39 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
796 d975f482 Michael Hanselmann
797 d975f482 Michael Hanselmann
    # Default to request data version 0
798 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
799 d975f482 Michael Hanselmann
800 d975f482 Michael Hanselmann
    if data_version == 0:
801 3fd7f652 Michael Hanselmann
      raise http.HttpBadRequest("Instance creation request version 0 is no"
802 3fd7f652 Michael Hanselmann
                                " longer supported")
803 09a43b39 Michael Hanselmann
    elif data_version != 1:
804 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
805 12eff9b9 Michael Hanselmann
                                data_version)
806 d975f482 Michael Hanselmann
807 09a43b39 Michael Hanselmann
    data = self.request_body.copy()
808 09a43b39 Michael Hanselmann
    # Remove "__version__"
809 09a43b39 Michael Hanselmann
    data.pop(_REQ_DATA_VERSION, None)
810 09a43b39 Michael Hanselmann
811 09a43b39 Michael Hanselmann
    return (data, {
812 09a43b39 Michael Hanselmann
      "dry_run": self.dryRun(),
813 09a43b39 Michael Hanselmann
      })
814 2f7635f4 Oleksiy Mishchenko
815 441e7cfd Oleksiy Mishchenko
816 4ee72287 René Nussbaumer
class R_2_instances_multi_alloc(baserlib.OpcodeResource):
817 4ee72287 René Nussbaumer
  """/2/instances-multi-alloc resource.
818 4ee72287 René Nussbaumer

819 4ee72287 René Nussbaumer
  """
820 4ee72287 René Nussbaumer
  POST_OPCODE = opcodes.OpInstanceMultiAlloc
821 4ee72287 René Nussbaumer
822 4ee72287 René Nussbaumer
  def GetPostOpInput(self):
823 4ee72287 René Nussbaumer
    """Try to allocate multiple instances.
824 4ee72287 René Nussbaumer

825 4ee72287 René Nussbaumer
    @return: A dict with submitted jobs, allocatable instances and failed
826 4ee72287 René Nussbaumer
             allocations
827 4ee72287 René Nussbaumer

828 4ee72287 René Nussbaumer
    """
829 e5ff1a47 René Nussbaumer
    if "instances" not in self.request_body:
830 e5ff1a47 René Nussbaumer
      raise http.HttpBadRequest("Request is missing required 'instances' field"
831 e5ff1a47 René Nussbaumer
                                " in body")
832 e5ff1a47 René Nussbaumer
833 e5ff1a47 René Nussbaumer
    op_id = {
834 e5ff1a47 René Nussbaumer
      "OP_ID": self.POST_OPCODE.OP_ID, # pylint: disable=E1101
835 e5ff1a47 René Nussbaumer
      }
836 e5ff1a47 René Nussbaumer
    body = objects.FillDict(self.request_body, {
837 e5ff1a47 René Nussbaumer
      "instances": [objects.FillDict(inst, op_id)
838 e5ff1a47 René Nussbaumer
                    for inst in self.request_body["instances"]],
839 e5ff1a47 René Nussbaumer
      })
840 e5ff1a47 René Nussbaumer
841 e5ff1a47 René Nussbaumer
    return (body, {
842 4ee72287 René Nussbaumer
      "dry_run": self.dryRun(),
843 4ee72287 René Nussbaumer
      })
844 4ee72287 René Nussbaumer
845 4ee72287 René Nussbaumer
846 a6fa7892 Michael Hanselmann
class R_2_instances_name(baserlib.OpcodeResource):
847 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name] resource.
848 028c6b76 Oleksiy Mishchenko

849 028c6b76 Oleksiy Mishchenko
  """
850 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQuery
851 a6fa7892 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpInstanceRemove
852 a6fa7892 Michael Hanselmann
853 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
854 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
855 4e5a68f8 Oleksiy Mishchenko

856 4e5a68f8 Oleksiy Mishchenko
    """
857 be1ddd09 Michael Hanselmann
    client = self.GetClient()
858 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
859 e8ebbd2b Michael Hanselmann
860 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
861 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
862 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
863 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
864 4e5a68f8 Oleksiy Mishchenko
865 28a45bfc René Nussbaumer
    return _UpdateBeparams(baserlib.MapFields(I_FIELDS, result[0]))
866 028c6b76 Oleksiy Mishchenko
867 a6fa7892 Michael Hanselmann
  def GetDeleteOpInput(self):
868 6e99c5a0 Iustin Pop
    """Delete an instance.
869 6e99c5a0 Iustin Pop

870 6e99c5a0 Iustin Pop
    """
871 a6fa7892 Michael Hanselmann
    assert len(self.items) == 1
872 a6fa7892 Michael Hanselmann
    return ({}, {
873 a6fa7892 Michael Hanselmann
      "instance_name": self.items[0],
874 a6fa7892 Michael Hanselmann
      "ignore_failures": False,
875 a6fa7892 Michael Hanselmann
      "dry_run": self.dryRun(),
876 a6fa7892 Michael Hanselmann
      })
877 6e99c5a0 Iustin Pop
878 028c6b76 Oleksiy Mishchenko
879 7b3df961 Michael Hanselmann
class R_2_instances_name_info(baserlib.OpcodeResource):
880 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
881 d8260842 Michael Hanselmann

882 d8260842 Michael Hanselmann
  """
883 7b3df961 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQueryData
884 7b3df961 Michael Hanselmann
885 7b3df961 Michael Hanselmann
  def GetGetOpInput(self):
886 d8260842 Michael Hanselmann
    """Request detailed instance information.
887 d8260842 Michael Hanselmann

888 d8260842 Michael Hanselmann
    """
889 7b3df961 Michael Hanselmann
    assert len(self.items) == 1
890 7b3df961 Michael Hanselmann
    return ({}, {
891 7b3df961 Michael Hanselmann
      "instances": [self.items[0]],
892 7b3df961 Michael Hanselmann
      "static": bool(self._checkIntVariable("static", default=0)),
893 7b3df961 Michael Hanselmann
      })
894 d8260842 Michael Hanselmann
895 d8260842 Michael Hanselmann
896 ac4888c1 Michael Hanselmann
class R_2_instances_name_reboot(baserlib.OpcodeResource):
897 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
898 2276aa29 Oleksiy Mishchenko

899 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
900 2276aa29 Oleksiy Mishchenko

901 2276aa29 Oleksiy Mishchenko
  """
902 ac4888c1 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReboot
903 ac4888c1 Michael Hanselmann
904 ac4888c1 Michael Hanselmann
  def GetPostOpInput(self):
905 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
906 2276aa29 Oleksiy Mishchenko

907 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
908 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
909 0c55c24b Oleksiy Mishchenko

910 2276aa29 Oleksiy Mishchenko
    """
911 ac4888c1 Michael Hanselmann
    return ({}, {
912 ac4888c1 Michael Hanselmann
      "instance_name": self.items[0],
913 ac4888c1 Michael Hanselmann
      "reboot_type":
914 ac4888c1 Michael Hanselmann
        self.queryargs.get("type", [constants.INSTANCE_REBOOT_HARD])[0],
915 ac4888c1 Michael Hanselmann
      "ignore_secondaries": bool(self._checkIntVariable("ignore_secondaries")),
916 ac4888c1 Michael Hanselmann
      "dry_run": self.dryRun(),
917 ac4888c1 Michael Hanselmann
      })
918 2276aa29 Oleksiy Mishchenko
919 2276aa29 Oleksiy Mishchenko
920 4717e6eb Michael Hanselmann
class R_2_instances_name_startup(baserlib.OpcodeResource):
921 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
922 0c55c24b Oleksiy Mishchenko

923 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
924 0c55c24b Oleksiy Mishchenko

925 0c55c24b Oleksiy Mishchenko
  """
926 4717e6eb Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceStartup
927 4717e6eb Michael Hanselmann
928 4717e6eb Michael Hanselmann
  def GetPutOpInput(self):
929 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
930 0c55c24b Oleksiy Mishchenko

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

934 0c55c24b Oleksiy Mishchenko
    """
935 4717e6eb Michael Hanselmann
    return ({}, {
936 4717e6eb Michael Hanselmann
      "instance_name": self.items[0],
937 4717e6eb Michael Hanselmann
      "force": self.useForce(),
938 4717e6eb Michael Hanselmann
      "dry_run": self.dryRun(),
939 4717e6eb Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
940 4717e6eb Michael Hanselmann
      })
941 0c55c24b Oleksiy Mishchenko
942 0c55c24b Oleksiy Mishchenko
943 3175ade6 Michael Hanselmann
class R_2_instances_name_shutdown(baserlib.OpcodeResource):
944 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
945 0c55c24b Oleksiy Mishchenko

946 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
947 0c55c24b Oleksiy Mishchenko

948 0c55c24b Oleksiy Mishchenko
  """
949 3175ade6 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceShutdown
950 0c55c24b Oleksiy Mishchenko
951 3175ade6 Michael Hanselmann
  def GetPutOpInput(self):
952 3175ade6 Michael Hanselmann
    """Shutdown an instance.
953 7fa310f6 René Nussbaumer

954 0c55c24b Oleksiy Mishchenko
    """
955 3175ade6 Michael Hanselmann
    return (self.request_body, {
956 3175ade6 Michael Hanselmann
      "instance_name": self.items[0],
957 3175ade6 Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
958 3175ade6 Michael Hanselmann
      "dry_run": self.dryRun(),
959 3175ade6 Michael Hanselmann
      })
960 0c55c24b Oleksiy Mishchenko
961 0c55c24b Oleksiy Mishchenko
962 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
963 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
964 c744425f Michael Hanselmann

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

989 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
990 e5b7c4ca Iustin Pop

991 e5b7c4ca Iustin Pop
  """
992 f6ce0ba2 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReinstall
993 f6ce0ba2 Michael Hanselmann
994 e5b7c4ca Iustin Pop
  def POST(self):
995 e5b7c4ca Iustin Pop
    """Reinstall an instance.
996 e5b7c4ca Iustin Pop

997 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
998 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
999 e5b7c4ca Iustin Pop
    automatically.
1000 e5b7c4ca Iustin Pop

1001 e5b7c4ca Iustin Pop
    """
1002 c744425f Michael Hanselmann
    if self.request_body:
1003 c744425f Michael Hanselmann
      if self.queryargs:
1004 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
1005 c744425f Michael Hanselmann
1006 c744425f Michael Hanselmann
      body = self.request_body
1007 bd0807fe Guido Trotter
    elif self.queryargs:
1008 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
1009 c744425f Michael Hanselmann
      body = {
1010 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
1011 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
1012 c744425f Michael Hanselmann
        }
1013 bd0807fe Guido Trotter
    else:
1014 bd0807fe Guido Trotter
      body = {}
1015 c744425f Michael Hanselmann
1016 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
1017 c744425f Michael Hanselmann
1018 be1ddd09 Michael Hanselmann
    return self.SubmitJob(ops)
1019 e5b7c4ca Iustin Pop
1020 e5b7c4ca Iustin Pop
1021 0dbc732c Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.OpcodeResource):
1022 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
1023 4c98b915 Michael Hanselmann

1024 4c98b915 Michael Hanselmann
  """
1025 0dbc732c Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReplaceDisks
1026 0dbc732c Michael Hanselmann
1027 0dbc732c Michael Hanselmann
  def GetPostOpInput(self):
1028 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1029 4c98b915 Michael Hanselmann

1030 4c98b915 Michael Hanselmann
    """
1031 0dbc732c Michael Hanselmann
    static = {
1032 0dbc732c Michael Hanselmann
      "instance_name": self.items[0],
1033 0dbc732c Michael Hanselmann
      }
1034 4c98b915 Michael Hanselmann
1035 539d65ba Michael Hanselmann
    if self.request_body:
1036 7dcf333d Michael Hanselmann
      data = self.request_body
1037 539d65ba Michael Hanselmann
    elif self.queryargs:
1038 539d65ba Michael Hanselmann
      # Legacy interface, do not modify/extend
1039 7dcf333d Michael Hanselmann
      data = {
1040 539d65ba Michael Hanselmann
        "remote_node": self._checkStringVariable("remote_node", default=None),
1041 539d65ba Michael Hanselmann
        "mode": self._checkStringVariable("mode", default=None),
1042 539d65ba Michael Hanselmann
        "disks": self._checkStringVariable("disks", default=None),
1043 539d65ba Michael Hanselmann
        "iallocator": self._checkStringVariable("iallocator", default=None),
1044 539d65ba Michael Hanselmann
        }
1045 539d65ba Michael Hanselmann
    else:
1046 7dcf333d Michael Hanselmann
      data = {}
1047 539d65ba Michael Hanselmann
1048 0dbc732c Michael Hanselmann
    # Parse disks
1049 0dbc732c Michael Hanselmann
    try:
1050 7dcf333d Michael Hanselmann
      raw_disks = data.pop("disks")
1051 0dbc732c Michael Hanselmann
    except KeyError:
1052 0dbc732c Michael Hanselmann
      pass
1053 0dbc732c Michael Hanselmann
    else:
1054 7dcf333d Michael Hanselmann
      if raw_disks:
1055 7dcf333d Michael Hanselmann
        if ht.TListOf(ht.TInt)(raw_disks): # pylint: disable=E1102
1056 7dcf333d Michael Hanselmann
          data["disks"] = raw_disks
1057 7dcf333d Michael Hanselmann
        else:
1058 7dcf333d Michael Hanselmann
          # Backwards compatibility for strings of the format "1, 2, 3"
1059 7dcf333d Michael Hanselmann
          try:
1060 7dcf333d Michael Hanselmann
            data["disks"] = [int(part) for part in raw_disks.split(",")]
1061 7dcf333d Michael Hanselmann
          except (TypeError, ValueError), err:
1062 7dcf333d Michael Hanselmann
            raise http.HttpBadRequest("Invalid disk index passed: %s" % err)
1063 0dbc732c Michael Hanselmann
1064 0dbc732c Michael Hanselmann
    return (data, static)
1065 4c98b915 Michael Hanselmann
1066 4c98b915 Michael Hanselmann
1067 1824a7a1 Michael Hanselmann
class R_2_instances_name_activate_disks(baserlib.OpcodeResource):
1068 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1069 2197b66f René Nussbaumer

1070 2197b66f René Nussbaumer
  """
1071 1824a7a1 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceActivateDisks
1072 1824a7a1 Michael Hanselmann
1073 1824a7a1 Michael Hanselmann
  def GetPutOpInput(self):
1074 2197b66f René Nussbaumer
    """Activate disks for an instance.
1075 2197b66f René Nussbaumer

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

1078 2197b66f René Nussbaumer
    """
1079 1824a7a1 Michael Hanselmann
    return ({}, {
1080 1824a7a1 Michael Hanselmann
      "instance_name": self.items[0],
1081 1824a7a1 Michael Hanselmann
      "ignore_size": bool(self._checkIntVariable("ignore_size")),
1082 1824a7a1 Michael Hanselmann
      })
1083 2197b66f René Nussbaumer
1084 2197b66f René Nussbaumer
1085 973ec124 Michael Hanselmann
class R_2_instances_name_deactivate_disks(baserlib.OpcodeResource):
1086 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1087 0a37de5f René Nussbaumer

1088 0a37de5f René Nussbaumer
  """
1089 973ec124 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceDeactivateDisks
1090 973ec124 Michael Hanselmann
1091 973ec124 Michael Hanselmann
  def GetPutOpInput(self):
1092 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1093 0a37de5f René Nussbaumer

1094 0a37de5f René Nussbaumer
    """
1095 973ec124 Michael Hanselmann
    return ({}, {
1096 973ec124 Michael Hanselmann
      "instance_name": self.items[0],
1097 973ec124 Michael Hanselmann
      })
1098 0a37de5f René Nussbaumer
1099 0a37de5f René Nussbaumer
1100 a52978c7 Michael Hanselmann
class R_2_instances_name_recreate_disks(baserlib.OpcodeResource):
1101 a52978c7 Michael Hanselmann
  """/2/instances/[instance_name]/recreate-disks resource.
1102 a52978c7 Michael Hanselmann

1103 a52978c7 Michael Hanselmann
  """
1104 a52978c7 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceRecreateDisks
1105 a52978c7 Michael Hanselmann
1106 a52978c7 Michael Hanselmann
  def GetPostOpInput(self):
1107 a52978c7 Michael Hanselmann
    """Recreate disks for an instance.
1108 a52978c7 Michael Hanselmann

1109 a52978c7 Michael Hanselmann
    """
1110 a52978c7 Michael Hanselmann
    return ({}, {
1111 a52978c7 Michael Hanselmann
      "instance_name": self.items[0],
1112 a52978c7 Michael Hanselmann
      })
1113 a52978c7 Michael Hanselmann
1114 a52978c7 Michael Hanselmann
1115 1c63311d Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.OpcodeResource):
1116 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1117 ebeb600f Michael Hanselmann

1118 ebeb600f Michael Hanselmann
  """
1119 1c63311d Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupPrepare
1120 ebeb600f Michael Hanselmann
1121 1c63311d Michael Hanselmann
  def GetPutOpInput(self):
1122 1c63311d Michael Hanselmann
    """Prepares an export for an instance.
1123 ebeb600f Michael Hanselmann

1124 ebeb600f Michael Hanselmann
    """
1125 1c63311d Michael Hanselmann
    return ({}, {
1126 1c63311d Michael Hanselmann
      "instance_name": self.items[0],
1127 1c63311d Michael Hanselmann
      "mode": self._checkStringVariable("mode"),
1128 1c63311d Michael Hanselmann
      })
1129 ebeb600f Michael Hanselmann
1130 ebeb600f Michael Hanselmann
1131 134afbe7 Michael Hanselmann
class R_2_instances_name_export(baserlib.OpcodeResource):
1132 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1133 ebeb600f Michael Hanselmann

1134 ebeb600f Michael Hanselmann
  """
1135 134afbe7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupExport
1136 134afbe7 Michael Hanselmann
  PUT_RENAME = {
1137 134afbe7 Michael Hanselmann
    "destination": "target_node",
1138 134afbe7 Michael Hanselmann
    }
1139 ebeb600f Michael Hanselmann
1140 134afbe7 Michael Hanselmann
  def GetPutOpInput(self):
1141 134afbe7 Michael Hanselmann
    """Exports an instance.
1142 ebeb600f Michael Hanselmann

1143 ebeb600f Michael Hanselmann
    """
1144 134afbe7 Michael Hanselmann
    return (self.request_body, {
1145 134afbe7 Michael Hanselmann
      "instance_name": self.items[0],
1146 134afbe7 Michael Hanselmann
      })
1147 ebeb600f Michael Hanselmann
1148 ebeb600f Michael Hanselmann
1149 075a29be Michael Hanselmann
class R_2_instances_name_migrate(baserlib.OpcodeResource):
1150 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1151 5823e0d2 Michael Hanselmann

1152 5823e0d2 Michael Hanselmann
  """
1153 075a29be Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceMigrate
1154 5823e0d2 Michael Hanselmann
1155 075a29be Michael Hanselmann
  def GetPutOpInput(self):
1156 075a29be Michael Hanselmann
    """Migrates an instance.
1157 5823e0d2 Michael Hanselmann

1158 5823e0d2 Michael Hanselmann
    """
1159 075a29be Michael Hanselmann
    return (self.request_body, {
1160 075a29be Michael Hanselmann
      "instance_name": self.items[0],
1161 075a29be Michael Hanselmann
      })
1162 5823e0d2 Michael Hanselmann
1163 5823e0d2 Michael Hanselmann
1164 b5f2ab80 Michael Hanselmann
class R_2_instances_name_failover(baserlib.OpcodeResource):
1165 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1166 c0a146a1 Michael Hanselmann

1167 c0a146a1 Michael Hanselmann
  """
1168 b5f2ab80 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceFailover
1169 c0a146a1 Michael Hanselmann
1170 b5f2ab80 Michael Hanselmann
  def GetPutOpInput(self):
1171 b5f2ab80 Michael Hanselmann
    """Does a failover of an instance.
1172 c0a146a1 Michael Hanselmann

1173 c0a146a1 Michael Hanselmann
    """
1174 b5f2ab80 Michael Hanselmann
    return (self.request_body, {
1175 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1176 c0a146a1 Michael Hanselmann
      })
1177 c0a146a1 Michael Hanselmann
1178 c0a146a1 Michael Hanselmann
1179 d76f9b5d Michael Hanselmann
class R_2_instances_name_rename(baserlib.OpcodeResource):
1180 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1181 d56e7dc7 Michael Hanselmann

1182 d56e7dc7 Michael Hanselmann
  """
1183 d76f9b5d Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceRename
1184 d56e7dc7 Michael Hanselmann
1185 d76f9b5d Michael Hanselmann
  def GetPutOpInput(self):
1186 d76f9b5d Michael Hanselmann
    """Changes the name of an instance.
1187 d56e7dc7 Michael Hanselmann

1188 d56e7dc7 Michael Hanselmann
    """
1189 d76f9b5d Michael Hanselmann
    return (self.request_body, {
1190 d76f9b5d Michael Hanselmann
      "instance_name": self.items[0],
1191 d76f9b5d Michael Hanselmann
      })
1192 d56e7dc7 Michael Hanselmann
1193 d56e7dc7 Michael Hanselmann
1194 f3db88ba Michael Hanselmann
class R_2_instances_name_modify(baserlib.OpcodeResource):
1195 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1196 3882937a Michael Hanselmann

1197 3882937a Michael Hanselmann
  """
1198 f3db88ba Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceSetParams
1199 3882937a Michael Hanselmann
1200 f3db88ba Michael Hanselmann
  def GetPutOpInput(self):
1201 f3db88ba Michael Hanselmann
    """Changes parameters of an instance.
1202 3882937a Michael Hanselmann

1203 3882937a Michael Hanselmann
    """
1204 f3db88ba Michael Hanselmann
    return (self.request_body, {
1205 f3db88ba Michael Hanselmann
      "instance_name": self.items[0],
1206 f3db88ba Michael Hanselmann
      })
1207 3882937a Michael Hanselmann
1208 3882937a Michael Hanselmann
1209 335965b9 Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.OpcodeResource):
1210 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1211 e23881ed Michael Hanselmann

1212 e23881ed Michael Hanselmann
  """
1213 335965b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceGrowDisk
1214 e23881ed Michael Hanselmann
1215 335965b9 Michael Hanselmann
  def GetPostOpInput(self):
1216 335965b9 Michael Hanselmann
    """Increases the size of an instance disk.
1217 e23881ed Michael Hanselmann

1218 e23881ed Michael Hanselmann
    """
1219 335965b9 Michael Hanselmann
    return (self.request_body, {
1220 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1221 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1222 e23881ed Michael Hanselmann
      })
1223 e23881ed Michael Hanselmann
1224 e23881ed Michael Hanselmann
1225 26ff6ee2 Michael Hanselmann
class R_2_instances_name_console(baserlib.ResourceBase):
1226 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1227 b82d4c5e Michael Hanselmann

1228 b82d4c5e Michael Hanselmann
  """
1229 5e12acfe Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE, rapi.RAPI_ACCESS_READ]
1230 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceConsole
1231 b82d4c5e Michael Hanselmann
1232 b82d4c5e Michael Hanselmann
  def GET(self):
1233 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1234 b82d4c5e Michael Hanselmann

1235 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1236 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1237 b82d4c5e Michael Hanselmann

1238 b82d4c5e Michael Hanselmann
    """
1239 be1ddd09 Michael Hanselmann
    client = self.GetClient()
1240 b82d4c5e Michael Hanselmann
1241 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1242 b82d4c5e Michael Hanselmann
1243 b82d4c5e Michael Hanselmann
    if console is None:
1244 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1245 b82d4c5e Michael Hanselmann
1246 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1247 b82d4c5e Michael Hanselmann
    return console
1248 b82d4c5e Michael Hanselmann
1249 b82d4c5e Michael Hanselmann
1250 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1251 2a38e913 Michael Hanselmann
  """Tries to extract C{fields} query parameter.
1252 2a38e913 Michael Hanselmann

1253 2a38e913 Michael Hanselmann
  @type args: dictionary
1254 2a38e913 Michael Hanselmann
  @rtype: list of string
1255 2a38e913 Michael Hanselmann
  @raise http.HttpBadRequest: When parameter can't be found
1256 208a6cff Michael Hanselmann

1257 208a6cff Michael Hanselmann
  """
1258 208a6cff Michael Hanselmann
  try:
1259 208a6cff Michael Hanselmann
    fields = args["fields"]
1260 208a6cff Michael Hanselmann
  except KeyError:
1261 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1262 208a6cff Michael Hanselmann
1263 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1264 208a6cff Michael Hanselmann
1265 208a6cff Michael Hanselmann
1266 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1267 2a38e913 Michael Hanselmann
  """Splits fields as given for a query request.
1268 2a38e913 Michael Hanselmann

1269 2a38e913 Michael Hanselmann
  @type fields: string
1270 2a38e913 Michael Hanselmann
  @rtype: list of string
1271 208a6cff Michael Hanselmann

1272 208a6cff Michael Hanselmann
  """
1273 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1274 208a6cff Michael Hanselmann
1275 208a6cff Michael Hanselmann
1276 26ff6ee2 Michael Hanselmann
class R_2_query(baserlib.ResourceBase):
1277 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1278 208a6cff Michael Hanselmann

1279 208a6cff Michael Hanselmann
  """
1280 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1281 5e12acfe Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE, rapi.RAPI_ACCESS_READ]
1282 5e12acfe Michael Hanselmann
  PUT_ACCESS = GET_ACCESS
1283 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpQuery
1284 f6ce0ba2 Michael Hanselmann
  PUT_OPCODE = opcodes.OpQuery
1285 208a6cff Michael Hanselmann
1286 2e5c33db Iustin Pop
  def _Query(self, fields, qfilter):
1287 2e5c33db Iustin Pop
    return self.GetClient().Query(self.items[0], fields, qfilter).ToDict()
1288 208a6cff Michael Hanselmann
1289 208a6cff Michael Hanselmann
  def GET(self):
1290 208a6cff Michael Hanselmann
    """Returns resource information.
1291 208a6cff Michael Hanselmann

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

1294 208a6cff Michael Hanselmann
    """
1295 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1296 208a6cff Michael Hanselmann
1297 208a6cff Michael Hanselmann
  def PUT(self):
1298 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1299 208a6cff Michael Hanselmann

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

1302 208a6cff Michael Hanselmann
    """
1303 208a6cff Michael Hanselmann
    body = self.request_body
1304 208a6cff Michael Hanselmann
1305 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1306 208a6cff Michael Hanselmann
1307 208a6cff Michael Hanselmann
    try:
1308 208a6cff Michael Hanselmann
      fields = body["fields"]
1309 208a6cff Michael Hanselmann
    except KeyError:
1310 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1311 208a6cff Michael Hanselmann
1312 2e5c33db Iustin Pop
    qfilter = body.get("qfilter", None)
1313 2e5c33db Iustin Pop
    # TODO: remove this after 2.7
1314 2e5c33db Iustin Pop
    if qfilter is None:
1315 2e5c33db Iustin Pop
      qfilter = body.get("filter", None)
1316 2e5c33db Iustin Pop
1317 2e5c33db Iustin Pop
    return self._Query(fields, qfilter)
1318 208a6cff Michael Hanselmann
1319 208a6cff Michael Hanselmann
1320 26ff6ee2 Michael Hanselmann
class R_2_query_fields(baserlib.ResourceBase):
1321 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1322 208a6cff Michael Hanselmann

1323 208a6cff Michael Hanselmann
  """
1324 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpQueryFields
1325 f6ce0ba2 Michael Hanselmann
1326 208a6cff Michael Hanselmann
  def GET(self):
1327 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1328 208a6cff Michael Hanselmann

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

1331 208a6cff Michael Hanselmann
    """
1332 208a6cff Michael Hanselmann
    try:
1333 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1334 208a6cff Michael Hanselmann
    except KeyError:
1335 208a6cff Michael Hanselmann
      fields = None
1336 208a6cff Michael Hanselmann
    else:
1337 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1338 208a6cff Michael Hanselmann
1339 be1ddd09 Michael Hanselmann
    return self.GetClient().QueryFields(self.items[0], fields).ToDict()
1340 208a6cff Michael Hanselmann
1341 208a6cff Michael Hanselmann
1342 460ef073 Michael Hanselmann
class _R_Tags(baserlib.OpcodeResource):
1343 3bd0f3d8 Iustin Pop
  """Quasiclass for tagging resources.
1344 441e7cfd Oleksiy Mishchenko

1345 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1346 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1347 441e7cfd Oleksiy Mishchenko

1348 441e7cfd Oleksiy Mishchenko
  """
1349 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1350 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpTagsGet
1351 460ef073 Michael Hanselmann
  PUT_OPCODE = opcodes.OpTagsSet
1352 460ef073 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpTagsDel
1353 18cb43a2 Oleksiy Mishchenko
1354 460ef073 Michael Hanselmann
  def __init__(self, items, queryargs, req, **kwargs):
1355 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1356 18cb43a2 Oleksiy Mishchenko

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

1359 18cb43a2 Oleksiy Mishchenko
    """
1360 460ef073 Michael Hanselmann
    baserlib.OpcodeResource.__init__(self, items, queryargs, req, **kwargs)
1361 18cb43a2 Oleksiy Mishchenko
1362 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1363 5313eed7 Michael Hanselmann
      self.name = None
1364 18cb43a2 Oleksiy Mishchenko
    else:
1365 5313eed7 Michael Hanselmann
      self.name = items[0]
1366 441e7cfd Oleksiy Mishchenko
1367 441e7cfd Oleksiy Mishchenko
  def GET(self):
1368 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1369 441e7cfd Oleksiy Mishchenko

1370 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1371 441e7cfd Oleksiy Mishchenko

1372 441e7cfd Oleksiy Mishchenko
    """
1373 f87ec53f Michael Hanselmann
    kind = self.TAG_LEVEL
1374 f87ec53f Michael Hanselmann
1375 f87ec53f Michael Hanselmann
    if kind in (constants.TAG_INSTANCE,
1376 f87ec53f Michael Hanselmann
                constants.TAG_NODEGROUP,
1377 f87ec53f Michael Hanselmann
                constants.TAG_NODE):
1378 f87ec53f Michael Hanselmann
      if not self.name:
1379 f87ec53f Michael Hanselmann
        raise http.HttpBadRequest("Missing name on tag request")
1380 f87ec53f Michael Hanselmann
1381 f2374060 Iustin Pop
      cl = self.GetClient(query=True)
1382 cebd85d8 Iustin Pop
      tags = list(cl.QueryTags(kind, self.name))
1383 f87ec53f Michael Hanselmann
1384 f87ec53f Michael Hanselmann
    elif kind == constants.TAG_CLUSTER:
1385 f87ec53f Michael Hanselmann
      assert not self.name
1386 f87ec53f Michael Hanselmann
      # TODO: Use query API?
1387 f87ec53f Michael Hanselmann
      ssc = ssconf.SimpleStore()
1388 f87ec53f Michael Hanselmann
      tags = ssc.GetClusterTags()
1389 f87ec53f Michael Hanselmann
1390 f87ec53f Michael Hanselmann
    return list(tags)
1391 441e7cfd Oleksiy Mishchenko
1392 460ef073 Michael Hanselmann
  def GetPutOpInput(self):
1393 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1394 441e7cfd Oleksiy Mishchenko

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

1398 441e7cfd Oleksiy Mishchenko
    """
1399 460ef073 Michael Hanselmann
    return ({}, {
1400 460ef073 Michael Hanselmann
      "kind": self.TAG_LEVEL,
1401 460ef073 Michael Hanselmann
      "name": self.name,
1402 460ef073 Michael Hanselmann
      "tags": self.queryargs.get("tag", []),
1403 460ef073 Michael Hanselmann
      "dry_run": self.dryRun(),
1404 460ef073 Michael Hanselmann
      })
1405 15fd9fd5 Oleksiy Mishchenko
1406 460ef073 Michael Hanselmann
  def GetDeleteOpInput(self):
1407 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1408 15fd9fd5 Oleksiy Mishchenko

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

1413 15fd9fd5 Oleksiy Mishchenko
    """
1414 460ef073 Michael Hanselmann
    # Re-use code
1415 460ef073 Michael Hanselmann
    return self.GetPutOpInput()
1416 18cb43a2 Oleksiy Mishchenko
1417 18cb43a2 Oleksiy Mishchenko
1418 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1419 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1420 18cb43a2 Oleksiy Mishchenko

1421 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1422 18cb43a2 Oleksiy Mishchenko

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

1430 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1431 18cb43a2 Oleksiy Mishchenko

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

1439 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1440 414ebaf1 Michael Hanselmann

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

1448 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1449 18cb43a2 Oleksiy Mishchenko

1450 18cb43a2 Oleksiy Mishchenko
  """
1451 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER