Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 566db1f2

History | View | Annotate | Download (38 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 539d65ba Michael Hanselmann
    raw_disks = data.pop("disks")
1025 d1c172de Michael Hanselmann
  except KeyError:
1026 d1c172de Michael Hanselmann
    pass
1027 d1c172de Michael Hanselmann
  else:
1028 539d65ba Michael Hanselmann
    if raw_disks:
1029 539d65ba Michael Hanselmann
      if ht.TListOf(ht.TInt)(raw_disks): # pylint: disable=E1102
1030 539d65ba Michael Hanselmann
        data["disks"] = raw_disks
1031 539d65ba Michael Hanselmann
      else:
1032 539d65ba Michael Hanselmann
        # Backwards compatibility for strings of the format "1, 2, 3"
1033 539d65ba Michael Hanselmann
        try:
1034 539d65ba Michael Hanselmann
          data["disks"] = [int(part) for part in raw_disks.split(",")]
1035 539d65ba Michael Hanselmann
        except (TypeError, ValueError), err:
1036 539d65ba Michael Hanselmann
          raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
1037 d1c172de Michael Hanselmann
1038 d1c172de Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceReplaceDisks, data, override)
1039 d1c172de Michael Hanselmann
1040 d1c172de Michael Hanselmann
1041 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
1042 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
1043 4c98b915 Michael Hanselmann

1044 4c98b915 Michael Hanselmann
  """
1045 4c98b915 Michael Hanselmann
  def POST(self):
1046 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1047 4c98b915 Michael Hanselmann

1048 4c98b915 Michael Hanselmann
    """
1049 539d65ba Michael Hanselmann
    if self.request_body:
1050 539d65ba Michael Hanselmann
      body = self.request_body
1051 539d65ba Michael Hanselmann
    elif self.queryargs:
1052 539d65ba Michael Hanselmann
      # Legacy interface, do not modify/extend
1053 539d65ba Michael Hanselmann
      body = {
1054 539d65ba Michael Hanselmann
        "remote_node": self._checkStringVariable("remote_node", default=None),
1055 539d65ba Michael Hanselmann
        "mode": self._checkStringVariable("mode", default=None),
1056 539d65ba Michael Hanselmann
        "disks": self._checkStringVariable("disks", default=None),
1057 539d65ba Michael Hanselmann
        "iallocator": self._checkStringVariable("iallocator", default=None),
1058 539d65ba Michael Hanselmann
        }
1059 539d65ba Michael Hanselmann
    else:
1060 539d65ba Michael Hanselmann
      body = {}
1061 539d65ba Michael Hanselmann
1062 539d65ba Michael Hanselmann
    op = _ParseInstanceReplaceDisksRequest(self.items[0], body)
1063 4c98b915 Michael Hanselmann
1064 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
1065 4c98b915 Michael Hanselmann
1066 4c98b915 Michael Hanselmann
1067 2197b66f René Nussbaumer
class R_2_instances_name_activate_disks(baserlib.R_Generic):
1068 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1069 2197b66f René Nussbaumer

1070 2197b66f René Nussbaumer
  """
1071 2197b66f René Nussbaumer
  def PUT(self):
1072 2197b66f René Nussbaumer
    """Activate disks for an instance.
1073 2197b66f René Nussbaumer

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

1076 2197b66f René Nussbaumer
    """
1077 2197b66f René Nussbaumer
    instance_name = self.items[0]
1078 d0c8c01d Iustin Pop
    ignore_size = bool(self._checkIntVariable("ignore_size"))
1079 2197b66f René Nussbaumer
1080 83f5d475 Iustin Pop
    op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
1081 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
1082 2197b66f René Nussbaumer
1083 2197b66f René Nussbaumer
    return baserlib.SubmitJob([op])
1084 2197b66f René Nussbaumer
1085 2197b66f René Nussbaumer
1086 0a37de5f René Nussbaumer
class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
1087 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1088 0a37de5f René Nussbaumer

1089 0a37de5f René Nussbaumer
  """
1090 0a37de5f René Nussbaumer
  def PUT(self):
1091 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1092 0a37de5f René Nussbaumer

1093 0a37de5f René Nussbaumer
    """
1094 0a37de5f René Nussbaumer
    instance_name = self.items[0]
1095 0a37de5f René Nussbaumer
1096 e176281f Iustin Pop
    op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name)
1097 0a37de5f René Nussbaumer
1098 0a37de5f René Nussbaumer
    return baserlib.SubmitJob([op])
1099 0a37de5f René Nussbaumer
1100 0a37de5f René Nussbaumer
1101 ebeb600f Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.R_Generic):
1102 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1103 ebeb600f Michael Hanselmann

1104 ebeb600f Michael Hanselmann
  """
1105 ebeb600f Michael Hanselmann
  def PUT(self):
1106 ebeb600f Michael Hanselmann
    """Prepares an export for an instance.
1107 ebeb600f Michael Hanselmann

1108 ebeb600f Michael Hanselmann
    @return: a job id
1109 ebeb600f Michael Hanselmann

1110 ebeb600f Michael Hanselmann
    """
1111 ebeb600f Michael Hanselmann
    instance_name = self.items[0]
1112 ebeb600f Michael Hanselmann
    mode = self._checkStringVariable("mode")
1113 ebeb600f Michael Hanselmann
1114 71910715 Iustin Pop
    op = opcodes.OpBackupPrepare(instance_name=instance_name,
1115 ebeb600f Michael Hanselmann
                                 mode=mode)
1116 ebeb600f Michael Hanselmann
1117 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1118 ebeb600f Michael Hanselmann
1119 ebeb600f Michael Hanselmann
1120 ebeb600f Michael Hanselmann
def _ParseExportInstanceRequest(name, data):
1121 ebeb600f Michael Hanselmann
  """Parses a request for an instance export.
1122 ebeb600f Michael Hanselmann

1123 4ff922a2 Iustin Pop
  @rtype: L{opcodes.OpBackupExport}
1124 ebeb600f Michael Hanselmann
  @return: Instance export opcode
1125 ebeb600f Michael Hanselmann

1126 ebeb600f Michael Hanselmann
  """
1127 07ce3e70 Michael Hanselmann
  # Rename "destination" to "target_node"
1128 07ce3e70 Michael Hanselmann
  try:
1129 07ce3e70 Michael Hanselmann
    data["target_node"] = data.pop("destination")
1130 07ce3e70 Michael Hanselmann
  except KeyError:
1131 07ce3e70 Michael Hanselmann
    pass
1132 07ce3e70 Michael Hanselmann
1133 07ce3e70 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpBackupExport, data, {
1134 07ce3e70 Michael Hanselmann
    "instance_name": name,
1135 07ce3e70 Michael Hanselmann
    })
1136 ebeb600f Michael Hanselmann
1137 ebeb600f Michael Hanselmann
1138 ebeb600f Michael Hanselmann
class R_2_instances_name_export(baserlib.R_Generic):
1139 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1140 ebeb600f Michael Hanselmann

1141 ebeb600f Michael Hanselmann
  """
1142 ebeb600f Michael Hanselmann
  def PUT(self):
1143 ebeb600f Michael Hanselmann
    """Exports an instance.
1144 ebeb600f Michael Hanselmann

1145 ebeb600f Michael Hanselmann
    @return: a job id
1146 ebeb600f Michael Hanselmann

1147 ebeb600f Michael Hanselmann
    """
1148 ebeb600f Michael Hanselmann
    if not isinstance(self.request_body, dict):
1149 ebeb600f Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
1150 ebeb600f Michael Hanselmann
1151 ebeb600f Michael Hanselmann
    op = _ParseExportInstanceRequest(self.items[0], self.request_body)
1152 ebeb600f Michael Hanselmann
1153 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1154 ebeb600f Michael Hanselmann
1155 ebeb600f Michael Hanselmann
1156 5823e0d2 Michael Hanselmann
def _ParseMigrateInstanceRequest(name, data):
1157 5823e0d2 Michael Hanselmann
  """Parses a request for an instance migration.
1158 5823e0d2 Michael Hanselmann

1159 75c866c2 Iustin Pop
  @rtype: L{opcodes.OpInstanceMigrate}
1160 5823e0d2 Michael Hanselmann
  @return: Instance migration opcode
1161 5823e0d2 Michael Hanselmann

1162 5823e0d2 Michael Hanselmann
  """
1163 c1a27c9a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceMigrate, data, {
1164 c1a27c9a Michael Hanselmann
    "instance_name": name,
1165 c1a27c9a Michael Hanselmann
    })
1166 5823e0d2 Michael Hanselmann
1167 5823e0d2 Michael Hanselmann
1168 5823e0d2 Michael Hanselmann
class R_2_instances_name_migrate(baserlib.R_Generic):
1169 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1170 5823e0d2 Michael Hanselmann

1171 5823e0d2 Michael Hanselmann
  """
1172 5823e0d2 Michael Hanselmann
  def PUT(self):
1173 5823e0d2 Michael Hanselmann
    """Migrates an instance.
1174 5823e0d2 Michael Hanselmann

1175 5823e0d2 Michael Hanselmann
    @return: a job id
1176 5823e0d2 Michael Hanselmann

1177 5823e0d2 Michael Hanselmann
    """
1178 5823e0d2 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1179 5823e0d2 Michael Hanselmann
1180 5823e0d2 Michael Hanselmann
    op = _ParseMigrateInstanceRequest(self.items[0], self.request_body)
1181 5823e0d2 Michael Hanselmann
1182 5823e0d2 Michael Hanselmann
    return baserlib.SubmitJob([op])
1183 5823e0d2 Michael Hanselmann
1184 5823e0d2 Michael Hanselmann
1185 c0a146a1 Michael Hanselmann
class R_2_instances_name_failover(baserlib.R_Generic):
1186 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1187 c0a146a1 Michael Hanselmann

1188 c0a146a1 Michael Hanselmann
  """
1189 c0a146a1 Michael Hanselmann
  def PUT(self):
1190 c0a146a1 Michael Hanselmann
    """Does a failover of an instance.
1191 c0a146a1 Michael Hanselmann

1192 c0a146a1 Michael Hanselmann
    @return: a job id
1193 c0a146a1 Michael Hanselmann

1194 c0a146a1 Michael Hanselmann
    """
1195 c0a146a1 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1196 c0a146a1 Michael Hanselmann
1197 c0a146a1 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpInstanceFailover, self.request_body, {
1198 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1199 c0a146a1 Michael Hanselmann
      })
1200 c0a146a1 Michael Hanselmann
1201 c0a146a1 Michael Hanselmann
    return baserlib.SubmitJob([op])
1202 c0a146a1 Michael Hanselmann
1203 c0a146a1 Michael Hanselmann
1204 d56e7dc7 Michael Hanselmann
def _ParseRenameInstanceRequest(name, data):
1205 d56e7dc7 Michael Hanselmann
  """Parses a request for renaming an instance.
1206 d56e7dc7 Michael Hanselmann

1207 5659e2e2 Iustin Pop
  @rtype: L{opcodes.OpInstanceRename}
1208 d56e7dc7 Michael Hanselmann
  @return: Instance rename opcode
1209 d56e7dc7 Michael Hanselmann

1210 d56e7dc7 Michael Hanselmann
  """
1211 88bc199a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceRename, data, {
1212 88bc199a Michael Hanselmann
    "instance_name": name,
1213 88bc199a Michael Hanselmann
    })
1214 d56e7dc7 Michael Hanselmann
1215 d56e7dc7 Michael Hanselmann
1216 d56e7dc7 Michael Hanselmann
class R_2_instances_name_rename(baserlib.R_Generic):
1217 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1218 d56e7dc7 Michael Hanselmann

1219 d56e7dc7 Michael Hanselmann
  """
1220 d56e7dc7 Michael Hanselmann
  def PUT(self):
1221 d56e7dc7 Michael Hanselmann
    """Changes the name of an instance.
1222 d56e7dc7 Michael Hanselmann

1223 d56e7dc7 Michael Hanselmann
    @return: a job id
1224 d56e7dc7 Michael Hanselmann

1225 d56e7dc7 Michael Hanselmann
    """
1226 d56e7dc7 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1227 d56e7dc7 Michael Hanselmann
1228 d56e7dc7 Michael Hanselmann
    op = _ParseRenameInstanceRequest(self.items[0], self.request_body)
1229 d56e7dc7 Michael Hanselmann
1230 d56e7dc7 Michael Hanselmann
    return baserlib.SubmitJob([op])
1231 d56e7dc7 Michael Hanselmann
1232 d56e7dc7 Michael Hanselmann
1233 3882937a Michael Hanselmann
def _ParseModifyInstanceRequest(name, data):
1234 3882937a Michael Hanselmann
  """Parses a request for modifying an instance.
1235 3882937a Michael Hanselmann

1236 9a3cc7ae Iustin Pop
  @rtype: L{opcodes.OpInstanceSetParams}
1237 3882937a Michael Hanselmann
  @return: Instance modify opcode
1238 3882937a Michael Hanselmann

1239 3882937a Michael Hanselmann
  """
1240 ee5549c7 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceSetParams, data, {
1241 ee5549c7 Michael Hanselmann
    "instance_name": name,
1242 ee5549c7 Michael Hanselmann
    })
1243 3882937a Michael Hanselmann
1244 3882937a Michael Hanselmann
1245 3882937a Michael Hanselmann
class R_2_instances_name_modify(baserlib.R_Generic):
1246 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1247 3882937a Michael Hanselmann

1248 3882937a Michael Hanselmann
  """
1249 3882937a Michael Hanselmann
  def PUT(self):
1250 3882937a Michael Hanselmann
    """Changes some parameters of an instance.
1251 3882937a Michael Hanselmann

1252 3882937a Michael Hanselmann
    @return: a job id
1253 3882937a Michael Hanselmann

1254 3882937a Michael Hanselmann
    """
1255 3882937a Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1256 3882937a Michael Hanselmann
1257 3882937a Michael Hanselmann
    op = _ParseModifyInstanceRequest(self.items[0], self.request_body)
1258 3882937a Michael Hanselmann
1259 3882937a Michael Hanselmann
    return baserlib.SubmitJob([op])
1260 3882937a Michael Hanselmann
1261 3882937a Michael Hanselmann
1262 e23881ed Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.R_Generic):
1263 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1264 e23881ed Michael Hanselmann

1265 e23881ed Michael Hanselmann
  """
1266 e23881ed Michael Hanselmann
  def POST(self):
1267 e23881ed Michael Hanselmann
    """Increases the size of an instance disk.
1268 e23881ed Michael Hanselmann

1269 e23881ed Michael Hanselmann
    @return: a job id
1270 e23881ed Michael Hanselmann

1271 e23881ed Michael Hanselmann
    """
1272 60472d29 Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpInstanceGrowDisk, self.request_body, {
1273 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1274 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1275 e23881ed Michael Hanselmann
      })
1276 e23881ed Michael Hanselmann
1277 e23881ed Michael Hanselmann
    return baserlib.SubmitJob([op])
1278 e23881ed Michael Hanselmann
1279 e23881ed Michael Hanselmann
1280 b82d4c5e Michael Hanselmann
class R_2_instances_name_console(baserlib.R_Generic):
1281 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1282 b82d4c5e Michael Hanselmann

1283 b82d4c5e Michael Hanselmann
  """
1284 b82d4c5e Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1285 b82d4c5e Michael Hanselmann
1286 b82d4c5e Michael Hanselmann
  def GET(self):
1287 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1288 b82d4c5e Michael Hanselmann

1289 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1290 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1291 b82d4c5e Michael Hanselmann

1292 b82d4c5e Michael Hanselmann
    """
1293 b82d4c5e Michael Hanselmann
    client = baserlib.GetClient()
1294 b82d4c5e Michael Hanselmann
1295 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1296 b82d4c5e Michael Hanselmann
1297 b82d4c5e Michael Hanselmann
    if console is None:
1298 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1299 b82d4c5e Michael Hanselmann
1300 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1301 b82d4c5e Michael Hanselmann
    return console
1302 b82d4c5e Michael Hanselmann
1303 b82d4c5e Michael Hanselmann
1304 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1305 208a6cff Michael Hanselmann
  """
1306 208a6cff Michael Hanselmann

1307 208a6cff Michael Hanselmann
  """
1308 208a6cff Michael Hanselmann
  try:
1309 208a6cff Michael Hanselmann
    fields = args["fields"]
1310 208a6cff Michael Hanselmann
  except KeyError:
1311 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1312 208a6cff Michael Hanselmann
1313 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1314 208a6cff Michael Hanselmann
1315 208a6cff Michael Hanselmann
1316 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1317 208a6cff Michael Hanselmann
  """
1318 208a6cff Michael Hanselmann

1319 208a6cff Michael Hanselmann
  """
1320 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1321 208a6cff Michael Hanselmann
1322 208a6cff Michael Hanselmann
1323 208a6cff Michael Hanselmann
class R_2_query(baserlib.R_Generic):
1324 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1325 208a6cff Michael Hanselmann

1326 208a6cff Michael Hanselmann
  """
1327 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1328 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1329 208a6cff Michael Hanselmann
1330 208a6cff Michael Hanselmann
  def _Query(self, fields, filter_):
1331 208a6cff Michael Hanselmann
    return baserlib.GetClient().Query(self.items[0], fields, filter_).ToDict()
1332 208a6cff Michael Hanselmann
1333 208a6cff Michael Hanselmann
  def GET(self):
1334 208a6cff Michael Hanselmann
    """Returns resource information.
1335 208a6cff Michael Hanselmann

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

1338 208a6cff Michael Hanselmann
    """
1339 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1340 208a6cff Michael Hanselmann
1341 208a6cff Michael Hanselmann
  def PUT(self):
1342 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1343 208a6cff Michael Hanselmann

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

1346 208a6cff Michael Hanselmann
    """
1347 208a6cff Michael Hanselmann
    body = self.request_body
1348 208a6cff Michael Hanselmann
1349 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1350 208a6cff Michael Hanselmann
1351 208a6cff Michael Hanselmann
    try:
1352 208a6cff Michael Hanselmann
      fields = body["fields"]
1353 208a6cff Michael Hanselmann
    except KeyError:
1354 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1355 208a6cff Michael Hanselmann
1356 208a6cff Michael Hanselmann
    return self._Query(fields, self.request_body.get("filter", None))
1357 208a6cff Michael Hanselmann
1358 208a6cff Michael Hanselmann
1359 208a6cff Michael Hanselmann
class R_2_query_fields(baserlib.R_Generic):
1360 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1361 208a6cff Michael Hanselmann

1362 208a6cff Michael Hanselmann
  """
1363 208a6cff Michael Hanselmann
  def GET(self):
1364 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1365 208a6cff Michael Hanselmann

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

1368 208a6cff Michael Hanselmann
    """
1369 208a6cff Michael Hanselmann
    try:
1370 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1371 208a6cff Michael Hanselmann
    except KeyError:
1372 208a6cff Michael Hanselmann
      fields = None
1373 208a6cff Michael Hanselmann
    else:
1374 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1375 208a6cff Michael Hanselmann
1376 208a6cff Michael Hanselmann
    return baserlib.GetClient().QueryFields(self.items[0], fields).ToDict()
1377 208a6cff Michael Hanselmann
1378 208a6cff Michael Hanselmann
1379 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
1380 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1381 441e7cfd Oleksiy Mishchenko

1382 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1383 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1384 441e7cfd Oleksiy Mishchenko

1385 441e7cfd Oleksiy Mishchenko
  """
1386 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1387 18cb43a2 Oleksiy Mishchenko
1388 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
1389 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1390 18cb43a2 Oleksiy Mishchenko

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

1393 18cb43a2 Oleksiy Mishchenko
    """
1394 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
1395 18cb43a2 Oleksiy Mishchenko
1396 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1397 5313eed7 Michael Hanselmann
      self.name = None
1398 18cb43a2 Oleksiy Mishchenko
    else:
1399 5313eed7 Michael Hanselmann
      self.name = items[0]
1400 441e7cfd Oleksiy Mishchenko
1401 441e7cfd Oleksiy Mishchenko
  def GET(self):
1402 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1403 441e7cfd Oleksiy Mishchenko

1404 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1405 441e7cfd Oleksiy Mishchenko

1406 441e7cfd Oleksiy Mishchenko
    """
1407 b459a848 Andrea Spadaccini
    # pylint: disable=W0212
1408 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
1409 441e7cfd Oleksiy Mishchenko
1410 21f04e5e Oleksiy Mishchenko
  def PUT(self):
1411 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1412 441e7cfd Oleksiy Mishchenko

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

1416 441e7cfd Oleksiy Mishchenko
    """
1417 b459a848 Andrea Spadaccini
    # pylint: disable=W0212
1418 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1419 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
1420 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
1421 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
1422 d0c8c01d Iustin Pop
                              self.queryargs["tag"], name=self.name,
1423 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
1424 15fd9fd5 Oleksiy Mishchenko
1425 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
1426 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1427 15fd9fd5 Oleksiy Mishchenko

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

1432 15fd9fd5 Oleksiy Mishchenko
    """
1433 b459a848 Andrea Spadaccini
    # pylint: disable=W0212
1434 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1435 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
1436 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
1437 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
1438 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
1439 d0c8c01d Iustin Pop
                                 self.queryargs["tag"],
1440 6f59b964 Iustin Pop
                                 name=self.name,
1441 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
1442 18cb43a2 Oleksiy Mishchenko
1443 18cb43a2 Oleksiy Mishchenko
1444 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1445 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1446 18cb43a2 Oleksiy Mishchenko

1447 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1448 18cb43a2 Oleksiy Mishchenko

1449 18cb43a2 Oleksiy Mishchenko
  """
1450 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1451 18cb43a2 Oleksiy Mishchenko
1452 18cb43a2 Oleksiy Mishchenko
1453 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1454 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1455 18cb43a2 Oleksiy Mishchenko

1456 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1457 18cb43a2 Oleksiy Mishchenko

1458 18cb43a2 Oleksiy Mishchenko
  """
1459 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1460 18cb43a2 Oleksiy Mishchenko
1461 18cb43a2 Oleksiy Mishchenko
1462 414ebaf1 Michael Hanselmann
class R_2_groups_name_tags(_R_Tags):
1463 414ebaf1 Michael Hanselmann
  """ /2/groups/[group_name]/tags resource.
1464 414ebaf1 Michael Hanselmann

1465 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1466 414ebaf1 Michael Hanselmann

1467 414ebaf1 Michael Hanselmann
  """
1468 414ebaf1 Michael Hanselmann
  TAG_LEVEL = constants.TAG_NODEGROUP
1469 414ebaf1 Michael Hanselmann
1470 414ebaf1 Michael Hanselmann
1471 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1472 b58a4d16 Michael Hanselmann
  """ /2/tags resource.
1473 18cb43a2 Oleksiy Mishchenko

1474 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1475 18cb43a2 Oleksiy Mishchenko

1476 18cb43a2 Oleksiy Mishchenko
  """
1477 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER