Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 31d3b918

History | View | Annotate | Download (39.8 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 17cda747 Guido Trotter
            "disk.sizes", "disk.spindles", "disk_usage", "disk.uuids",
78 17cda747 Guido Trotter
            "disk.names",
79 a5b9d725 Iustin Pop
            "beparams", "hvparams",
80 4ea3de4e Balazs Lecz
            "oper_state", "oper_ram", "oper_vcpus", "status",
81 90224407 Iustin Pop
            "custom_hvparams", "custom_beparams", "custom_nicparams",
82 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
83 9031ee8e Iustin Pop
84 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
85 06fb92cf Bernardo Dal Seno
            "dtotal", "dfree", "sptotal", "spfree",
86 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
87 7118a0df Iustin Pop
            "pinst_cnt", "sinst_cnt",
88 f43c898d Bernardo Dal Seno
            "ctotal", "cnos", "cnodes", "csockets",
89 7118a0df Iustin Pop
            "pip", "sip", "role",
90 93962b80 Iustin Pop
            "pinst_list", "sinst_list",
91 c190e817 Iustin Pop
            "master_capable", "vm_capable",
92 37e61a77 Iustin Pop
            "ndparams",
93 fd254195 Iustin Pop
            "group.uuid",
94 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
95 4e5a68f8 Oleksiy Mishchenko
96 4588b4bd Dimitris Aragiorgis
NET_FIELDS = ["name", "network", "gateway",
97 4588b4bd Dimitris Aragiorgis
              "network6", "gateway6",
98 5cfa6c37 Dimitris Aragiorgis
              "mac_prefix",
99 4588b4bd Dimitris Aragiorgis
              "free_count", "reserved_count",
100 4588b4bd Dimitris Aragiorgis
              "map", "group_list", "inst_list",
101 95c83fe6 Christos Stavrakakis
              "external_reservations",
102 95c83fe6 Christos Stavrakakis
              ] + _COMMON_FIELDS
103 4588b4bd Dimitris Aragiorgis
104 f4e86448 Michael Hanselmann
G_FIELDS = [
105 f4e86448 Michael Hanselmann
  "alloc_policy",
106 f4e86448 Michael Hanselmann
  "name",
107 f4e86448 Michael Hanselmann
  "node_cnt",
108 f4e86448 Michael Hanselmann
  "node_list",
109 edd49f9b Agata Murawska
  "ipolicy",
110 003306f9 Iustin Pop
  "custom_ipolicy",
111 003306f9 Iustin Pop
  "diskparams",
112 003306f9 Iustin Pop
  "custom_diskparams",
113 003306f9 Iustin Pop
  "ndparams",
114 003306f9 Iustin Pop
  "custom_ndparams",
115 f4e86448 Michael Hanselmann
  ] + _COMMON_FIELDS
116 0897dc97 Adeodato Simo
117 bd7b2070 Michael Hanselmann
J_FIELDS_BULK = [
118 e987f166 Michael Hanselmann
  "id", "ops", "status", "summary",
119 bd7b2070 Michael Hanselmann
  "opstatus",
120 e987f166 Michael Hanselmann
  "received_ts", "start_ts", "end_ts",
121 e987f166 Michael Hanselmann
  ]
122 e987f166 Michael Hanselmann
123 bd7b2070 Michael Hanselmann
J_FIELDS = J_FIELDS_BULK + [
124 bd7b2070 Michael Hanselmann
  "oplog",
125 bd7b2070 Michael Hanselmann
  "opresult",
126 bd7b2070 Michael Hanselmann
  ]
127 bd7b2070 Michael Hanselmann
128 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
129 51cc8637 Michael Hanselmann
_NR_MASTER_CANDIDATE = "master-candidate"
130 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
131 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
132 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
133 64dae8fc Michael Hanselmann
134 64dae8fc Michael Hanselmann
_NR_MAP = {
135 1e28e3b8 Michael Hanselmann
  constants.NR_MASTER: _NR_MASTER,
136 51cc8637 Michael Hanselmann
  constants.NR_MCANDIDATE: _NR_MASTER_CANDIDATE,
137 1e28e3b8 Michael Hanselmann
  constants.NR_DRAINED: _NR_DRAINED,
138 1e28e3b8 Michael Hanselmann
  constants.NR_OFFLINE: _NR_OFFLINE,
139 1e28e3b8 Michael Hanselmann
  constants.NR_REGULAR: _NR_REGULAR,
140 64dae8fc Michael Hanselmann
  }
141 64dae8fc Michael Hanselmann
142 1e28e3b8 Michael Hanselmann
assert frozenset(_NR_MAP.keys()) == constants.NR_ALL
143 1e28e3b8 Michael Hanselmann
144 d975f482 Michael Hanselmann
# Request data version field
145 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
146 d975f482 Michael Hanselmann
147 6395cebb Michael Hanselmann
# Feature string for instance creation request data version 1
148 6395cebb Michael Hanselmann
_INST_CREATE_REQV1 = "instance-create-reqv1"
149 6395cebb Michael Hanselmann
150 c744425f Michael Hanselmann
# Feature string for instance reinstall request version 1
151 c744425f Michael Hanselmann
_INST_REINSTALL_REQV1 = "instance-reinstall-reqv1"
152 c744425f Michael Hanselmann
153 b7a1c816 Michael Hanselmann
# Feature string for node migration version 1
154 b7a1c816 Michael Hanselmann
_NODE_MIGRATE_REQV1 = "node-migrate-reqv1"
155 b7a1c816 Michael Hanselmann
156 de40437a Michael Hanselmann
# Feature string for node evacuation with LU-generated jobs
157 de40437a Michael Hanselmann
_NODE_EVAC_RES1 = "node-evac-res1"
158 de40437a Michael Hanselmann
159 b8028dcf Michael Hanselmann
ALL_FEATURES = compat.UniqueFrozenset([
160 b4fcee5b Michael Hanselmann
  _INST_CREATE_REQV1,
161 b4fcee5b Michael Hanselmann
  _INST_REINSTALL_REQV1,
162 b4fcee5b Michael Hanselmann
  _NODE_MIGRATE_REQV1,
163 b4fcee5b Michael Hanselmann
  _NODE_EVAC_RES1,
164 b4fcee5b Michael Hanselmann
  ])
165 b4fcee5b Michael Hanselmann
166 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
167 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
168 793a8f7c Michael Hanselmann
169 4e5a68f8 Oleksiy Mishchenko
170 28a45bfc René Nussbaumer
# FIXME: For compatibility we update the beparams/memory field. Needs to be
171 09b7b6f2 Michele Tartara
#        removed in Ganeti 2.8
172 28a45bfc René Nussbaumer
def _UpdateBeparams(inst):
173 28a45bfc René Nussbaumer
  """Updates the beparams dict of inst to support the memory field.
174 28a45bfc René Nussbaumer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

394 10b207d4 Oleksiy Mishchenko
  """
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
417 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
418 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
419 4e5a68f8 Oleksiy Mishchenko

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

781 4588b4bd Dimitris Aragiorgis

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

935 d975f482 Michael Hanselmann
    @return: a job id
936 d975f482 Michael Hanselmann

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

964 4ee72287 René Nussbaumer
  """
965 4ee72287 René Nussbaumer
  POST_OPCODE = opcodes.OpInstanceMultiAlloc
966 4ee72287 René Nussbaumer
967 4ee72287 René Nussbaumer
  def GetPostOpInput(self):
968 4ee72287 René Nussbaumer
    """Try to allocate multiple instances.
969 4ee72287 René Nussbaumer

970 4ee72287 René Nussbaumer
    @return: A dict with submitted jobs, allocatable instances and failed
971 4ee72287 René Nussbaumer
             allocations
972 4ee72287 René Nussbaumer

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

994 028c6b76 Oleksiy Mishchenko
  """
995 a6fa7892 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpInstanceRemove
996 a6fa7892 Michael Hanselmann
997 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
998 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
999 4e5a68f8 Oleksiy Mishchenko

1000 4e5a68f8 Oleksiy Mishchenko
    """
1001 bc57fa8d Helga Velroyen
    client = self.GetClient(query=True)
1002 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
1003 e8ebbd2b Michael Hanselmann
1004 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
1005 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
1006 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
1007 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
1008 4e5a68f8 Oleksiy Mishchenko
1009 28a45bfc René Nussbaumer
    return _UpdateBeparams(baserlib.MapFields(I_FIELDS, result[0]))
1010 028c6b76 Oleksiy Mishchenko
1011 a6fa7892 Michael Hanselmann
  def GetDeleteOpInput(self):
1012 6e99c5a0 Iustin Pop
    """Delete an instance.
1013 6e99c5a0 Iustin Pop

1014 6e99c5a0 Iustin Pop
    """
1015 a6fa7892 Michael Hanselmann
    assert len(self.items) == 1
1016 077892f8 Dimitris Aragiorgis
    return (self.request_body, {
1017 a6fa7892 Michael Hanselmann
      "instance_name": self.items[0],
1018 a6fa7892 Michael Hanselmann
      "ignore_failures": False,
1019 a6fa7892 Michael Hanselmann
      "dry_run": self.dryRun(),
1020 a6fa7892 Michael Hanselmann
      })
1021 6e99c5a0 Iustin Pop
1022 028c6b76 Oleksiy Mishchenko
1023 7b3df961 Michael Hanselmann
class R_2_instances_name_info(baserlib.OpcodeResource):
1024 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
1025 d8260842 Michael Hanselmann

1026 d8260842 Michael Hanselmann
  """
1027 7b3df961 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQueryData
1028 7b3df961 Michael Hanselmann
1029 7b3df961 Michael Hanselmann
  def GetGetOpInput(self):
1030 d8260842 Michael Hanselmann
    """Request detailed instance information.
1031 d8260842 Michael Hanselmann

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

1043 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
1044 2276aa29 Oleksiy Mishchenko

1045 2276aa29 Oleksiy Mishchenko
  """
1046 ac4888c1 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReboot
1047 ac4888c1 Michael Hanselmann
1048 ac4888c1 Michael Hanselmann
  def GetPostOpInput(self):
1049 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
1050 2276aa29 Oleksiy Mishchenko

1051 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
1052 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
1053 0c55c24b Oleksiy Mishchenko

1054 2276aa29 Oleksiy Mishchenko
    """
1055 077892f8 Dimitris Aragiorgis
    return (self.request_body, {
1056 ac4888c1 Michael Hanselmann
      "instance_name": self.items[0],
1057 ac4888c1 Michael Hanselmann
      "reboot_type":
1058 ac4888c1 Michael Hanselmann
        self.queryargs.get("type", [constants.INSTANCE_REBOOT_HARD])[0],
1059 ac4888c1 Michael Hanselmann
      "ignore_secondaries": bool(self._checkIntVariable("ignore_secondaries")),
1060 ac4888c1 Michael Hanselmann
      "dry_run": self.dryRun(),
1061 ac4888c1 Michael Hanselmann
      })
1062 2276aa29 Oleksiy Mishchenko
1063 2276aa29 Oleksiy Mishchenko
1064 4717e6eb Michael Hanselmann
class R_2_instances_name_startup(baserlib.OpcodeResource):
1065 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
1066 0c55c24b Oleksiy Mishchenko

1067 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
1068 0c55c24b Oleksiy Mishchenko

1069 0c55c24b Oleksiy Mishchenko
  """
1070 4717e6eb Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceStartup
1071 4717e6eb Michael Hanselmann
1072 4717e6eb Michael Hanselmann
  def GetPutOpInput(self):
1073 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
1074 0c55c24b Oleksiy Mishchenko

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

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

1090 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
1091 0c55c24b Oleksiy Mishchenko

1092 0c55c24b Oleksiy Mishchenko
  """
1093 3175ade6 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceShutdown
1094 0c55c24b Oleksiy Mishchenko
1095 3175ade6 Michael Hanselmann
  def GetPutOpInput(self):
1096 3175ade6 Michael Hanselmann
    """Shutdown an instance.
1097 7fa310f6 René Nussbaumer

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

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

1133 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
1134 e5b7c4ca Iustin Pop

1135 e5b7c4ca Iustin Pop
  """
1136 f6ce0ba2 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReinstall
1137 f6ce0ba2 Michael Hanselmann
1138 e5b7c4ca Iustin Pop
  def POST(self):
1139 e5b7c4ca Iustin Pop
    """Reinstall an instance.
1140 e5b7c4ca Iustin Pop

1141 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
1142 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
1143 e5b7c4ca Iustin Pop
    automatically.
1144 e5b7c4ca Iustin Pop

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

1168 4c98b915 Michael Hanselmann
  """
1169 0dbc732c Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReplaceDisks
1170 0dbc732c Michael Hanselmann
1171 0dbc732c Michael Hanselmann
  def GetPostOpInput(self):
1172 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1173 4c98b915 Michael Hanselmann

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

1214 2197b66f René Nussbaumer
  """
1215 1824a7a1 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceActivateDisks
1216 1824a7a1 Michael Hanselmann
1217 1824a7a1 Michael Hanselmann
  def GetPutOpInput(self):
1218 2197b66f René Nussbaumer
    """Activate disks for an instance.
1219 2197b66f René Nussbaumer

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

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

1232 0a37de5f René Nussbaumer
  """
1233 973ec124 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceDeactivateDisks
1234 973ec124 Michael Hanselmann
1235 973ec124 Michael Hanselmann
  def GetPutOpInput(self):
1236 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1237 0a37de5f René Nussbaumer

1238 0a37de5f René Nussbaumer
    """
1239 973ec124 Michael Hanselmann
    return ({}, {
1240 973ec124 Michael Hanselmann
      "instance_name": self.items[0],
1241 973ec124 Michael Hanselmann
      })
1242 0a37de5f René Nussbaumer
1243 0a37de5f René Nussbaumer
1244 a52978c7 Michael Hanselmann
class R_2_instances_name_recreate_disks(baserlib.OpcodeResource):
1245 a52978c7 Michael Hanselmann
  """/2/instances/[instance_name]/recreate-disks resource.
1246 a52978c7 Michael Hanselmann

1247 a52978c7 Michael Hanselmann
  """
1248 a52978c7 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceRecreateDisks
1249 a52978c7 Michael Hanselmann
1250 a52978c7 Michael Hanselmann
  def GetPostOpInput(self):
1251 a52978c7 Michael Hanselmann
    """Recreate disks for an instance.
1252 a52978c7 Michael Hanselmann

1253 a52978c7 Michael Hanselmann
    """
1254 a52978c7 Michael Hanselmann
    return ({}, {
1255 a52978c7 Michael Hanselmann
      "instance_name": self.items[0],
1256 a52978c7 Michael Hanselmann
      })
1257 a52978c7 Michael Hanselmann
1258 a52978c7 Michael Hanselmann
1259 1c63311d Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.OpcodeResource):
1260 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1261 ebeb600f Michael Hanselmann

1262 ebeb600f Michael Hanselmann
  """
1263 1c63311d Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupPrepare
1264 ebeb600f Michael Hanselmann
1265 1c63311d Michael Hanselmann
  def GetPutOpInput(self):
1266 1c63311d Michael Hanselmann
    """Prepares an export for an instance.
1267 ebeb600f Michael Hanselmann

1268 ebeb600f Michael Hanselmann
    """
1269 1c63311d Michael Hanselmann
    return ({}, {
1270 1c63311d Michael Hanselmann
      "instance_name": self.items[0],
1271 1c63311d Michael Hanselmann
      "mode": self._checkStringVariable("mode"),
1272 1c63311d Michael Hanselmann
      })
1273 ebeb600f Michael Hanselmann
1274 ebeb600f Michael Hanselmann
1275 134afbe7 Michael Hanselmann
class R_2_instances_name_export(baserlib.OpcodeResource):
1276 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1277 ebeb600f Michael Hanselmann

1278 ebeb600f Michael Hanselmann
  """
1279 134afbe7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupExport
1280 134afbe7 Michael Hanselmann
  PUT_RENAME = {
1281 134afbe7 Michael Hanselmann
    "destination": "target_node",
1282 134afbe7 Michael Hanselmann
    }
1283 ebeb600f Michael Hanselmann
1284 134afbe7 Michael Hanselmann
  def GetPutOpInput(self):
1285 134afbe7 Michael Hanselmann
    """Exports an instance.
1286 ebeb600f Michael Hanselmann

1287 ebeb600f Michael Hanselmann
    """
1288 134afbe7 Michael Hanselmann
    return (self.request_body, {
1289 134afbe7 Michael Hanselmann
      "instance_name": self.items[0],
1290 134afbe7 Michael Hanselmann
      })
1291 ebeb600f Michael Hanselmann
1292 ebeb600f Michael Hanselmann
1293 075a29be Michael Hanselmann
class R_2_instances_name_migrate(baserlib.OpcodeResource):
1294 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1295 5823e0d2 Michael Hanselmann

1296 5823e0d2 Michael Hanselmann
  """
1297 075a29be Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceMigrate
1298 5823e0d2 Michael Hanselmann
1299 075a29be Michael Hanselmann
  def GetPutOpInput(self):
1300 075a29be Michael Hanselmann
    """Migrates an instance.
1301 5823e0d2 Michael Hanselmann

1302 5823e0d2 Michael Hanselmann
    """
1303 075a29be Michael Hanselmann
    return (self.request_body, {
1304 075a29be Michael Hanselmann
      "instance_name": self.items[0],
1305 075a29be Michael Hanselmann
      })
1306 5823e0d2 Michael Hanselmann
1307 5823e0d2 Michael Hanselmann
1308 b5f2ab80 Michael Hanselmann
class R_2_instances_name_failover(baserlib.OpcodeResource):
1309 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1310 c0a146a1 Michael Hanselmann

1311 c0a146a1 Michael Hanselmann
  """
1312 b5f2ab80 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceFailover
1313 c0a146a1 Michael Hanselmann
1314 b5f2ab80 Michael Hanselmann
  def GetPutOpInput(self):
1315 b5f2ab80 Michael Hanselmann
    """Does a failover of an instance.
1316 c0a146a1 Michael Hanselmann

1317 c0a146a1 Michael Hanselmann
    """
1318 b5f2ab80 Michael Hanselmann
    return (self.request_body, {
1319 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1320 c0a146a1 Michael Hanselmann
      })
1321 c0a146a1 Michael Hanselmann
1322 c0a146a1 Michael Hanselmann
1323 d76f9b5d Michael Hanselmann
class R_2_instances_name_rename(baserlib.OpcodeResource):
1324 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1325 d56e7dc7 Michael Hanselmann

1326 d56e7dc7 Michael Hanselmann
  """
1327 d76f9b5d Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceRename
1328 d56e7dc7 Michael Hanselmann
1329 d76f9b5d Michael Hanselmann
  def GetPutOpInput(self):
1330 d76f9b5d Michael Hanselmann
    """Changes the name of an instance.
1331 d56e7dc7 Michael Hanselmann

1332 d56e7dc7 Michael Hanselmann
    """
1333 d76f9b5d Michael Hanselmann
    return (self.request_body, {
1334 d76f9b5d Michael Hanselmann
      "instance_name": self.items[0],
1335 d76f9b5d Michael Hanselmann
      })
1336 d56e7dc7 Michael Hanselmann
1337 d56e7dc7 Michael Hanselmann
1338 f3db88ba Michael Hanselmann
class R_2_instances_name_modify(baserlib.OpcodeResource):
1339 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1340 3882937a Michael Hanselmann

1341 3882937a Michael Hanselmann
  """
1342 f3db88ba Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceSetParams
1343 3882937a Michael Hanselmann
1344 f3db88ba Michael Hanselmann
  def GetPutOpInput(self):
1345 f3db88ba Michael Hanselmann
    """Changes parameters of an instance.
1346 3882937a Michael Hanselmann

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

1359 e23881ed Michael Hanselmann
  """
1360 335965b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceGrowDisk
1361 e23881ed Michael Hanselmann
1362 335965b9 Michael Hanselmann
  def GetPostOpInput(self):
1363 335965b9 Michael Hanselmann
    """Increases the size of an instance disk.
1364 e23881ed Michael Hanselmann

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

1375 b82d4c5e Michael Hanselmann
  """
1376 5e12acfe Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE, rapi.RAPI_ACCESS_READ]
1377 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceConsole
1378 b82d4c5e Michael Hanselmann
1379 b82d4c5e Michael Hanselmann
  def GET(self):
1380 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1381 b82d4c5e Michael Hanselmann

1382 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1383 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1384 b82d4c5e Michael Hanselmann

1385 b82d4c5e Michael Hanselmann
    """
1386 9045e2c6 Helga Velroyen
    instance_name = self.items[0]
1387 981224e9 Helga Velroyen
    client = self.GetClient(query=True)
1388 b82d4c5e Michael Hanselmann
1389 9045e2c6 Helga Velroyen
    ((console, oper_state), ) = \
1390 9045e2c6 Helga Velroyen
        client.QueryInstances([instance_name], ["console", "oper_state"], False)
1391 b82d4c5e Michael Hanselmann
1392 9045e2c6 Helga Velroyen
    if not oper_state:
1393 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1394 b82d4c5e Michael Hanselmann
1395 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1396 b82d4c5e Michael Hanselmann
    return console
1397 b82d4c5e Michael Hanselmann
1398 b82d4c5e Michael Hanselmann
1399 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1400 2a38e913 Michael Hanselmann
  """Tries to extract C{fields} query parameter.
1401 2a38e913 Michael Hanselmann

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

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

1418 2a38e913 Michael Hanselmann
  @type fields: string
1419 2a38e913 Michael Hanselmann
  @rtype: list of string
1420 208a6cff Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

1520 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1521 441e7cfd Oleksiy Mishchenko

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

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

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

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

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

1575 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1576 18cb43a2 Oleksiy Mishchenko

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

1584 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1585 18cb43a2 Oleksiy Mishchenko

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

1593 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1594 414ebaf1 Michael Hanselmann

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

1602 6e8091f9 Dimitris Aragiorgis
  Manages per-network tags.
1603 6e8091f9 Dimitris Aragiorgis

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

1611 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1612 18cb43a2 Oleksiy Mishchenko

1613 18cb43a2 Oleksiy Mishchenko
  """
1614 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER