Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ d6f8db24

History | View | Annotate | Download (33.7 kB)

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

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

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

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

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

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

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

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

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

160 0f945c65 Michael Hanselmann
    """
161 0f945c65 Michael Hanselmann
    return None
162 0f945c65 Michael Hanselmann
163 0f945c65 Michael Hanselmann
164 132cdb87 Michael Hanselmann
class R_2(R_root):
165 132cdb87 Michael Hanselmann
  """/2 resource.
166 132cdb87 Michael Hanselmann

167 132cdb87 Michael Hanselmann
  """
168 132cdb87 Michael Hanselmann
169 132cdb87 Michael Hanselmann
170 26ff6ee2 Michael Hanselmann
class R_version(baserlib.ResourceBase):
171 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
172 4e5a68f8 Oleksiy Mishchenko

173 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
174 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
175 4e5a68f8 Oleksiy Mishchenko

176 4e5a68f8 Oleksiy Mishchenko
  """
177 7e950d31 Iustin Pop
  @staticmethod
178 7e950d31 Iustin Pop
  def GET():
179 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
180 4e5a68f8 Oleksiy Mishchenko

181 4e5a68f8 Oleksiy Mishchenko
    """
182 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
183 4e5a68f8 Oleksiy Mishchenko
184 4e5a68f8 Oleksiy Mishchenko
185 f6ce0ba2 Michael Hanselmann
class R_2_info(baserlib.OpcodeResource):
186 b58a4d16 Michael Hanselmann
  """/2/info resource.
187 4e5a68f8 Oleksiy Mishchenko

188 4e5a68f8 Oleksiy Mishchenko
  """
189 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpClusterQuery
190 f6ce0ba2 Michael Hanselmann
191 be1ddd09 Michael Hanselmann
  def GET(self):
192 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
193 4e5a68f8 Oleksiy Mishchenko

194 4e5a68f8 Oleksiy Mishchenko
    """
195 be1ddd09 Michael Hanselmann
    client = self.GetClient()
196 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
197 4e5a68f8 Oleksiy Mishchenko
198 4e5a68f8 Oleksiy Mishchenko
199 26ff6ee2 Michael Hanselmann
class R_2_features(baserlib.ResourceBase):
200 7eac4a4d Michael Hanselmann
  """/2/features resource.
201 7eac4a4d Michael Hanselmann

202 7eac4a4d Michael Hanselmann
  """
203 7eac4a4d Michael Hanselmann
  @staticmethod
204 7eac4a4d Michael Hanselmann
  def GET():
205 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
206 7eac4a4d Michael Hanselmann

207 7eac4a4d Michael Hanselmann
    """
208 b4fcee5b Michael Hanselmann
    return list(ALL_FEATURES)
209 7eac4a4d Michael Hanselmann
210 7eac4a4d Michael Hanselmann
211 f6ce0ba2 Michael Hanselmann
class R_2_os(baserlib.OpcodeResource):
212 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
213 4e5a68f8 Oleksiy Mishchenko

214 4e5a68f8 Oleksiy Mishchenko
  """
215 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpOsDiagnose
216 f6ce0ba2 Michael Hanselmann
217 be1ddd09 Michael Hanselmann
  def GET(self):
218 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
219 4e5a68f8 Oleksiy Mishchenko

220 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
221 4e5a68f8 Oleksiy Mishchenko

222 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
223 4e5a68f8 Oleksiy Mishchenko

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

245 508e9b20 Michael Hanselmann
  """
246 8fd625fc Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterRedistConf
247 508e9b20 Michael Hanselmann
248 508e9b20 Michael Hanselmann
249 50c7d82e Michael Hanselmann
class R_2_cluster_modify(baserlib.OpcodeResource):
250 62e999a5 Michael Hanselmann
  """/2/modify resource.
251 62e999a5 Michael Hanselmann

252 62e999a5 Michael Hanselmann
  """
253 50c7d82e Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterSetParams
254 62e999a5 Michael Hanselmann
255 62e999a5 Michael Hanselmann
256 26ff6ee2 Michael Hanselmann
class R_2_jobs(baserlib.ResourceBase):
257 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
258 10b207d4 Oleksiy Mishchenko

259 10b207d4 Oleksiy Mishchenko
  """
260 e987f166 Michael Hanselmann
  def GET(self):
261 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
262 10b207d4 Oleksiy Mishchenko

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

265 10b207d4 Oleksiy Mishchenko
    """
266 be1ddd09 Michael Hanselmann
    client = self.GetClient()
267 e987f166 Michael Hanselmann
268 e987f166 Michael Hanselmann
    if self.useBulk():
269 bd7b2070 Michael Hanselmann
      bulkdata = client.QueryJobs(None, J_FIELDS_BULK)
270 bd7b2070 Michael Hanselmann
      return baserlib.MapBulkFields(bulkdata, J_FIELDS_BULK)
271 e987f166 Michael Hanselmann
    else:
272 e987f166 Michael Hanselmann
      jobdata = map(compat.fst, client.QueryJobs(None, ["id"]))
273 e987f166 Michael Hanselmann
      return baserlib.BuildUriList(jobdata, "/2/jobs/%s",
274 e987f166 Michael Hanselmann
                                   uri_fields=("id", "uri"))
275 10b207d4 Oleksiy Mishchenko
276 10b207d4 Oleksiy Mishchenko
277 26ff6ee2 Michael Hanselmann
class R_2_jobs_id(baserlib.ResourceBase):
278 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
279 10b207d4 Oleksiy Mishchenko

280 10b207d4 Oleksiy Mishchenko
  """
281 10b207d4 Oleksiy Mishchenko
  def GET(self):
282 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
283 10b207d4 Oleksiy Mishchenko

284 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
285 c41eea6e Iustin Pop
        The result includes:
286 c41eea6e Iustin Pop
            - id: job ID as a number
287 c41eea6e Iustin Pop
            - status: current job status as a string
288 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
289 c41eea6e Iustin Pop
              opcodes in the job
290 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
291 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
292 38206f3c Iustin Pop

293 10b207d4 Oleksiy Mishchenko
    """
294 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
295 be1ddd09 Michael Hanselmann
    result = self.GetClient().QueryJobs([job_id, ], J_FIELDS)[0]
296 ee69c97f Iustin Pop
    if result is None:
297 ee69c97f Iustin Pop
      raise http.HttpNotFound()
298 e987f166 Michael Hanselmann
    return baserlib.MapFields(J_FIELDS, result)
299 10b207d4 Oleksiy Mishchenko
300 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
301 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
302 c7f5f338 Oleksiy Mishchenko

303 c7f5f338 Oleksiy Mishchenko
    """
304 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
305 be1ddd09 Michael Hanselmann
    result = self.GetClient().CancelJob(job_id)
306 c7f5f338 Oleksiy Mishchenko
    return result
307 c7f5f338 Oleksiy Mishchenko
308 10b207d4 Oleksiy Mishchenko
309 26ff6ee2 Michael Hanselmann
class R_2_jobs_id_wait(baserlib.ResourceBase):
310 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
311 793a8f7c Michael Hanselmann

312 793a8f7c Michael Hanselmann
  """
313 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
314 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
315 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
316 793a8f7c Michael Hanselmann
317 793a8f7c Michael Hanselmann
  def GET(self):
318 793a8f7c Michael Hanselmann
    """Waits for job changes.
319 793a8f7c Michael Hanselmann

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

361 10b207d4 Oleksiy Mishchenko
  """
362 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQuery
363 f6ce0ba2 Michael Hanselmann
364 10b207d4 Oleksiy Mishchenko
  def GET(self):
365 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
366 38206f3c Iustin Pop

367 10b207d4 Oleksiy Mishchenko
    """
368 be1ddd09 Michael Hanselmann
    client = self.GetClient()
369 38206f3c Iustin Pop
370 3d103742 Iustin Pop
    if self.useBulk():
371 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
372 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
373 9031ee8e Iustin Pop
    else:
374 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
375 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
376 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
377 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
378 441e7cfd Oleksiy Mishchenko
379 441e7cfd Oleksiy Mishchenko
380 f6ce0ba2 Michael Hanselmann
class R_2_nodes_name(baserlib.OpcodeResource):
381 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name] resource.
382 028c6b76 Oleksiy Mishchenko

383 028c6b76 Oleksiy Mishchenko
  """
384 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQuery
385 f6ce0ba2 Michael Hanselmann
386 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
387 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
388 4e5a68f8 Oleksiy Mishchenko

389 4e5a68f8 Oleksiy Mishchenko
    """
390 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
391 be1ddd09 Michael Hanselmann
    client = self.GetClient()
392 e8ebbd2b Michael Hanselmann
393 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
394 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
395 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
396 4e5a68f8 Oleksiy Mishchenko
397 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
398 028c6b76 Oleksiy Mishchenko
399 028c6b76 Oleksiy Mishchenko
400 42d4d8b9 Michael Hanselmann
class R_2_nodes_name_powercycle(baserlib.OpcodeResource):
401 42d4d8b9 Michael Hanselmann
  """/2/nodes/[node_name]/powercycle resource.
402 42d4d8b9 Michael Hanselmann

403 42d4d8b9 Michael Hanselmann
  """
404 42d4d8b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodePowercycle
405 42d4d8b9 Michael Hanselmann
406 42d4d8b9 Michael Hanselmann
  def GetPostOpInput(self):
407 42d4d8b9 Michael Hanselmann
    """Tries to powercycle a node.
408 42d4d8b9 Michael Hanselmann

409 42d4d8b9 Michael Hanselmann
    """
410 42d4d8b9 Michael Hanselmann
    return (self.request_body, {
411 42d4d8b9 Michael Hanselmann
      "node_name": self.items[0],
412 42d4d8b9 Michael Hanselmann
      "force": self.useForce(),
413 42d4d8b9 Michael Hanselmann
      })
414 42d4d8b9 Michael Hanselmann
415 42d4d8b9 Michael Hanselmann
416 51cc8637 Michael Hanselmann
class R_2_nodes_name_role(baserlib.OpcodeResource):
417 51cc8637 Michael Hanselmann
  """/2/nodes/[node_name]/role resource.
418 64dae8fc Michael Hanselmann

419 64dae8fc Michael Hanselmann
  """
420 51cc8637 Michael Hanselmann
  PUT_OPCODE = opcodes.OpNodeSetParams
421 51cc8637 Michael Hanselmann
422 64dae8fc Michael Hanselmann
  def GET(self):
423 64dae8fc Michael Hanselmann
    """Returns the current node role.
424 64dae8fc Michael Hanselmann

425 64dae8fc Michael Hanselmann
    @return: Node role
426 64dae8fc Michael Hanselmann

427 64dae8fc Michael Hanselmann
    """
428 64dae8fc Michael Hanselmann
    node_name = self.items[0]
429 be1ddd09 Michael Hanselmann
    client = self.GetClient()
430 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
431 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
432 64dae8fc Michael Hanselmann
433 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
434 64dae8fc Michael Hanselmann
435 51cc8637 Michael Hanselmann
  def GetPutOpInput(self):
436 64dae8fc Michael Hanselmann
    """Sets the node role.
437 64dae8fc Michael Hanselmann

438 64dae8fc Michael Hanselmann
    """
439 51cc8637 Michael Hanselmann
    baserlib.CheckType(self.request_body, basestring, "Body contents")
440 64dae8fc Michael Hanselmann
441 627ad739 Michael Hanselmann
    role = self.request_body
442 64dae8fc Michael Hanselmann
443 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
444 64dae8fc Michael Hanselmann
      candidate = False
445 64dae8fc Michael Hanselmann
      offline = False
446 64dae8fc Michael Hanselmann
      drained = False
447 64dae8fc Michael Hanselmann
448 51cc8637 Michael Hanselmann
    elif role == _NR_MASTER_CANDIDATE:
449 64dae8fc Michael Hanselmann
      candidate = True
450 64dae8fc Michael Hanselmann
      offline = drained = None
451 64dae8fc Michael Hanselmann
452 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
453 64dae8fc Michael Hanselmann
      drained = True
454 64dae8fc Michael Hanselmann
      candidate = offline = None
455 64dae8fc Michael Hanselmann
456 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
457 64dae8fc Michael Hanselmann
      offline = True
458 64dae8fc Michael Hanselmann
      candidate = drained = None
459 64dae8fc Michael Hanselmann
460 64dae8fc Michael Hanselmann
    else:
461 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
462 64dae8fc Michael Hanselmann
463 51cc8637 Michael Hanselmann
    assert len(self.items) == 1
464 64dae8fc Michael Hanselmann
465 51cc8637 Michael Hanselmann
    return ({}, {
466 51cc8637 Michael Hanselmann
      "node_name": self.items[0],
467 51cc8637 Michael Hanselmann
      "master_candidate": candidate,
468 51cc8637 Michael Hanselmann
      "offline": offline,
469 51cc8637 Michael Hanselmann
      "drained": drained,
470 51cc8637 Michael Hanselmann
      "force": self.useForce(),
471 682878d9 Guido Trotter
      "auto_promote": bool(self._checkIntVariable("auto-promote", default=0)),
472 51cc8637 Michael Hanselmann
      })
473 64dae8fc Michael Hanselmann
474 64dae8fc Michael Hanselmann
475 7fa91722 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.OpcodeResource):
476 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
477 73452f12 Michael Hanselmann

478 73452f12 Michael Hanselmann
  """
479 7fa91722 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodeEvacuate
480 7fa91722 Michael Hanselmann
481 7fa91722 Michael Hanselmann
  def GetPostOpInput(self):
482 de40437a Michael Hanselmann
    """Evacuate all instances off a node.
483 73452f12 Michael Hanselmann

484 73452f12 Michael Hanselmann
    """
485 7fa91722 Michael Hanselmann
    return (self.request_body, {
486 de40437a Michael Hanselmann
      "node_name": self.items[0],
487 de40437a Michael Hanselmann
      "dry_run": self.dryRun(),
488 de40437a Michael Hanselmann
      })
489 941b9309 Iustin Pop
490 73452f12 Michael Hanselmann
491 55168cc7 Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.OpcodeResource):
492 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
493 1c482bab Michael Hanselmann

494 1c482bab Michael Hanselmann
  """
495 55168cc7 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodeMigrate
496 55168cc7 Michael Hanselmann
497 55168cc7 Michael Hanselmann
  def GetPostOpInput(self):
498 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
499 1c482bab Michael Hanselmann

500 1c482bab Michael Hanselmann
    """
501 b7a1c816 Michael Hanselmann
    if self.queryargs:
502 b7a1c816 Michael Hanselmann
      # Support old-style requests
503 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs and "mode" in self.queryargs:
504 b7a1c816 Michael Hanselmann
        raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
505 b7a1c816 Michael Hanselmann
                                  " be passed")
506 b7a1c816 Michael Hanselmann
507 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs:
508 b7a1c816 Michael Hanselmann
        if self._checkIntVariable("live", default=1):
509 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_LIVE
510 b7a1c816 Michael Hanselmann
        else:
511 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_NONLIVE
512 52194140 Iustin Pop
      else:
513 b7a1c816 Michael Hanselmann
        mode = self._checkStringVariable("mode", default=None)
514 b7a1c816 Michael Hanselmann
515 b7a1c816 Michael Hanselmann
      data = {
516 b7a1c816 Michael Hanselmann
        "mode": mode,
517 b7a1c816 Michael Hanselmann
        }
518 52194140 Iustin Pop
    else:
519 b7a1c816 Michael Hanselmann
      data = self.request_body
520 52194140 Iustin Pop
521 55168cc7 Michael Hanselmann
    return (data, {
522 55168cc7 Michael Hanselmann
      "node_name": self.items[0],
523 b7a1c816 Michael Hanselmann
      })
524 1c482bab Michael Hanselmann
525 1c482bab Michael Hanselmann
526 682878d9 Guido Trotter
class R_2_nodes_name_modify(baserlib.OpcodeResource):
527 94497dd1 Michael Hanselmann
  """/2/nodes/[node_name]/modify resource.
528 94497dd1 Michael Hanselmann

529 94497dd1 Michael Hanselmann
  """
530 8b8f54dd Guido Trotter
  POST_OPCODE = opcodes.OpNodeSetParams
531 94497dd1 Michael Hanselmann
532 8b8f54dd Guido Trotter
  def GetPostOpInput(self):
533 682878d9 Guido Trotter
    """Changes parameters of a node.
534 94497dd1 Michael Hanselmann

535 94497dd1 Michael Hanselmann
    """
536 682878d9 Guido Trotter
    assert len(self.items) == 1
537 94497dd1 Michael Hanselmann
538 682878d9 Guido Trotter
    return (self.request_body, {
539 370f2042 Guido Trotter
      "node_name": self.items[0],
540 94497dd1 Michael Hanselmann
      })
541 94497dd1 Michael Hanselmann
542 94497dd1 Michael Hanselmann
543 eb08e09d Michael Hanselmann
class R_2_nodes_name_storage(baserlib.OpcodeResource):
544 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
545 7a95a954 Michael Hanselmann

546 7a95a954 Michael Hanselmann
  """
547 ad8d0595 Iustin Pop
  # LUNodeQueryStorage acquires locks, hence restricting access to GET
548 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
549 eb08e09d Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQueryStorage
550 7a95a954 Michael Hanselmann
551 eb08e09d Michael Hanselmann
  def GetGetOpInput(self):
552 eb08e09d Michael Hanselmann
    """List storage available on a node.
553 7a95a954 Michael Hanselmann

554 eb08e09d Michael Hanselmann
    """
555 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
556 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
557 eb08e09d Michael Hanselmann
558 7a95a954 Michael Hanselmann
    if not output_fields:
559 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
560 7a95a954 Michael Hanselmann
                                " parameter")
561 7a95a954 Michael Hanselmann
562 eb08e09d Michael Hanselmann
    return ({}, {
563 eb08e09d Michael Hanselmann
      "nodes": [self.items[0]],
564 eb08e09d Michael Hanselmann
      "storage_type": storage_type,
565 eb08e09d Michael Hanselmann
      "output_fields": output_fields.split(","),
566 eb08e09d Michael Hanselmann
      })
567 7a95a954 Michael Hanselmann
568 7a95a954 Michael Hanselmann
569 8d232068 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.OpcodeResource):
570 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify resource.
571 1e82bc80 Michael Hanselmann

572 1e82bc80 Michael Hanselmann
  """
573 8d232068 Michael Hanselmann
  PUT_OPCODE = opcodes.OpNodeModifyStorage
574 1e82bc80 Michael Hanselmann
575 8d232068 Michael Hanselmann
  def GetPutOpInput(self):
576 8d232068 Michael Hanselmann
    """Modifies a storage volume on a node.
577 1e82bc80 Michael Hanselmann

578 8d232068 Michael Hanselmann
    """
579 8d232068 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
580 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
581 8d232068 Michael Hanselmann
582 1e82bc80 Michael Hanselmann
    if not name:
583 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
584 1e82bc80 Michael Hanselmann
                                " parameter")
585 1e82bc80 Michael Hanselmann
586 1e82bc80 Michael Hanselmann
    changes = {}
587 1e82bc80 Michael Hanselmann
588 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
589 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
590 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
591 1e82bc80 Michael Hanselmann
592 8d232068 Michael Hanselmann
    return ({}, {
593 8d232068 Michael Hanselmann
      "node_name": self.items[0],
594 8d232068 Michael Hanselmann
      "storage_type": storage_type,
595 8d232068 Michael Hanselmann
      "name": name,
596 8d232068 Michael Hanselmann
      "changes": changes,
597 8d232068 Michael Hanselmann
      })
598 1e82bc80 Michael Hanselmann
599 1e82bc80 Michael Hanselmann
600 98270691 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.OpcodeResource):
601 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair resource.
602 723f4565 Michael Hanselmann

603 723f4565 Michael Hanselmann
  """
604 98270691 Michael Hanselmann
  PUT_OPCODE = opcodes.OpRepairNodeStorage
605 723f4565 Michael Hanselmann
606 98270691 Michael Hanselmann
  def GetPutOpInput(self):
607 98270691 Michael Hanselmann
    """Repairs a storage volume on a node.
608 723f4565 Michael Hanselmann

609 98270691 Michael Hanselmann
    """
610 98270691 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
611 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
612 723f4565 Michael Hanselmann
    if not name:
613 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
614 723f4565 Michael Hanselmann
                                " parameter")
615 723f4565 Michael Hanselmann
616 98270691 Michael Hanselmann
    return ({}, {
617 98270691 Michael Hanselmann
      "node_name": self.items[0],
618 98270691 Michael Hanselmann
      "storage_type": storage_type,
619 98270691 Michael Hanselmann
      "name": name,
620 98270691 Michael Hanselmann
      })
621 723f4565 Michael Hanselmann
622 723f4565 Michael Hanselmann
623 c91407bc Michael Hanselmann
class R_2_groups(baserlib.OpcodeResource):
624 c91407bc Michael Hanselmann
  """/2/groups resource.
625 90e99856 Adeodato Simo

626 90e99856 Adeodato Simo
  """
627 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpGroupQuery
628 c91407bc Michael Hanselmann
  POST_OPCODE = opcodes.OpGroupAdd
629 c91407bc Michael Hanselmann
  POST_RENAME = {
630 527fbde8 Michael Hanselmann
    "name": "group_name",
631 527fbde8 Michael Hanselmann
    }
632 527fbde8 Michael Hanselmann
633 c91407bc Michael Hanselmann
  def GetPostOpInput(self):
634 c91407bc Michael Hanselmann
    """Create a node group.
635 90e99856 Adeodato Simo

636 c91407bc Michael Hanselmann
    """
637 c91407bc Michael Hanselmann
    assert not self.items
638 c91407bc Michael Hanselmann
    return (self.request_body, {
639 c91407bc Michael Hanselmann
      "dry_run": self.dryRun(),
640 c91407bc Michael Hanselmann
      })
641 0897dc97 Adeodato Simo
642 0897dc97 Adeodato Simo
  def GET(self):
643 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
644 0897dc97 Adeodato Simo

645 0897dc97 Adeodato Simo
    """
646 be1ddd09 Michael Hanselmann
    client = self.GetClient()
647 0897dc97 Adeodato Simo
648 0897dc97 Adeodato Simo
    if self.useBulk():
649 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
650 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
651 0897dc97 Adeodato Simo
    else:
652 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
653 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
654 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
655 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
656 0897dc97 Adeodato Simo
657 0897dc97 Adeodato Simo
658 86f1f5d4 Michael Hanselmann
class R_2_groups_name(baserlib.OpcodeResource):
659 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name] resource.
660 0897dc97 Adeodato Simo

661 0897dc97 Adeodato Simo
  """
662 86f1f5d4 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpGroupRemove
663 86f1f5d4 Michael Hanselmann
664 0897dc97 Adeodato Simo
  def GET(self):
665 0897dc97 Adeodato Simo
    """Send information about a node group.
666 0897dc97 Adeodato Simo

667 0897dc97 Adeodato Simo
    """
668 0897dc97 Adeodato Simo
    group_name = self.items[0]
669 be1ddd09 Michael Hanselmann
    client = self.GetClient()
670 0897dc97 Adeodato Simo
671 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
672 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
673 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
674 0897dc97 Adeodato Simo
675 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
676 0897dc97 Adeodato Simo
677 86f1f5d4 Michael Hanselmann
  def GetDeleteOpInput(self):
678 0dbaa9ca Adeodato Simo
    """Delete a node group.
679 0dbaa9ca Adeodato Simo

680 0dbaa9ca Adeodato Simo
    """
681 86f1f5d4 Michael Hanselmann
    assert len(self.items) == 1
682 86f1f5d4 Michael Hanselmann
    return ({}, {
683 86f1f5d4 Michael Hanselmann
      "group_name": self.items[0],
684 86f1f5d4 Michael Hanselmann
      "dry_run": self.dryRun(),
685 86f1f5d4 Michael Hanselmann
      })
686 0dbaa9ca Adeodato Simo
687 0dbaa9ca Adeodato Simo
688 d5211458 Michael Hanselmann
class R_2_groups_name_modify(baserlib.OpcodeResource):
689 f18fab7d Adeodato Simo
  """/2/groups/[group_name]/modify resource.
690 f18fab7d Adeodato Simo

691 f18fab7d Adeodato Simo
  """
692 d5211458 Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupSetParams
693 f18fab7d Adeodato Simo
694 d5211458 Michael Hanselmann
  def GetPutOpInput(self):
695 d5211458 Michael Hanselmann
    """Changes some parameters of node group.
696 f18fab7d Adeodato Simo

697 f18fab7d Adeodato Simo
    """
698 d5211458 Michael Hanselmann
    assert self.items
699 d5211458 Michael Hanselmann
    return (self.request_body, {
700 d5211458 Michael Hanselmann
      "group_name": self.items[0],
701 d5211458 Michael Hanselmann
      })
702 f18fab7d Adeodato Simo
703 f18fab7d Adeodato Simo
704 cd0d4d5a Michael Hanselmann
class R_2_groups_name_rename(baserlib.OpcodeResource):
705 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/rename resource.
706 0dbaa9ca Adeodato Simo

707 0dbaa9ca Adeodato Simo
  """
708 cd0d4d5a Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupRename
709 0dbaa9ca Adeodato Simo
710 cd0d4d5a Michael Hanselmann
  def GetPutOpInput(self):
711 cd0d4d5a Michael Hanselmann
    """Changes the name of a node group.
712 0dbaa9ca Adeodato Simo

713 0dbaa9ca Adeodato Simo
    """
714 cd0d4d5a Michael Hanselmann
    assert len(self.items) == 1
715 cd0d4d5a Michael Hanselmann
    return (self.request_body, {
716 cd0d4d5a Michael Hanselmann
      "group_name": self.items[0],
717 cd0d4d5a Michael Hanselmann
      "dry_run": self.dryRun(),
718 cd0d4d5a Michael Hanselmann
      })
719 0897dc97 Adeodato Simo
720 0897dc97 Adeodato Simo
721 87fd3ec7 Michael Hanselmann
class R_2_groups_name_assign_nodes(baserlib.OpcodeResource):
722 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/assign-nodes resource.
723 4245446f Adeodato Simo

724 4245446f Adeodato Simo
  """
725 87fd3ec7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupAssignNodes
726 4245446f Adeodato Simo
727 87fd3ec7 Michael Hanselmann
  def GetPutOpInput(self):
728 87fd3ec7 Michael Hanselmann
    """Assigns nodes to a group.
729 4245446f Adeodato Simo

730 4245446f Adeodato Simo
    """
731 87fd3ec7 Michael Hanselmann
    assert len(self.items) == 1
732 87fd3ec7 Michael Hanselmann
    return (self.request_body, {
733 4245446f Adeodato Simo
      "group_name": self.items[0],
734 4245446f Adeodato Simo
      "dry_run": self.dryRun(),
735 4245446f Adeodato Simo
      "force": self.useForce(),
736 4245446f Adeodato Simo
      })
737 4245446f Adeodato Simo
738 4245446f Adeodato Simo
739 09a43b39 Michael Hanselmann
class R_2_instances(baserlib.OpcodeResource):
740 09a43b39 Michael Hanselmann
  """/2/instances resource.
741 6395cebb Michael Hanselmann

742 6395cebb Michael Hanselmann
  """
743 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQuery
744 09a43b39 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceCreate
745 09a43b39 Michael Hanselmann
  POST_RENAME = {
746 526a662a Michael Hanselmann
    "os": "os_type",
747 526a662a Michael Hanselmann
    "name": "instance_name",
748 526a662a Michael Hanselmann
    }
749 526a662a Michael Hanselmann
750 441e7cfd Oleksiy Mishchenko
  def GET(self):
751 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
752 441e7cfd Oleksiy Mishchenko

753 441e7cfd Oleksiy Mishchenko
    """
754 be1ddd09 Michael Hanselmann
    client = self.GetClient()
755 441e7cfd Oleksiy Mishchenko
756 3d103742 Iustin Pop
    use_locking = self.useLocking()
757 3d103742 Iustin Pop
    if self.useBulk():
758 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
759 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
760 441e7cfd Oleksiy Mishchenko
    else:
761 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
762 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
763 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
764 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
765 441e7cfd Oleksiy Mishchenko
766 09a43b39 Michael Hanselmann
  def GetPostOpInput(self):
767 d975f482 Michael Hanselmann
    """Create an instance.
768 d975f482 Michael Hanselmann

769 d975f482 Michael Hanselmann
    @return: a job id
770 d975f482 Michael Hanselmann

771 d975f482 Michael Hanselmann
    """
772 09a43b39 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
773 d975f482 Michael Hanselmann
774 d975f482 Michael Hanselmann
    # Default to request data version 0
775 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
776 d975f482 Michael Hanselmann
777 d975f482 Michael Hanselmann
    if data_version == 0:
778 3fd7f652 Michael Hanselmann
      raise http.HttpBadRequest("Instance creation request version 0 is no"
779 3fd7f652 Michael Hanselmann
                                " longer supported")
780 09a43b39 Michael Hanselmann
    elif data_version != 1:
781 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
782 12eff9b9 Michael Hanselmann
                                data_version)
783 d975f482 Michael Hanselmann
784 09a43b39 Michael Hanselmann
    data = self.request_body.copy()
785 09a43b39 Michael Hanselmann
    # Remove "__version__"
786 09a43b39 Michael Hanselmann
    data.pop(_REQ_DATA_VERSION, None)
787 09a43b39 Michael Hanselmann
788 09a43b39 Michael Hanselmann
    return (data, {
789 09a43b39 Michael Hanselmann
      "dry_run": self.dryRun(),
790 09a43b39 Michael Hanselmann
      })
791 2f7635f4 Oleksiy Mishchenko
792 441e7cfd Oleksiy Mishchenko
793 a6fa7892 Michael Hanselmann
class R_2_instances_name(baserlib.OpcodeResource):
794 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name] resource.
795 028c6b76 Oleksiy Mishchenko

796 028c6b76 Oleksiy Mishchenko
  """
797 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQuery
798 a6fa7892 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpInstanceRemove
799 a6fa7892 Michael Hanselmann
800 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
801 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
802 4e5a68f8 Oleksiy Mishchenko

803 4e5a68f8 Oleksiy Mishchenko
    """
804 be1ddd09 Michael Hanselmann
    client = self.GetClient()
805 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
806 e8ebbd2b Michael Hanselmann
807 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
808 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
809 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
810 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
811 4e5a68f8 Oleksiy Mishchenko
812 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
813 028c6b76 Oleksiy Mishchenko
814 a6fa7892 Michael Hanselmann
  def GetDeleteOpInput(self):
815 6e99c5a0 Iustin Pop
    """Delete an instance.
816 6e99c5a0 Iustin Pop

817 6e99c5a0 Iustin Pop
    """
818 a6fa7892 Michael Hanselmann
    assert len(self.items) == 1
819 a6fa7892 Michael Hanselmann
    return ({}, {
820 a6fa7892 Michael Hanselmann
      "instance_name": self.items[0],
821 a6fa7892 Michael Hanselmann
      "ignore_failures": False,
822 a6fa7892 Michael Hanselmann
      "dry_run": self.dryRun(),
823 a6fa7892 Michael Hanselmann
      })
824 6e99c5a0 Iustin Pop
825 028c6b76 Oleksiy Mishchenko
826 7b3df961 Michael Hanselmann
class R_2_instances_name_info(baserlib.OpcodeResource):
827 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
828 d8260842 Michael Hanselmann

829 d8260842 Michael Hanselmann
  """
830 7b3df961 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQueryData
831 7b3df961 Michael Hanselmann
832 7b3df961 Michael Hanselmann
  def GetGetOpInput(self):
833 d8260842 Michael Hanselmann
    """Request detailed instance information.
834 d8260842 Michael Hanselmann

835 d8260842 Michael Hanselmann
    """
836 7b3df961 Michael Hanselmann
    assert len(self.items) == 1
837 7b3df961 Michael Hanselmann
    return ({}, {
838 7b3df961 Michael Hanselmann
      "instances": [self.items[0]],
839 7b3df961 Michael Hanselmann
      "static": bool(self._checkIntVariable("static", default=0)),
840 7b3df961 Michael Hanselmann
      })
841 d8260842 Michael Hanselmann
842 d8260842 Michael Hanselmann
843 ac4888c1 Michael Hanselmann
class R_2_instances_name_reboot(baserlib.OpcodeResource):
844 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
845 2276aa29 Oleksiy Mishchenko

846 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
847 2276aa29 Oleksiy Mishchenko

848 2276aa29 Oleksiy Mishchenko
  """
849 ac4888c1 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReboot
850 ac4888c1 Michael Hanselmann
851 ac4888c1 Michael Hanselmann
  def GetPostOpInput(self):
852 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
853 2276aa29 Oleksiy Mishchenko

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

857 2276aa29 Oleksiy Mishchenko
    """
858 ac4888c1 Michael Hanselmann
    return ({}, {
859 ac4888c1 Michael Hanselmann
      "instance_name": self.items[0],
860 ac4888c1 Michael Hanselmann
      "reboot_type":
861 ac4888c1 Michael Hanselmann
        self.queryargs.get("type", [constants.INSTANCE_REBOOT_HARD])[0],
862 ac4888c1 Michael Hanselmann
      "ignore_secondaries": bool(self._checkIntVariable("ignore_secondaries")),
863 ac4888c1 Michael Hanselmann
      "dry_run": self.dryRun(),
864 ac4888c1 Michael Hanselmann
      })
865 2276aa29 Oleksiy Mishchenko
866 2276aa29 Oleksiy Mishchenko
867 4717e6eb Michael Hanselmann
class R_2_instances_name_startup(baserlib.OpcodeResource):
868 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
869 0c55c24b Oleksiy Mishchenko

870 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
871 0c55c24b Oleksiy Mishchenko

872 0c55c24b Oleksiy Mishchenko
  """
873 4717e6eb Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceStartup
874 4717e6eb Michael Hanselmann
875 4717e6eb Michael Hanselmann
  def GetPutOpInput(self):
876 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
877 0c55c24b Oleksiy Mishchenko

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

881 0c55c24b Oleksiy Mishchenko
    """
882 4717e6eb Michael Hanselmann
    return ({}, {
883 4717e6eb Michael Hanselmann
      "instance_name": self.items[0],
884 4717e6eb Michael Hanselmann
      "force": self.useForce(),
885 4717e6eb Michael Hanselmann
      "dry_run": self.dryRun(),
886 4717e6eb Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
887 4717e6eb Michael Hanselmann
      })
888 0c55c24b Oleksiy Mishchenko
889 0c55c24b Oleksiy Mishchenko
890 3175ade6 Michael Hanselmann
class R_2_instances_name_shutdown(baserlib.OpcodeResource):
891 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
892 0c55c24b Oleksiy Mishchenko

893 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
894 0c55c24b Oleksiy Mishchenko

895 0c55c24b Oleksiy Mishchenko
  """
896 3175ade6 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceShutdown
897 0c55c24b Oleksiy Mishchenko
898 3175ade6 Michael Hanselmann
  def GetPutOpInput(self):
899 3175ade6 Michael Hanselmann
    """Shutdown an instance.
900 7fa310f6 René Nussbaumer

901 0c55c24b Oleksiy Mishchenko
    """
902 3175ade6 Michael Hanselmann
    return (self.request_body, {
903 3175ade6 Michael Hanselmann
      "instance_name": self.items[0],
904 3175ade6 Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
905 3175ade6 Michael Hanselmann
      "dry_run": self.dryRun(),
906 3175ade6 Michael Hanselmann
      })
907 0c55c24b Oleksiy Mishchenko
908 0c55c24b Oleksiy Mishchenko
909 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
910 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
911 c744425f Michael Hanselmann

912 c744425f Michael Hanselmann
  """
913 c744425f Michael Hanselmann
  if not isinstance(data, dict):
914 c744425f Michael Hanselmann
    raise http.HttpBadRequest("Invalid body contents, not a dictionary")
915 c744425f Michael Hanselmann
916 bd0807fe Guido Trotter
  ostype = baserlib.CheckParameter(data, "os", default=None)
917 c744425f Michael Hanselmann
  start = baserlib.CheckParameter(data, "start", exptype=bool,
918 c744425f Michael Hanselmann
                                  default=True)
919 c744425f Michael Hanselmann
  osparams = baserlib.CheckParameter(data, "osparams", default=None)
920 c744425f Michael Hanselmann
921 c744425f Michael Hanselmann
  ops = [
922 ee3e37a7 Iustin Pop
    opcodes.OpInstanceShutdown(instance_name=name),
923 5073fd8f Iustin Pop
    opcodes.OpInstanceReinstall(instance_name=name, os_type=ostype,
924 c744425f Michael Hanselmann
                                osparams=osparams),
925 c744425f Michael Hanselmann
    ]
926 c744425f Michael Hanselmann
927 c744425f Michael Hanselmann
  if start:
928 c873d91c Iustin Pop
    ops.append(opcodes.OpInstanceStartup(instance_name=name, force=False))
929 c744425f Michael Hanselmann
930 c744425f Michael Hanselmann
  return ops
931 c744425f Michael Hanselmann
932 c744425f Michael Hanselmann
933 f6ce0ba2 Michael Hanselmann
class R_2_instances_name_reinstall(baserlib.OpcodeResource):
934 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
935 e5b7c4ca Iustin Pop

936 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
937 e5b7c4ca Iustin Pop

938 e5b7c4ca Iustin Pop
  """
939 f6ce0ba2 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReinstall
940 f6ce0ba2 Michael Hanselmann
941 e5b7c4ca Iustin Pop
  def POST(self):
942 e5b7c4ca Iustin Pop
    """Reinstall an instance.
943 e5b7c4ca Iustin Pop

944 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
945 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
946 e5b7c4ca Iustin Pop
    automatically.
947 e5b7c4ca Iustin Pop

948 e5b7c4ca Iustin Pop
    """
949 c744425f Michael Hanselmann
    if self.request_body:
950 c744425f Michael Hanselmann
      if self.queryargs:
951 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
952 c744425f Michael Hanselmann
953 c744425f Michael Hanselmann
      body = self.request_body
954 bd0807fe Guido Trotter
    elif self.queryargs:
955 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
956 c744425f Michael Hanselmann
      body = {
957 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
958 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
959 c744425f Michael Hanselmann
        }
960 bd0807fe Guido Trotter
    else:
961 bd0807fe Guido Trotter
      body = {}
962 c744425f Michael Hanselmann
963 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
964 c744425f Michael Hanselmann
965 be1ddd09 Michael Hanselmann
    return self.SubmitJob(ops)
966 e5b7c4ca Iustin Pop
967 e5b7c4ca Iustin Pop
968 0dbc732c Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.OpcodeResource):
969 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
970 4c98b915 Michael Hanselmann

971 4c98b915 Michael Hanselmann
  """
972 0dbc732c Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReplaceDisks
973 0dbc732c Michael Hanselmann
974 0dbc732c Michael Hanselmann
  def GetPostOpInput(self):
975 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
976 4c98b915 Michael Hanselmann

977 4c98b915 Michael Hanselmann
    """
978 0dbc732c Michael Hanselmann
    data = self.request_body.copy()
979 0dbc732c Michael Hanselmann
    static = {
980 0dbc732c Michael Hanselmann
      "instance_name": self.items[0],
981 0dbc732c Michael Hanselmann
      }
982 4c98b915 Michael Hanselmann
983 0dbc732c Michael Hanselmann
    # Parse disks
984 0dbc732c Michael Hanselmann
    try:
985 0dbc732c Michael Hanselmann
      raw_disks = data["disks"]
986 0dbc732c Michael Hanselmann
    except KeyError:
987 0dbc732c Michael Hanselmann
      pass
988 0dbc732c Michael Hanselmann
    else:
989 471a31b6 Andrea Spadaccini
      if not ht.TListOf(ht.TInt)(raw_disks): # pylint: disable=E1102
990 0dbc732c Michael Hanselmann
        # Backwards compatibility for strings of the format "1, 2, 3"
991 0dbc732c Michael Hanselmann
        try:
992 0dbc732c Michael Hanselmann
          data["disks"] = [int(part) for part in raw_disks.split(",")]
993 0dbc732c Michael Hanselmann
        except (TypeError, ValueError), err:
994 0dbc732c Michael Hanselmann
          raise http.HttpBadRequest("Invalid disk index passed: %s" % err)
995 0dbc732c Michael Hanselmann
996 0dbc732c Michael Hanselmann
    return (data, static)
997 4c98b915 Michael Hanselmann
998 4c98b915 Michael Hanselmann
999 1824a7a1 Michael Hanselmann
class R_2_instances_name_activate_disks(baserlib.OpcodeResource):
1000 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1001 2197b66f René Nussbaumer

1002 2197b66f René Nussbaumer
  """
1003 1824a7a1 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceActivateDisks
1004 1824a7a1 Michael Hanselmann
1005 1824a7a1 Michael Hanselmann
  def GetPutOpInput(self):
1006 2197b66f René Nussbaumer
    """Activate disks for an instance.
1007 2197b66f René Nussbaumer

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

1010 2197b66f René Nussbaumer
    """
1011 1824a7a1 Michael Hanselmann
    return ({}, {
1012 1824a7a1 Michael Hanselmann
      "instance_name": self.items[0],
1013 1824a7a1 Michael Hanselmann
      "ignore_size": bool(self._checkIntVariable("ignore_size")),
1014 1824a7a1 Michael Hanselmann
      })
1015 2197b66f René Nussbaumer
1016 2197b66f René Nussbaumer
1017 973ec124 Michael Hanselmann
class R_2_instances_name_deactivate_disks(baserlib.OpcodeResource):
1018 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1019 0a37de5f René Nussbaumer

1020 0a37de5f René Nussbaumer
  """
1021 973ec124 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceDeactivateDisks
1022 973ec124 Michael Hanselmann
1023 973ec124 Michael Hanselmann
  def GetPutOpInput(self):
1024 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1025 0a37de5f René Nussbaumer

1026 0a37de5f René Nussbaumer
    """
1027 973ec124 Michael Hanselmann
    return ({}, {
1028 973ec124 Michael Hanselmann
      "instance_name": self.items[0],
1029 973ec124 Michael Hanselmann
      })
1030 0a37de5f René Nussbaumer
1031 0a37de5f René Nussbaumer
1032 a52978c7 Michael Hanselmann
class R_2_instances_name_recreate_disks(baserlib.OpcodeResource):
1033 a52978c7 Michael Hanselmann
  """/2/instances/[instance_name]/recreate-disks resource.
1034 a52978c7 Michael Hanselmann

1035 a52978c7 Michael Hanselmann
  """
1036 a52978c7 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceRecreateDisks
1037 a52978c7 Michael Hanselmann
1038 a52978c7 Michael Hanselmann
  def GetPostOpInput(self):
1039 a52978c7 Michael Hanselmann
    """Recreate disks for an instance.
1040 a52978c7 Michael Hanselmann

1041 a52978c7 Michael Hanselmann
    """
1042 a52978c7 Michael Hanselmann
    return ({}, {
1043 a52978c7 Michael Hanselmann
      "instance_name": self.items[0],
1044 a52978c7 Michael Hanselmann
      })
1045 a52978c7 Michael Hanselmann
1046 a52978c7 Michael Hanselmann
1047 1c63311d Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.OpcodeResource):
1048 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1049 ebeb600f Michael Hanselmann

1050 ebeb600f Michael Hanselmann
  """
1051 1c63311d Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupPrepare
1052 ebeb600f Michael Hanselmann
1053 1c63311d Michael Hanselmann
  def GetPutOpInput(self):
1054 1c63311d Michael Hanselmann
    """Prepares an export for an instance.
1055 ebeb600f Michael Hanselmann

1056 ebeb600f Michael Hanselmann
    """
1057 1c63311d Michael Hanselmann
    return ({}, {
1058 1c63311d Michael Hanselmann
      "instance_name": self.items[0],
1059 1c63311d Michael Hanselmann
      "mode": self._checkStringVariable("mode"),
1060 1c63311d Michael Hanselmann
      })
1061 ebeb600f Michael Hanselmann
1062 ebeb600f Michael Hanselmann
1063 134afbe7 Michael Hanselmann
class R_2_instances_name_export(baserlib.OpcodeResource):
1064 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1065 ebeb600f Michael Hanselmann

1066 ebeb600f Michael Hanselmann
  """
1067 134afbe7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupExport
1068 134afbe7 Michael Hanselmann
  PUT_RENAME = {
1069 134afbe7 Michael Hanselmann
    "destination": "target_node",
1070 134afbe7 Michael Hanselmann
    }
1071 ebeb600f Michael Hanselmann
1072 134afbe7 Michael Hanselmann
  def GetPutOpInput(self):
1073 134afbe7 Michael Hanselmann
    """Exports an instance.
1074 ebeb600f Michael Hanselmann

1075 ebeb600f Michael Hanselmann
    """
1076 134afbe7 Michael Hanselmann
    return (self.request_body, {
1077 134afbe7 Michael Hanselmann
      "instance_name": self.items[0],
1078 134afbe7 Michael Hanselmann
      })
1079 ebeb600f Michael Hanselmann
1080 ebeb600f Michael Hanselmann
1081 075a29be Michael Hanselmann
class R_2_instances_name_migrate(baserlib.OpcodeResource):
1082 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1083 5823e0d2 Michael Hanselmann

1084 5823e0d2 Michael Hanselmann
  """
1085 075a29be Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceMigrate
1086 5823e0d2 Michael Hanselmann
1087 075a29be Michael Hanselmann
  def GetPutOpInput(self):
1088 075a29be Michael Hanselmann
    """Migrates an instance.
1089 5823e0d2 Michael Hanselmann

1090 5823e0d2 Michael Hanselmann
    """
1091 075a29be Michael Hanselmann
    return (self.request_body, {
1092 075a29be Michael Hanselmann
      "instance_name": self.items[0],
1093 075a29be Michael Hanselmann
      })
1094 5823e0d2 Michael Hanselmann
1095 5823e0d2 Michael Hanselmann
1096 b5f2ab80 Michael Hanselmann
class R_2_instances_name_failover(baserlib.OpcodeResource):
1097 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1098 c0a146a1 Michael Hanselmann

1099 c0a146a1 Michael Hanselmann
  """
1100 b5f2ab80 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceFailover
1101 c0a146a1 Michael Hanselmann
1102 b5f2ab80 Michael Hanselmann
  def GetPutOpInput(self):
1103 b5f2ab80 Michael Hanselmann
    """Does a failover of an instance.
1104 c0a146a1 Michael Hanselmann

1105 c0a146a1 Michael Hanselmann
    """
1106 b5f2ab80 Michael Hanselmann
    return (self.request_body, {
1107 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1108 c0a146a1 Michael Hanselmann
      })
1109 c0a146a1 Michael Hanselmann
1110 c0a146a1 Michael Hanselmann
1111 d76f9b5d Michael Hanselmann
class R_2_instances_name_rename(baserlib.OpcodeResource):
1112 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1113 d56e7dc7 Michael Hanselmann

1114 d56e7dc7 Michael Hanselmann
  """
1115 d76f9b5d Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceRename
1116 d56e7dc7 Michael Hanselmann
1117 d76f9b5d Michael Hanselmann
  def GetPutOpInput(self):
1118 d76f9b5d Michael Hanselmann
    """Changes the name of an instance.
1119 d56e7dc7 Michael Hanselmann

1120 d56e7dc7 Michael Hanselmann
    """
1121 d76f9b5d Michael Hanselmann
    return (self.request_body, {
1122 d76f9b5d Michael Hanselmann
      "instance_name": self.items[0],
1123 d76f9b5d Michael Hanselmann
      })
1124 d56e7dc7 Michael Hanselmann
1125 d56e7dc7 Michael Hanselmann
1126 f3db88ba Michael Hanselmann
class R_2_instances_name_modify(baserlib.OpcodeResource):
1127 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1128 3882937a Michael Hanselmann

1129 3882937a Michael Hanselmann
  """
1130 f3db88ba Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceSetParams
1131 3882937a Michael Hanselmann
1132 f3db88ba Michael Hanselmann
  def GetPutOpInput(self):
1133 f3db88ba Michael Hanselmann
    """Changes parameters of an instance.
1134 3882937a Michael Hanselmann

1135 3882937a Michael Hanselmann
    """
1136 f3db88ba Michael Hanselmann
    return (self.request_body, {
1137 f3db88ba Michael Hanselmann
      "instance_name": self.items[0],
1138 f3db88ba Michael Hanselmann
      })
1139 3882937a Michael Hanselmann
1140 3882937a Michael Hanselmann
1141 335965b9 Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.OpcodeResource):
1142 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1143 e23881ed Michael Hanselmann

1144 e23881ed Michael Hanselmann
  """
1145 335965b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceGrowDisk
1146 e23881ed Michael Hanselmann
1147 335965b9 Michael Hanselmann
  def GetPostOpInput(self):
1148 335965b9 Michael Hanselmann
    """Increases the size of an instance disk.
1149 e23881ed Michael Hanselmann

1150 e23881ed Michael Hanselmann
    """
1151 335965b9 Michael Hanselmann
    return (self.request_body, {
1152 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1153 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1154 e23881ed Michael Hanselmann
      })
1155 e23881ed Michael Hanselmann
1156 e23881ed Michael Hanselmann
1157 26ff6ee2 Michael Hanselmann
class R_2_instances_name_console(baserlib.ResourceBase):
1158 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1159 b82d4c5e Michael Hanselmann

1160 b82d4c5e Michael Hanselmann
  """
1161 b82d4c5e Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1162 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceConsole
1163 b82d4c5e Michael Hanselmann
1164 b82d4c5e Michael Hanselmann
  def GET(self):
1165 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1166 b82d4c5e Michael Hanselmann

1167 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1168 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1169 b82d4c5e Michael Hanselmann

1170 b82d4c5e Michael Hanselmann
    """
1171 be1ddd09 Michael Hanselmann
    client = self.GetClient()
1172 b82d4c5e Michael Hanselmann
1173 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1174 b82d4c5e Michael Hanselmann
1175 b82d4c5e Michael Hanselmann
    if console is None:
1176 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1177 b82d4c5e Michael Hanselmann
1178 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1179 b82d4c5e Michael Hanselmann
    return console
1180 b82d4c5e Michael Hanselmann
1181 b82d4c5e Michael Hanselmann
1182 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1183 208a6cff Michael Hanselmann
  """
1184 208a6cff Michael Hanselmann

1185 208a6cff Michael Hanselmann
  """
1186 208a6cff Michael Hanselmann
  try:
1187 208a6cff Michael Hanselmann
    fields = args["fields"]
1188 208a6cff Michael Hanselmann
  except KeyError:
1189 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1190 208a6cff Michael Hanselmann
1191 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1192 208a6cff Michael Hanselmann
1193 208a6cff Michael Hanselmann
1194 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1195 208a6cff Michael Hanselmann
  """
1196 208a6cff Michael Hanselmann

1197 208a6cff Michael Hanselmann
  """
1198 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1199 208a6cff Michael Hanselmann
1200 208a6cff Michael Hanselmann
1201 26ff6ee2 Michael Hanselmann
class R_2_query(baserlib.ResourceBase):
1202 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1203 208a6cff Michael Hanselmann

1204 208a6cff Michael Hanselmann
  """
1205 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1206 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1207 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpQuery
1208 f6ce0ba2 Michael Hanselmann
  PUT_OPCODE = opcodes.OpQuery
1209 208a6cff Michael Hanselmann
1210 2e5c33db Iustin Pop
  def _Query(self, fields, qfilter):
1211 2e5c33db Iustin Pop
    return self.GetClient().Query(self.items[0], fields, qfilter).ToDict()
1212 208a6cff Michael Hanselmann
1213 208a6cff Michael Hanselmann
  def GET(self):
1214 208a6cff Michael Hanselmann
    """Returns resource information.
1215 208a6cff Michael Hanselmann

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

1218 208a6cff Michael Hanselmann
    """
1219 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1220 208a6cff Michael Hanselmann
1221 208a6cff Michael Hanselmann
  def PUT(self):
1222 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1223 208a6cff Michael Hanselmann

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

1226 208a6cff Michael Hanselmann
    """
1227 208a6cff Michael Hanselmann
    body = self.request_body
1228 208a6cff Michael Hanselmann
1229 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1230 208a6cff Michael Hanselmann
1231 208a6cff Michael Hanselmann
    try:
1232 208a6cff Michael Hanselmann
      fields = body["fields"]
1233 208a6cff Michael Hanselmann
    except KeyError:
1234 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1235 208a6cff Michael Hanselmann
1236 2e5c33db Iustin Pop
    qfilter = body.get("qfilter", None)
1237 2e5c33db Iustin Pop
    # TODO: remove this after 2.7
1238 2e5c33db Iustin Pop
    if qfilter is None:
1239 2e5c33db Iustin Pop
      qfilter = body.get("filter", None)
1240 2e5c33db Iustin Pop
1241 2e5c33db Iustin Pop
    return self._Query(fields, qfilter)
1242 208a6cff Michael Hanselmann
1243 208a6cff Michael Hanselmann
1244 26ff6ee2 Michael Hanselmann
class R_2_query_fields(baserlib.ResourceBase):
1245 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1246 208a6cff Michael Hanselmann

1247 208a6cff Michael Hanselmann
  """
1248 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpQueryFields
1249 f6ce0ba2 Michael Hanselmann
1250 208a6cff Michael Hanselmann
  def GET(self):
1251 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1252 208a6cff Michael Hanselmann

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

1255 208a6cff Michael Hanselmann
    """
1256 208a6cff Michael Hanselmann
    try:
1257 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1258 208a6cff Michael Hanselmann
    except KeyError:
1259 208a6cff Michael Hanselmann
      fields = None
1260 208a6cff Michael Hanselmann
    else:
1261 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1262 208a6cff Michael Hanselmann
1263 be1ddd09 Michael Hanselmann
    return self.GetClient().QueryFields(self.items[0], fields).ToDict()
1264 208a6cff Michael Hanselmann
1265 208a6cff Michael Hanselmann
1266 460ef073 Michael Hanselmann
class _R_Tags(baserlib.OpcodeResource):
1267 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1268 441e7cfd Oleksiy Mishchenko

1269 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1270 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1271 441e7cfd Oleksiy Mishchenko

1272 441e7cfd Oleksiy Mishchenko
  """
1273 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1274 f6ce0ba2 Michael Hanselmann
  GET_OPCODE = opcodes.OpTagsGet
1275 460ef073 Michael Hanselmann
  PUT_OPCODE = opcodes.OpTagsSet
1276 460ef073 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpTagsDel
1277 18cb43a2 Oleksiy Mishchenko
1278 460ef073 Michael Hanselmann
  def __init__(self, items, queryargs, req, **kwargs):
1279 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1280 18cb43a2 Oleksiy Mishchenko

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

1283 18cb43a2 Oleksiy Mishchenko
    """
1284 460ef073 Michael Hanselmann
    baserlib.OpcodeResource.__init__(self, items, queryargs, req, **kwargs)
1285 18cb43a2 Oleksiy Mishchenko
1286 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1287 5313eed7 Michael Hanselmann
      self.name = None
1288 18cb43a2 Oleksiy Mishchenko
    else:
1289 5313eed7 Michael Hanselmann
      self.name = items[0]
1290 441e7cfd Oleksiy Mishchenko
1291 441e7cfd Oleksiy Mishchenko
  def GET(self):
1292 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1293 441e7cfd Oleksiy Mishchenko

1294 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1295 441e7cfd Oleksiy Mishchenko

1296 441e7cfd Oleksiy Mishchenko
    """
1297 f87ec53f Michael Hanselmann
    kind = self.TAG_LEVEL
1298 f87ec53f Michael Hanselmann
1299 f87ec53f Michael Hanselmann
    if kind in (constants.TAG_INSTANCE,
1300 f87ec53f Michael Hanselmann
                constants.TAG_NODEGROUP,
1301 f87ec53f Michael Hanselmann
                constants.TAG_NODE):
1302 f87ec53f Michael Hanselmann
      if not self.name:
1303 f87ec53f Michael Hanselmann
        raise http.HttpBadRequest("Missing name on tag request")
1304 f87ec53f Michael Hanselmann
1305 be1ddd09 Michael Hanselmann
      cl = self.GetClient()
1306 f87ec53f Michael Hanselmann
      if kind == constants.TAG_INSTANCE:
1307 f87ec53f Michael Hanselmann
        fn = cl.QueryInstances
1308 f87ec53f Michael Hanselmann
      elif kind == constants.TAG_NODEGROUP:
1309 f87ec53f Michael Hanselmann
        fn = cl.QueryGroups
1310 f87ec53f Michael Hanselmann
      else:
1311 f87ec53f Michael Hanselmann
        fn = cl.QueryNodes
1312 f87ec53f Michael Hanselmann
      result = fn(names=[self.name], fields=["tags"], use_locking=False)
1313 f87ec53f Michael Hanselmann
      if not result or not result[0]:
1314 f87ec53f Michael Hanselmann
        raise http.HttpBadGateway("Invalid response from tag query")
1315 f87ec53f Michael Hanselmann
      tags = result[0][0]
1316 f87ec53f Michael Hanselmann
1317 f87ec53f Michael Hanselmann
    elif kind == constants.TAG_CLUSTER:
1318 f87ec53f Michael Hanselmann
      assert not self.name
1319 f87ec53f Michael Hanselmann
      # TODO: Use query API?
1320 f87ec53f Michael Hanselmann
      ssc = ssconf.SimpleStore()
1321 f87ec53f Michael Hanselmann
      tags = ssc.GetClusterTags()
1322 f87ec53f Michael Hanselmann
1323 f87ec53f Michael Hanselmann
    return list(tags)
1324 441e7cfd Oleksiy Mishchenko
1325 460ef073 Michael Hanselmann
  def GetPutOpInput(self):
1326 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1327 441e7cfd Oleksiy Mishchenko

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

1331 441e7cfd Oleksiy Mishchenko
    """
1332 460ef073 Michael Hanselmann
    return ({}, {
1333 460ef073 Michael Hanselmann
      "kind": self.TAG_LEVEL,
1334 460ef073 Michael Hanselmann
      "name": self.name,
1335 460ef073 Michael Hanselmann
      "tags": self.queryargs.get("tag", []),
1336 460ef073 Michael Hanselmann
      "dry_run": self.dryRun(),
1337 460ef073 Michael Hanselmann
      })
1338 15fd9fd5 Oleksiy Mishchenko
1339 460ef073 Michael Hanselmann
  def GetDeleteOpInput(self):
1340 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1341 15fd9fd5 Oleksiy Mishchenko

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

1346 15fd9fd5 Oleksiy Mishchenko
    """
1347 460ef073 Michael Hanselmann
    # Re-use code
1348 460ef073 Michael Hanselmann
    return self.GetPutOpInput()
1349 18cb43a2 Oleksiy Mishchenko
1350 18cb43a2 Oleksiy Mishchenko
1351 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1352 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1353 18cb43a2 Oleksiy Mishchenko

1354 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1355 18cb43a2 Oleksiy Mishchenko

1356 18cb43a2 Oleksiy Mishchenko
  """
1357 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1358 18cb43a2 Oleksiy Mishchenko
1359 18cb43a2 Oleksiy Mishchenko
1360 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1361 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1362 18cb43a2 Oleksiy Mishchenko

1363 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1364 18cb43a2 Oleksiy Mishchenko

1365 18cb43a2 Oleksiy Mishchenko
  """
1366 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1367 18cb43a2 Oleksiy Mishchenko
1368 18cb43a2 Oleksiy Mishchenko
1369 414ebaf1 Michael Hanselmann
class R_2_groups_name_tags(_R_Tags):
1370 414ebaf1 Michael Hanselmann
  """ /2/groups/[group_name]/tags resource.
1371 414ebaf1 Michael Hanselmann

1372 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1373 414ebaf1 Michael Hanselmann

1374 414ebaf1 Michael Hanselmann
  """
1375 414ebaf1 Michael Hanselmann
  TAG_LEVEL = constants.TAG_NODEGROUP
1376 414ebaf1 Michael Hanselmann
1377 414ebaf1 Michael Hanselmann
1378 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1379 b58a4d16 Michael Hanselmann
  """ /2/tags resource.
1380 18cb43a2 Oleksiy Mishchenko

1381 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1382 18cb43a2 Oleksiy Mishchenko

1383 18cb43a2 Oleksiy Mishchenko
  """
1384 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER