Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 62457f51

History | View | Annotate | Download (34.7 kB)

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

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

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

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

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

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

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

52 10b207d4 Oleksiy Mishchenko
"""
53 10b207d4 Oleksiy Mishchenko
54 b459a848 Andrea Spadaccini
# pylint: disable=C0103
55 fe267188 Iustin Pop
56 fe267188 Iustin Pop
# C0103: Invalid name, since the R_* names are not conforming
57 fe267188 Iustin Pop
58 59b4eeef Iustin Pop
from ganeti import opcodes
59 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 37e61a77 Iustin Pop
            "ndparams",
90 fd254195 Iustin Pop
            "group.uuid",
91 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
92 4e5a68f8 Oleksiy Mishchenko
93 f4e86448 Michael Hanselmann
G_FIELDS = [
94 f4e86448 Michael Hanselmann
  "alloc_policy",
95 f4e86448 Michael Hanselmann
  "name",
96 f4e86448 Michael Hanselmann
  "node_cnt",
97 f4e86448 Michael Hanselmann
  "node_list",
98 edd49f9b Agata Murawska
  "ipolicy",
99 003306f9 Iustin Pop
  "custom_ipolicy",
100 003306f9 Iustin Pop
  "diskparams",
101 003306f9 Iustin Pop
  "custom_diskparams",
102 003306f9 Iustin Pop
  "ndparams",
103 003306f9 Iustin Pop
  "custom_ndparams",
104 f4e86448 Michael Hanselmann
  ] + _COMMON_FIELDS
105 0897dc97 Adeodato Simo
106 bd7b2070 Michael Hanselmann
J_FIELDS_BULK = [
107 e987f166 Michael Hanselmann
  "id", "ops", "status", "summary",
108 bd7b2070 Michael Hanselmann
  "opstatus",
109 e987f166 Michael Hanselmann
  "received_ts", "start_ts", "end_ts",
110 e987f166 Michael Hanselmann
  ]
111 e987f166 Michael Hanselmann
112 bd7b2070 Michael Hanselmann
J_FIELDS = J_FIELDS_BULK + [
113 bd7b2070 Michael Hanselmann
  "oplog",
114 bd7b2070 Michael Hanselmann
  "opresult",
115 bd7b2070 Michael Hanselmann
  ]
116 bd7b2070 Michael Hanselmann
117 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
118 51cc8637 Michael Hanselmann
_NR_MASTER_CANDIDATE = "master-candidate"
119 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
120 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
121 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
122 64dae8fc Michael Hanselmann
123 64dae8fc Michael Hanselmann
_NR_MAP = {
124 1e28e3b8 Michael Hanselmann
  constants.NR_MASTER: _NR_MASTER,
125 51cc8637 Michael Hanselmann
  constants.NR_MCANDIDATE: _NR_MASTER_CANDIDATE,
126 1e28e3b8 Michael Hanselmann
  constants.NR_DRAINED: _NR_DRAINED,
127 1e28e3b8 Michael Hanselmann
  constants.NR_OFFLINE: _NR_OFFLINE,
128 1e28e3b8 Michael Hanselmann
  constants.NR_REGULAR: _NR_REGULAR,
129 64dae8fc Michael Hanselmann
  }
130 64dae8fc Michael Hanselmann
131 1e28e3b8 Michael Hanselmann
assert frozenset(_NR_MAP.keys()) == constants.NR_ALL
132 1e28e3b8 Michael Hanselmann
133 d975f482 Michael Hanselmann
# Request data version field
134 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
135 d975f482 Michael Hanselmann
136 6395cebb Michael Hanselmann
# Feature string for instance creation request data version 1
137 6395cebb Michael Hanselmann
_INST_CREATE_REQV1 = "instance-create-reqv1"
138 6395cebb Michael Hanselmann
139 c744425f Michael Hanselmann
# Feature string for instance reinstall request version 1
140 c744425f Michael Hanselmann
_INST_REINSTALL_REQV1 = "instance-reinstall-reqv1"
141 c744425f Michael Hanselmann
142 b7a1c816 Michael Hanselmann
# Feature string for node migration version 1
143 b7a1c816 Michael Hanselmann
_NODE_MIGRATE_REQV1 = "node-migrate-reqv1"
144 b7a1c816 Michael Hanselmann
145 de40437a Michael Hanselmann
# Feature string for node evacuation with LU-generated jobs
146 de40437a Michael Hanselmann
_NODE_EVAC_RES1 = "node-evac-res1"
147 de40437a Michael Hanselmann
148 b4fcee5b Michael Hanselmann
ALL_FEATURES = frozenset([
149 b4fcee5b Michael Hanselmann
  _INST_CREATE_REQV1,
150 b4fcee5b Michael Hanselmann
  _INST_REINSTALL_REQV1,
151 b4fcee5b Michael Hanselmann
  _NODE_MIGRATE_REQV1,
152 b4fcee5b Michael Hanselmann
  _NODE_EVAC_RES1,
153 b4fcee5b Michael Hanselmann
  ])
154 b4fcee5b Michael Hanselmann
155 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
156 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
157 793a8f7c Michael Hanselmann
158 4e5a68f8 Oleksiy Mishchenko
159 28a45bfc René Nussbaumer
# FIXME: For compatibility we update the beparams/memory field. Needs to be
160 28a45bfc René Nussbaumer
#        removed in Ganeti 2.7
161 28a45bfc René Nussbaumer
def _UpdateBeparams(inst):
162 28a45bfc René Nussbaumer
  """Updates the beparams dict of inst to support the memory field.
163 28a45bfc René Nussbaumer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

818 028c6b76 Oleksiy Mishchenko
  """
819 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQuery
820 a6fa7892 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpInstanceRemove
821 a6fa7892 Michael Hanselmann
822 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
823 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
824 4e5a68f8 Oleksiy Mishchenko

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

839 6e99c5a0 Iustin Pop
    """
840 a6fa7892 Michael Hanselmann
    assert len(self.items) == 1
841 a6fa7892 Michael Hanselmann
    return ({}, {
842 a6fa7892 Michael Hanselmann
      "instance_name": self.items[0],
843 a6fa7892 Michael Hanselmann
      "ignore_failures": False,
844 a6fa7892 Michael Hanselmann
      "dry_run": self.dryRun(),
845 a6fa7892 Michael Hanselmann
      })
846 6e99c5a0 Iustin Pop
847 028c6b76 Oleksiy Mishchenko
848 7b3df961 Michael Hanselmann
class R_2_instances_name_info(baserlib.OpcodeResource):
849 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
850 d8260842 Michael Hanselmann

851 d8260842 Michael Hanselmann
  """
852 7b3df961 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQueryData
853 7b3df961 Michael Hanselmann
854 7b3df961 Michael Hanselmann
  def GetGetOpInput(self):
855 d8260842 Michael Hanselmann
    """Request detailed instance information.
856 d8260842 Michael Hanselmann

857 d8260842 Michael Hanselmann
    """
858 7b3df961 Michael Hanselmann
    assert len(self.items) == 1
859 7b3df961 Michael Hanselmann
    return ({}, {
860 7b3df961 Michael Hanselmann
      "instances": [self.items[0]],
861 7b3df961 Michael Hanselmann
      "static": bool(self._checkIntVariable("static", default=0)),
862 7b3df961 Michael Hanselmann
      })
863 d8260842 Michael Hanselmann
864 d8260842 Michael Hanselmann
865 ac4888c1 Michael Hanselmann
class R_2_instances_name_reboot(baserlib.OpcodeResource):
866 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
867 2276aa29 Oleksiy Mishchenko

868 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
869 2276aa29 Oleksiy Mishchenko

870 2276aa29 Oleksiy Mishchenko
  """
871 ac4888c1 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReboot
872 ac4888c1 Michael Hanselmann
873 ac4888c1 Michael Hanselmann
  def GetPostOpInput(self):
874 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
875 2276aa29 Oleksiy Mishchenko

876 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
877 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
878 0c55c24b Oleksiy Mishchenko

879 2276aa29 Oleksiy Mishchenko
    """
880 ac4888c1 Michael Hanselmann
    return ({}, {
881 ac4888c1 Michael Hanselmann
      "instance_name": self.items[0],
882 ac4888c1 Michael Hanselmann
      "reboot_type":
883 ac4888c1 Michael Hanselmann
        self.queryargs.get("type", [constants.INSTANCE_REBOOT_HARD])[0],
884 ac4888c1 Michael Hanselmann
      "ignore_secondaries": bool(self._checkIntVariable("ignore_secondaries")),
885 ac4888c1 Michael Hanselmann
      "dry_run": self.dryRun(),
886 ac4888c1 Michael Hanselmann
      })
887 2276aa29 Oleksiy Mishchenko
888 2276aa29 Oleksiy Mishchenko
889 4717e6eb Michael Hanselmann
class R_2_instances_name_startup(baserlib.OpcodeResource):
890 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
891 0c55c24b Oleksiy Mishchenko

892 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
893 0c55c24b Oleksiy Mishchenko

894 0c55c24b Oleksiy Mishchenko
  """
895 4717e6eb Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceStartup
896 4717e6eb Michael Hanselmann
897 4717e6eb Michael Hanselmann
  def GetPutOpInput(self):
898 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
899 0c55c24b Oleksiy Mishchenko

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

903 0c55c24b Oleksiy Mishchenko
    """
904 4717e6eb Michael Hanselmann
    return ({}, {
905 4717e6eb Michael Hanselmann
      "instance_name": self.items[0],
906 4717e6eb Michael Hanselmann
      "force": self.useForce(),
907 4717e6eb Michael Hanselmann
      "dry_run": self.dryRun(),
908 4717e6eb Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
909 4717e6eb Michael Hanselmann
      })
910 0c55c24b Oleksiy Mishchenko
911 0c55c24b Oleksiy Mishchenko
912 3175ade6 Michael Hanselmann
class R_2_instances_name_shutdown(baserlib.OpcodeResource):
913 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
914 0c55c24b Oleksiy Mishchenko

915 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
916 0c55c24b Oleksiy Mishchenko

917 0c55c24b Oleksiy Mishchenko
  """
918 3175ade6 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceShutdown
919 0c55c24b Oleksiy Mishchenko
920 3175ade6 Michael Hanselmann
  def GetPutOpInput(self):
921 3175ade6 Michael Hanselmann
    """Shutdown an instance.
922 7fa310f6 René Nussbaumer

923 0c55c24b Oleksiy Mishchenko
    """
924 3175ade6 Michael Hanselmann
    return (self.request_body, {
925 3175ade6 Michael Hanselmann
      "instance_name": self.items[0],
926 3175ade6 Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
927 3175ade6 Michael Hanselmann
      "dry_run": self.dryRun(),
928 3175ade6 Michael Hanselmann
      })
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 f6ce0ba2 Michael Hanselmann
class R_2_instances_name_reinstall(baserlib.OpcodeResource):
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 f6ce0ba2 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReinstall
962 f6ce0ba2 Michael Hanselmann
963 e5b7c4ca Iustin Pop
  def POST(self):
964 e5b7c4ca Iustin Pop
    """Reinstall an instance.
965 e5b7c4ca Iustin Pop

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

970 e5b7c4ca Iustin Pop
    """
971 c744425f Michael Hanselmann
    if self.request_body:
972 c744425f Michael Hanselmann
      if self.queryargs:
973 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
974 c744425f Michael Hanselmann
975 c744425f Michael Hanselmann
      body = self.request_body
976 bd0807fe Guido Trotter
    elif self.queryargs:
977 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
978 c744425f Michael Hanselmann
      body = {
979 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
980 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
981 c744425f Michael Hanselmann
        }
982 bd0807fe Guido Trotter
    else:
983 bd0807fe Guido Trotter
      body = {}
984 c744425f Michael Hanselmann
985 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
986 c744425f Michael Hanselmann
987 be1ddd09 Michael Hanselmann
    return self.SubmitJob(ops)
988 e5b7c4ca Iustin Pop
989 e5b7c4ca Iustin Pop
990 0dbc732c Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.OpcodeResource):
991 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
992 4c98b915 Michael Hanselmann

993 4c98b915 Michael Hanselmann
  """
994 0dbc732c Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReplaceDisks
995 0dbc732c Michael Hanselmann
996 0dbc732c Michael Hanselmann
  def GetPostOpInput(self):
997 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
998 4c98b915 Michael Hanselmann

999 4c98b915 Michael Hanselmann
    """
1000 0dbc732c Michael Hanselmann
    static = {
1001 0dbc732c Michael Hanselmann
      "instance_name": self.items[0],
1002 0dbc732c Michael Hanselmann
      }
1003 4c98b915 Michael Hanselmann
1004 539d65ba Michael Hanselmann
    if self.request_body:
1005 7dcf333d Michael Hanselmann
      data = self.request_body
1006 539d65ba Michael Hanselmann
    elif self.queryargs:
1007 539d65ba Michael Hanselmann
      # Legacy interface, do not modify/extend
1008 7dcf333d Michael Hanselmann
      data = {
1009 539d65ba Michael Hanselmann
        "remote_node": self._checkStringVariable("remote_node", default=None),
1010 539d65ba Michael Hanselmann
        "mode": self._checkStringVariable("mode", default=None),
1011 539d65ba Michael Hanselmann
        "disks": self._checkStringVariable("disks", default=None),
1012 539d65ba Michael Hanselmann
        "iallocator": self._checkStringVariable("iallocator", default=None),
1013 539d65ba Michael Hanselmann
        }
1014 539d65ba Michael Hanselmann
    else:
1015 7dcf333d Michael Hanselmann
      data = {}
1016 539d65ba Michael Hanselmann
1017 0dbc732c Michael Hanselmann
    # Parse disks
1018 0dbc732c Michael Hanselmann
    try:
1019 7dcf333d Michael Hanselmann
      raw_disks = data.pop("disks")
1020 0dbc732c Michael Hanselmann
    except KeyError:
1021 0dbc732c Michael Hanselmann
      pass
1022 0dbc732c Michael Hanselmann
    else:
1023 7dcf333d Michael Hanselmann
      if raw_disks:
1024 7dcf333d Michael Hanselmann
        if ht.TListOf(ht.TInt)(raw_disks): # pylint: disable=E1102
1025 7dcf333d Michael Hanselmann
          data["disks"] = raw_disks
1026 7dcf333d Michael Hanselmann
        else:
1027 7dcf333d Michael Hanselmann
          # Backwards compatibility for strings of the format "1, 2, 3"
1028 7dcf333d Michael Hanselmann
          try:
1029 7dcf333d Michael Hanselmann
            data["disks"] = [int(part) for part in raw_disks.split(",")]
1030 7dcf333d Michael Hanselmann
          except (TypeError, ValueError), err:
1031 7dcf333d Michael Hanselmann
            raise http.HttpBadRequest("Invalid disk index passed: %s" % err)
1032 0dbc732c Michael Hanselmann
1033 0dbc732c Michael Hanselmann
    return (data, static)
1034 4c98b915 Michael Hanselmann
1035 4c98b915 Michael Hanselmann
1036 1824a7a1 Michael Hanselmann
class R_2_instances_name_activate_disks(baserlib.OpcodeResource):
1037 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1038 2197b66f René Nussbaumer

1039 2197b66f René Nussbaumer
  """
1040 1824a7a1 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceActivateDisks
1041 1824a7a1 Michael Hanselmann
1042 1824a7a1 Michael Hanselmann
  def GetPutOpInput(self):
1043 2197b66f René Nussbaumer
    """Activate disks for an instance.
1044 2197b66f René Nussbaumer

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

1047 2197b66f René Nussbaumer
    """
1048 1824a7a1 Michael Hanselmann
    return ({}, {
1049 1824a7a1 Michael Hanselmann
      "instance_name": self.items[0],
1050 1824a7a1 Michael Hanselmann
      "ignore_size": bool(self._checkIntVariable("ignore_size")),
1051 1824a7a1 Michael Hanselmann
      })
1052 2197b66f René Nussbaumer
1053 2197b66f René Nussbaumer
1054 973ec124 Michael Hanselmann
class R_2_instances_name_deactivate_disks(baserlib.OpcodeResource):
1055 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1056 0a37de5f René Nussbaumer

1057 0a37de5f René Nussbaumer
  """
1058 973ec124 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceDeactivateDisks
1059 973ec124 Michael Hanselmann
1060 973ec124 Michael Hanselmann
  def GetPutOpInput(self):
1061 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1062 0a37de5f René Nussbaumer

1063 0a37de5f René Nussbaumer
    """
1064 973ec124 Michael Hanselmann
    return ({}, {
1065 973ec124 Michael Hanselmann
      "instance_name": self.items[0],
1066 973ec124 Michael Hanselmann
      })
1067 0a37de5f René Nussbaumer
1068 0a37de5f René Nussbaumer
1069 a52978c7 Michael Hanselmann
class R_2_instances_name_recreate_disks(baserlib.OpcodeResource):
1070 a52978c7 Michael Hanselmann
  """/2/instances/[instance_name]/recreate-disks resource.
1071 a52978c7 Michael Hanselmann

1072 a52978c7 Michael Hanselmann
  """
1073 a52978c7 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceRecreateDisks
1074 a52978c7 Michael Hanselmann
1075 a52978c7 Michael Hanselmann
  def GetPostOpInput(self):
1076 a52978c7 Michael Hanselmann
    """Recreate disks for an instance.
1077 a52978c7 Michael Hanselmann

1078 a52978c7 Michael Hanselmann
    """
1079 a52978c7 Michael Hanselmann
    return ({}, {
1080 a52978c7 Michael Hanselmann
      "instance_name": self.items[0],
1081 a52978c7 Michael Hanselmann
      })
1082 a52978c7 Michael Hanselmann
1083 a52978c7 Michael Hanselmann
1084 1c63311d Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.OpcodeResource):
1085 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1086 ebeb600f Michael Hanselmann

1087 ebeb600f Michael Hanselmann
  """
1088 1c63311d Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupPrepare
1089 ebeb600f Michael Hanselmann
1090 1c63311d Michael Hanselmann
  def GetPutOpInput(self):
1091 1c63311d Michael Hanselmann
    """Prepares an export for an instance.
1092 ebeb600f Michael Hanselmann

1093 ebeb600f Michael Hanselmann
    """
1094 1c63311d Michael Hanselmann
    return ({}, {
1095 1c63311d Michael Hanselmann
      "instance_name": self.items[0],
1096 1c63311d Michael Hanselmann
      "mode": self._checkStringVariable("mode"),
1097 1c63311d Michael Hanselmann
      })
1098 ebeb600f Michael Hanselmann
1099 ebeb600f Michael Hanselmann
1100 134afbe7 Michael Hanselmann
class R_2_instances_name_export(baserlib.OpcodeResource):
1101 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1102 ebeb600f Michael Hanselmann

1103 ebeb600f Michael Hanselmann
  """
1104 134afbe7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupExport
1105 134afbe7 Michael Hanselmann
  PUT_RENAME = {
1106 134afbe7 Michael Hanselmann
    "destination": "target_node",
1107 134afbe7 Michael Hanselmann
    }
1108 ebeb600f Michael Hanselmann
1109 134afbe7 Michael Hanselmann
  def GetPutOpInput(self):
1110 134afbe7 Michael Hanselmann
    """Exports an instance.
1111 ebeb600f Michael Hanselmann

1112 ebeb600f Michael Hanselmann
    """
1113 134afbe7 Michael Hanselmann
    return (self.request_body, {
1114 134afbe7 Michael Hanselmann
      "instance_name": self.items[0],
1115 134afbe7 Michael Hanselmann
      })
1116 ebeb600f Michael Hanselmann
1117 ebeb600f Michael Hanselmann
1118 075a29be Michael Hanselmann
class R_2_instances_name_migrate(baserlib.OpcodeResource):
1119 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1120 5823e0d2 Michael Hanselmann

1121 5823e0d2 Michael Hanselmann
  """
1122 075a29be Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceMigrate
1123 5823e0d2 Michael Hanselmann
1124 075a29be Michael Hanselmann
  def GetPutOpInput(self):
1125 075a29be Michael Hanselmann
    """Migrates an instance.
1126 5823e0d2 Michael Hanselmann

1127 5823e0d2 Michael Hanselmann
    """
1128 075a29be Michael Hanselmann
    return (self.request_body, {
1129 075a29be Michael Hanselmann
      "instance_name": self.items[0],
1130 075a29be Michael Hanselmann
      })
1131 5823e0d2 Michael Hanselmann
1132 5823e0d2 Michael Hanselmann
1133 b5f2ab80 Michael Hanselmann
class R_2_instances_name_failover(baserlib.OpcodeResource):
1134 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1135 c0a146a1 Michael Hanselmann

1136 c0a146a1 Michael Hanselmann
  """
1137 b5f2ab80 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceFailover
1138 c0a146a1 Michael Hanselmann
1139 b5f2ab80 Michael Hanselmann
  def GetPutOpInput(self):
1140 b5f2ab80 Michael Hanselmann
    """Does a failover of an instance.
1141 c0a146a1 Michael Hanselmann

1142 c0a146a1 Michael Hanselmann
    """
1143 b5f2ab80 Michael Hanselmann
    return (self.request_body, {
1144 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1145 c0a146a1 Michael Hanselmann
      })
1146 c0a146a1 Michael Hanselmann
1147 c0a146a1 Michael Hanselmann
1148 d76f9b5d Michael Hanselmann
class R_2_instances_name_rename(baserlib.OpcodeResource):
1149 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1150 d56e7dc7 Michael Hanselmann

1151 d56e7dc7 Michael Hanselmann
  """
1152 d76f9b5d Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceRename
1153 d56e7dc7 Michael Hanselmann
1154 d76f9b5d Michael Hanselmann
  def GetPutOpInput(self):
1155 d76f9b5d Michael Hanselmann
    """Changes the name of an instance.
1156 d56e7dc7 Michael Hanselmann

1157 d56e7dc7 Michael Hanselmann
    """
1158 d76f9b5d Michael Hanselmann
    return (self.request_body, {
1159 d76f9b5d Michael Hanselmann
      "instance_name": self.items[0],
1160 d76f9b5d Michael Hanselmann
      })
1161 d56e7dc7 Michael Hanselmann
1162 d56e7dc7 Michael Hanselmann
1163 f3db88ba Michael Hanselmann
class R_2_instances_name_modify(baserlib.OpcodeResource):
1164 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1165 3882937a Michael Hanselmann

1166 3882937a Michael Hanselmann
  """
1167 f3db88ba Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceSetParams
1168 3882937a Michael Hanselmann
1169 f3db88ba Michael Hanselmann
  def GetPutOpInput(self):
1170 f3db88ba Michael Hanselmann
    """Changes parameters of an instance.
1171 3882937a Michael Hanselmann

1172 3882937a Michael Hanselmann
    """
1173 f3db88ba Michael Hanselmann
    return (self.request_body, {
1174 f3db88ba Michael Hanselmann
      "instance_name": self.items[0],
1175 f3db88ba Michael Hanselmann
      })
1176 3882937a Michael Hanselmann
1177 3882937a Michael Hanselmann
1178 335965b9 Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.OpcodeResource):
1179 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1180 e23881ed Michael Hanselmann

1181 e23881ed Michael Hanselmann
  """
1182 335965b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceGrowDisk
1183 e23881ed Michael Hanselmann
1184 335965b9 Michael Hanselmann
  def GetPostOpInput(self):
1185 335965b9 Michael Hanselmann
    """Increases the size of an instance disk.
1186 e23881ed Michael Hanselmann

1187 e23881ed Michael Hanselmann
    """
1188 335965b9 Michael Hanselmann
    return (self.request_body, {
1189 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1190 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1191 e23881ed Michael Hanselmann
      })
1192 e23881ed Michael Hanselmann
1193 e23881ed Michael Hanselmann
1194 26ff6ee2 Michael Hanselmann
class R_2_instances_name_console(baserlib.ResourceBase):
1195 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1196 b82d4c5e Michael Hanselmann

1197 b82d4c5e Michael Hanselmann
  """
1198 b82d4c5e Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1199 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceConsole
1200 b82d4c5e Michael Hanselmann
1201 b82d4c5e Michael Hanselmann
  def GET(self):
1202 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1203 b82d4c5e Michael Hanselmann

1204 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1205 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1206 b82d4c5e Michael Hanselmann

1207 b82d4c5e Michael Hanselmann
    """
1208 be1ddd09 Michael Hanselmann
    client = self.GetClient()
1209 b82d4c5e Michael Hanselmann
1210 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1211 b82d4c5e Michael Hanselmann
1212 b82d4c5e Michael Hanselmann
    if console is None:
1213 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1214 b82d4c5e Michael Hanselmann
1215 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1216 b82d4c5e Michael Hanselmann
    return console
1217 b82d4c5e Michael Hanselmann
1218 b82d4c5e Michael Hanselmann
1219 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1220 208a6cff Michael Hanselmann
  """
1221 208a6cff Michael Hanselmann

1222 208a6cff Michael Hanselmann
  """
1223 208a6cff Michael Hanselmann
  try:
1224 208a6cff Michael Hanselmann
    fields = args["fields"]
1225 208a6cff Michael Hanselmann
  except KeyError:
1226 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1227 208a6cff Michael Hanselmann
1228 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1229 208a6cff Michael Hanselmann
1230 208a6cff Michael Hanselmann
1231 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1232 208a6cff Michael Hanselmann
  """
1233 208a6cff Michael Hanselmann

1234 208a6cff Michael Hanselmann
  """
1235 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1236 208a6cff Michael Hanselmann
1237 208a6cff Michael Hanselmann
1238 26ff6ee2 Michael Hanselmann
class R_2_query(baserlib.ResourceBase):
1239 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1240 208a6cff Michael Hanselmann

1241 208a6cff Michael Hanselmann
  """
1242 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1243 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1244 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpQuery
1245 f6ce0ba2 Michael Hanselmann
  PUT_OPCODE = opcodes.OpQuery
1246 208a6cff Michael Hanselmann
1247 2e5c33db Iustin Pop
  def _Query(self, fields, qfilter):
1248 2e5c33db Iustin Pop
    return self.GetClient().Query(self.items[0], fields, qfilter).ToDict()
1249 208a6cff Michael Hanselmann
1250 208a6cff Michael Hanselmann
  def GET(self):
1251 208a6cff Michael Hanselmann
    """Returns resource information.
1252 208a6cff Michael Hanselmann

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

1255 208a6cff Michael Hanselmann
    """
1256 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1257 208a6cff Michael Hanselmann
1258 208a6cff Michael Hanselmann
  def PUT(self):
1259 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1260 208a6cff Michael Hanselmann

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

1263 208a6cff Michael Hanselmann
    """
1264 208a6cff Michael Hanselmann
    body = self.request_body
1265 208a6cff Michael Hanselmann
1266 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1267 208a6cff Michael Hanselmann
1268 208a6cff Michael Hanselmann
    try:
1269 208a6cff Michael Hanselmann
      fields = body["fields"]
1270 208a6cff Michael Hanselmann
    except KeyError:
1271 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1272 208a6cff Michael Hanselmann
1273 2e5c33db Iustin Pop
    qfilter = body.get("qfilter", None)
1274 2e5c33db Iustin Pop
    # TODO: remove this after 2.7
1275 2e5c33db Iustin Pop
    if qfilter is None:
1276 2e5c33db Iustin Pop
      qfilter = body.get("filter", None)
1277 2e5c33db Iustin Pop
1278 2e5c33db Iustin Pop
    return self._Query(fields, qfilter)
1279 208a6cff Michael Hanselmann
1280 208a6cff Michael Hanselmann
1281 26ff6ee2 Michael Hanselmann
class R_2_query_fields(baserlib.ResourceBase):
1282 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1283 208a6cff Michael Hanselmann

1284 208a6cff Michael Hanselmann
  """
1285 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpQueryFields
1286 f6ce0ba2 Michael Hanselmann
1287 208a6cff Michael Hanselmann
  def GET(self):
1288 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1289 208a6cff Michael Hanselmann

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

1292 208a6cff Michael Hanselmann
    """
1293 208a6cff Michael Hanselmann
    try:
1294 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1295 208a6cff Michael Hanselmann
    except KeyError:
1296 208a6cff Michael Hanselmann
      fields = None
1297 208a6cff Michael Hanselmann
    else:
1298 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1299 208a6cff Michael Hanselmann
1300 be1ddd09 Michael Hanselmann
    return self.GetClient().QueryFields(self.items[0], fields).ToDict()
1301 208a6cff Michael Hanselmann
1302 208a6cff Michael Hanselmann
1303 460ef073 Michael Hanselmann
class _R_Tags(baserlib.OpcodeResource):
1304 3bd0f3d8 Iustin Pop
  """Quasiclass for tagging resources.
1305 441e7cfd Oleksiy Mishchenko

1306 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1307 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1308 441e7cfd Oleksiy Mishchenko

1309 441e7cfd Oleksiy Mishchenko
  """
1310 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1311 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpTagsGet
1312 460ef073 Michael Hanselmann
  PUT_OPCODE = opcodes.OpTagsSet
1313 460ef073 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpTagsDel
1314 18cb43a2 Oleksiy Mishchenko
1315 460ef073 Michael Hanselmann
  def __init__(self, items, queryargs, req, **kwargs):
1316 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1317 18cb43a2 Oleksiy Mishchenko

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

1320 18cb43a2 Oleksiy Mishchenko
    """
1321 460ef073 Michael Hanselmann
    baserlib.OpcodeResource.__init__(self, items, queryargs, req, **kwargs)
1322 18cb43a2 Oleksiy Mishchenko
1323 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1324 5313eed7 Michael Hanselmann
      self.name = None
1325 18cb43a2 Oleksiy Mishchenko
    else:
1326 5313eed7 Michael Hanselmann
      self.name = items[0]
1327 441e7cfd Oleksiy Mishchenko
1328 441e7cfd Oleksiy Mishchenko
  def GET(self):
1329 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1330 441e7cfd Oleksiy Mishchenko

1331 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1332 441e7cfd Oleksiy Mishchenko

1333 441e7cfd Oleksiy Mishchenko
    """
1334 f87ec53f Michael Hanselmann
    kind = self.TAG_LEVEL
1335 f87ec53f Michael Hanselmann
1336 f87ec53f Michael Hanselmann
    if kind in (constants.TAG_INSTANCE,
1337 f87ec53f Michael Hanselmann
                constants.TAG_NODEGROUP,
1338 f87ec53f Michael Hanselmann
                constants.TAG_NODE):
1339 f87ec53f Michael Hanselmann
      if not self.name:
1340 f87ec53f Michael Hanselmann
        raise http.HttpBadRequest("Missing name on tag request")
1341 f87ec53f Michael Hanselmann
1342 be1ddd09 Michael Hanselmann
      cl = self.GetClient()
1343 f87ec53f Michael Hanselmann
      if kind == constants.TAG_INSTANCE:
1344 f87ec53f Michael Hanselmann
        fn = cl.QueryInstances
1345 f87ec53f Michael Hanselmann
      elif kind == constants.TAG_NODEGROUP:
1346 f87ec53f Michael Hanselmann
        fn = cl.QueryGroups
1347 f87ec53f Michael Hanselmann
      else:
1348 f87ec53f Michael Hanselmann
        fn = cl.QueryNodes
1349 f87ec53f Michael Hanselmann
      result = fn(names=[self.name], fields=["tags"], use_locking=False)
1350 f87ec53f Michael Hanselmann
      if not result or not result[0]:
1351 f87ec53f Michael Hanselmann
        raise http.HttpBadGateway("Invalid response from tag query")
1352 f87ec53f Michael Hanselmann
      tags = result[0][0]
1353 f87ec53f Michael Hanselmann
1354 f87ec53f Michael Hanselmann
    elif kind == constants.TAG_CLUSTER:
1355 f87ec53f Michael Hanselmann
      assert not self.name
1356 f87ec53f Michael Hanselmann
      # TODO: Use query API?
1357 f87ec53f Michael Hanselmann
      ssc = ssconf.SimpleStore()
1358 f87ec53f Michael Hanselmann
      tags = ssc.GetClusterTags()
1359 f87ec53f Michael Hanselmann
1360 f87ec53f Michael Hanselmann
    return list(tags)
1361 441e7cfd Oleksiy Mishchenko
1362 460ef073 Michael Hanselmann
  def GetPutOpInput(self):
1363 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1364 441e7cfd Oleksiy Mishchenko

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

1368 441e7cfd Oleksiy Mishchenko
    """
1369 460ef073 Michael Hanselmann
    return ({}, {
1370 460ef073 Michael Hanselmann
      "kind": self.TAG_LEVEL,
1371 460ef073 Michael Hanselmann
      "name": self.name,
1372 460ef073 Michael Hanselmann
      "tags": self.queryargs.get("tag", []),
1373 460ef073 Michael Hanselmann
      "dry_run": self.dryRun(),
1374 460ef073 Michael Hanselmann
      })
1375 15fd9fd5 Oleksiy Mishchenko
1376 460ef073 Michael Hanselmann
  def GetDeleteOpInput(self):
1377 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1378 15fd9fd5 Oleksiy Mishchenko

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

1383 15fd9fd5 Oleksiy Mishchenko
    """
1384 460ef073 Michael Hanselmann
    # Re-use code
1385 460ef073 Michael Hanselmann
    return self.GetPutOpInput()
1386 18cb43a2 Oleksiy Mishchenko
1387 18cb43a2 Oleksiy Mishchenko
1388 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1389 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1390 18cb43a2 Oleksiy Mishchenko

1391 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1392 18cb43a2 Oleksiy Mishchenko

1393 18cb43a2 Oleksiy Mishchenko
  """
1394 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1395 18cb43a2 Oleksiy Mishchenko
1396 18cb43a2 Oleksiy Mishchenko
1397 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1398 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1399 18cb43a2 Oleksiy Mishchenko

1400 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1401 18cb43a2 Oleksiy Mishchenko

1402 18cb43a2 Oleksiy Mishchenko
  """
1403 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1404 18cb43a2 Oleksiy Mishchenko
1405 18cb43a2 Oleksiy Mishchenko
1406 414ebaf1 Michael Hanselmann
class R_2_groups_name_tags(_R_Tags):
1407 414ebaf1 Michael Hanselmann
  """ /2/groups/[group_name]/tags resource.
1408 414ebaf1 Michael Hanselmann

1409 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1410 414ebaf1 Michael Hanselmann

1411 414ebaf1 Michael Hanselmann
  """
1412 414ebaf1 Michael Hanselmann
  TAG_LEVEL = constants.TAG_NODEGROUP
1413 414ebaf1 Michael Hanselmann
1414 414ebaf1 Michael Hanselmann
1415 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1416 b58a4d16 Michael Hanselmann
  """ /2/tags resource.
1417 18cb43a2 Oleksiy Mishchenko

1418 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1419 18cb43a2 Oleksiy Mishchenko

1420 18cb43a2 Oleksiy Mishchenko
  """
1421 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER