Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 8fd625fc

History | View | Annotate | Download (37.5 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

182 4e5a68f8 Oleksiy Mishchenko
  """
183 be1ddd09 Michael Hanselmann
  def GET(self):
184 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
185 4e5a68f8 Oleksiy Mishchenko

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

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

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

206 4e5a68f8 Oleksiy Mishchenko
  """
207 be1ddd09 Michael Hanselmann
  def GET(self):
208 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
209 4e5a68f8 Oleksiy Mishchenko

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

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

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

235 508e9b20 Michael Hanselmann
  """
236 8fd625fc Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterRedistConf
237 508e9b20 Michael Hanselmann
238 508e9b20 Michael Hanselmann
239 50c7d82e Michael Hanselmann
class R_2_cluster_modify(baserlib.OpcodeResource):
240 62e999a5 Michael Hanselmann
  """/2/modify resource.
241 62e999a5 Michael Hanselmann

242 62e999a5 Michael Hanselmann
  """
243 50c7d82e Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterSetParams
244 62e999a5 Michael Hanselmann
245 62e999a5 Michael Hanselmann
246 26ff6ee2 Michael Hanselmann
class R_2_jobs(baserlib.ResourceBase):
247 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
248 10b207d4 Oleksiy Mishchenko

249 10b207d4 Oleksiy Mishchenko
  """
250 e987f166 Michael Hanselmann
  def GET(self):
251 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
252 10b207d4 Oleksiy Mishchenko

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

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

270 10b207d4 Oleksiy Mishchenko
  """
271 10b207d4 Oleksiy Mishchenko
  def GET(self):
272 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
273 10b207d4 Oleksiy Mishchenko

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

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

293 c7f5f338 Oleksiy Mishchenko
    """
294 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
295 be1ddd09 Michael Hanselmann
    result = self.GetClient().CancelJob(job_id)
296 c7f5f338 Oleksiy Mishchenko
    return result
297 c7f5f338 Oleksiy Mishchenko
298 10b207d4 Oleksiy Mishchenko
299 26ff6ee2 Michael Hanselmann
class R_2_jobs_id_wait(baserlib.ResourceBase):
300 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
301 793a8f7c Michael Hanselmann

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

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

351 10b207d4 Oleksiy Mishchenko
  """
352 10b207d4 Oleksiy Mishchenko
  def GET(self):
353 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
354 38206f3c Iustin Pop

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

371 028c6b76 Oleksiy Mishchenko
  """
372 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
373 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
374 4e5a68f8 Oleksiy Mishchenko

375 4e5a68f8 Oleksiy Mishchenko
    """
376 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
377 be1ddd09 Michael Hanselmann
    client = self.GetClient()
378 e8ebbd2b Michael Hanselmann
379 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
380 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
381 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
382 4e5a68f8 Oleksiy Mishchenko
383 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
384 028c6b76 Oleksiy Mishchenko
385 028c6b76 Oleksiy Mishchenko
386 26ff6ee2 Michael Hanselmann
class R_2_nodes_name_role(baserlib.ResourceBase):
387 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
388 64dae8fc Michael Hanselmann

389 64dae8fc Michael Hanselmann
  """
390 64dae8fc Michael Hanselmann
  def GET(self):
391 64dae8fc Michael Hanselmann
    """Returns the current node role.
392 64dae8fc Michael Hanselmann

393 64dae8fc Michael Hanselmann
    @return: Node role
394 64dae8fc Michael Hanselmann

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

406 64dae8fc Michael Hanselmann
    @return: a job id
407 64dae8fc Michael Hanselmann

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

447 73452f12 Michael Hanselmann
  """
448 73452f12 Michael Hanselmann
  def POST(self):
449 de40437a Michael Hanselmann
    """Evacuate all instances off a node.
450 73452f12 Michael Hanselmann

451 73452f12 Michael Hanselmann
    """
452 de40437a Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeEvacuate, self.request_body, {
453 de40437a Michael Hanselmann
      "node_name": self.items[0],
454 de40437a Michael Hanselmann
      "dry_run": self.dryRun(),
455 de40437a Michael Hanselmann
      })
456 941b9309 Iustin Pop
457 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
458 73452f12 Michael Hanselmann
459 73452f12 Michael Hanselmann
460 26ff6ee2 Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.ResourceBase):
461 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
462 1c482bab Michael Hanselmann

463 1c482bab Michael Hanselmann
  """
464 1c482bab Michael Hanselmann
  def POST(self):
465 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
466 1c482bab Michael Hanselmann

467 1c482bab Michael Hanselmann
    """
468 1c482bab Michael Hanselmann
    node_name = self.items[0]
469 1c482bab Michael Hanselmann
470 b7a1c816 Michael Hanselmann
    if self.queryargs:
471 b7a1c816 Michael Hanselmann
      # Support old-style requests
472 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs and "mode" in self.queryargs:
473 b7a1c816 Michael Hanselmann
        raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
474 b7a1c816 Michael Hanselmann
                                  " be passed")
475 b7a1c816 Michael Hanselmann
476 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs:
477 b7a1c816 Michael Hanselmann
        if self._checkIntVariable("live", default=1):
478 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_LIVE
479 b7a1c816 Michael Hanselmann
        else:
480 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_NONLIVE
481 52194140 Iustin Pop
      else:
482 b7a1c816 Michael Hanselmann
        mode = self._checkStringVariable("mode", default=None)
483 b7a1c816 Michael Hanselmann
484 b7a1c816 Michael Hanselmann
      data = {
485 b7a1c816 Michael Hanselmann
        "mode": mode,
486 b7a1c816 Michael Hanselmann
        }
487 52194140 Iustin Pop
    else:
488 b7a1c816 Michael Hanselmann
      data = self.request_body
489 52194140 Iustin Pop
490 b7a1c816 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeMigrate, data, {
491 b7a1c816 Michael Hanselmann
      "node_name": node_name,
492 b7a1c816 Michael Hanselmann
      })
493 1c482bab Michael Hanselmann
494 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
495 1c482bab Michael Hanselmann
496 1c482bab Michael Hanselmann
497 26ff6ee2 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.ResourceBase):
498 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
499 7a95a954 Michael Hanselmann

500 7a95a954 Michael Hanselmann
  """
501 ad8d0595 Iustin Pop
  # LUNodeQueryStorage acquires locks, hence restricting access to GET
502 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
503 7a95a954 Michael Hanselmann
504 7a95a954 Michael Hanselmann
  def GET(self):
505 7a95a954 Michael Hanselmann
    node_name = self.items[0]
506 7a95a954 Michael Hanselmann
507 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
508 7a95a954 Michael Hanselmann
    if not storage_type:
509 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
510 7a95a954 Michael Hanselmann
                                " parameter")
511 7a95a954 Michael Hanselmann
512 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
513 7a95a954 Michael Hanselmann
    if not output_fields:
514 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
515 7a95a954 Michael Hanselmann
                                " parameter")
516 7a95a954 Michael Hanselmann
517 ad8d0595 Iustin Pop
    op = opcodes.OpNodeQueryStorage(nodes=[node_name],
518 7a95a954 Michael Hanselmann
                                    storage_type=storage_type,
519 7a95a954 Michael Hanselmann
                                    output_fields=output_fields.split(","))
520 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
521 7a95a954 Michael Hanselmann
522 7a95a954 Michael Hanselmann
523 26ff6ee2 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.ResourceBase):
524 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify resource.
525 1e82bc80 Michael Hanselmann

526 1e82bc80 Michael Hanselmann
  """
527 1e82bc80 Michael Hanselmann
  def PUT(self):
528 1e82bc80 Michael Hanselmann
    node_name = self.items[0]
529 1e82bc80 Michael Hanselmann
530 1e82bc80 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
531 1e82bc80 Michael Hanselmann
    if not storage_type:
532 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
533 1e82bc80 Michael Hanselmann
                                " parameter")
534 1e82bc80 Michael Hanselmann
535 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
536 1e82bc80 Michael Hanselmann
    if not name:
537 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
538 1e82bc80 Michael Hanselmann
                                " parameter")
539 1e82bc80 Michael Hanselmann
540 1e82bc80 Michael Hanselmann
    changes = {}
541 1e82bc80 Michael Hanselmann
542 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
543 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
544 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
545 1e82bc80 Michael Hanselmann
546 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
547 1e82bc80 Michael Hanselmann
                                     storage_type=storage_type,
548 1e82bc80 Michael Hanselmann
                                     name=name,
549 1e82bc80 Michael Hanselmann
                                     changes=changes)
550 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
551 1e82bc80 Michael Hanselmann
552 1e82bc80 Michael Hanselmann
553 26ff6ee2 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.ResourceBase):
554 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair resource.
555 723f4565 Michael Hanselmann

556 723f4565 Michael Hanselmann
  """
557 723f4565 Michael Hanselmann
  def PUT(self):
558 723f4565 Michael Hanselmann
    node_name = self.items[0]
559 723f4565 Michael Hanselmann
560 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
561 723f4565 Michael Hanselmann
    if not storage_type:
562 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
563 723f4565 Michael Hanselmann
                                " parameter")
564 723f4565 Michael Hanselmann
565 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
566 723f4565 Michael Hanselmann
    if not name:
567 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
568 723f4565 Michael Hanselmann
                                " parameter")
569 723f4565 Michael Hanselmann
570 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
571 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
572 723f4565 Michael Hanselmann
                                     name=name)
573 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
574 723f4565 Michael Hanselmann
575 723f4565 Michael Hanselmann
576 90e99856 Adeodato Simo
def _ParseCreateGroupRequest(data, dry_run):
577 90e99856 Adeodato Simo
  """Parses a request for creating a node group.
578 90e99856 Adeodato Simo

579 fabf1731 Iustin Pop
  @rtype: L{opcodes.OpGroupAdd}
580 90e99856 Adeodato Simo
  @return: Group creation opcode
581 90e99856 Adeodato Simo

582 90e99856 Adeodato Simo
  """
583 527fbde8 Michael Hanselmann
  override = {
584 527fbde8 Michael Hanselmann
    "dry_run": dry_run,
585 527fbde8 Michael Hanselmann
    }
586 90e99856 Adeodato Simo
587 527fbde8 Michael Hanselmann
  rename = {
588 527fbde8 Michael Hanselmann
    "name": "group_name",
589 527fbde8 Michael Hanselmann
    }
590 527fbde8 Michael Hanselmann
591 527fbde8 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupAdd, data, override,
592 527fbde8 Michael Hanselmann
                             rename=rename)
593 90e99856 Adeodato Simo
594 90e99856 Adeodato Simo
595 26ff6ee2 Michael Hanselmann
class R_2_groups(baserlib.ResourceBase):
596 0897dc97 Adeodato Simo
  """/2/groups resource.
597 0897dc97 Adeodato Simo

598 0897dc97 Adeodato Simo
  """
599 0897dc97 Adeodato Simo
  def GET(self):
600 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
601 0897dc97 Adeodato Simo

602 0897dc97 Adeodato Simo
    """
603 be1ddd09 Michael Hanselmann
    client = self.GetClient()
604 0897dc97 Adeodato Simo
605 0897dc97 Adeodato Simo
    if self.useBulk():
606 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
607 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
608 0897dc97 Adeodato Simo
    else:
609 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
610 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
611 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
612 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
613 0897dc97 Adeodato Simo
614 0dbaa9ca Adeodato Simo
  def POST(self):
615 0dbaa9ca Adeodato Simo
    """Create a node group.
616 0dbaa9ca Adeodato Simo

617 0dbaa9ca Adeodato Simo
    @return: a job id
618 0dbaa9ca Adeodato Simo

619 0dbaa9ca Adeodato Simo
    """
620 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
621 90e99856 Adeodato Simo
    op = _ParseCreateGroupRequest(self.request_body, self.dryRun())
622 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
623 0dbaa9ca Adeodato Simo
624 0897dc97 Adeodato Simo
625 26ff6ee2 Michael Hanselmann
class R_2_groups_name(baserlib.ResourceBase):
626 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name] resource.
627 0897dc97 Adeodato Simo

628 0897dc97 Adeodato Simo
  """
629 0897dc97 Adeodato Simo
  def GET(self):
630 0897dc97 Adeodato Simo
    """Send information about a node group.
631 0897dc97 Adeodato Simo

632 0897dc97 Adeodato Simo
    """
633 0897dc97 Adeodato Simo
    group_name = self.items[0]
634 be1ddd09 Michael Hanselmann
    client = self.GetClient()
635 0897dc97 Adeodato Simo
636 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
637 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
638 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
639 0897dc97 Adeodato Simo
640 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
641 0897dc97 Adeodato Simo
642 0dbaa9ca Adeodato Simo
  def DELETE(self):
643 0dbaa9ca Adeodato Simo
    """Delete a node group.
644 0dbaa9ca Adeodato Simo

645 0dbaa9ca Adeodato Simo
    """
646 4d1baa51 Iustin Pop
    op = opcodes.OpGroupRemove(group_name=self.items[0],
647 0dbaa9ca Adeodato Simo
                               dry_run=bool(self.dryRun()))
648 0dbaa9ca Adeodato Simo
649 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
650 0dbaa9ca Adeodato Simo
651 0dbaa9ca Adeodato Simo
652 f18fab7d Adeodato Simo
def _ParseModifyGroupRequest(name, data):
653 f18fab7d Adeodato Simo
  """Parses a request for modifying a node group.
654 f18fab7d Adeodato Simo

655 7cbf74f0 Iustin Pop
  @rtype: L{opcodes.OpGroupSetParams}
656 f18fab7d Adeodato Simo
  @return: Group modify opcode
657 f18fab7d Adeodato Simo

658 f18fab7d Adeodato Simo
  """
659 df340fae Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupSetParams, data, {
660 df340fae Michael Hanselmann
    "group_name": name,
661 df340fae Michael Hanselmann
    })
662 df340fae Michael Hanselmann
663 f18fab7d Adeodato Simo
664 26ff6ee2 Michael Hanselmann
class R_2_groups_name_modify(baserlib.ResourceBase):
665 f18fab7d Adeodato Simo
  """/2/groups/[group_name]/modify resource.
666 f18fab7d Adeodato Simo

667 f18fab7d Adeodato Simo
  """
668 f18fab7d Adeodato Simo
  def PUT(self):
669 f18fab7d Adeodato Simo
    """Changes some parameters of node group.
670 f18fab7d Adeodato Simo

671 f18fab7d Adeodato Simo
    @return: a job id
672 f18fab7d Adeodato Simo

673 f18fab7d Adeodato Simo
    """
674 f18fab7d Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
675 f18fab7d Adeodato Simo
676 f18fab7d Adeodato Simo
    op = _ParseModifyGroupRequest(self.items[0], self.request_body)
677 f18fab7d Adeodato Simo
678 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
679 f18fab7d Adeodato Simo
680 f18fab7d Adeodato Simo
681 0dbaa9ca Adeodato Simo
def _ParseRenameGroupRequest(name, data, dry_run):
682 0dbaa9ca Adeodato Simo
  """Parses a request for renaming a node group.
683 0dbaa9ca Adeodato Simo

684 0dbaa9ca Adeodato Simo
  @type name: string
685 0dbaa9ca Adeodato Simo
  @param name: name of the node group to rename
686 0dbaa9ca Adeodato Simo
  @type data: dict
687 0dbaa9ca Adeodato Simo
  @param data: the body received by the rename request
688 0dbaa9ca Adeodato Simo
  @type dry_run: bool
689 0dbaa9ca Adeodato Simo
  @param dry_run: whether to perform a dry run
690 0dbaa9ca Adeodato Simo

691 a8173e82 Iustin Pop
  @rtype: L{opcodes.OpGroupRename}
692 0dbaa9ca Adeodato Simo
  @return: Node group rename opcode
693 0dbaa9ca Adeodato Simo

694 0dbaa9ca Adeodato Simo
  """
695 8a08be3b Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupRename, data, {
696 8a08be3b Michael Hanselmann
    "group_name": name,
697 8a08be3b Michael Hanselmann
    "dry_run": dry_run,
698 8a08be3b Michael Hanselmann
    })
699 0dbaa9ca Adeodato Simo
700 0dbaa9ca Adeodato Simo
701 26ff6ee2 Michael Hanselmann
class R_2_groups_name_rename(baserlib.ResourceBase):
702 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/rename resource.
703 0dbaa9ca Adeodato Simo

704 0dbaa9ca Adeodato Simo
  """
705 0dbaa9ca Adeodato Simo
  def PUT(self):
706 0dbaa9ca Adeodato Simo
    """Changes the name of a node group.
707 0dbaa9ca Adeodato Simo

708 0dbaa9ca Adeodato Simo
    @return: a job id
709 0dbaa9ca Adeodato Simo

710 0dbaa9ca Adeodato Simo
    """
711 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
712 0dbaa9ca Adeodato Simo
    op = _ParseRenameGroupRequest(self.items[0], self.request_body,
713 0dbaa9ca Adeodato Simo
                                  self.dryRun())
714 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
715 0897dc97 Adeodato Simo
716 0897dc97 Adeodato Simo
717 26ff6ee2 Michael Hanselmann
class R_2_groups_name_assign_nodes(baserlib.ResourceBase):
718 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/assign-nodes resource.
719 4245446f Adeodato Simo

720 4245446f Adeodato Simo
  """
721 4245446f Adeodato Simo
  def PUT(self):
722 4245446f Adeodato Simo
    """Assigns nodes to a group.
723 4245446f Adeodato Simo

724 4245446f Adeodato Simo
    @return: a job id
725 4245446f Adeodato Simo

726 4245446f Adeodato Simo
    """
727 934704ae Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpGroupAssignNodes, self.request_body, {
728 4245446f Adeodato Simo
      "group_name": self.items[0],
729 4245446f Adeodato Simo
      "dry_run": self.dryRun(),
730 4245446f Adeodato Simo
      "force": self.useForce(),
731 4245446f Adeodato Simo
      })
732 4245446f Adeodato Simo
733 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
734 4245446f Adeodato Simo
735 4245446f Adeodato Simo
736 6395cebb Michael Hanselmann
def _ParseInstanceCreateRequestVersion1(data, dry_run):
737 6395cebb Michael Hanselmann
  """Parses an instance creation request version 1.
738 6395cebb Michael Hanselmann

739 e1530b10 Iustin Pop
  @rtype: L{opcodes.OpInstanceCreate}
740 6395cebb Michael Hanselmann
  @return: Instance creation opcode
741 6395cebb Michael Hanselmann

742 6395cebb Michael Hanselmann
  """
743 526a662a Michael Hanselmann
  override = {
744 526a662a Michael Hanselmann
    "dry_run": dry_run,
745 526a662a Michael Hanselmann
    }
746 6395cebb Michael Hanselmann
747 526a662a Michael Hanselmann
  rename = {
748 526a662a Michael Hanselmann
    "os": "os_type",
749 526a662a Michael Hanselmann
    "name": "instance_name",
750 526a662a Michael Hanselmann
    }
751 526a662a Michael Hanselmann
752 526a662a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceCreate, data, override,
753 526a662a Michael Hanselmann
                             rename=rename)
754 6395cebb Michael Hanselmann
755 6395cebb Michael Hanselmann
756 26ff6ee2 Michael Hanselmann
class R_2_instances(baserlib.ResourceBase):
757 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
758 441e7cfd Oleksiy Mishchenko

759 441e7cfd Oleksiy Mishchenko
  """
760 441e7cfd Oleksiy Mishchenko
  def GET(self):
761 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
762 441e7cfd Oleksiy Mishchenko

763 441e7cfd Oleksiy Mishchenko
    """
764 be1ddd09 Michael Hanselmann
    client = self.GetClient()
765 441e7cfd Oleksiy Mishchenko
766 3d103742 Iustin Pop
    use_locking = self.useLocking()
767 3d103742 Iustin Pop
    if self.useBulk():
768 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
769 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
770 441e7cfd Oleksiy Mishchenko
    else:
771 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
772 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
773 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
774 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
775 441e7cfd Oleksiy Mishchenko
776 d975f482 Michael Hanselmann
  def POST(self):
777 d975f482 Michael Hanselmann
    """Create an instance.
778 d975f482 Michael Hanselmann

779 d975f482 Michael Hanselmann
    @return: a job id
780 d975f482 Michael Hanselmann

781 d975f482 Michael Hanselmann
    """
782 1c54156d Luca Bigliardi
    if not isinstance(self.request_body, dict):
783 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
784 d975f482 Michael Hanselmann
785 d975f482 Michael Hanselmann
    # Default to request data version 0
786 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
787 d975f482 Michael Hanselmann
788 d975f482 Michael Hanselmann
    if data_version == 0:
789 3fd7f652 Michael Hanselmann
      raise http.HttpBadRequest("Instance creation request version 0 is no"
790 3fd7f652 Michael Hanselmann
                                " longer supported")
791 6395cebb Michael Hanselmann
    elif data_version == 1:
792 4b163794 Michael Hanselmann
      data = self.request_body.copy()
793 4b163794 Michael Hanselmann
      # Remove "__version__"
794 4b163794 Michael Hanselmann
      data.pop(_REQ_DATA_VERSION, None)
795 4b163794 Michael Hanselmann
      op = _ParseInstanceCreateRequestVersion1(data, self.dryRun())
796 d975f482 Michael Hanselmann
    else:
797 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
798 12eff9b9 Michael Hanselmann
                                data_version)
799 d975f482 Michael Hanselmann
800 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
801 2f7635f4 Oleksiy Mishchenko
802 441e7cfd Oleksiy Mishchenko
803 26ff6ee2 Michael Hanselmann
class R_2_instances_name(baserlib.ResourceBase):
804 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name] resource.
805 028c6b76 Oleksiy Mishchenko

806 028c6b76 Oleksiy Mishchenko
  """
807 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
808 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
809 4e5a68f8 Oleksiy Mishchenko

810 4e5a68f8 Oleksiy Mishchenko
    """
811 be1ddd09 Michael Hanselmann
    client = self.GetClient()
812 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
813 e8ebbd2b Michael Hanselmann
814 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
815 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
816 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
817 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
818 4e5a68f8 Oleksiy Mishchenko
819 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
820 028c6b76 Oleksiy Mishchenko
821 6e99c5a0 Iustin Pop
  def DELETE(self):
822 6e99c5a0 Iustin Pop
    """Delete an instance.
823 6e99c5a0 Iustin Pop

824 6e99c5a0 Iustin Pop
    """
825 3cd2d4b1 Iustin Pop
    op = opcodes.OpInstanceRemove(instance_name=self.items[0],
826 6f59b964 Iustin Pop
                                  ignore_failures=False,
827 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
828 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
829 6e99c5a0 Iustin Pop
830 028c6b76 Oleksiy Mishchenko
831 26ff6ee2 Michael Hanselmann
class R_2_instances_name_info(baserlib.ResourceBase):
832 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
833 d8260842 Michael Hanselmann

834 d8260842 Michael Hanselmann
  """
835 d8260842 Michael Hanselmann
  def GET(self):
836 d8260842 Michael Hanselmann
    """Request detailed instance information.
837 d8260842 Michael Hanselmann

838 d8260842 Michael Hanselmann
    """
839 d8260842 Michael Hanselmann
    instance_name = self.items[0]
840 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
841 d8260842 Michael Hanselmann
842 dc28c4e4 Iustin Pop
    op = opcodes.OpInstanceQueryData(instances=[instance_name],
843 d8260842 Michael Hanselmann
                                     static=static)
844 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
845 d8260842 Michael Hanselmann
846 d8260842 Michael Hanselmann
847 26ff6ee2 Michael Hanselmann
class R_2_instances_name_reboot(baserlib.ResourceBase):
848 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
849 2276aa29 Oleksiy Mishchenko

850 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
851 2276aa29 Oleksiy Mishchenko

852 2276aa29 Oleksiy Mishchenko
  """
853 21f04e5e Oleksiy Mishchenko
  def POST(self):
854 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
855 2276aa29 Oleksiy Mishchenko

856 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
857 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
858 0c55c24b Oleksiy Mishchenko

859 2276aa29 Oleksiy Mishchenko
    """
860 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
861 d0c8c01d Iustin Pop
    reboot_type = self.queryargs.get("type",
862 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
863 d0c8c01d Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable("ignore_secondaries"))
864 90ab1a95 Iustin Pop
    op = opcodes.OpInstanceReboot(instance_name=instance_name,
865 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
866 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
867 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
868 2276aa29 Oleksiy Mishchenko
869 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
870 2276aa29 Oleksiy Mishchenko
871 2276aa29 Oleksiy Mishchenko
872 26ff6ee2 Michael Hanselmann
class R_2_instances_name_startup(baserlib.ResourceBase):
873 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
874 0c55c24b Oleksiy Mishchenko

875 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
876 0c55c24b Oleksiy Mishchenko

877 0c55c24b Oleksiy Mishchenko
  """
878 21f04e5e Oleksiy Mishchenko
  def PUT(self):
879 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
880 0c55c24b Oleksiy Mishchenko

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

884 0c55c24b Oleksiy Mishchenko
    """
885 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
886 d0c8c01d Iustin Pop
    force_startup = bool(self._checkIntVariable("force"))
887 d0c8c01d Iustin Pop
    no_remember = bool(self._checkIntVariable("no_remember"))
888 c873d91c Iustin Pop
    op = opcodes.OpInstanceStartup(instance_name=instance_name,
889 6f59b964 Iustin Pop
                                   force=force_startup,
890 2ba39b8f Iustin Pop
                                   dry_run=bool(self.dryRun()),
891 2ba39b8f Iustin Pop
                                   no_remember=no_remember)
892 0c55c24b Oleksiy Mishchenko
893 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
894 0c55c24b Oleksiy Mishchenko
895 0c55c24b Oleksiy Mishchenko
896 6aac5aef Iustin Pop
def _ParseShutdownInstanceRequest(name, data, dry_run, no_remember):
897 7fa310f6 René Nussbaumer
  """Parses a request for an instance shutdown.
898 7fa310f6 René Nussbaumer

899 7fa310f6 René Nussbaumer
  @rtype: L{opcodes.OpInstanceShutdown}
900 7fa310f6 René Nussbaumer
  @return: Instance shutdown opcode
901 7fa310f6 René Nussbaumer

902 7fa310f6 René Nussbaumer
  """
903 7fa310f6 René Nussbaumer
  return baserlib.FillOpcode(opcodes.OpInstanceShutdown, data, {
904 7fa310f6 René Nussbaumer
    "instance_name": name,
905 7fa310f6 René Nussbaumer
    "dry_run": dry_run,
906 6aac5aef Iustin Pop
    "no_remember": no_remember,
907 7fa310f6 René Nussbaumer
    })
908 7fa310f6 René Nussbaumer
909 7fa310f6 René Nussbaumer
910 26ff6ee2 Michael Hanselmann
class R_2_instances_name_shutdown(baserlib.ResourceBase):
911 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
912 0c55c24b Oleksiy Mishchenko

913 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
914 0c55c24b Oleksiy Mishchenko

915 0c55c24b Oleksiy Mishchenko
  """
916 21f04e5e Oleksiy Mishchenko
  def PUT(self):
917 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
918 0c55c24b Oleksiy Mishchenko

919 7fa310f6 René Nussbaumer
    @return: a job id
920 7fa310f6 René Nussbaumer

921 0c55c24b Oleksiy Mishchenko
    """
922 7fa310f6 René Nussbaumer
    baserlib.CheckType(self.request_body, dict, "Body contents")
923 7fa310f6 René Nussbaumer
924 d0c8c01d Iustin Pop
    no_remember = bool(self._checkIntVariable("no_remember"))
925 7fa310f6 René Nussbaumer
    op = _ParseShutdownInstanceRequest(self.items[0], self.request_body,
926 6aac5aef Iustin Pop
                                       bool(self.dryRun()), no_remember)
927 0c55c24b Oleksiy Mishchenko
928 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
929 0c55c24b Oleksiy Mishchenko
930 0c55c24b Oleksiy Mishchenko
931 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
932 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
933 c744425f Michael Hanselmann

934 c744425f Michael Hanselmann
  """
935 c744425f Michael Hanselmann
  if not isinstance(data, dict):
936 c744425f Michael Hanselmann
    raise http.HttpBadRequest("Invalid body contents, not a dictionary")
937 c744425f Michael Hanselmann
938 bd0807fe Guido Trotter
  ostype = baserlib.CheckParameter(data, "os", default=None)
939 c744425f Michael Hanselmann
  start = baserlib.CheckParameter(data, "start", exptype=bool,
940 c744425f Michael Hanselmann
                                  default=True)
941 c744425f Michael Hanselmann
  osparams = baserlib.CheckParameter(data, "osparams", default=None)
942 c744425f Michael Hanselmann
943 c744425f Michael Hanselmann
  ops = [
944 ee3e37a7 Iustin Pop
    opcodes.OpInstanceShutdown(instance_name=name),
945 5073fd8f Iustin Pop
    opcodes.OpInstanceReinstall(instance_name=name, os_type=ostype,
946 c744425f Michael Hanselmann
                                osparams=osparams),
947 c744425f Michael Hanselmann
    ]
948 c744425f Michael Hanselmann
949 c744425f Michael Hanselmann
  if start:
950 c873d91c Iustin Pop
    ops.append(opcodes.OpInstanceStartup(instance_name=name, force=False))
951 c744425f Michael Hanselmann
952 c744425f Michael Hanselmann
  return ops
953 c744425f Michael Hanselmann
954 c744425f Michael Hanselmann
955 26ff6ee2 Michael Hanselmann
class R_2_instances_name_reinstall(baserlib.ResourceBase):
956 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
957 e5b7c4ca Iustin Pop

958 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
959 e5b7c4ca Iustin Pop

960 e5b7c4ca Iustin Pop
  """
961 e5b7c4ca Iustin Pop
  def POST(self):
962 e5b7c4ca Iustin Pop
    """Reinstall an instance.
963 e5b7c4ca Iustin Pop

964 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
965 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
966 e5b7c4ca Iustin Pop
    automatically.
967 e5b7c4ca Iustin Pop

968 e5b7c4ca Iustin Pop
    """
969 c744425f Michael Hanselmann
    if self.request_body:
970 c744425f Michael Hanselmann
      if self.queryargs:
971 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
972 c744425f Michael Hanselmann
973 c744425f Michael Hanselmann
      body = self.request_body
974 bd0807fe Guido Trotter
    elif self.queryargs:
975 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
976 c744425f Michael Hanselmann
      body = {
977 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
978 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
979 c744425f Michael Hanselmann
        }
980 bd0807fe Guido Trotter
    else:
981 bd0807fe Guido Trotter
      body = {}
982 c744425f Michael Hanselmann
983 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
984 c744425f Michael Hanselmann
985 be1ddd09 Michael Hanselmann
    return self.SubmitJob(ops)
986 e5b7c4ca Iustin Pop
987 e5b7c4ca Iustin Pop
988 d1c172de Michael Hanselmann
def _ParseInstanceReplaceDisksRequest(name, data):
989 d1c172de Michael Hanselmann
  """Parses a request for an instance export.
990 d1c172de Michael Hanselmann

991 d1c172de Michael Hanselmann
  @rtype: L{opcodes.OpInstanceReplaceDisks}
992 d1c172de Michael Hanselmann
  @return: Instance export opcode
993 d1c172de Michael Hanselmann

994 d1c172de Michael Hanselmann
  """
995 d1c172de Michael Hanselmann
  override = {
996 d1c172de Michael Hanselmann
    "instance_name": name,
997 d1c172de Michael Hanselmann
    }
998 d1c172de Michael Hanselmann
999 d1c172de Michael Hanselmann
  # Parse disks
1000 d1c172de Michael Hanselmann
  try:
1001 d1c172de Michael Hanselmann
    raw_disks = data["disks"]
1002 d1c172de Michael Hanselmann
  except KeyError:
1003 d1c172de Michael Hanselmann
    pass
1004 d1c172de Michael Hanselmann
  else:
1005 d1c172de Michael Hanselmann
    if not ht.TListOf(ht.TInt)(raw_disks): # pylint: disable-msg=E1102
1006 d1c172de Michael Hanselmann
      # Backwards compatibility for strings of the format "1, 2, 3"
1007 d1c172de Michael Hanselmann
      try:
1008 d1c172de Michael Hanselmann
        data["disks"] = [int(part) for part in raw_disks.split(",")]
1009 d1c172de Michael Hanselmann
      except (TypeError, ValueError), err:
1010 d1c172de Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
1011 d1c172de Michael Hanselmann
1012 d1c172de Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceReplaceDisks, data, override)
1013 d1c172de Michael Hanselmann
1014 d1c172de Michael Hanselmann
1015 26ff6ee2 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.ResourceBase):
1016 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
1017 4c98b915 Michael Hanselmann

1018 4c98b915 Michael Hanselmann
  """
1019 4c98b915 Michael Hanselmann
  def POST(self):
1020 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1021 4c98b915 Michael Hanselmann

1022 4c98b915 Michael Hanselmann
    """
1023 d1c172de Michael Hanselmann
    op = _ParseInstanceReplaceDisksRequest(self.items[0], self.request_body)
1024 4c98b915 Michael Hanselmann
1025 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1026 4c98b915 Michael Hanselmann
1027 4c98b915 Michael Hanselmann
1028 26ff6ee2 Michael Hanselmann
class R_2_instances_name_activate_disks(baserlib.ResourceBase):
1029 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1030 2197b66f René Nussbaumer

1031 2197b66f René Nussbaumer
  """
1032 2197b66f René Nussbaumer
  def PUT(self):
1033 2197b66f René Nussbaumer
    """Activate disks for an instance.
1034 2197b66f René Nussbaumer

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

1037 2197b66f René Nussbaumer
    """
1038 2197b66f René Nussbaumer
    instance_name = self.items[0]
1039 d0c8c01d Iustin Pop
    ignore_size = bool(self._checkIntVariable("ignore_size"))
1040 2197b66f René Nussbaumer
1041 83f5d475 Iustin Pop
    op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
1042 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
1043 2197b66f René Nussbaumer
1044 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1045 2197b66f René Nussbaumer
1046 2197b66f René Nussbaumer
1047 26ff6ee2 Michael Hanselmann
class R_2_instances_name_deactivate_disks(baserlib.ResourceBase):
1048 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1049 0a37de5f René Nussbaumer

1050 0a37de5f René Nussbaumer
  """
1051 0a37de5f René Nussbaumer
  def PUT(self):
1052 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1053 0a37de5f René Nussbaumer

1054 0a37de5f René Nussbaumer
    """
1055 0a37de5f René Nussbaumer
    instance_name = self.items[0]
1056 0a37de5f René Nussbaumer
1057 e176281f Iustin Pop
    op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name)
1058 0a37de5f René Nussbaumer
1059 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1060 0a37de5f René Nussbaumer
1061 0a37de5f René Nussbaumer
1062 26ff6ee2 Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.ResourceBase):
1063 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1064 ebeb600f Michael Hanselmann

1065 ebeb600f Michael Hanselmann
  """
1066 ebeb600f Michael Hanselmann
  def PUT(self):
1067 ebeb600f Michael Hanselmann
    """Prepares an export for an instance.
1068 ebeb600f Michael Hanselmann

1069 ebeb600f Michael Hanselmann
    @return: a job id
1070 ebeb600f Michael Hanselmann

1071 ebeb600f Michael Hanselmann
    """
1072 ebeb600f Michael Hanselmann
    instance_name = self.items[0]
1073 ebeb600f Michael Hanselmann
    mode = self._checkStringVariable("mode")
1074 ebeb600f Michael Hanselmann
1075 71910715 Iustin Pop
    op = opcodes.OpBackupPrepare(instance_name=instance_name,
1076 ebeb600f Michael Hanselmann
                                 mode=mode)
1077 ebeb600f Michael Hanselmann
1078 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1079 ebeb600f Michael Hanselmann
1080 ebeb600f Michael Hanselmann
1081 ebeb600f Michael Hanselmann
def _ParseExportInstanceRequest(name, data):
1082 ebeb600f Michael Hanselmann
  """Parses a request for an instance export.
1083 ebeb600f Michael Hanselmann

1084 4ff922a2 Iustin Pop
  @rtype: L{opcodes.OpBackupExport}
1085 ebeb600f Michael Hanselmann
  @return: Instance export opcode
1086 ebeb600f Michael Hanselmann

1087 ebeb600f Michael Hanselmann
  """
1088 07ce3e70 Michael Hanselmann
  # Rename "destination" to "target_node"
1089 07ce3e70 Michael Hanselmann
  try:
1090 07ce3e70 Michael Hanselmann
    data["target_node"] = data.pop("destination")
1091 07ce3e70 Michael Hanselmann
  except KeyError:
1092 07ce3e70 Michael Hanselmann
    pass
1093 07ce3e70 Michael Hanselmann
1094 07ce3e70 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpBackupExport, data, {
1095 07ce3e70 Michael Hanselmann
    "instance_name": name,
1096 07ce3e70 Michael Hanselmann
    })
1097 ebeb600f Michael Hanselmann
1098 ebeb600f Michael Hanselmann
1099 26ff6ee2 Michael Hanselmann
class R_2_instances_name_export(baserlib.ResourceBase):
1100 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1101 ebeb600f Michael Hanselmann

1102 ebeb600f Michael Hanselmann
  """
1103 ebeb600f Michael Hanselmann
  def PUT(self):
1104 ebeb600f Michael Hanselmann
    """Exports an instance.
1105 ebeb600f Michael Hanselmann

1106 ebeb600f Michael Hanselmann
    @return: a job id
1107 ebeb600f Michael Hanselmann

1108 ebeb600f Michael Hanselmann
    """
1109 ebeb600f Michael Hanselmann
    if not isinstance(self.request_body, dict):
1110 ebeb600f Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
1111 ebeb600f Michael Hanselmann
1112 ebeb600f Michael Hanselmann
    op = _ParseExportInstanceRequest(self.items[0], self.request_body)
1113 ebeb600f Michael Hanselmann
1114 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1115 ebeb600f Michael Hanselmann
1116 ebeb600f Michael Hanselmann
1117 5823e0d2 Michael Hanselmann
def _ParseMigrateInstanceRequest(name, data):
1118 5823e0d2 Michael Hanselmann
  """Parses a request for an instance migration.
1119 5823e0d2 Michael Hanselmann

1120 75c866c2 Iustin Pop
  @rtype: L{opcodes.OpInstanceMigrate}
1121 5823e0d2 Michael Hanselmann
  @return: Instance migration opcode
1122 5823e0d2 Michael Hanselmann

1123 5823e0d2 Michael Hanselmann
  """
1124 c1a27c9a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceMigrate, data, {
1125 c1a27c9a Michael Hanselmann
    "instance_name": name,
1126 c1a27c9a Michael Hanselmann
    })
1127 5823e0d2 Michael Hanselmann
1128 5823e0d2 Michael Hanselmann
1129 26ff6ee2 Michael Hanselmann
class R_2_instances_name_migrate(baserlib.ResourceBase):
1130 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1131 5823e0d2 Michael Hanselmann

1132 5823e0d2 Michael Hanselmann
  """
1133 5823e0d2 Michael Hanselmann
  def PUT(self):
1134 5823e0d2 Michael Hanselmann
    """Migrates an instance.
1135 5823e0d2 Michael Hanselmann

1136 5823e0d2 Michael Hanselmann
    @return: a job id
1137 5823e0d2 Michael Hanselmann

1138 5823e0d2 Michael Hanselmann
    """
1139 5823e0d2 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1140 5823e0d2 Michael Hanselmann
1141 5823e0d2 Michael Hanselmann
    op = _ParseMigrateInstanceRequest(self.items[0], self.request_body)
1142 5823e0d2 Michael Hanselmann
1143 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1144 5823e0d2 Michael Hanselmann
1145 5823e0d2 Michael Hanselmann
1146 26ff6ee2 Michael Hanselmann
class R_2_instances_name_failover(baserlib.ResourceBase):
1147 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1148 c0a146a1 Michael Hanselmann

1149 c0a146a1 Michael Hanselmann
  """
1150 c0a146a1 Michael Hanselmann
  def PUT(self):
1151 c0a146a1 Michael Hanselmann
    """Does a failover of an instance.
1152 c0a146a1 Michael Hanselmann

1153 c0a146a1 Michael Hanselmann
    @return: a job id
1154 c0a146a1 Michael Hanselmann

1155 c0a146a1 Michael Hanselmann
    """
1156 c0a146a1 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1157 c0a146a1 Michael Hanselmann
1158 c0a146a1 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpInstanceFailover, self.request_body, {
1159 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1160 c0a146a1 Michael Hanselmann
      })
1161 c0a146a1 Michael Hanselmann
1162 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1163 c0a146a1 Michael Hanselmann
1164 c0a146a1 Michael Hanselmann
1165 d56e7dc7 Michael Hanselmann
def _ParseRenameInstanceRequest(name, data):
1166 d56e7dc7 Michael Hanselmann
  """Parses a request for renaming an instance.
1167 d56e7dc7 Michael Hanselmann

1168 5659e2e2 Iustin Pop
  @rtype: L{opcodes.OpInstanceRename}
1169 d56e7dc7 Michael Hanselmann
  @return: Instance rename opcode
1170 d56e7dc7 Michael Hanselmann

1171 d56e7dc7 Michael Hanselmann
  """
1172 88bc199a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceRename, data, {
1173 88bc199a Michael Hanselmann
    "instance_name": name,
1174 88bc199a Michael Hanselmann
    })
1175 d56e7dc7 Michael Hanselmann
1176 d56e7dc7 Michael Hanselmann
1177 26ff6ee2 Michael Hanselmann
class R_2_instances_name_rename(baserlib.ResourceBase):
1178 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1179 d56e7dc7 Michael Hanselmann

1180 d56e7dc7 Michael Hanselmann
  """
1181 d56e7dc7 Michael Hanselmann
  def PUT(self):
1182 d56e7dc7 Michael Hanselmann
    """Changes the name of an instance.
1183 d56e7dc7 Michael Hanselmann

1184 d56e7dc7 Michael Hanselmann
    @return: a job id
1185 d56e7dc7 Michael Hanselmann

1186 d56e7dc7 Michael Hanselmann
    """
1187 d56e7dc7 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1188 d56e7dc7 Michael Hanselmann
1189 d56e7dc7 Michael Hanselmann
    op = _ParseRenameInstanceRequest(self.items[0], self.request_body)
1190 d56e7dc7 Michael Hanselmann
1191 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1192 d56e7dc7 Michael Hanselmann
1193 d56e7dc7 Michael Hanselmann
1194 3882937a Michael Hanselmann
def _ParseModifyInstanceRequest(name, data):
1195 3882937a Michael Hanselmann
  """Parses a request for modifying an instance.
1196 3882937a Michael Hanselmann

1197 9a3cc7ae Iustin Pop
  @rtype: L{opcodes.OpInstanceSetParams}
1198 3882937a Michael Hanselmann
  @return: Instance modify opcode
1199 3882937a Michael Hanselmann

1200 3882937a Michael Hanselmann
  """
1201 ee5549c7 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceSetParams, data, {
1202 ee5549c7 Michael Hanselmann
    "instance_name": name,
1203 ee5549c7 Michael Hanselmann
    })
1204 3882937a Michael Hanselmann
1205 3882937a Michael Hanselmann
1206 26ff6ee2 Michael Hanselmann
class R_2_instances_name_modify(baserlib.ResourceBase):
1207 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1208 3882937a Michael Hanselmann

1209 3882937a Michael Hanselmann
  """
1210 3882937a Michael Hanselmann
  def PUT(self):
1211 3882937a Michael Hanselmann
    """Changes some parameters of an instance.
1212 3882937a Michael Hanselmann

1213 3882937a Michael Hanselmann
    @return: a job id
1214 3882937a Michael Hanselmann

1215 3882937a Michael Hanselmann
    """
1216 3882937a Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1217 3882937a Michael Hanselmann
1218 3882937a Michael Hanselmann
    op = _ParseModifyInstanceRequest(self.items[0], self.request_body)
1219 3882937a Michael Hanselmann
1220 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1221 3882937a Michael Hanselmann
1222 3882937a Michael Hanselmann
1223 26ff6ee2 Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.ResourceBase):
1224 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1225 e23881ed Michael Hanselmann

1226 e23881ed Michael Hanselmann
  """
1227 e23881ed Michael Hanselmann
  def POST(self):
1228 e23881ed Michael Hanselmann
    """Increases the size of an instance disk.
1229 e23881ed Michael Hanselmann

1230 e23881ed Michael Hanselmann
    @return: a job id
1231 e23881ed Michael Hanselmann

1232 e23881ed Michael Hanselmann
    """
1233 60472d29 Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpInstanceGrowDisk, self.request_body, {
1234 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1235 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1236 e23881ed Michael Hanselmann
      })
1237 e23881ed Michael Hanselmann
1238 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1239 e23881ed Michael Hanselmann
1240 e23881ed Michael Hanselmann
1241 26ff6ee2 Michael Hanselmann
class R_2_instances_name_console(baserlib.ResourceBase):
1242 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1243 b82d4c5e Michael Hanselmann

1244 b82d4c5e Michael Hanselmann
  """
1245 b82d4c5e Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1246 b82d4c5e Michael Hanselmann
1247 b82d4c5e Michael Hanselmann
  def GET(self):
1248 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1249 b82d4c5e Michael Hanselmann

1250 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1251 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1252 b82d4c5e Michael Hanselmann

1253 b82d4c5e Michael Hanselmann
    """
1254 be1ddd09 Michael Hanselmann
    client = self.GetClient()
1255 b82d4c5e Michael Hanselmann
1256 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1257 b82d4c5e Michael Hanselmann
1258 b82d4c5e Michael Hanselmann
    if console is None:
1259 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1260 b82d4c5e Michael Hanselmann
1261 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1262 b82d4c5e Michael Hanselmann
    return console
1263 b82d4c5e Michael Hanselmann
1264 b82d4c5e Michael Hanselmann
1265 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1266 208a6cff Michael Hanselmann
  """
1267 208a6cff Michael Hanselmann

1268 208a6cff Michael Hanselmann
  """
1269 208a6cff Michael Hanselmann
  try:
1270 208a6cff Michael Hanselmann
    fields = args["fields"]
1271 208a6cff Michael Hanselmann
  except KeyError:
1272 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1273 208a6cff Michael Hanselmann
1274 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1275 208a6cff Michael Hanselmann
1276 208a6cff Michael Hanselmann
1277 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1278 208a6cff Michael Hanselmann
  """
1279 208a6cff Michael Hanselmann

1280 208a6cff Michael Hanselmann
  """
1281 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1282 208a6cff Michael Hanselmann
1283 208a6cff Michael Hanselmann
1284 26ff6ee2 Michael Hanselmann
class R_2_query(baserlib.ResourceBase):
1285 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1286 208a6cff Michael Hanselmann

1287 208a6cff Michael Hanselmann
  """
1288 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1289 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1290 208a6cff Michael Hanselmann
1291 208a6cff Michael Hanselmann
  def _Query(self, fields, filter_):
1292 be1ddd09 Michael Hanselmann
    return self.GetClient().Query(self.items[0], fields, filter_).ToDict()
1293 208a6cff Michael Hanselmann
1294 208a6cff Michael Hanselmann
  def GET(self):
1295 208a6cff Michael Hanselmann
    """Returns resource information.
1296 208a6cff Michael Hanselmann

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

1299 208a6cff Michael Hanselmann
    """
1300 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1301 208a6cff Michael Hanselmann
1302 208a6cff Michael Hanselmann
  def PUT(self):
1303 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1304 208a6cff Michael Hanselmann

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

1307 208a6cff Michael Hanselmann
    """
1308 208a6cff Michael Hanselmann
    body = self.request_body
1309 208a6cff Michael Hanselmann
1310 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1311 208a6cff Michael Hanselmann
1312 208a6cff Michael Hanselmann
    try:
1313 208a6cff Michael Hanselmann
      fields = body["fields"]
1314 208a6cff Michael Hanselmann
    except KeyError:
1315 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1316 208a6cff Michael Hanselmann
1317 208a6cff Michael Hanselmann
    return self._Query(fields, self.request_body.get("filter", None))
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 208a6cff Michael Hanselmann
  def GET(self):
1325 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1326 208a6cff Michael Hanselmann

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

1329 208a6cff Michael Hanselmann
    """
1330 208a6cff Michael Hanselmann
    try:
1331 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1332 208a6cff Michael Hanselmann
    except KeyError:
1333 208a6cff Michael Hanselmann
      fields = None
1334 208a6cff Michael Hanselmann
    else:
1335 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1336 208a6cff Michael Hanselmann
1337 be1ddd09 Michael Hanselmann
    return self.GetClient().QueryFields(self.items[0], fields).ToDict()
1338 208a6cff Michael Hanselmann
1339 208a6cff Michael Hanselmann
1340 26ff6ee2 Michael Hanselmann
class _R_Tags(baserlib.ResourceBase):
1341 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1342 441e7cfd Oleksiy Mishchenko

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

1346 441e7cfd Oleksiy Mishchenko
  """
1347 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1348 18cb43a2 Oleksiy Mishchenko
1349 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
1350 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1351 18cb43a2 Oleksiy Mishchenko

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

1354 18cb43a2 Oleksiy Mishchenko
    """
1355 26ff6ee2 Michael Hanselmann
    baserlib.ResourceBase.__init__(self, items, queryargs, req)
1356 18cb43a2 Oleksiy Mishchenko
1357 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1358 5313eed7 Michael Hanselmann
      self.name = None
1359 18cb43a2 Oleksiy Mishchenko
    else:
1360 5313eed7 Michael Hanselmann
      self.name = items[0]
1361 441e7cfd Oleksiy Mishchenko
1362 441e7cfd Oleksiy Mishchenko
  def GET(self):
1363 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1364 441e7cfd Oleksiy Mishchenko

1365 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1366 441e7cfd Oleksiy Mishchenko

1367 441e7cfd Oleksiy Mishchenko
    """
1368 f87ec53f Michael Hanselmann
    kind = self.TAG_LEVEL
1369 f87ec53f Michael Hanselmann
1370 f87ec53f Michael Hanselmann
    if kind in (constants.TAG_INSTANCE,
1371 f87ec53f Michael Hanselmann
                constants.TAG_NODEGROUP,
1372 f87ec53f Michael Hanselmann
                constants.TAG_NODE):
1373 f87ec53f Michael Hanselmann
      if not self.name:
1374 f87ec53f Michael Hanselmann
        raise http.HttpBadRequest("Missing name on tag request")
1375 f87ec53f Michael Hanselmann
1376 be1ddd09 Michael Hanselmann
      cl = self.GetClient()
1377 f87ec53f Michael Hanselmann
      if kind == constants.TAG_INSTANCE:
1378 f87ec53f Michael Hanselmann
        fn = cl.QueryInstances
1379 f87ec53f Michael Hanselmann
      elif kind == constants.TAG_NODEGROUP:
1380 f87ec53f Michael Hanselmann
        fn = cl.QueryGroups
1381 f87ec53f Michael Hanselmann
      else:
1382 f87ec53f Michael Hanselmann
        fn = cl.QueryNodes
1383 f87ec53f Michael Hanselmann
      result = fn(names=[self.name], fields=["tags"], use_locking=False)
1384 f87ec53f Michael Hanselmann
      if not result or not result[0]:
1385 f87ec53f Michael Hanselmann
        raise http.HttpBadGateway("Invalid response from tag query")
1386 f87ec53f Michael Hanselmann
      tags = result[0][0]
1387 f87ec53f Michael Hanselmann
1388 f87ec53f Michael Hanselmann
    elif kind == constants.TAG_CLUSTER:
1389 f87ec53f Michael Hanselmann
      assert not self.name
1390 f87ec53f Michael Hanselmann
      # TODO: Use query API?
1391 f87ec53f Michael Hanselmann
      ssc = ssconf.SimpleStore()
1392 f87ec53f Michael Hanselmann
      tags = ssc.GetClusterTags()
1393 f87ec53f Michael Hanselmann
1394 f87ec53f Michael Hanselmann
    return list(tags)
1395 441e7cfd Oleksiy Mishchenko
1396 21f04e5e Oleksiy Mishchenko
  def PUT(self):
1397 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1398 441e7cfd Oleksiy Mishchenko

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

1402 441e7cfd Oleksiy Mishchenko
    """
1403 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1404 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1405 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
1406 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
1407 f87ec53f Michael Hanselmann
    op = opcodes.OpTagsSet(kind=self.TAG_LEVEL, name=self.name,
1408 f87ec53f Michael Hanselmann
                           tags=self.queryargs["tag"], dry_run=self.dryRun())
1409 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1410 15fd9fd5 Oleksiy Mishchenko
1411 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
1412 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1413 15fd9fd5 Oleksiy Mishchenko

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

1418 15fd9fd5 Oleksiy Mishchenko
    """
1419 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1420 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1421 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
1422 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
1423 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
1424 f87ec53f Michael Hanselmann
    op = opcodes.OpTagsDel(kind=self.TAG_LEVEL, name=self.name,
1425 f87ec53f Michael Hanselmann
                           tags=self.queryargs["tag"], dry_run=self.dryRun())
1426 be1ddd09 Michael Hanselmann
    return self.SubmitJob([op])
1427 18cb43a2 Oleksiy Mishchenko
1428 18cb43a2 Oleksiy Mishchenko
1429 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1430 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1431 18cb43a2 Oleksiy Mishchenko

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

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

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

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

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

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

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

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