Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 02a6b50a

History | View | Annotate | Download (39.9 kB)

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

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

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

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

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

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

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

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

174 28a45bfc René Nussbaumer
  @param inst: Inst dict
175 28a45bfc René Nussbaumer
  @return: Updated inst dict
176 28a45bfc René Nussbaumer

177 28a45bfc René Nussbaumer
  """
178 28a45bfc René Nussbaumer
  beparams = inst["beparams"]
179 28a45bfc René Nussbaumer
  beparams[constants.BE_MEMORY] = beparams[constants.BE_MAXMEM]
180 28a45bfc René Nussbaumer
181 28a45bfc René Nussbaumer
  return inst
182 28a45bfc René Nussbaumer
183 28a45bfc René Nussbaumer
184 26ff6ee2 Michael Hanselmann
class R_root(baserlib.ResourceBase):
185 0f945c65 Michael Hanselmann
  """/ resource.
186 0f945c65 Michael Hanselmann

187 0f945c65 Michael Hanselmann
  """
188 0f945c65 Michael Hanselmann
  @staticmethod
189 0f945c65 Michael Hanselmann
  def GET():
190 0f945c65 Michael Hanselmann
    """Supported for legacy reasons.
191 0f945c65 Michael Hanselmann

192 0f945c65 Michael Hanselmann
    """
193 0f945c65 Michael Hanselmann
    return None
194 0f945c65 Michael Hanselmann
195 0f945c65 Michael Hanselmann
196 132cdb87 Michael Hanselmann
class R_2(R_root):
197 132cdb87 Michael Hanselmann
  """/2 resource.
198 132cdb87 Michael Hanselmann

199 132cdb87 Michael Hanselmann
  """
200 132cdb87 Michael Hanselmann
201 132cdb87 Michael Hanselmann
202 26ff6ee2 Michael Hanselmann
class R_version(baserlib.ResourceBase):
203 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
204 4e5a68f8 Oleksiy Mishchenko

205 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
206 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
207 4e5a68f8 Oleksiy Mishchenko

208 4e5a68f8 Oleksiy Mishchenko
  """
209 7e950d31 Iustin Pop
  @staticmethod
210 7e950d31 Iustin Pop
  def GET():
211 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
212 4e5a68f8 Oleksiy Mishchenko

213 4e5a68f8 Oleksiy Mishchenko
    """
214 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
215 4e5a68f8 Oleksiy Mishchenko
216 4e5a68f8 Oleksiy Mishchenko
217 f6ce0ba2 Michael Hanselmann
class R_2_info(baserlib.OpcodeResource):
218 b58a4d16 Michael Hanselmann
  """/2/info resource.
219 4e5a68f8 Oleksiy Mishchenko

220 4e5a68f8 Oleksiy Mishchenko
  """
221 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpClusterQuery
222 f6ce0ba2 Michael Hanselmann
223 be1ddd09 Michael Hanselmann
  def GET(self):
224 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
225 4e5a68f8 Oleksiy Mishchenko

226 4e5a68f8 Oleksiy Mishchenko
    """
227 a2160e57 Iustin Pop
    client = self.GetClient(query=True)
228 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
229 4e5a68f8 Oleksiy Mishchenko
230 4e5a68f8 Oleksiy Mishchenko
231 26ff6ee2 Michael Hanselmann
class R_2_features(baserlib.ResourceBase):
232 7eac4a4d Michael Hanselmann
  """/2/features resource.
233 7eac4a4d Michael Hanselmann

234 7eac4a4d Michael Hanselmann
  """
235 7eac4a4d Michael Hanselmann
  @staticmethod
236 7eac4a4d Michael Hanselmann
  def GET():
237 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
238 7eac4a4d Michael Hanselmann

239 7eac4a4d Michael Hanselmann
    """
240 b4fcee5b Michael Hanselmann
    return list(ALL_FEATURES)
241 7eac4a4d Michael Hanselmann
242 7eac4a4d Michael Hanselmann
243 f6ce0ba2 Michael Hanselmann
class R_2_os(baserlib.OpcodeResource):
244 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
245 4e5a68f8 Oleksiy Mishchenko

246 4e5a68f8 Oleksiy Mishchenko
  """
247 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpOsDiagnose
248 f6ce0ba2 Michael Hanselmann
249 be1ddd09 Michael Hanselmann
  def GET(self):
250 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
251 4e5a68f8 Oleksiy Mishchenko

252 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
253 4e5a68f8 Oleksiy Mishchenko

254 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
255 4e5a68f8 Oleksiy Mishchenko

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

277 508e9b20 Michael Hanselmann
  """
278 8fd625fc Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterRedistConf
279 508e9b20 Michael Hanselmann
280 508e9b20 Michael Hanselmann
281 50c7d82e Michael Hanselmann
class R_2_cluster_modify(baserlib.OpcodeResource):
282 62e999a5 Michael Hanselmann
  """/2/modify resource.
283 62e999a5 Michael Hanselmann

284 62e999a5 Michael Hanselmann
  """
285 50c7d82e Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterSetParams
286 62e999a5 Michael Hanselmann
287 62e999a5 Michael Hanselmann
288 26ff6ee2 Michael Hanselmann
class R_2_jobs(baserlib.ResourceBase):
289 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
290 10b207d4 Oleksiy Mishchenko

291 10b207d4 Oleksiy Mishchenko
  """
292 e987f166 Michael Hanselmann
  def GET(self):
293 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
294 10b207d4 Oleksiy Mishchenko

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

297 10b207d4 Oleksiy Mishchenko
    """
298 d45a824b Iustin Pop
    client = self.GetClient(query=True)
299 e987f166 Michael Hanselmann
300 e987f166 Michael Hanselmann
    if self.useBulk():
301 bd7b2070 Michael Hanselmann
      bulkdata = client.QueryJobs(None, J_FIELDS_BULK)
302 bd7b2070 Michael Hanselmann
      return baserlib.MapBulkFields(bulkdata, J_FIELDS_BULK)
303 e987f166 Michael Hanselmann
    else:
304 e987f166 Michael Hanselmann
      jobdata = map(compat.fst, client.QueryJobs(None, ["id"]))
305 e987f166 Michael Hanselmann
      return baserlib.BuildUriList(jobdata, "/2/jobs/%s",
306 e987f166 Michael Hanselmann
                                   uri_fields=("id", "uri"))
307 10b207d4 Oleksiy Mishchenko
308 10b207d4 Oleksiy Mishchenko
309 26ff6ee2 Michael Hanselmann
class R_2_jobs_id(baserlib.ResourceBase):
310 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
311 10b207d4 Oleksiy Mishchenko

312 10b207d4 Oleksiy Mishchenko
  """
313 10b207d4 Oleksiy Mishchenko
  def GET(self):
314 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
315 10b207d4 Oleksiy Mishchenko

316 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
317 c41eea6e Iustin Pop
        The result includes:
318 c41eea6e Iustin Pop
            - id: job ID as a number
319 c41eea6e Iustin Pop
            - status: current job status as a string
320 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
321 c41eea6e Iustin Pop
              opcodes in the job
322 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
323 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
324 38206f3c Iustin Pop

325 10b207d4 Oleksiy Mishchenko
    """
326 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
327 d45a824b Iustin Pop
    result = self.GetClient(query=True).QueryJobs([job_id, ], J_FIELDS)[0]
328 ee69c97f Iustin Pop
    if result is None:
329 ee69c97f Iustin Pop
      raise http.HttpNotFound()
330 e987f166 Michael Hanselmann
    return baserlib.MapFields(J_FIELDS, result)
331 10b207d4 Oleksiy Mishchenko
332 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
333 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
334 c7f5f338 Oleksiy Mishchenko

335 c7f5f338 Oleksiy Mishchenko
    """
336 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
337 be1ddd09 Michael Hanselmann
    result = self.GetClient().CancelJob(job_id)
338 c7f5f338 Oleksiy Mishchenko
    return result
339 c7f5f338 Oleksiy Mishchenko
340 10b207d4 Oleksiy Mishchenko
341 26ff6ee2 Michael Hanselmann
class R_2_jobs_id_wait(baserlib.ResourceBase):
342 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
343 793a8f7c Michael Hanselmann

344 793a8f7c Michael Hanselmann
  """
345 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
346 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
347 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
348 793a8f7c Michael Hanselmann
349 793a8f7c Michael Hanselmann
  def GET(self):
350 793a8f7c Michael Hanselmann
    """Waits for job changes.
351 793a8f7c Michael Hanselmann

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

393 10b207d4 Oleksiy Mishchenko
  """
394 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQuery
395 f6ce0ba2 Michael Hanselmann
396 10b207d4 Oleksiy Mishchenko
  def GET(self):
397 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
398 38206f3c Iustin Pop

399 10b207d4 Oleksiy Mishchenko
    """
400 d9a22528 Iustin Pop
    client = self.GetClient(query=True)
401 38206f3c Iustin Pop
402 3d103742 Iustin Pop
    if self.useBulk():
403 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
404 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
405 9031ee8e Iustin Pop
    else:
406 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
407 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
408 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
409 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
410 441e7cfd Oleksiy Mishchenko
411 441e7cfd Oleksiy Mishchenko
412 f6ce0ba2 Michael Hanselmann
class R_2_nodes_name(baserlib.OpcodeResource):
413 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name] resource.
414 028c6b76 Oleksiy Mishchenko

415 028c6b76 Oleksiy Mishchenko
  """
416 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQuery
417 f6ce0ba2 Michael Hanselmann
418 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
419 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
420 4e5a68f8 Oleksiy Mishchenko

421 4e5a68f8 Oleksiy Mishchenko
    """
422 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
423 d9a22528 Iustin Pop
    client = self.GetClient(query=True)
424 e8ebbd2b Michael Hanselmann
425 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
426 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
427 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
428 4e5a68f8 Oleksiy Mishchenko
429 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
430 028c6b76 Oleksiy Mishchenko
431 028c6b76 Oleksiy Mishchenko
432 42d4d8b9 Michael Hanselmann
class R_2_nodes_name_powercycle(baserlib.OpcodeResource):
433 42d4d8b9 Michael Hanselmann
  """/2/nodes/[node_name]/powercycle resource.
434 42d4d8b9 Michael Hanselmann

435 42d4d8b9 Michael Hanselmann
  """
436 42d4d8b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodePowercycle
437 42d4d8b9 Michael Hanselmann
438 42d4d8b9 Michael Hanselmann
  def GetPostOpInput(self):
439 42d4d8b9 Michael Hanselmann
    """Tries to powercycle a node.
440 42d4d8b9 Michael Hanselmann

441 42d4d8b9 Michael Hanselmann
    """
442 42d4d8b9 Michael Hanselmann
    return (self.request_body, {
443 42d4d8b9 Michael Hanselmann
      "node_name": self.items[0],
444 42d4d8b9 Michael Hanselmann
      "force": self.useForce(),
445 42d4d8b9 Michael Hanselmann
      })
446 42d4d8b9 Michael Hanselmann
447 42d4d8b9 Michael Hanselmann
448 51cc8637 Michael Hanselmann
class R_2_nodes_name_role(baserlib.OpcodeResource):
449 51cc8637 Michael Hanselmann
  """/2/nodes/[node_name]/role resource.
450 64dae8fc Michael Hanselmann

451 64dae8fc Michael Hanselmann
  """
452 51cc8637 Michael Hanselmann
  PUT_OPCODE = opcodes.OpNodeSetParams
453 51cc8637 Michael Hanselmann
454 64dae8fc Michael Hanselmann
  def GET(self):
455 64dae8fc Michael Hanselmann
    """Returns the current node role.
456 64dae8fc Michael Hanselmann

457 64dae8fc Michael Hanselmann
    @return: Node role
458 64dae8fc Michael Hanselmann

459 64dae8fc Michael Hanselmann
    """
460 64dae8fc Michael Hanselmann
    node_name = self.items[0]
461 9fbf0098 Iustin Pop
    client = self.GetClient(query=True)
462 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
463 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
464 64dae8fc Michael Hanselmann
465 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
466 64dae8fc Michael Hanselmann
467 51cc8637 Michael Hanselmann
  def GetPutOpInput(self):
468 64dae8fc Michael Hanselmann
    """Sets the node role.
469 64dae8fc Michael Hanselmann

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

510 73452f12 Michael Hanselmann
  """
511 7fa91722 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodeEvacuate
512 7fa91722 Michael Hanselmann
513 7fa91722 Michael Hanselmann
  def GetPostOpInput(self):
514 de40437a Michael Hanselmann
    """Evacuate all instances off a node.
515 73452f12 Michael Hanselmann

516 73452f12 Michael Hanselmann
    """
517 7fa91722 Michael Hanselmann
    return (self.request_body, {
518 de40437a Michael Hanselmann
      "node_name": self.items[0],
519 de40437a Michael Hanselmann
      "dry_run": self.dryRun(),
520 de40437a Michael Hanselmann
      })
521 941b9309 Iustin Pop
522 73452f12 Michael Hanselmann
523 55168cc7 Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.OpcodeResource):
524 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
525 1c482bab Michael Hanselmann

526 1c482bab Michael Hanselmann
  """
527 55168cc7 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodeMigrate
528 55168cc7 Michael Hanselmann
529 55168cc7 Michael Hanselmann
  def GetPostOpInput(self):
530 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
531 1c482bab Michael Hanselmann

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

561 94497dd1 Michael Hanselmann
  """
562 8b8f54dd Guido Trotter
  POST_OPCODE = opcodes.OpNodeSetParams
563 94497dd1 Michael Hanselmann
564 8b8f54dd Guido Trotter
  def GetPostOpInput(self):
565 682878d9 Guido Trotter
    """Changes parameters of a node.
566 94497dd1 Michael Hanselmann

567 94497dd1 Michael Hanselmann
    """
568 682878d9 Guido Trotter
    assert len(self.items) == 1
569 94497dd1 Michael Hanselmann
570 682878d9 Guido Trotter
    return (self.request_body, {
571 370f2042 Guido Trotter
      "node_name": self.items[0],
572 94497dd1 Michael Hanselmann
      })
573 94497dd1 Michael Hanselmann
574 94497dd1 Michael Hanselmann
575 eb08e09d Michael Hanselmann
class R_2_nodes_name_storage(baserlib.OpcodeResource):
576 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
577 7a95a954 Michael Hanselmann

578 7a95a954 Michael Hanselmann
  """
579 ad8d0595 Iustin Pop
  # LUNodeQueryStorage acquires locks, hence restricting access to GET
580 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
581 eb08e09d Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQueryStorage
582 7a95a954 Michael Hanselmann
583 eb08e09d Michael Hanselmann
  def GetGetOpInput(self):
584 eb08e09d Michael Hanselmann
    """List storage available on a node.
585 7a95a954 Michael Hanselmann

586 eb08e09d Michael Hanselmann
    """
587 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
588 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
589 eb08e09d Michael Hanselmann
590 7a95a954 Michael Hanselmann
    if not output_fields:
591 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
592 7a95a954 Michael Hanselmann
                                " parameter")
593 7a95a954 Michael Hanselmann
594 eb08e09d Michael Hanselmann
    return ({}, {
595 eb08e09d Michael Hanselmann
      "nodes": [self.items[0]],
596 eb08e09d Michael Hanselmann
      "storage_type": storage_type,
597 eb08e09d Michael Hanselmann
      "output_fields": output_fields.split(","),
598 eb08e09d Michael Hanselmann
      })
599 7a95a954 Michael Hanselmann
600 7a95a954 Michael Hanselmann
601 8d232068 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.OpcodeResource):
602 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify resource.
603 1e82bc80 Michael Hanselmann

604 1e82bc80 Michael Hanselmann
  """
605 8d232068 Michael Hanselmann
  PUT_OPCODE = opcodes.OpNodeModifyStorage
606 1e82bc80 Michael Hanselmann
607 8d232068 Michael Hanselmann
  def GetPutOpInput(self):
608 8d232068 Michael Hanselmann
    """Modifies a storage volume on a node.
609 1e82bc80 Michael Hanselmann

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

635 723f4565 Michael Hanselmann
  """
636 98270691 Michael Hanselmann
  PUT_OPCODE = opcodes.OpRepairNodeStorage
637 723f4565 Michael Hanselmann
638 98270691 Michael Hanselmann
  def GetPutOpInput(self):
639 98270691 Michael Hanselmann
    """Repairs a storage volume on a node.
640 723f4565 Michael Hanselmann

641 98270691 Michael Hanselmann
    """
642 98270691 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
643 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
644 723f4565 Michael Hanselmann
    if not name:
645 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
646 723f4565 Michael Hanselmann
                                " parameter")
647 723f4565 Michael Hanselmann
648 98270691 Michael Hanselmann
    return ({}, {
649 98270691 Michael Hanselmann
      "node_name": self.items[0],
650 98270691 Michael Hanselmann
      "storage_type": storage_type,
651 98270691 Michael Hanselmann
      "name": name,
652 98270691 Michael Hanselmann
      })
653 723f4565 Michael Hanselmann
654 723f4565 Michael Hanselmann
655 4588b4bd Dimitris Aragiorgis
class R_2_networks(baserlib.OpcodeResource):
656 4588b4bd Dimitris Aragiorgis
  """/2/networks resource.
657 4588b4bd Dimitris Aragiorgis

658 4588b4bd Dimitris Aragiorgis
  """
659 4588b4bd Dimitris Aragiorgis
  GET_OPCODE = opcodes.OpNetworkQuery
660 4588b4bd Dimitris Aragiorgis
  POST_OPCODE = opcodes.OpNetworkAdd
661 4588b4bd Dimitris Aragiorgis
  POST_RENAME = {
662 4588b4bd Dimitris Aragiorgis
    "name": "network_name",
663 4588b4bd Dimitris Aragiorgis
    }
664 4588b4bd Dimitris Aragiorgis
665 4588b4bd Dimitris Aragiorgis
  def GetPostOpInput(self):
666 4588b4bd Dimitris Aragiorgis
    """Create a network.
667 4588b4bd Dimitris Aragiorgis

668 4588b4bd Dimitris Aragiorgis
    """
669 4588b4bd Dimitris Aragiorgis
    assert not self.items
670 4588b4bd Dimitris Aragiorgis
    return (self.request_body, {
671 4588b4bd Dimitris Aragiorgis
      "dry_run": self.dryRun(),
672 4588b4bd Dimitris Aragiorgis
      })
673 4588b4bd Dimitris Aragiorgis
674 4588b4bd Dimitris Aragiorgis
  def GET(self):
675 4588b4bd Dimitris Aragiorgis
    """Returns a list of all networks.
676 4588b4bd Dimitris Aragiorgis

677 4588b4bd Dimitris Aragiorgis
    """
678 ab9e48d1 Iustin Pop
    client = self.GetClient(query=True)
679 4588b4bd Dimitris Aragiorgis
680 4588b4bd Dimitris Aragiorgis
    if self.useBulk():
681 4588b4bd Dimitris Aragiorgis
      bulkdata = client.QueryNetworks([], NET_FIELDS, False)
682 4588b4bd Dimitris Aragiorgis
      return baserlib.MapBulkFields(bulkdata, NET_FIELDS)
683 4588b4bd Dimitris Aragiorgis
    else:
684 4588b4bd Dimitris Aragiorgis
      data = client.QueryNetworks([], ["name"], False)
685 4588b4bd Dimitris Aragiorgis
      networknames = [row[0] for row in data]
686 4588b4bd Dimitris Aragiorgis
      return baserlib.BuildUriList(networknames, "/2/networks/%s",
687 4588b4bd Dimitris Aragiorgis
                                   uri_fields=("name", "uri"))
688 4588b4bd Dimitris Aragiorgis
689 4588b4bd Dimitris Aragiorgis
690 4588b4bd Dimitris Aragiorgis
class R_2_networks_name(baserlib.OpcodeResource):
691 6e8091f9 Dimitris Aragiorgis
  """/2/networks/[network_name] resource.
692 4588b4bd Dimitris Aragiorgis

693 4588b4bd Dimitris Aragiorgis
  """
694 4588b4bd Dimitris Aragiorgis
  DELETE_OPCODE = opcodes.OpNetworkRemove
695 4588b4bd Dimitris Aragiorgis
696 4588b4bd Dimitris Aragiorgis
  def GET(self):
697 4588b4bd Dimitris Aragiorgis
    """Send information about a network.
698 4588b4bd Dimitris Aragiorgis

699 4588b4bd Dimitris Aragiorgis
    """
700 4588b4bd Dimitris Aragiorgis
    network_name = self.items[0]
701 ab9e48d1 Iustin Pop
    client = self.GetClient(query=True)
702 4588b4bd Dimitris Aragiorgis
703 4588b4bd Dimitris Aragiorgis
    result = baserlib.HandleItemQueryErrors(client.QueryNetworks,
704 4588b4bd Dimitris Aragiorgis
                                            names=[network_name],
705 4588b4bd Dimitris Aragiorgis
                                            fields=NET_FIELDS,
706 4588b4bd Dimitris Aragiorgis
                                            use_locking=self.useLocking())
707 4588b4bd Dimitris Aragiorgis
708 4588b4bd Dimitris Aragiorgis
    return baserlib.MapFields(NET_FIELDS, result[0])
709 4588b4bd Dimitris Aragiorgis
710 4588b4bd Dimitris Aragiorgis
  def GetDeleteOpInput(self):
711 4588b4bd Dimitris Aragiorgis
    """Delete a network.
712 4588b4bd Dimitris Aragiorgis

713 4588b4bd Dimitris Aragiorgis
    """
714 4588b4bd Dimitris Aragiorgis
    assert len(self.items) == 1
715 4588b4bd Dimitris Aragiorgis
    return (self.request_body, {
716 4588b4bd Dimitris Aragiorgis
      "network_name": self.items[0],
717 4588b4bd Dimitris Aragiorgis
      "dry_run": self.dryRun(),
718 4588b4bd Dimitris Aragiorgis
      })
719 4588b4bd Dimitris Aragiorgis
720 3c286190 Dimitris Aragiorgis
721 4588b4bd Dimitris Aragiorgis
class R_2_networks_name_connect(baserlib.OpcodeResource):
722 6e8091f9 Dimitris Aragiorgis
  """/2/networks/[network_name]/connect resource.
723 4588b4bd Dimitris Aragiorgis

724 4588b4bd Dimitris Aragiorgis
  """
725 4588b4bd Dimitris Aragiorgis
  PUT_OPCODE = opcodes.OpNetworkConnect
726 4588b4bd Dimitris Aragiorgis
727 4588b4bd Dimitris Aragiorgis
  def GetPutOpInput(self):
728 4588b4bd Dimitris Aragiorgis
    """Changes some parameters of node group.
729 4588b4bd Dimitris Aragiorgis

730 4588b4bd Dimitris Aragiorgis
    """
731 4588b4bd Dimitris Aragiorgis
    assert self.items
732 4588b4bd Dimitris Aragiorgis
    return (self.request_body, {
733 4588b4bd Dimitris Aragiorgis
      "network_name": self.items[0],
734 6e8091f9 Dimitris Aragiorgis
      "dry_run": self.dryRun(),
735 4588b4bd Dimitris Aragiorgis
      })
736 4588b4bd Dimitris Aragiorgis
737 3c286190 Dimitris Aragiorgis
738 4588b4bd Dimitris Aragiorgis
class R_2_networks_name_disconnect(baserlib.OpcodeResource):
739 6e8091f9 Dimitris Aragiorgis
  """/2/networks/[network_name]/disconnect resource.
740 4588b4bd Dimitris Aragiorgis

741 4588b4bd Dimitris Aragiorgis
  """
742 4588b4bd Dimitris Aragiorgis
  PUT_OPCODE = opcodes.OpNetworkDisconnect
743 4588b4bd Dimitris Aragiorgis
744 4588b4bd Dimitris Aragiorgis
  def GetPutOpInput(self):
745 4588b4bd Dimitris Aragiorgis
    """Changes some parameters of node group.
746 4588b4bd Dimitris Aragiorgis

747 4588b4bd Dimitris Aragiorgis
    """
748 4588b4bd Dimitris Aragiorgis
    assert self.items
749 4588b4bd Dimitris Aragiorgis
    return (self.request_body, {
750 4588b4bd Dimitris Aragiorgis
      "network_name": self.items[0],
751 6e8091f9 Dimitris Aragiorgis
      "dry_run": self.dryRun(),
752 6e8091f9 Dimitris Aragiorgis
      })
753 6e8091f9 Dimitris Aragiorgis
754 3c286190 Dimitris Aragiorgis
755 6e8091f9 Dimitris Aragiorgis
class R_2_networks_name_modify(baserlib.OpcodeResource):
756 6e8091f9 Dimitris Aragiorgis
  """/2/networks/[network_name]/modify resource.
757 6e8091f9 Dimitris Aragiorgis

758 6e8091f9 Dimitris Aragiorgis
  """
759 6e8091f9 Dimitris Aragiorgis
  PUT_OPCODE = opcodes.OpNetworkSetParams
760 6e8091f9 Dimitris Aragiorgis
761 6e8091f9 Dimitris Aragiorgis
  def GetPutOpInput(self):
762 6e8091f9 Dimitris Aragiorgis
    """Changes some parameters of network.
763 6e8091f9 Dimitris Aragiorgis

764 6e8091f9 Dimitris Aragiorgis
    """
765 6e8091f9 Dimitris Aragiorgis
    assert self.items
766 6e8091f9 Dimitris Aragiorgis
    return (self.request_body, {
767 6e8091f9 Dimitris Aragiorgis
      "network_name": self.items[0],
768 4588b4bd Dimitris Aragiorgis
      })
769 4588b4bd Dimitris Aragiorgis
770 6e8091f9 Dimitris Aragiorgis
771 c91407bc Michael Hanselmann
class R_2_groups(baserlib.OpcodeResource):
772 c91407bc Michael Hanselmann
  """/2/groups resource.
773 90e99856 Adeodato Simo

774 90e99856 Adeodato Simo
  """
775 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpGroupQuery
776 c91407bc Michael Hanselmann
  POST_OPCODE = opcodes.OpGroupAdd
777 c91407bc Michael Hanselmann
  POST_RENAME = {
778 527fbde8 Michael Hanselmann
    "name": "group_name",
779 527fbde8 Michael Hanselmann
    }
780 527fbde8 Michael Hanselmann
781 c91407bc Michael Hanselmann
  def GetPostOpInput(self):
782 c91407bc Michael Hanselmann
    """Create a node group.
783 90e99856 Adeodato Simo

784 4588b4bd Dimitris Aragiorgis

785 c91407bc Michael Hanselmann
    """
786 c91407bc Michael Hanselmann
    assert not self.items
787 c91407bc Michael Hanselmann
    return (self.request_body, {
788 c91407bc Michael Hanselmann
      "dry_run": self.dryRun(),
789 c91407bc Michael Hanselmann
      })
790 0897dc97 Adeodato Simo
791 0897dc97 Adeodato Simo
  def GET(self):
792 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
793 0897dc97 Adeodato Simo

794 0897dc97 Adeodato Simo
    """
795 9fbf0098 Iustin Pop
    client = self.GetClient(query=True)
796 0897dc97 Adeodato Simo
797 0897dc97 Adeodato Simo
    if self.useBulk():
798 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
799 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
800 0897dc97 Adeodato Simo
    else:
801 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
802 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
803 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
804 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
805 0897dc97 Adeodato Simo
806 0897dc97 Adeodato Simo
807 86f1f5d4 Michael Hanselmann
class R_2_groups_name(baserlib.OpcodeResource):
808 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name] resource.
809 0897dc97 Adeodato Simo

810 0897dc97 Adeodato Simo
  """
811 86f1f5d4 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpGroupRemove
812 86f1f5d4 Michael Hanselmann
813 0897dc97 Adeodato Simo
  def GET(self):
814 0897dc97 Adeodato Simo
    """Send information about a node group.
815 0897dc97 Adeodato Simo

816 0897dc97 Adeodato Simo
    """
817 0897dc97 Adeodato Simo
    group_name = self.items[0]
818 9fbf0098 Iustin Pop
    client = self.GetClient(query=True)
819 0897dc97 Adeodato Simo
820 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
821 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
822 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
823 0897dc97 Adeodato Simo
824 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
825 0897dc97 Adeodato Simo
826 86f1f5d4 Michael Hanselmann
  def GetDeleteOpInput(self):
827 0dbaa9ca Adeodato Simo
    """Delete a node group.
828 0dbaa9ca Adeodato Simo

829 0dbaa9ca Adeodato Simo
    """
830 86f1f5d4 Michael Hanselmann
    assert len(self.items) == 1
831 86f1f5d4 Michael Hanselmann
    return ({}, {
832 86f1f5d4 Michael Hanselmann
      "group_name": self.items[0],
833 86f1f5d4 Michael Hanselmann
      "dry_run": self.dryRun(),
834 86f1f5d4 Michael Hanselmann
      })
835 0dbaa9ca Adeodato Simo
836 0dbaa9ca Adeodato Simo
837 d5211458 Michael Hanselmann
class R_2_groups_name_modify(baserlib.OpcodeResource):
838 f18fab7d Adeodato Simo
  """/2/groups/[group_name]/modify resource.
839 f18fab7d Adeodato Simo

840 f18fab7d Adeodato Simo
  """
841 d5211458 Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupSetParams
842 f18fab7d Adeodato Simo
843 d5211458 Michael Hanselmann
  def GetPutOpInput(self):
844 d5211458 Michael Hanselmann
    """Changes some parameters of node group.
845 f18fab7d Adeodato Simo

846 f18fab7d Adeodato Simo
    """
847 d5211458 Michael Hanselmann
    assert self.items
848 d5211458 Michael Hanselmann
    return (self.request_body, {
849 d5211458 Michael Hanselmann
      "group_name": self.items[0],
850 d5211458 Michael Hanselmann
      })
851 f18fab7d Adeodato Simo
852 f18fab7d Adeodato Simo
853 cd0d4d5a Michael Hanselmann
class R_2_groups_name_rename(baserlib.OpcodeResource):
854 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/rename resource.
855 0dbaa9ca Adeodato Simo

856 0dbaa9ca Adeodato Simo
  """
857 cd0d4d5a Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupRename
858 0dbaa9ca Adeodato Simo
859 cd0d4d5a Michael Hanselmann
  def GetPutOpInput(self):
860 cd0d4d5a Michael Hanselmann
    """Changes the name of a node group.
861 0dbaa9ca Adeodato Simo

862 0dbaa9ca Adeodato Simo
    """
863 cd0d4d5a Michael Hanselmann
    assert len(self.items) == 1
864 cd0d4d5a Michael Hanselmann
    return (self.request_body, {
865 cd0d4d5a Michael Hanselmann
      "group_name": self.items[0],
866 cd0d4d5a Michael Hanselmann
      "dry_run": self.dryRun(),
867 cd0d4d5a Michael Hanselmann
      })
868 0897dc97 Adeodato Simo
869 0897dc97 Adeodato Simo
870 87fd3ec7 Michael Hanselmann
class R_2_groups_name_assign_nodes(baserlib.OpcodeResource):
871 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/assign-nodes resource.
872 4245446f Adeodato Simo

873 4245446f Adeodato Simo
  """
874 87fd3ec7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupAssignNodes
875 4245446f Adeodato Simo
876 87fd3ec7 Michael Hanselmann
  def GetPutOpInput(self):
877 87fd3ec7 Michael Hanselmann
    """Assigns nodes to a group.
878 4245446f Adeodato Simo

879 4245446f Adeodato Simo
    """
880 87fd3ec7 Michael Hanselmann
    assert len(self.items) == 1
881 87fd3ec7 Michael Hanselmann
    return (self.request_body, {
882 4245446f Adeodato Simo
      "group_name": self.items[0],
883 4245446f Adeodato Simo
      "dry_run": self.dryRun(),
884 4245446f Adeodato Simo
      "force": self.useForce(),
885 4245446f Adeodato Simo
      })
886 4245446f Adeodato Simo
887 4245446f Adeodato Simo
888 02a6b50a Michele Tartara
def _ConvertUsbDevices(data):
889 02a6b50a Michele Tartara
  """Convert in place the usb_devices string to the proper format.
890 02a6b50a Michele Tartara

891 02a6b50a Michele Tartara
  In Ganeti 2.8.4 the separator for the usb_devices hvparam was changed from
892 02a6b50a Michele Tartara
  comma to space because commas cannot be accepted on the command line
893 02a6b50a Michele Tartara
  (they already act as the separator between different hvparams). RAPI
894 02a6b50a Michele Tartara
  should be able to accept commas for backwards compatibility, but we want
895 02a6b50a Michele Tartara
  it to also accept the new space separator. Therefore, we convert
896 02a6b50a Michele Tartara
  spaces into commas here and keep the old parsing logic elsewhere.
897 02a6b50a Michele Tartara

898 02a6b50a Michele Tartara
  """
899 02a6b50a Michele Tartara
  try:
900 02a6b50a Michele Tartara
    hvparams = data["hvparams"]
901 02a6b50a Michele Tartara
    usb_devices = hvparams[constants.HV_USB_DEVICES]
902 02a6b50a Michele Tartara
    hvparams[constants.HV_USB_DEVICES] = usb_devices.replace(" ", ",")
903 02a6b50a Michele Tartara
    data["hvparams"] = hvparams
904 02a6b50a Michele Tartara
  except KeyError:
905 02a6b50a Michele Tartara
    #No usb_devices, no modification required
906 02a6b50a Michele Tartara
    pass
907 02a6b50a Michele Tartara
908 02a6b50a Michele Tartara
909 09a43b39 Michael Hanselmann
class R_2_instances(baserlib.OpcodeResource):
910 09a43b39 Michael Hanselmann
  """/2/instances resource.
911 6395cebb Michael Hanselmann

912 6395cebb Michael Hanselmann
  """
913 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQuery
914 09a43b39 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceCreate
915 09a43b39 Michael Hanselmann
  POST_RENAME = {
916 526a662a Michael Hanselmann
    "os": "os_type",
917 526a662a Michael Hanselmann
    "name": "instance_name",
918 526a662a Michael Hanselmann
    }
919 526a662a Michael Hanselmann
920 441e7cfd Oleksiy Mishchenko
  def GET(self):
921 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
922 441e7cfd Oleksiy Mishchenko

923 441e7cfd Oleksiy Mishchenko
    """
924 be1ddd09 Michael Hanselmann
    client = self.GetClient()
925 441e7cfd Oleksiy Mishchenko
926 3d103742 Iustin Pop
    use_locking = self.useLocking()
927 3d103742 Iustin Pop
    if self.useBulk():
928 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
929 28a45bfc René Nussbaumer
      return map(_UpdateBeparams, baserlib.MapBulkFields(bulkdata, I_FIELDS))
930 441e7cfd Oleksiy Mishchenko
    else:
931 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
932 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
933 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
934 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
935 441e7cfd Oleksiy Mishchenko
936 09a43b39 Michael Hanselmann
  def GetPostOpInput(self):
937 d975f482 Michael Hanselmann
    """Create an instance.
938 d975f482 Michael Hanselmann

939 d975f482 Michael Hanselmann
    @return: a job id
940 d975f482 Michael Hanselmann

941 d975f482 Michael Hanselmann
    """
942 09a43b39 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
943 d975f482 Michael Hanselmann
944 d975f482 Michael Hanselmann
    # Default to request data version 0
945 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
946 d975f482 Michael Hanselmann
947 d975f482 Michael Hanselmann
    if data_version == 0:
948 3fd7f652 Michael Hanselmann
      raise http.HttpBadRequest("Instance creation request version 0 is no"
949 3fd7f652 Michael Hanselmann
                                " longer supported")
950 09a43b39 Michael Hanselmann
    elif data_version != 1:
951 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
952 12eff9b9 Michael Hanselmann
                                data_version)
953 d975f482 Michael Hanselmann
954 09a43b39 Michael Hanselmann
    data = self.request_body.copy()
955 09a43b39 Michael Hanselmann
    # Remove "__version__"
956 09a43b39 Michael Hanselmann
    data.pop(_REQ_DATA_VERSION, None)
957 09a43b39 Michael Hanselmann
958 02a6b50a Michele Tartara
    _ConvertUsbDevices(data)
959 02a6b50a Michele Tartara
960 09a43b39 Michael Hanselmann
    return (data, {
961 09a43b39 Michael Hanselmann
      "dry_run": self.dryRun(),
962 09a43b39 Michael Hanselmann
      })
963 2f7635f4 Oleksiy Mishchenko
964 441e7cfd Oleksiy Mishchenko
965 4ee72287 René Nussbaumer
class R_2_instances_multi_alloc(baserlib.OpcodeResource):
966 4ee72287 René Nussbaumer
  """/2/instances-multi-alloc resource.
967 4ee72287 René Nussbaumer

968 4ee72287 René Nussbaumer
  """
969 4ee72287 René Nussbaumer
  POST_OPCODE = opcodes.OpInstanceMultiAlloc
970 4ee72287 René Nussbaumer
971 4ee72287 René Nussbaumer
  def GetPostOpInput(self):
972 4ee72287 René Nussbaumer
    """Try to allocate multiple instances.
973 4ee72287 René Nussbaumer

974 4ee72287 René Nussbaumer
    @return: A dict with submitted jobs, allocatable instances and failed
975 4ee72287 René Nussbaumer
             allocations
976 4ee72287 René Nussbaumer

977 4ee72287 René Nussbaumer
    """
978 e5ff1a47 René Nussbaumer
    if "instances" not in self.request_body:
979 e5ff1a47 René Nussbaumer
      raise http.HttpBadRequest("Request is missing required 'instances' field"
980 e5ff1a47 René Nussbaumer
                                " in body")
981 e5ff1a47 René Nussbaumer
982 e5ff1a47 René Nussbaumer
    op_id = {
983 e5ff1a47 René Nussbaumer
      "OP_ID": self.POST_OPCODE.OP_ID, # pylint: disable=E1101
984 e5ff1a47 René Nussbaumer
      }
985 e5ff1a47 René Nussbaumer
    body = objects.FillDict(self.request_body, {
986 e5ff1a47 René Nussbaumer
      "instances": [objects.FillDict(inst, op_id)
987 e5ff1a47 René Nussbaumer
                    for inst in self.request_body["instances"]],
988 e5ff1a47 René Nussbaumer
      })
989 e5ff1a47 René Nussbaumer
990 e5ff1a47 René Nussbaumer
    return (body, {
991 4ee72287 René Nussbaumer
      "dry_run": self.dryRun(),
992 4ee72287 René Nussbaumer
      })
993 4ee72287 René Nussbaumer
994 4ee72287 René Nussbaumer
995 a6fa7892 Michael Hanselmann
class R_2_instances_name(baserlib.OpcodeResource):
996 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name] resource.
997 028c6b76 Oleksiy Mishchenko

998 028c6b76 Oleksiy Mishchenko
  """
999 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQuery
1000 a6fa7892 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpInstanceRemove
1001 a6fa7892 Michael Hanselmann
1002 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
1003 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
1004 4e5a68f8 Oleksiy Mishchenko

1005 4e5a68f8 Oleksiy Mishchenko
    """
1006 be1ddd09 Michael Hanselmann
    client = self.GetClient()
1007 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
1008 e8ebbd2b Michael Hanselmann
1009 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
1010 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
1011 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
1012 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
1013 4e5a68f8 Oleksiy Mishchenko
1014 28a45bfc René Nussbaumer
    return _UpdateBeparams(baserlib.MapFields(I_FIELDS, result[0]))
1015 028c6b76 Oleksiy Mishchenko
1016 a6fa7892 Michael Hanselmann
  def GetDeleteOpInput(self):
1017 6e99c5a0 Iustin Pop
    """Delete an instance.
1018 6e99c5a0 Iustin Pop

1019 6e99c5a0 Iustin Pop
    """
1020 a6fa7892 Michael Hanselmann
    assert len(self.items) == 1
1021 a6fa7892 Michael Hanselmann
    return ({}, {
1022 a6fa7892 Michael Hanselmann
      "instance_name": self.items[0],
1023 a6fa7892 Michael Hanselmann
      "ignore_failures": False,
1024 a6fa7892 Michael Hanselmann
      "dry_run": self.dryRun(),
1025 a6fa7892 Michael Hanselmann
      })
1026 6e99c5a0 Iustin Pop
1027 028c6b76 Oleksiy Mishchenko
1028 7b3df961 Michael Hanselmann
class R_2_instances_name_info(baserlib.OpcodeResource):
1029 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
1030 d8260842 Michael Hanselmann

1031 d8260842 Michael Hanselmann
  """
1032 7b3df961 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQueryData
1033 7b3df961 Michael Hanselmann
1034 7b3df961 Michael Hanselmann
  def GetGetOpInput(self):
1035 d8260842 Michael Hanselmann
    """Request detailed instance information.
1036 d8260842 Michael Hanselmann

1037 d8260842 Michael Hanselmann
    """
1038 7b3df961 Michael Hanselmann
    assert len(self.items) == 1
1039 7b3df961 Michael Hanselmann
    return ({}, {
1040 7b3df961 Michael Hanselmann
      "instances": [self.items[0]],
1041 7b3df961 Michael Hanselmann
      "static": bool(self._checkIntVariable("static", default=0)),
1042 7b3df961 Michael Hanselmann
      })
1043 d8260842 Michael Hanselmann
1044 d8260842 Michael Hanselmann
1045 ac4888c1 Michael Hanselmann
class R_2_instances_name_reboot(baserlib.OpcodeResource):
1046 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
1047 2276aa29 Oleksiy Mishchenko

1048 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
1049 2276aa29 Oleksiy Mishchenko

1050 2276aa29 Oleksiy Mishchenko
  """
1051 ac4888c1 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReboot
1052 ac4888c1 Michael Hanselmann
1053 ac4888c1 Michael Hanselmann
  def GetPostOpInput(self):
1054 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
1055 2276aa29 Oleksiy Mishchenko

1056 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
1057 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
1058 0c55c24b Oleksiy Mishchenko

1059 2276aa29 Oleksiy Mishchenko
    """
1060 ac4888c1 Michael Hanselmann
    return ({}, {
1061 ac4888c1 Michael Hanselmann
      "instance_name": self.items[0],
1062 ac4888c1 Michael Hanselmann
      "reboot_type":
1063 ac4888c1 Michael Hanselmann
        self.queryargs.get("type", [constants.INSTANCE_REBOOT_HARD])[0],
1064 ac4888c1 Michael Hanselmann
      "ignore_secondaries": bool(self._checkIntVariable("ignore_secondaries")),
1065 ac4888c1 Michael Hanselmann
      "dry_run": self.dryRun(),
1066 ac4888c1 Michael Hanselmann
      })
1067 2276aa29 Oleksiy Mishchenko
1068 2276aa29 Oleksiy Mishchenko
1069 4717e6eb Michael Hanselmann
class R_2_instances_name_startup(baserlib.OpcodeResource):
1070 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
1071 0c55c24b Oleksiy Mishchenko

1072 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
1073 0c55c24b Oleksiy Mishchenko

1074 0c55c24b Oleksiy Mishchenko
  """
1075 4717e6eb Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceStartup
1076 4717e6eb Michael Hanselmann
1077 4717e6eb Michael Hanselmann
  def GetPutOpInput(self):
1078 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
1079 0c55c24b Oleksiy Mishchenko

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

1083 0c55c24b Oleksiy Mishchenko
    """
1084 4717e6eb Michael Hanselmann
    return ({}, {
1085 4717e6eb Michael Hanselmann
      "instance_name": self.items[0],
1086 4717e6eb Michael Hanselmann
      "force": self.useForce(),
1087 4717e6eb Michael Hanselmann
      "dry_run": self.dryRun(),
1088 4717e6eb Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
1089 4717e6eb Michael Hanselmann
      })
1090 0c55c24b Oleksiy Mishchenko
1091 0c55c24b Oleksiy Mishchenko
1092 3175ade6 Michael Hanselmann
class R_2_instances_name_shutdown(baserlib.OpcodeResource):
1093 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
1094 0c55c24b Oleksiy Mishchenko

1095 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
1096 0c55c24b Oleksiy Mishchenko

1097 0c55c24b Oleksiy Mishchenko
  """
1098 3175ade6 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceShutdown
1099 0c55c24b Oleksiy Mishchenko
1100 3175ade6 Michael Hanselmann
  def GetPutOpInput(self):
1101 3175ade6 Michael Hanselmann
    """Shutdown an instance.
1102 7fa310f6 René Nussbaumer

1103 0c55c24b Oleksiy Mishchenko
    """
1104 3175ade6 Michael Hanselmann
    return (self.request_body, {
1105 3175ade6 Michael Hanselmann
      "instance_name": self.items[0],
1106 3175ade6 Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
1107 3175ade6 Michael Hanselmann
      "dry_run": self.dryRun(),
1108 3175ade6 Michael Hanselmann
      })
1109 0c55c24b Oleksiy Mishchenko
1110 0c55c24b Oleksiy Mishchenko
1111 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
1112 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
1113 c744425f Michael Hanselmann

1114 c744425f Michael Hanselmann
  """
1115 c744425f Michael Hanselmann
  if not isinstance(data, dict):
1116 c744425f Michael Hanselmann
    raise http.HttpBadRequest("Invalid body contents, not a dictionary")
1117 c744425f Michael Hanselmann
1118 bd0807fe Guido Trotter
  ostype = baserlib.CheckParameter(data, "os", default=None)
1119 c744425f Michael Hanselmann
  start = baserlib.CheckParameter(data, "start", exptype=bool,
1120 c744425f Michael Hanselmann
                                  default=True)
1121 c744425f Michael Hanselmann
  osparams = baserlib.CheckParameter(data, "osparams", default=None)
1122 c744425f Michael Hanselmann
1123 c744425f Michael Hanselmann
  ops = [
1124 ee3e37a7 Iustin Pop
    opcodes.OpInstanceShutdown(instance_name=name),
1125 5073fd8f Iustin Pop
    opcodes.OpInstanceReinstall(instance_name=name, os_type=ostype,
1126 c744425f Michael Hanselmann
                                osparams=osparams),
1127 c744425f Michael Hanselmann
    ]
1128 c744425f Michael Hanselmann
1129 c744425f Michael Hanselmann
  if start:
1130 c873d91c Iustin Pop
    ops.append(opcodes.OpInstanceStartup(instance_name=name, force=False))
1131 c744425f Michael Hanselmann
1132 c744425f Michael Hanselmann
  return ops
1133 c744425f Michael Hanselmann
1134 c744425f Michael Hanselmann
1135 f6ce0ba2 Michael Hanselmann
class R_2_instances_name_reinstall(baserlib.OpcodeResource):
1136 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
1137 e5b7c4ca Iustin Pop

1138 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
1139 e5b7c4ca Iustin Pop

1140 e5b7c4ca Iustin Pop
  """
1141 f6ce0ba2 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReinstall
1142 f6ce0ba2 Michael Hanselmann
1143 e5b7c4ca Iustin Pop
  def POST(self):
1144 e5b7c4ca Iustin Pop
    """Reinstall an instance.
1145 e5b7c4ca Iustin Pop

1146 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
1147 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
1148 e5b7c4ca Iustin Pop
    automatically.
1149 e5b7c4ca Iustin Pop

1150 e5b7c4ca Iustin Pop
    """
1151 c744425f Michael Hanselmann
    if self.request_body:
1152 c744425f Michael Hanselmann
      if self.queryargs:
1153 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
1154 c744425f Michael Hanselmann
1155 c744425f Michael Hanselmann
      body = self.request_body
1156 bd0807fe Guido Trotter
    elif self.queryargs:
1157 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
1158 c744425f Michael Hanselmann
      body = {
1159 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
1160 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
1161 c744425f Michael Hanselmann
        }
1162 bd0807fe Guido Trotter
    else:
1163 bd0807fe Guido Trotter
      body = {}
1164 c744425f Michael Hanselmann
1165 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
1166 c744425f Michael Hanselmann
1167 be1ddd09 Michael Hanselmann
    return self.SubmitJob(ops)
1168 e5b7c4ca Iustin Pop
1169 e5b7c4ca Iustin Pop
1170 0dbc732c Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.OpcodeResource):
1171 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
1172 4c98b915 Michael Hanselmann

1173 4c98b915 Michael Hanselmann
  """
1174 0dbc732c Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReplaceDisks
1175 0dbc732c Michael Hanselmann
1176 0dbc732c Michael Hanselmann
  def GetPostOpInput(self):
1177 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1178 4c98b915 Michael Hanselmann

1179 4c98b915 Michael Hanselmann
    """
1180 0dbc732c Michael Hanselmann
    static = {
1181 0dbc732c Michael Hanselmann
      "instance_name": self.items[0],
1182 0dbc732c Michael Hanselmann
      }
1183 4c98b915 Michael Hanselmann
1184 539d65ba Michael Hanselmann
    if self.request_body:
1185 7dcf333d Michael Hanselmann
      data = self.request_body
1186 539d65ba Michael Hanselmann
    elif self.queryargs:
1187 539d65ba Michael Hanselmann
      # Legacy interface, do not modify/extend
1188 7dcf333d Michael Hanselmann
      data = {
1189 539d65ba Michael Hanselmann
        "remote_node": self._checkStringVariable("remote_node", default=None),
1190 539d65ba Michael Hanselmann
        "mode": self._checkStringVariable("mode", default=None),
1191 539d65ba Michael Hanselmann
        "disks": self._checkStringVariable("disks", default=None),
1192 539d65ba Michael Hanselmann
        "iallocator": self._checkStringVariable("iallocator", default=None),
1193 539d65ba Michael Hanselmann
        }
1194 539d65ba Michael Hanselmann
    else:
1195 7dcf333d Michael Hanselmann
      data = {}
1196 539d65ba Michael Hanselmann
1197 0dbc732c Michael Hanselmann
    # Parse disks
1198 0dbc732c Michael Hanselmann
    try:
1199 7dcf333d Michael Hanselmann
      raw_disks = data.pop("disks")
1200 0dbc732c Michael Hanselmann
    except KeyError:
1201 0dbc732c Michael Hanselmann
      pass
1202 0dbc732c Michael Hanselmann
    else:
1203 7dcf333d Michael Hanselmann
      if raw_disks:
1204 7dcf333d Michael Hanselmann
        if ht.TListOf(ht.TInt)(raw_disks): # pylint: disable=E1102
1205 7dcf333d Michael Hanselmann
          data["disks"] = raw_disks
1206 7dcf333d Michael Hanselmann
        else:
1207 7dcf333d Michael Hanselmann
          # Backwards compatibility for strings of the format "1, 2, 3"
1208 7dcf333d Michael Hanselmann
          try:
1209 7dcf333d Michael Hanselmann
            data["disks"] = [int(part) for part in raw_disks.split(",")]
1210 7dcf333d Michael Hanselmann
          except (TypeError, ValueError), err:
1211 7dcf333d Michael Hanselmann
            raise http.HttpBadRequest("Invalid disk index passed: %s" % err)
1212 0dbc732c Michael Hanselmann
1213 0dbc732c Michael Hanselmann
    return (data, static)
1214 4c98b915 Michael Hanselmann
1215 4c98b915 Michael Hanselmann
1216 1824a7a1 Michael Hanselmann
class R_2_instances_name_activate_disks(baserlib.OpcodeResource):
1217 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1218 2197b66f René Nussbaumer

1219 2197b66f René Nussbaumer
  """
1220 1824a7a1 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceActivateDisks
1221 1824a7a1 Michael Hanselmann
1222 1824a7a1 Michael Hanselmann
  def GetPutOpInput(self):
1223 2197b66f René Nussbaumer
    """Activate disks for an instance.
1224 2197b66f René Nussbaumer

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

1227 2197b66f René Nussbaumer
    """
1228 1824a7a1 Michael Hanselmann
    return ({}, {
1229 1824a7a1 Michael Hanselmann
      "instance_name": self.items[0],
1230 1824a7a1 Michael Hanselmann
      "ignore_size": bool(self._checkIntVariable("ignore_size")),
1231 1824a7a1 Michael Hanselmann
      })
1232 2197b66f René Nussbaumer
1233 2197b66f René Nussbaumer
1234 973ec124 Michael Hanselmann
class R_2_instances_name_deactivate_disks(baserlib.OpcodeResource):
1235 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1236 0a37de5f René Nussbaumer

1237 0a37de5f René Nussbaumer
  """
1238 973ec124 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceDeactivateDisks
1239 973ec124 Michael Hanselmann
1240 973ec124 Michael Hanselmann
  def GetPutOpInput(self):
1241 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1242 0a37de5f René Nussbaumer

1243 0a37de5f René Nussbaumer
    """
1244 973ec124 Michael Hanselmann
    return ({}, {
1245 973ec124 Michael Hanselmann
      "instance_name": self.items[0],
1246 973ec124 Michael Hanselmann
      })
1247 0a37de5f René Nussbaumer
1248 0a37de5f René Nussbaumer
1249 a52978c7 Michael Hanselmann
class R_2_instances_name_recreate_disks(baserlib.OpcodeResource):
1250 a52978c7 Michael Hanselmann
  """/2/instances/[instance_name]/recreate-disks resource.
1251 a52978c7 Michael Hanselmann

1252 a52978c7 Michael Hanselmann
  """
1253 a52978c7 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceRecreateDisks
1254 a52978c7 Michael Hanselmann
1255 a52978c7 Michael Hanselmann
  def GetPostOpInput(self):
1256 a52978c7 Michael Hanselmann
    """Recreate disks for an instance.
1257 a52978c7 Michael Hanselmann

1258 a52978c7 Michael Hanselmann
    """
1259 a52978c7 Michael Hanselmann
    return ({}, {
1260 a52978c7 Michael Hanselmann
      "instance_name": self.items[0],
1261 a52978c7 Michael Hanselmann
      })
1262 a52978c7 Michael Hanselmann
1263 a52978c7 Michael Hanselmann
1264 1c63311d Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.OpcodeResource):
1265 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1266 ebeb600f Michael Hanselmann

1267 ebeb600f Michael Hanselmann
  """
1268 1c63311d Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupPrepare
1269 ebeb600f Michael Hanselmann
1270 1c63311d Michael Hanselmann
  def GetPutOpInput(self):
1271 1c63311d Michael Hanselmann
    """Prepares an export for an instance.
1272 ebeb600f Michael Hanselmann

1273 ebeb600f Michael Hanselmann
    """
1274 1c63311d Michael Hanselmann
    return ({}, {
1275 1c63311d Michael Hanselmann
      "instance_name": self.items[0],
1276 1c63311d Michael Hanselmann
      "mode": self._checkStringVariable("mode"),
1277 1c63311d Michael Hanselmann
      })
1278 ebeb600f Michael Hanselmann
1279 ebeb600f Michael Hanselmann
1280 134afbe7 Michael Hanselmann
class R_2_instances_name_export(baserlib.OpcodeResource):
1281 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1282 ebeb600f Michael Hanselmann

1283 ebeb600f Michael Hanselmann
  """
1284 134afbe7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupExport
1285 134afbe7 Michael Hanselmann
  PUT_RENAME = {
1286 134afbe7 Michael Hanselmann
    "destination": "target_node",
1287 134afbe7 Michael Hanselmann
    }
1288 ebeb600f Michael Hanselmann
1289 134afbe7 Michael Hanselmann
  def GetPutOpInput(self):
1290 134afbe7 Michael Hanselmann
    """Exports an instance.
1291 ebeb600f Michael Hanselmann

1292 ebeb600f Michael Hanselmann
    """
1293 134afbe7 Michael Hanselmann
    return (self.request_body, {
1294 134afbe7 Michael Hanselmann
      "instance_name": self.items[0],
1295 134afbe7 Michael Hanselmann
      })
1296 ebeb600f Michael Hanselmann
1297 ebeb600f Michael Hanselmann
1298 075a29be Michael Hanselmann
class R_2_instances_name_migrate(baserlib.OpcodeResource):
1299 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1300 5823e0d2 Michael Hanselmann

1301 5823e0d2 Michael Hanselmann
  """
1302 075a29be Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceMigrate
1303 5823e0d2 Michael Hanselmann
1304 075a29be Michael Hanselmann
  def GetPutOpInput(self):
1305 075a29be Michael Hanselmann
    """Migrates an instance.
1306 5823e0d2 Michael Hanselmann

1307 5823e0d2 Michael Hanselmann
    """
1308 075a29be Michael Hanselmann
    return (self.request_body, {
1309 075a29be Michael Hanselmann
      "instance_name": self.items[0],
1310 075a29be Michael Hanselmann
      })
1311 5823e0d2 Michael Hanselmann
1312 5823e0d2 Michael Hanselmann
1313 b5f2ab80 Michael Hanselmann
class R_2_instances_name_failover(baserlib.OpcodeResource):
1314 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1315 c0a146a1 Michael Hanselmann

1316 c0a146a1 Michael Hanselmann
  """
1317 b5f2ab80 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceFailover
1318 c0a146a1 Michael Hanselmann
1319 b5f2ab80 Michael Hanselmann
  def GetPutOpInput(self):
1320 b5f2ab80 Michael Hanselmann
    """Does a failover of an instance.
1321 c0a146a1 Michael Hanselmann

1322 c0a146a1 Michael Hanselmann
    """
1323 b5f2ab80 Michael Hanselmann
    return (self.request_body, {
1324 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1325 c0a146a1 Michael Hanselmann
      })
1326 c0a146a1 Michael Hanselmann
1327 c0a146a1 Michael Hanselmann
1328 d76f9b5d Michael Hanselmann
class R_2_instances_name_rename(baserlib.OpcodeResource):
1329 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1330 d56e7dc7 Michael Hanselmann

1331 d56e7dc7 Michael Hanselmann
  """
1332 d76f9b5d Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceRename
1333 d56e7dc7 Michael Hanselmann
1334 d76f9b5d Michael Hanselmann
  def GetPutOpInput(self):
1335 d76f9b5d Michael Hanselmann
    """Changes the name of an instance.
1336 d56e7dc7 Michael Hanselmann

1337 d56e7dc7 Michael Hanselmann
    """
1338 d76f9b5d Michael Hanselmann
    return (self.request_body, {
1339 d76f9b5d Michael Hanselmann
      "instance_name": self.items[0],
1340 d76f9b5d Michael Hanselmann
      })
1341 d56e7dc7 Michael Hanselmann
1342 d56e7dc7 Michael Hanselmann
1343 f3db88ba Michael Hanselmann
class R_2_instances_name_modify(baserlib.OpcodeResource):
1344 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1345 3882937a Michael Hanselmann

1346 3882937a Michael Hanselmann
  """
1347 f3db88ba Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceSetParams
1348 3882937a Michael Hanselmann
1349 f3db88ba Michael Hanselmann
  def GetPutOpInput(self):
1350 f3db88ba Michael Hanselmann
    """Changes parameters of an instance.
1351 3882937a Michael Hanselmann

1352 3882937a Michael Hanselmann
    """
1353 02a6b50a Michele Tartara
    data = self.request_body.copy()
1354 02a6b50a Michele Tartara
    _ConvertUsbDevices(data)
1355 02a6b50a Michele Tartara
1356 02a6b50a Michele Tartara
    return (data, {
1357 f3db88ba Michael Hanselmann
      "instance_name": self.items[0],
1358 f3db88ba Michael Hanselmann
      })
1359 3882937a Michael Hanselmann
1360 3882937a Michael Hanselmann
1361 335965b9 Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.OpcodeResource):
1362 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1363 e23881ed Michael Hanselmann

1364 e23881ed Michael Hanselmann
  """
1365 335965b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceGrowDisk
1366 e23881ed Michael Hanselmann
1367 335965b9 Michael Hanselmann
  def GetPostOpInput(self):
1368 335965b9 Michael Hanselmann
    """Increases the size of an instance disk.
1369 e23881ed Michael Hanselmann

1370 e23881ed Michael Hanselmann
    """
1371 335965b9 Michael Hanselmann
    return (self.request_body, {
1372 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1373 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1374 e23881ed Michael Hanselmann
      })
1375 e23881ed Michael Hanselmann
1376 e23881ed Michael Hanselmann
1377 26ff6ee2 Michael Hanselmann
class R_2_instances_name_console(baserlib.ResourceBase):
1378 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1379 b82d4c5e Michael Hanselmann

1380 b82d4c5e Michael Hanselmann
  """
1381 5e12acfe Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE, rapi.RAPI_ACCESS_READ]
1382 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceConsole
1383 b82d4c5e Michael Hanselmann
1384 b82d4c5e Michael Hanselmann
  def GET(self):
1385 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1386 b82d4c5e Michael Hanselmann

1387 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1388 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1389 b82d4c5e Michael Hanselmann

1390 b82d4c5e Michael Hanselmann
    """
1391 be1ddd09 Michael Hanselmann
    client = self.GetClient()
1392 b82d4c5e Michael Hanselmann
1393 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1394 b82d4c5e Michael Hanselmann
1395 b82d4c5e Michael Hanselmann
    if console is None:
1396 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1397 b82d4c5e Michael Hanselmann
1398 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1399 b82d4c5e Michael Hanselmann
    return console
1400 b82d4c5e Michael Hanselmann
1401 b82d4c5e Michael Hanselmann
1402 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1403 2a38e913 Michael Hanselmann
  """Tries to extract C{fields} query parameter.
1404 2a38e913 Michael Hanselmann

1405 2a38e913 Michael Hanselmann
  @type args: dictionary
1406 2a38e913 Michael Hanselmann
  @rtype: list of string
1407 2a38e913 Michael Hanselmann
  @raise http.HttpBadRequest: When parameter can't be found
1408 208a6cff Michael Hanselmann

1409 208a6cff Michael Hanselmann
  """
1410 208a6cff Michael Hanselmann
  try:
1411 208a6cff Michael Hanselmann
    fields = args["fields"]
1412 208a6cff Michael Hanselmann
  except KeyError:
1413 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1414 208a6cff Michael Hanselmann
1415 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1416 208a6cff Michael Hanselmann
1417 208a6cff Michael Hanselmann
1418 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1419 2a38e913 Michael Hanselmann
  """Splits fields as given for a query request.
1420 2a38e913 Michael Hanselmann

1421 2a38e913 Michael Hanselmann
  @type fields: string
1422 2a38e913 Michael Hanselmann
  @rtype: list of string
1423 208a6cff Michael Hanselmann

1424 208a6cff Michael Hanselmann
  """
1425 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1426 208a6cff Michael Hanselmann
1427 208a6cff Michael Hanselmann
1428 26ff6ee2 Michael Hanselmann
class R_2_query(baserlib.ResourceBase):
1429 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1430 208a6cff Michael Hanselmann

1431 208a6cff Michael Hanselmann
  """
1432 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1433 5e12acfe Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE, rapi.RAPI_ACCESS_READ]
1434 5e12acfe Michael Hanselmann
  PUT_ACCESS = GET_ACCESS
1435 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpQuery
1436 f6ce0ba2 Michael Hanselmann
  PUT_OPCODE = opcodes.OpQuery
1437 208a6cff Michael Hanselmann
1438 2e5c33db Iustin Pop
  def _Query(self, fields, qfilter):
1439 2e5c33db Iustin Pop
    return self.GetClient().Query(self.items[0], fields, qfilter).ToDict()
1440 208a6cff Michael Hanselmann
1441 208a6cff Michael Hanselmann
  def GET(self):
1442 208a6cff Michael Hanselmann
    """Returns resource information.
1443 208a6cff Michael Hanselmann

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

1446 208a6cff Michael Hanselmann
    """
1447 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1448 208a6cff Michael Hanselmann
1449 208a6cff Michael Hanselmann
  def PUT(self):
1450 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1451 208a6cff Michael Hanselmann

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

1454 208a6cff Michael Hanselmann
    """
1455 208a6cff Michael Hanselmann
    body = self.request_body
1456 208a6cff Michael Hanselmann
1457 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1458 208a6cff Michael Hanselmann
1459 208a6cff Michael Hanselmann
    try:
1460 208a6cff Michael Hanselmann
      fields = body["fields"]
1461 208a6cff Michael Hanselmann
    except KeyError:
1462 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1463 208a6cff Michael Hanselmann
1464 2e5c33db Iustin Pop
    qfilter = body.get("qfilter", None)
1465 2e5c33db Iustin Pop
    # TODO: remove this after 2.7
1466 2e5c33db Iustin Pop
    if qfilter is None:
1467 2e5c33db Iustin Pop
      qfilter = body.get("filter", None)
1468 2e5c33db Iustin Pop
1469 2e5c33db Iustin Pop
    return self._Query(fields, qfilter)
1470 208a6cff Michael Hanselmann
1471 208a6cff Michael Hanselmann
1472 26ff6ee2 Michael Hanselmann
class R_2_query_fields(baserlib.ResourceBase):
1473 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1474 208a6cff Michael Hanselmann

1475 208a6cff Michael Hanselmann
  """
1476 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpQueryFields
1477 f6ce0ba2 Michael Hanselmann
1478 208a6cff Michael Hanselmann
  def GET(self):
1479 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1480 208a6cff Michael Hanselmann

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

1483 208a6cff Michael Hanselmann
    """
1484 208a6cff Michael Hanselmann
    try:
1485 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1486 208a6cff Michael Hanselmann
    except KeyError:
1487 208a6cff Michael Hanselmann
      fields = None
1488 208a6cff Michael Hanselmann
    else:
1489 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1490 208a6cff Michael Hanselmann
1491 be1ddd09 Michael Hanselmann
    return self.GetClient().QueryFields(self.items[0], fields).ToDict()
1492 208a6cff Michael Hanselmann
1493 208a6cff Michael Hanselmann
1494 460ef073 Michael Hanselmann
class _R_Tags(baserlib.OpcodeResource):
1495 3bd0f3d8 Iustin Pop
  """Quasiclass for tagging resources.
1496 441e7cfd Oleksiy Mishchenko

1497 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1498 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1499 441e7cfd Oleksiy Mishchenko

1500 441e7cfd Oleksiy Mishchenko
  """
1501 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1502 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpTagsGet
1503 460ef073 Michael Hanselmann
  PUT_OPCODE = opcodes.OpTagsSet
1504 460ef073 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpTagsDel
1505 18cb43a2 Oleksiy Mishchenko
1506 460ef073 Michael Hanselmann
  def __init__(self, items, queryargs, req, **kwargs):
1507 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1508 18cb43a2 Oleksiy Mishchenko

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

1511 18cb43a2 Oleksiy Mishchenko
    """
1512 460ef073 Michael Hanselmann
    baserlib.OpcodeResource.__init__(self, items, queryargs, req, **kwargs)
1513 18cb43a2 Oleksiy Mishchenko
1514 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1515 5313eed7 Michael Hanselmann
      self.name = None
1516 18cb43a2 Oleksiy Mishchenko
    else:
1517 5313eed7 Michael Hanselmann
      self.name = items[0]
1518 441e7cfd Oleksiy Mishchenko
1519 441e7cfd Oleksiy Mishchenko
  def GET(self):
1520 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1521 441e7cfd Oleksiy Mishchenko

1522 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1523 441e7cfd Oleksiy Mishchenko

1524 441e7cfd Oleksiy Mishchenko
    """
1525 f87ec53f Michael Hanselmann
    kind = self.TAG_LEVEL
1526 f87ec53f Michael Hanselmann
1527 f87ec53f Michael Hanselmann
    if kind in (constants.TAG_INSTANCE,
1528 f87ec53f Michael Hanselmann
                constants.TAG_NODEGROUP,
1529 92ea7d79 Hrvoje Ribicic
                constants.TAG_NODE,
1530 92ea7d79 Hrvoje Ribicic
                constants.TAG_NETWORK):
1531 f87ec53f Michael Hanselmann
      if not self.name:
1532 f87ec53f Michael Hanselmann
        raise http.HttpBadRequest("Missing name on tag request")
1533 f87ec53f Michael Hanselmann
1534 f2374060 Iustin Pop
      cl = self.GetClient(query=True)
1535 cebd85d8 Iustin Pop
      tags = list(cl.QueryTags(kind, self.name))
1536 f87ec53f Michael Hanselmann
1537 f87ec53f Michael Hanselmann
    elif kind == constants.TAG_CLUSTER:
1538 f87ec53f Michael Hanselmann
      assert not self.name
1539 f87ec53f Michael Hanselmann
      # TODO: Use query API?
1540 f87ec53f Michael Hanselmann
      ssc = ssconf.SimpleStore()
1541 f87ec53f Michael Hanselmann
      tags = ssc.GetClusterTags()
1542 f87ec53f Michael Hanselmann
1543 92ea7d79 Hrvoje Ribicic
    else:
1544 92ea7d79 Hrvoje Ribicic
      raise http.HttpBadRequest("Unhandled tag type!")
1545 92ea7d79 Hrvoje Ribicic
1546 f87ec53f Michael Hanselmann
    return list(tags)
1547 441e7cfd Oleksiy Mishchenko
1548 460ef073 Michael Hanselmann
  def GetPutOpInput(self):
1549 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1550 441e7cfd Oleksiy Mishchenko

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

1554 441e7cfd Oleksiy Mishchenko
    """
1555 460ef073 Michael Hanselmann
    return ({}, {
1556 460ef073 Michael Hanselmann
      "kind": self.TAG_LEVEL,
1557 460ef073 Michael Hanselmann
      "name": self.name,
1558 460ef073 Michael Hanselmann
      "tags": self.queryargs.get("tag", []),
1559 460ef073 Michael Hanselmann
      "dry_run": self.dryRun(),
1560 460ef073 Michael Hanselmann
      })
1561 15fd9fd5 Oleksiy Mishchenko
1562 460ef073 Michael Hanselmann
  def GetDeleteOpInput(self):
1563 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1564 15fd9fd5 Oleksiy Mishchenko

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

1569 15fd9fd5 Oleksiy Mishchenko
    """
1570 460ef073 Michael Hanselmann
    # Re-use code
1571 460ef073 Michael Hanselmann
    return self.GetPutOpInput()
1572 18cb43a2 Oleksiy Mishchenko
1573 18cb43a2 Oleksiy Mishchenko
1574 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1575 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1576 18cb43a2 Oleksiy Mishchenko

1577 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1578 18cb43a2 Oleksiy Mishchenko

1579 18cb43a2 Oleksiy Mishchenko
  """
1580 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1581 18cb43a2 Oleksiy Mishchenko
1582 18cb43a2 Oleksiy Mishchenko
1583 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1584 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1585 18cb43a2 Oleksiy Mishchenko

1586 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1587 18cb43a2 Oleksiy Mishchenko

1588 18cb43a2 Oleksiy Mishchenko
  """
1589 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1590 18cb43a2 Oleksiy Mishchenko
1591 18cb43a2 Oleksiy Mishchenko
1592 414ebaf1 Michael Hanselmann
class R_2_groups_name_tags(_R_Tags):
1593 414ebaf1 Michael Hanselmann
  """ /2/groups/[group_name]/tags resource.
1594 414ebaf1 Michael Hanselmann

1595 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1596 414ebaf1 Michael Hanselmann

1597 414ebaf1 Michael Hanselmann
  """
1598 414ebaf1 Michael Hanselmann
  TAG_LEVEL = constants.TAG_NODEGROUP
1599 414ebaf1 Michael Hanselmann
1600 3c286190 Dimitris Aragiorgis
1601 6e8091f9 Dimitris Aragiorgis
class R_2_networks_name_tags(_R_Tags):
1602 6e8091f9 Dimitris Aragiorgis
  """ /2/networks/[network_name]/tags resource.
1603 6e8091f9 Dimitris Aragiorgis

1604 6e8091f9 Dimitris Aragiorgis
  Manages per-network tags.
1605 6e8091f9 Dimitris Aragiorgis

1606 6e8091f9 Dimitris Aragiorgis
  """
1607 6e8091f9 Dimitris Aragiorgis
  TAG_LEVEL = constants.TAG_NETWORK
1608 6e8091f9 Dimitris Aragiorgis
1609 414ebaf1 Michael Hanselmann
1610 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1611 b58a4d16 Michael Hanselmann
  """ /2/tags resource.
1612 18cb43a2 Oleksiy Mishchenko

1613 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1614 18cb43a2 Oleksiy Mishchenko

1615 18cb43a2 Oleksiy Mishchenko
  """
1616 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER