Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 132cdb87

History | View | Annotate | Download (32.1 kB)

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

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

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

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

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

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

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

52 10b207d4 Oleksiy Mishchenko
"""
53 10b207d4 Oleksiy Mishchenko
54 fe267188 Iustin Pop
# pylint: disable-msg=C0103
55 fe267188 Iustin Pop
56 fe267188 Iustin Pop
# C0103: Invalid name, since the R_* names are not conforming
57 fe267188 Iustin Pop
58 59b4eeef Iustin Pop
from ganeti import opcodes
59 15fd9fd5 Oleksiy Mishchenko
from ganeti import http
60 15fd9fd5 Oleksiy Mishchenko
from ganeti import constants
61 59b4eeef Iustin Pop
from ganeti import cli
62 8381fa2d Michael Hanselmann
from ganeti import rapi
63 d1c172de Michael Hanselmann
from ganeti import ht
64 e987f166 Michael Hanselmann
from ganeti import compat
65 be1ddd09 Michael Hanselmann
from ganeti import ssconf
66 38206f3c Iustin Pop
from ganeti.rapi import baserlib
67 10b207d4 Oleksiy Mishchenko
68 4e5a68f8 Oleksiy Mishchenko
69 7118a0df Iustin Pop
_COMMON_FIELDS = ["ctime", "mtime", "uuid", "serial_no", "tags"]
70 9031ee8e Iustin Pop
I_FIELDS = ["name", "admin_state", "os",
71 9031ee8e Iustin Pop
            "pnode", "snodes",
72 9031ee8e Iustin Pop
            "disk_template",
73 82e186f8 Michael Hanselmann
            "nic.ips", "nic.macs", "nic.modes", "nic.links", "nic.bridges",
74 a8b16c4e Tim Boring
            "network_port",
75 024e157f Iustin Pop
            "disk.sizes", "disk_usage",
76 a5b9d725 Iustin Pop
            "beparams", "hvparams",
77 4ea3de4e Balazs Lecz
            "oper_state", "oper_ram", "oper_vcpus", "status",
78 90224407 Iustin Pop
            "custom_hvparams", "custom_beparams", "custom_nicparams",
79 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
80 9031ee8e Iustin Pop
81 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
82 9031ee8e Iustin Pop
            "dtotal", "dfree",
83 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
84 7118a0df Iustin Pop
            "pinst_cnt", "sinst_cnt",
85 0105bad3 Iustin Pop
            "ctotal", "cnodes", "csockets",
86 7118a0df Iustin Pop
            "pip", "sip", "role",
87 93962b80 Iustin Pop
            "pinst_list", "sinst_list",
88 c190e817 Iustin Pop
            "master_capable", "vm_capable",
89 fd254195 Iustin Pop
            "group.uuid",
90 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
91 4e5a68f8 Oleksiy Mishchenko
92 f4e86448 Michael Hanselmann
G_FIELDS = [
93 f4e86448 Michael Hanselmann
  "alloc_policy",
94 f4e86448 Michael Hanselmann
  "name",
95 f4e86448 Michael Hanselmann
  "node_cnt",
96 f4e86448 Michael Hanselmann
  "node_list",
97 f4e86448 Michael Hanselmann
  ] + _COMMON_FIELDS
98 0897dc97 Adeodato Simo
99 bd7b2070 Michael Hanselmann
J_FIELDS_BULK = [
100 e987f166 Michael Hanselmann
  "id", "ops", "status", "summary",
101 bd7b2070 Michael Hanselmann
  "opstatus",
102 e987f166 Michael Hanselmann
  "received_ts", "start_ts", "end_ts",
103 e987f166 Michael Hanselmann
  ]
104 e987f166 Michael Hanselmann
105 bd7b2070 Michael Hanselmann
J_FIELDS = J_FIELDS_BULK + [
106 bd7b2070 Michael Hanselmann
  "oplog",
107 bd7b2070 Michael Hanselmann
  "opresult",
108 bd7b2070 Michael Hanselmann
  ]
109 bd7b2070 Michael Hanselmann
110 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
111 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 26ff6ee2 Michael Hanselmann
class R_2_info(baserlib.ResourceBase):
186 b58a4d16 Michael Hanselmann
  """/2/info resource.
187 4e5a68f8 Oleksiy Mishchenko

188 4e5a68f8 Oleksiy Mishchenko
  """
189 be1ddd09 Michael Hanselmann
  def GET(self):
190 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
191 4e5a68f8 Oleksiy Mishchenko

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

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

205 7eac4a4d Michael Hanselmann
    """
206 b4fcee5b Michael Hanselmann
    return list(ALL_FEATURES)
207 7eac4a4d Michael Hanselmann
208 7eac4a4d Michael Hanselmann
209 26ff6ee2 Michael Hanselmann
class R_2_os(baserlib.ResourceBase):
210 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
211 4e5a68f8 Oleksiy Mishchenko

212 4e5a68f8 Oleksiy Mishchenko
  """
213 be1ddd09 Michael Hanselmann
  def GET(self):
214 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
215 4e5a68f8 Oleksiy Mishchenko

216 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
217 4e5a68f8 Oleksiy Mishchenko

218 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
219 4e5a68f8 Oleksiy Mishchenko

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

241 508e9b20 Michael Hanselmann
  """
242 8fd625fc Michael Hanselmann
  PUT_OPCODE = opcodes.OpClusterRedistConf
243 508e9b20 Michael Hanselmann
244 508e9b20 Michael Hanselmann
245 50c7d82e Michael Hanselmann
class R_2_cluster_modify(baserlib.OpcodeResource):
246 62e999a5 Michael Hanselmann
  """/2/modify resource.
247 62e999a5 Michael Hanselmann

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

255 10b207d4 Oleksiy Mishchenko
  """
256 e987f166 Michael Hanselmann
  def GET(self):
257 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
258 10b207d4 Oleksiy Mishchenko

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

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

276 10b207d4 Oleksiy Mishchenko
  """
277 10b207d4 Oleksiy Mishchenko
  def GET(self):
278 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
279 10b207d4 Oleksiy Mishchenko

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

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

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

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

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

357 10b207d4 Oleksiy Mishchenko
  """
358 10b207d4 Oleksiy Mishchenko
  def GET(self):
359 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
360 38206f3c Iustin Pop

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

377 028c6b76 Oleksiy Mishchenko
  """
378 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
379 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
380 4e5a68f8 Oleksiy Mishchenko

381 4e5a68f8 Oleksiy Mishchenko
    """
382 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
383 be1ddd09 Michael Hanselmann
    client = self.GetClient()
384 e8ebbd2b Michael Hanselmann
385 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
386 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
387 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
388 4e5a68f8 Oleksiy Mishchenko
389 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
390 028c6b76 Oleksiy Mishchenko
391 028c6b76 Oleksiy Mishchenko
392 51cc8637 Michael Hanselmann
class R_2_nodes_name_role(baserlib.OpcodeResource):
393 51cc8637 Michael Hanselmann
  """/2/nodes/[node_name]/role resource.
394 64dae8fc Michael Hanselmann

395 64dae8fc Michael Hanselmann
  """
396 51cc8637 Michael Hanselmann
  PUT_OPCODE = opcodes.OpNodeSetParams
397 51cc8637 Michael Hanselmann
398 64dae8fc Michael Hanselmann
  def GET(self):
399 64dae8fc Michael Hanselmann
    """Returns the current node role.
400 64dae8fc Michael Hanselmann

401 64dae8fc Michael Hanselmann
    @return: Node role
402 64dae8fc Michael Hanselmann

403 64dae8fc Michael Hanselmann
    """
404 64dae8fc Michael Hanselmann
    node_name = self.items[0]
405 be1ddd09 Michael Hanselmann
    client = self.GetClient()
406 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
407 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
408 64dae8fc Michael Hanselmann
409 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
410 64dae8fc Michael Hanselmann
411 51cc8637 Michael Hanselmann
  def GetPutOpInput(self):
412 64dae8fc Michael Hanselmann
    """Sets the node role.
413 64dae8fc Michael Hanselmann

414 64dae8fc Michael Hanselmann
    """
415 51cc8637 Michael Hanselmann
    baserlib.CheckType(self.request_body, basestring, "Body contents")
416 64dae8fc Michael Hanselmann
417 627ad739 Michael Hanselmann
    role = self.request_body
418 64dae8fc Michael Hanselmann
419 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
420 64dae8fc Michael Hanselmann
      candidate = False
421 64dae8fc Michael Hanselmann
      offline = False
422 64dae8fc Michael Hanselmann
      drained = False
423 64dae8fc Michael Hanselmann
424 51cc8637 Michael Hanselmann
    elif role == _NR_MASTER_CANDIDATE:
425 64dae8fc Michael Hanselmann
      candidate = True
426 64dae8fc Michael Hanselmann
      offline = drained = None
427 64dae8fc Michael Hanselmann
428 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
429 64dae8fc Michael Hanselmann
      drained = True
430 64dae8fc Michael Hanselmann
      candidate = offline = None
431 64dae8fc Michael Hanselmann
432 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
433 64dae8fc Michael Hanselmann
      offline = True
434 64dae8fc Michael Hanselmann
      candidate = drained = None
435 64dae8fc Michael Hanselmann
436 64dae8fc Michael Hanselmann
    else:
437 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
438 64dae8fc Michael Hanselmann
439 51cc8637 Michael Hanselmann
    assert len(self.items) == 1
440 64dae8fc Michael Hanselmann
441 51cc8637 Michael Hanselmann
    return ({}, {
442 51cc8637 Michael Hanselmann
      "node_name": self.items[0],
443 51cc8637 Michael Hanselmann
      "master_candidate": candidate,
444 51cc8637 Michael Hanselmann
      "offline": offline,
445 51cc8637 Michael Hanselmann
      "drained": drained,
446 51cc8637 Michael Hanselmann
      "force": self.useForce(),
447 51cc8637 Michael Hanselmann
      })
448 64dae8fc Michael Hanselmann
449 64dae8fc Michael Hanselmann
450 7fa91722 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.OpcodeResource):
451 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
452 73452f12 Michael Hanselmann

453 73452f12 Michael Hanselmann
  """
454 7fa91722 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodeEvacuate
455 7fa91722 Michael Hanselmann
456 7fa91722 Michael Hanselmann
  def GetPostOpInput(self):
457 de40437a Michael Hanselmann
    """Evacuate all instances off a node.
458 73452f12 Michael Hanselmann

459 73452f12 Michael Hanselmann
    """
460 7fa91722 Michael Hanselmann
    return (self.request_body, {
461 de40437a Michael Hanselmann
      "node_name": self.items[0],
462 de40437a Michael Hanselmann
      "dry_run": self.dryRun(),
463 de40437a Michael Hanselmann
      })
464 941b9309 Iustin Pop
465 73452f12 Michael Hanselmann
466 55168cc7 Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.OpcodeResource):
467 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
468 1c482bab Michael Hanselmann

469 1c482bab Michael Hanselmann
  """
470 55168cc7 Michael Hanselmann
  POST_OPCODE = opcodes.OpNodeMigrate
471 55168cc7 Michael Hanselmann
472 55168cc7 Michael Hanselmann
  def GetPostOpInput(self):
473 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
474 1c482bab Michael Hanselmann

475 1c482bab Michael Hanselmann
    """
476 b7a1c816 Michael Hanselmann
    if self.queryargs:
477 b7a1c816 Michael Hanselmann
      # Support old-style requests
478 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs and "mode" in self.queryargs:
479 b7a1c816 Michael Hanselmann
        raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
480 b7a1c816 Michael Hanselmann
                                  " be passed")
481 b7a1c816 Michael Hanselmann
482 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs:
483 b7a1c816 Michael Hanselmann
        if self._checkIntVariable("live", default=1):
484 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_LIVE
485 b7a1c816 Michael Hanselmann
        else:
486 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_NONLIVE
487 52194140 Iustin Pop
      else:
488 b7a1c816 Michael Hanselmann
        mode = self._checkStringVariable("mode", default=None)
489 b7a1c816 Michael Hanselmann
490 b7a1c816 Michael Hanselmann
      data = {
491 b7a1c816 Michael Hanselmann
        "mode": mode,
492 b7a1c816 Michael Hanselmann
        }
493 52194140 Iustin Pop
    else:
494 b7a1c816 Michael Hanselmann
      data = self.request_body
495 52194140 Iustin Pop
496 55168cc7 Michael Hanselmann
    return (data, {
497 55168cc7 Michael Hanselmann
      "node_name": self.items[0],
498 b7a1c816 Michael Hanselmann
      })
499 1c482bab Michael Hanselmann
500 1c482bab Michael Hanselmann
501 eb08e09d Michael Hanselmann
class R_2_nodes_name_storage(baserlib.OpcodeResource):
502 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
503 7a95a954 Michael Hanselmann

504 7a95a954 Michael Hanselmann
  """
505 ad8d0595 Iustin Pop
  # LUNodeQueryStorage acquires locks, hence restricting access to GET
506 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
507 eb08e09d Michael Hanselmann
  GET_OPCODE = opcodes.OpNodeQueryStorage
508 7a95a954 Michael Hanselmann
509 eb08e09d Michael Hanselmann
  def GetGetOpInput(self):
510 eb08e09d Michael Hanselmann
    """List storage available on a node.
511 7a95a954 Michael Hanselmann

512 eb08e09d Michael Hanselmann
    """
513 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
514 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
515 eb08e09d Michael Hanselmann
516 7a95a954 Michael Hanselmann
    if not output_fields:
517 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
518 7a95a954 Michael Hanselmann
                                " parameter")
519 7a95a954 Michael Hanselmann
520 eb08e09d Michael Hanselmann
    return ({}, {
521 eb08e09d Michael Hanselmann
      "nodes": [self.items[0]],
522 eb08e09d Michael Hanselmann
      "storage_type": storage_type,
523 eb08e09d Michael Hanselmann
      "output_fields": output_fields.split(","),
524 eb08e09d Michael Hanselmann
      })
525 7a95a954 Michael Hanselmann
526 7a95a954 Michael Hanselmann
527 8d232068 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.OpcodeResource):
528 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify resource.
529 1e82bc80 Michael Hanselmann

530 1e82bc80 Michael Hanselmann
  """
531 8d232068 Michael Hanselmann
  PUT_OPCODE = opcodes.OpNodeModifyStorage
532 1e82bc80 Michael Hanselmann
533 8d232068 Michael Hanselmann
  def GetPutOpInput(self):
534 8d232068 Michael Hanselmann
    """Modifies a storage volume on a node.
535 1e82bc80 Michael Hanselmann

536 8d232068 Michael Hanselmann
    """
537 8d232068 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
538 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
539 8d232068 Michael Hanselmann
540 1e82bc80 Michael Hanselmann
    if not name:
541 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
542 1e82bc80 Michael Hanselmann
                                " parameter")
543 1e82bc80 Michael Hanselmann
544 1e82bc80 Michael Hanselmann
    changes = {}
545 1e82bc80 Michael Hanselmann
546 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
547 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
548 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
549 1e82bc80 Michael Hanselmann
550 8d232068 Michael Hanselmann
    return ({}, {
551 8d232068 Michael Hanselmann
      "node_name": self.items[0],
552 8d232068 Michael Hanselmann
      "storage_type": storage_type,
553 8d232068 Michael Hanselmann
      "name": name,
554 8d232068 Michael Hanselmann
      "changes": changes,
555 8d232068 Michael Hanselmann
      })
556 1e82bc80 Michael Hanselmann
557 1e82bc80 Michael Hanselmann
558 98270691 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.OpcodeResource):
559 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair resource.
560 723f4565 Michael Hanselmann

561 723f4565 Michael Hanselmann
  """
562 98270691 Michael Hanselmann
  PUT_OPCODE = opcodes.OpRepairNodeStorage
563 723f4565 Michael Hanselmann
564 98270691 Michael Hanselmann
  def GetPutOpInput(self):
565 98270691 Michael Hanselmann
    """Repairs a storage volume on a node.
566 723f4565 Michael Hanselmann

567 98270691 Michael Hanselmann
    """
568 98270691 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
569 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
570 723f4565 Michael Hanselmann
    if not name:
571 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
572 723f4565 Michael Hanselmann
                                " parameter")
573 723f4565 Michael Hanselmann
574 98270691 Michael Hanselmann
    return ({}, {
575 98270691 Michael Hanselmann
      "node_name": self.items[0],
576 98270691 Michael Hanselmann
      "storage_type": storage_type,
577 98270691 Michael Hanselmann
      "name": name,
578 98270691 Michael Hanselmann
      })
579 723f4565 Michael Hanselmann
580 723f4565 Michael Hanselmann
581 c91407bc Michael Hanselmann
class R_2_groups(baserlib.OpcodeResource):
582 c91407bc Michael Hanselmann
  """/2/groups resource.
583 90e99856 Adeodato Simo

584 90e99856 Adeodato Simo
  """
585 c91407bc Michael Hanselmann
  POST_OPCODE = opcodes.OpGroupAdd
586 c91407bc Michael Hanselmann
  POST_RENAME = {
587 527fbde8 Michael Hanselmann
    "name": "group_name",
588 527fbde8 Michael Hanselmann
    }
589 527fbde8 Michael Hanselmann
590 c91407bc Michael Hanselmann
  def GetPostOpInput(self):
591 c91407bc Michael Hanselmann
    """Create a node group.
592 90e99856 Adeodato Simo

593 c91407bc Michael Hanselmann
    """
594 c91407bc Michael Hanselmann
    assert not self.items
595 c91407bc Michael Hanselmann
    return (self.request_body, {
596 c91407bc Michael Hanselmann
      "dry_run": self.dryRun(),
597 c91407bc Michael Hanselmann
      })
598 0897dc97 Adeodato Simo
599 0897dc97 Adeodato Simo
  def GET(self):
600 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
601 0897dc97 Adeodato Simo

602 0897dc97 Adeodato Simo
    """
603 be1ddd09 Michael Hanselmann
    client = self.GetClient()
604 0897dc97 Adeodato Simo
605 0897dc97 Adeodato Simo
    if self.useBulk():
606 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
607 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
608 0897dc97 Adeodato Simo
    else:
609 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
610 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
611 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
612 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
613 0897dc97 Adeodato Simo
614 0897dc97 Adeodato Simo
615 86f1f5d4 Michael Hanselmann
class R_2_groups_name(baserlib.OpcodeResource):
616 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name] resource.
617 0897dc97 Adeodato Simo

618 0897dc97 Adeodato Simo
  """
619 86f1f5d4 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpGroupRemove
620 86f1f5d4 Michael Hanselmann
621 0897dc97 Adeodato Simo
  def GET(self):
622 0897dc97 Adeodato Simo
    """Send information about a node group.
623 0897dc97 Adeodato Simo

624 0897dc97 Adeodato Simo
    """
625 0897dc97 Adeodato Simo
    group_name = self.items[0]
626 be1ddd09 Michael Hanselmann
    client = self.GetClient()
627 0897dc97 Adeodato Simo
628 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
629 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
630 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
631 0897dc97 Adeodato Simo
632 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
633 0897dc97 Adeodato Simo
634 86f1f5d4 Michael Hanselmann
  def GetDeleteOpInput(self):
635 0dbaa9ca Adeodato Simo
    """Delete a node group.
636 0dbaa9ca Adeodato Simo

637 0dbaa9ca Adeodato Simo
    """
638 86f1f5d4 Michael Hanselmann
    assert len(self.items) == 1
639 86f1f5d4 Michael Hanselmann
    return ({}, {
640 86f1f5d4 Michael Hanselmann
      "group_name": self.items[0],
641 86f1f5d4 Michael Hanselmann
      "dry_run": self.dryRun(),
642 86f1f5d4 Michael Hanselmann
      })
643 0dbaa9ca Adeodato Simo
644 0dbaa9ca Adeodato Simo
645 d5211458 Michael Hanselmann
class R_2_groups_name_modify(baserlib.OpcodeResource):
646 f18fab7d Adeodato Simo
  """/2/groups/[group_name]/modify resource.
647 f18fab7d Adeodato Simo

648 f18fab7d Adeodato Simo
  """
649 d5211458 Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupSetParams
650 f18fab7d Adeodato Simo
651 d5211458 Michael Hanselmann
  def GetPutOpInput(self):
652 d5211458 Michael Hanselmann
    """Changes some parameters of node group.
653 f18fab7d Adeodato Simo

654 f18fab7d Adeodato Simo
    """
655 d5211458 Michael Hanselmann
    assert self.items
656 d5211458 Michael Hanselmann
    return (self.request_body, {
657 d5211458 Michael Hanselmann
      "group_name": self.items[0],
658 d5211458 Michael Hanselmann
      })
659 f18fab7d Adeodato Simo
660 f18fab7d Adeodato Simo
661 cd0d4d5a Michael Hanselmann
class R_2_groups_name_rename(baserlib.OpcodeResource):
662 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/rename resource.
663 0dbaa9ca Adeodato Simo

664 0dbaa9ca Adeodato Simo
  """
665 cd0d4d5a Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupRename
666 0dbaa9ca Adeodato Simo
667 cd0d4d5a Michael Hanselmann
  def GetPutOpInput(self):
668 cd0d4d5a Michael Hanselmann
    """Changes the name of a node group.
669 0dbaa9ca Adeodato Simo

670 0dbaa9ca Adeodato Simo
    """
671 cd0d4d5a Michael Hanselmann
    assert len(self.items) == 1
672 cd0d4d5a Michael Hanselmann
    return (self.request_body, {
673 cd0d4d5a Michael Hanselmann
      "group_name": self.items[0],
674 cd0d4d5a Michael Hanselmann
      "dry_run": self.dryRun(),
675 cd0d4d5a Michael Hanselmann
      })
676 0897dc97 Adeodato Simo
677 0897dc97 Adeodato Simo
678 87fd3ec7 Michael Hanselmann
class R_2_groups_name_assign_nodes(baserlib.OpcodeResource):
679 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/assign-nodes resource.
680 4245446f Adeodato Simo

681 4245446f Adeodato Simo
  """
682 87fd3ec7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpGroupAssignNodes
683 4245446f Adeodato Simo
684 87fd3ec7 Michael Hanselmann
  def GetPutOpInput(self):
685 87fd3ec7 Michael Hanselmann
    """Assigns nodes to a group.
686 4245446f Adeodato Simo

687 4245446f Adeodato Simo
    """
688 87fd3ec7 Michael Hanselmann
    assert len(self.items) == 1
689 87fd3ec7 Michael Hanselmann
    return (self.request_body, {
690 4245446f Adeodato Simo
      "group_name": self.items[0],
691 4245446f Adeodato Simo
      "dry_run": self.dryRun(),
692 4245446f Adeodato Simo
      "force": self.useForce(),
693 4245446f Adeodato Simo
      })
694 4245446f Adeodato Simo
695 4245446f Adeodato Simo
696 09a43b39 Michael Hanselmann
class R_2_instances(baserlib.OpcodeResource):
697 09a43b39 Michael Hanselmann
  """/2/instances resource.
698 6395cebb Michael Hanselmann

699 6395cebb Michael Hanselmann
  """
700 09a43b39 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceCreate
701 09a43b39 Michael Hanselmann
  POST_RENAME = {
702 526a662a Michael Hanselmann
    "os": "os_type",
703 526a662a Michael Hanselmann
    "name": "instance_name",
704 526a662a Michael Hanselmann
    }
705 526a662a Michael Hanselmann
706 441e7cfd Oleksiy Mishchenko
  def GET(self):
707 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
708 441e7cfd Oleksiy Mishchenko

709 441e7cfd Oleksiy Mishchenko
    """
710 be1ddd09 Michael Hanselmann
    client = self.GetClient()
711 441e7cfd Oleksiy Mishchenko
712 3d103742 Iustin Pop
    use_locking = self.useLocking()
713 3d103742 Iustin Pop
    if self.useBulk():
714 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
715 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
716 441e7cfd Oleksiy Mishchenko
    else:
717 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
718 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
719 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
720 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
721 441e7cfd Oleksiy Mishchenko
722 09a43b39 Michael Hanselmann
  def GetPostOpInput(self):
723 d975f482 Michael Hanselmann
    """Create an instance.
724 d975f482 Michael Hanselmann

725 d975f482 Michael Hanselmann
    @return: a job id
726 d975f482 Michael Hanselmann

727 d975f482 Michael Hanselmann
    """
728 09a43b39 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
729 d975f482 Michael Hanselmann
730 d975f482 Michael Hanselmann
    # Default to request data version 0
731 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
732 d975f482 Michael Hanselmann
733 d975f482 Michael Hanselmann
    if data_version == 0:
734 3fd7f652 Michael Hanselmann
      raise http.HttpBadRequest("Instance creation request version 0 is no"
735 3fd7f652 Michael Hanselmann
                                " longer supported")
736 09a43b39 Michael Hanselmann
    elif data_version != 1:
737 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
738 12eff9b9 Michael Hanselmann
                                data_version)
739 d975f482 Michael Hanselmann
740 09a43b39 Michael Hanselmann
    data = self.request_body.copy()
741 09a43b39 Michael Hanselmann
    # Remove "__version__"
742 09a43b39 Michael Hanselmann
    data.pop(_REQ_DATA_VERSION, None)
743 09a43b39 Michael Hanselmann
744 09a43b39 Michael Hanselmann
    return (data, {
745 09a43b39 Michael Hanselmann
      "dry_run": self.dryRun(),
746 09a43b39 Michael Hanselmann
      })
747 2f7635f4 Oleksiy Mishchenko
748 441e7cfd Oleksiy Mishchenko
749 a6fa7892 Michael Hanselmann
class R_2_instances_name(baserlib.OpcodeResource):
750 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name] resource.
751 028c6b76 Oleksiy Mishchenko

752 028c6b76 Oleksiy Mishchenko
  """
753 a6fa7892 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpInstanceRemove
754 a6fa7892 Michael Hanselmann
755 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
756 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
757 4e5a68f8 Oleksiy Mishchenko

758 4e5a68f8 Oleksiy Mishchenko
    """
759 be1ddd09 Michael Hanselmann
    client = self.GetClient()
760 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
761 e8ebbd2b Michael Hanselmann
762 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
763 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
764 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
765 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
766 4e5a68f8 Oleksiy Mishchenko
767 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
768 028c6b76 Oleksiy Mishchenko
769 a6fa7892 Michael Hanselmann
  def GetDeleteOpInput(self):
770 6e99c5a0 Iustin Pop
    """Delete an instance.
771 6e99c5a0 Iustin Pop

772 6e99c5a0 Iustin Pop
    """
773 a6fa7892 Michael Hanselmann
    assert len(self.items) == 1
774 a6fa7892 Michael Hanselmann
    return ({}, {
775 a6fa7892 Michael Hanselmann
      "instance_name": self.items[0],
776 a6fa7892 Michael Hanselmann
      "ignore_failures": False,
777 a6fa7892 Michael Hanselmann
      "dry_run": self.dryRun(),
778 a6fa7892 Michael Hanselmann
      })
779 6e99c5a0 Iustin Pop
780 028c6b76 Oleksiy Mishchenko
781 7b3df961 Michael Hanselmann
class R_2_instances_name_info(baserlib.OpcodeResource):
782 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
783 d8260842 Michael Hanselmann

784 d8260842 Michael Hanselmann
  """
785 7b3df961 Michael Hanselmann
  GET_OPCODE = opcodes.OpInstanceQueryData
786 7b3df961 Michael Hanselmann
787 7b3df961 Michael Hanselmann
  def GetGetOpInput(self):
788 d8260842 Michael Hanselmann
    """Request detailed instance information.
789 d8260842 Michael Hanselmann

790 d8260842 Michael Hanselmann
    """
791 7b3df961 Michael Hanselmann
    assert len(self.items) == 1
792 7b3df961 Michael Hanselmann
    return ({}, {
793 7b3df961 Michael Hanselmann
      "instances": [self.items[0]],
794 7b3df961 Michael Hanselmann
      "static": bool(self._checkIntVariable("static", default=0)),
795 7b3df961 Michael Hanselmann
      })
796 d8260842 Michael Hanselmann
797 d8260842 Michael Hanselmann
798 ac4888c1 Michael Hanselmann
class R_2_instances_name_reboot(baserlib.OpcodeResource):
799 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
800 2276aa29 Oleksiy Mishchenko

801 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
802 2276aa29 Oleksiy Mishchenko

803 2276aa29 Oleksiy Mishchenko
  """
804 ac4888c1 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReboot
805 ac4888c1 Michael Hanselmann
806 ac4888c1 Michael Hanselmann
  def GetPostOpInput(self):
807 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
808 2276aa29 Oleksiy Mishchenko

809 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
810 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
811 0c55c24b Oleksiy Mishchenko

812 2276aa29 Oleksiy Mishchenko
    """
813 ac4888c1 Michael Hanselmann
    return ({}, {
814 ac4888c1 Michael Hanselmann
      "instance_name": self.items[0],
815 ac4888c1 Michael Hanselmann
      "reboot_type":
816 ac4888c1 Michael Hanselmann
        self.queryargs.get("type", [constants.INSTANCE_REBOOT_HARD])[0],
817 ac4888c1 Michael Hanselmann
      "ignore_secondaries": bool(self._checkIntVariable("ignore_secondaries")),
818 ac4888c1 Michael Hanselmann
      "dry_run": self.dryRun(),
819 ac4888c1 Michael Hanselmann
      })
820 2276aa29 Oleksiy Mishchenko
821 2276aa29 Oleksiy Mishchenko
822 4717e6eb Michael Hanselmann
class R_2_instances_name_startup(baserlib.OpcodeResource):
823 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
824 0c55c24b Oleksiy Mishchenko

825 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
826 0c55c24b Oleksiy Mishchenko

827 0c55c24b Oleksiy Mishchenko
  """
828 4717e6eb Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceStartup
829 4717e6eb Michael Hanselmann
830 4717e6eb Michael Hanselmann
  def GetPutOpInput(self):
831 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
832 0c55c24b Oleksiy Mishchenko

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

836 0c55c24b Oleksiy Mishchenko
    """
837 4717e6eb Michael Hanselmann
    return ({}, {
838 4717e6eb Michael Hanselmann
      "instance_name": self.items[0],
839 4717e6eb Michael Hanselmann
      "force": self.useForce(),
840 4717e6eb Michael Hanselmann
      "dry_run": self.dryRun(),
841 4717e6eb Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
842 4717e6eb Michael Hanselmann
      })
843 0c55c24b Oleksiy Mishchenko
844 0c55c24b Oleksiy Mishchenko
845 3175ade6 Michael Hanselmann
class R_2_instances_name_shutdown(baserlib.OpcodeResource):
846 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
847 0c55c24b Oleksiy Mishchenko

848 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
849 0c55c24b Oleksiy Mishchenko

850 0c55c24b Oleksiy Mishchenko
  """
851 3175ade6 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceShutdown
852 0c55c24b Oleksiy Mishchenko
853 3175ade6 Michael Hanselmann
  def GetPutOpInput(self):
854 3175ade6 Michael Hanselmann
    """Shutdown an instance.
855 7fa310f6 René Nussbaumer

856 0c55c24b Oleksiy Mishchenko
    """
857 3175ade6 Michael Hanselmann
    return (self.request_body, {
858 3175ade6 Michael Hanselmann
      "instance_name": self.items[0],
859 3175ade6 Michael Hanselmann
      "no_remember": bool(self._checkIntVariable("no_remember")),
860 3175ade6 Michael Hanselmann
      "dry_run": self.dryRun(),
861 3175ade6 Michael Hanselmann
      })
862 0c55c24b Oleksiy Mishchenko
863 0c55c24b Oleksiy Mishchenko
864 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
865 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
866 c744425f Michael Hanselmann

867 c744425f Michael Hanselmann
  """
868 c744425f Michael Hanselmann
  if not isinstance(data, dict):
869 c744425f Michael Hanselmann
    raise http.HttpBadRequest("Invalid body contents, not a dictionary")
870 c744425f Michael Hanselmann
871 bd0807fe Guido Trotter
  ostype = baserlib.CheckParameter(data, "os", default=None)
872 c744425f Michael Hanselmann
  start = baserlib.CheckParameter(data, "start", exptype=bool,
873 c744425f Michael Hanselmann
                                  default=True)
874 c744425f Michael Hanselmann
  osparams = baserlib.CheckParameter(data, "osparams", default=None)
875 c744425f Michael Hanselmann
876 c744425f Michael Hanselmann
  ops = [
877 ee3e37a7 Iustin Pop
    opcodes.OpInstanceShutdown(instance_name=name),
878 5073fd8f Iustin Pop
    opcodes.OpInstanceReinstall(instance_name=name, os_type=ostype,
879 c744425f Michael Hanselmann
                                osparams=osparams),
880 c744425f Michael Hanselmann
    ]
881 c744425f Michael Hanselmann
882 c744425f Michael Hanselmann
  if start:
883 c873d91c Iustin Pop
    ops.append(opcodes.OpInstanceStartup(instance_name=name, force=False))
884 c744425f Michael Hanselmann
885 c744425f Michael Hanselmann
  return ops
886 c744425f Michael Hanselmann
887 c744425f Michael Hanselmann
888 26ff6ee2 Michael Hanselmann
class R_2_instances_name_reinstall(baserlib.ResourceBase):
889 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
890 e5b7c4ca Iustin Pop

891 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
892 e5b7c4ca Iustin Pop

893 e5b7c4ca Iustin Pop
  """
894 e5b7c4ca Iustin Pop
  def POST(self):
895 e5b7c4ca Iustin Pop
    """Reinstall an instance.
896 e5b7c4ca Iustin Pop

897 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
898 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
899 e5b7c4ca Iustin Pop
    automatically.
900 e5b7c4ca Iustin Pop

901 e5b7c4ca Iustin Pop
    """
902 c744425f Michael Hanselmann
    if self.request_body:
903 c744425f Michael Hanselmann
      if self.queryargs:
904 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
905 c744425f Michael Hanselmann
906 c744425f Michael Hanselmann
      body = self.request_body
907 bd0807fe Guido Trotter
    elif self.queryargs:
908 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
909 c744425f Michael Hanselmann
      body = {
910 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
911 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
912 c744425f Michael Hanselmann
        }
913 bd0807fe Guido Trotter
    else:
914 bd0807fe Guido Trotter
      body = {}
915 c744425f Michael Hanselmann
916 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
917 c744425f Michael Hanselmann
918 be1ddd09 Michael Hanselmann
    return self.SubmitJob(ops)
919 e5b7c4ca Iustin Pop
920 e5b7c4ca Iustin Pop
921 0dbc732c Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.OpcodeResource):
922 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
923 4c98b915 Michael Hanselmann

924 4c98b915 Michael Hanselmann
  """
925 0dbc732c Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceReplaceDisks
926 0dbc732c Michael Hanselmann
927 0dbc732c Michael Hanselmann
  def GetPostOpInput(self):
928 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
929 4c98b915 Michael Hanselmann

930 4c98b915 Michael Hanselmann
    """
931 0dbc732c Michael Hanselmann
    data = self.request_body.copy()
932 0dbc732c Michael Hanselmann
    static = {
933 0dbc732c Michael Hanselmann
      "instance_name": self.items[0],
934 0dbc732c Michael Hanselmann
      }
935 4c98b915 Michael Hanselmann
936 0dbc732c Michael Hanselmann
    # Parse disks
937 0dbc732c Michael Hanselmann
    try:
938 0dbc732c Michael Hanselmann
      raw_disks = data["disks"]
939 0dbc732c Michael Hanselmann
    except KeyError:
940 0dbc732c Michael Hanselmann
      pass
941 0dbc732c Michael Hanselmann
    else:
942 0dbc732c Michael Hanselmann
      if not ht.TListOf(ht.TInt)(raw_disks): # pylint: disable-msg=E1102
943 0dbc732c Michael Hanselmann
        # Backwards compatibility for strings of the format "1, 2, 3"
944 0dbc732c Michael Hanselmann
        try:
945 0dbc732c Michael Hanselmann
          data["disks"] = [int(part) for part in raw_disks.split(",")]
946 0dbc732c Michael Hanselmann
        except (TypeError, ValueError), err:
947 0dbc732c Michael Hanselmann
          raise http.HttpBadRequest("Invalid disk index passed: %s" % err)
948 0dbc732c Michael Hanselmann
949 0dbc732c Michael Hanselmann
    return (data, static)
950 4c98b915 Michael Hanselmann
951 4c98b915 Michael Hanselmann
952 1824a7a1 Michael Hanselmann
class R_2_instances_name_activate_disks(baserlib.OpcodeResource):
953 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
954 2197b66f René Nussbaumer

955 2197b66f René Nussbaumer
  """
956 1824a7a1 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceActivateDisks
957 1824a7a1 Michael Hanselmann
958 1824a7a1 Michael Hanselmann
  def GetPutOpInput(self):
959 2197b66f René Nussbaumer
    """Activate disks for an instance.
960 2197b66f René Nussbaumer

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

963 2197b66f René Nussbaumer
    """
964 1824a7a1 Michael Hanselmann
    return ({}, {
965 1824a7a1 Michael Hanselmann
      "instance_name": self.items[0],
966 1824a7a1 Michael Hanselmann
      "ignore_size": bool(self._checkIntVariable("ignore_size")),
967 1824a7a1 Michael Hanselmann
      })
968 2197b66f René Nussbaumer
969 2197b66f René Nussbaumer
970 973ec124 Michael Hanselmann
class R_2_instances_name_deactivate_disks(baserlib.OpcodeResource):
971 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
972 0a37de5f René Nussbaumer

973 0a37de5f René Nussbaumer
  """
974 973ec124 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceDeactivateDisks
975 973ec124 Michael Hanselmann
976 973ec124 Michael Hanselmann
  def GetPutOpInput(self):
977 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
978 0a37de5f René Nussbaumer

979 0a37de5f René Nussbaumer
    """
980 973ec124 Michael Hanselmann
    return ({}, {
981 973ec124 Michael Hanselmann
      "instance_name": self.items[0],
982 973ec124 Michael Hanselmann
      })
983 0a37de5f René Nussbaumer
984 0a37de5f René Nussbaumer
985 1c63311d Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.OpcodeResource):
986 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
987 ebeb600f Michael Hanselmann

988 ebeb600f Michael Hanselmann
  """
989 1c63311d Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupPrepare
990 ebeb600f Michael Hanselmann
991 1c63311d Michael Hanselmann
  def GetPutOpInput(self):
992 1c63311d Michael Hanselmann
    """Prepares an export for an instance.
993 ebeb600f Michael Hanselmann

994 ebeb600f Michael Hanselmann
    """
995 1c63311d Michael Hanselmann
    return ({}, {
996 1c63311d Michael Hanselmann
      "instance_name": self.items[0],
997 1c63311d Michael Hanselmann
      "mode": self._checkStringVariable("mode"),
998 1c63311d Michael Hanselmann
      })
999 ebeb600f Michael Hanselmann
1000 ebeb600f Michael Hanselmann
1001 134afbe7 Michael Hanselmann
class R_2_instances_name_export(baserlib.OpcodeResource):
1002 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1003 ebeb600f Michael Hanselmann

1004 ebeb600f Michael Hanselmann
  """
1005 134afbe7 Michael Hanselmann
  PUT_OPCODE = opcodes.OpBackupExport
1006 134afbe7 Michael Hanselmann
  PUT_RENAME = {
1007 134afbe7 Michael Hanselmann
    "destination": "target_node",
1008 134afbe7 Michael Hanselmann
    }
1009 ebeb600f Michael Hanselmann
1010 134afbe7 Michael Hanselmann
  def GetPutOpInput(self):
1011 134afbe7 Michael Hanselmann
    """Exports an instance.
1012 ebeb600f Michael Hanselmann

1013 ebeb600f Michael Hanselmann
    """
1014 134afbe7 Michael Hanselmann
    return (self.request_body, {
1015 134afbe7 Michael Hanselmann
      "instance_name": self.items[0],
1016 134afbe7 Michael Hanselmann
      })
1017 ebeb600f Michael Hanselmann
1018 ebeb600f Michael Hanselmann
1019 075a29be Michael Hanselmann
class R_2_instances_name_migrate(baserlib.OpcodeResource):
1020 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1021 5823e0d2 Michael Hanselmann

1022 5823e0d2 Michael Hanselmann
  """
1023 075a29be Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceMigrate
1024 5823e0d2 Michael Hanselmann
1025 075a29be Michael Hanselmann
  def GetPutOpInput(self):
1026 075a29be Michael Hanselmann
    """Migrates an instance.
1027 5823e0d2 Michael Hanselmann

1028 5823e0d2 Michael Hanselmann
    """
1029 075a29be Michael Hanselmann
    return (self.request_body, {
1030 075a29be Michael Hanselmann
      "instance_name": self.items[0],
1031 075a29be Michael Hanselmann
      })
1032 5823e0d2 Michael Hanselmann
1033 5823e0d2 Michael Hanselmann
1034 b5f2ab80 Michael Hanselmann
class R_2_instances_name_failover(baserlib.OpcodeResource):
1035 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1036 c0a146a1 Michael Hanselmann

1037 c0a146a1 Michael Hanselmann
  """
1038 b5f2ab80 Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceFailover
1039 c0a146a1 Michael Hanselmann
1040 b5f2ab80 Michael Hanselmann
  def GetPutOpInput(self):
1041 b5f2ab80 Michael Hanselmann
    """Does a failover of an instance.
1042 c0a146a1 Michael Hanselmann

1043 c0a146a1 Michael Hanselmann
    """
1044 b5f2ab80 Michael Hanselmann
    return (self.request_body, {
1045 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1046 c0a146a1 Michael Hanselmann
      })
1047 c0a146a1 Michael Hanselmann
1048 c0a146a1 Michael Hanselmann
1049 d76f9b5d Michael Hanselmann
class R_2_instances_name_rename(baserlib.OpcodeResource):
1050 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1051 d56e7dc7 Michael Hanselmann

1052 d56e7dc7 Michael Hanselmann
  """
1053 d76f9b5d Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceRename
1054 d56e7dc7 Michael Hanselmann
1055 d76f9b5d Michael Hanselmann
  def GetPutOpInput(self):
1056 d76f9b5d Michael Hanselmann
    """Changes the name of an instance.
1057 d56e7dc7 Michael Hanselmann

1058 d56e7dc7 Michael Hanselmann
    """
1059 d76f9b5d Michael Hanselmann
    return (self.request_body, {
1060 d76f9b5d Michael Hanselmann
      "instance_name": self.items[0],
1061 d76f9b5d Michael Hanselmann
      })
1062 d56e7dc7 Michael Hanselmann
1063 d56e7dc7 Michael Hanselmann
1064 f3db88ba Michael Hanselmann
class R_2_instances_name_modify(baserlib.OpcodeResource):
1065 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1066 3882937a Michael Hanselmann

1067 3882937a Michael Hanselmann
  """
1068 f3db88ba Michael Hanselmann
  PUT_OPCODE = opcodes.OpInstanceSetParams
1069 3882937a Michael Hanselmann
1070 f3db88ba Michael Hanselmann
  def GetPutOpInput(self):
1071 f3db88ba Michael Hanselmann
    """Changes parameters of an instance.
1072 3882937a Michael Hanselmann

1073 3882937a Michael Hanselmann
    """
1074 f3db88ba Michael Hanselmann
    return (self.request_body, {
1075 f3db88ba Michael Hanselmann
      "instance_name": self.items[0],
1076 f3db88ba Michael Hanselmann
      })
1077 3882937a Michael Hanselmann
1078 3882937a Michael Hanselmann
1079 335965b9 Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.OpcodeResource):
1080 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1081 e23881ed Michael Hanselmann

1082 e23881ed Michael Hanselmann
  """
1083 335965b9 Michael Hanselmann
  POST_OPCODE = opcodes.OpInstanceGrowDisk
1084 e23881ed Michael Hanselmann
1085 335965b9 Michael Hanselmann
  def GetPostOpInput(self):
1086 335965b9 Michael Hanselmann
    """Increases the size of an instance disk.
1087 e23881ed Michael Hanselmann

1088 e23881ed Michael Hanselmann
    """
1089 335965b9 Michael Hanselmann
    return (self.request_body, {
1090 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1091 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1092 e23881ed Michael Hanselmann
      })
1093 e23881ed Michael Hanselmann
1094 e23881ed Michael Hanselmann
1095 26ff6ee2 Michael Hanselmann
class R_2_instances_name_console(baserlib.ResourceBase):
1096 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1097 b82d4c5e Michael Hanselmann

1098 b82d4c5e Michael Hanselmann
  """
1099 b82d4c5e Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1100 b82d4c5e Michael Hanselmann
1101 b82d4c5e Michael Hanselmann
  def GET(self):
1102 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1103 b82d4c5e Michael Hanselmann

1104 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1105 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1106 b82d4c5e Michael Hanselmann

1107 b82d4c5e Michael Hanselmann
    """
1108 be1ddd09 Michael Hanselmann
    client = self.GetClient()
1109 b82d4c5e Michael Hanselmann
1110 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1111 b82d4c5e Michael Hanselmann
1112 b82d4c5e Michael Hanselmann
    if console is None:
1113 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1114 b82d4c5e Michael Hanselmann
1115 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1116 b82d4c5e Michael Hanselmann
    return console
1117 b82d4c5e Michael Hanselmann
1118 b82d4c5e Michael Hanselmann
1119 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1120 208a6cff Michael Hanselmann
  """
1121 208a6cff Michael Hanselmann

1122 208a6cff Michael Hanselmann
  """
1123 208a6cff Michael Hanselmann
  try:
1124 208a6cff Michael Hanselmann
    fields = args["fields"]
1125 208a6cff Michael Hanselmann
  except KeyError:
1126 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1127 208a6cff Michael Hanselmann
1128 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1129 208a6cff Michael Hanselmann
1130 208a6cff Michael Hanselmann
1131 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1132 208a6cff Michael Hanselmann
  """
1133 208a6cff Michael Hanselmann

1134 208a6cff Michael Hanselmann
  """
1135 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1136 208a6cff Michael Hanselmann
1137 208a6cff Michael Hanselmann
1138 26ff6ee2 Michael Hanselmann
class R_2_query(baserlib.ResourceBase):
1139 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1140 208a6cff Michael Hanselmann

1141 208a6cff Michael Hanselmann
  """
1142 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1143 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1144 208a6cff Michael Hanselmann
1145 208a6cff Michael Hanselmann
  def _Query(self, fields, filter_):
1146 be1ddd09 Michael Hanselmann
    return self.GetClient().Query(self.items[0], fields, filter_).ToDict()
1147 208a6cff Michael Hanselmann
1148 208a6cff Michael Hanselmann
  def GET(self):
1149 208a6cff Michael Hanselmann
    """Returns resource information.
1150 208a6cff Michael Hanselmann

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

1153 208a6cff Michael Hanselmann
    """
1154 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1155 208a6cff Michael Hanselmann
1156 208a6cff Michael Hanselmann
  def PUT(self):
1157 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1158 208a6cff Michael Hanselmann

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

1161 208a6cff Michael Hanselmann
    """
1162 208a6cff Michael Hanselmann
    body = self.request_body
1163 208a6cff Michael Hanselmann
1164 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1165 208a6cff Michael Hanselmann
1166 208a6cff Michael Hanselmann
    try:
1167 208a6cff Michael Hanselmann
      fields = body["fields"]
1168 208a6cff Michael Hanselmann
    except KeyError:
1169 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1170 208a6cff Michael Hanselmann
1171 208a6cff Michael Hanselmann
    return self._Query(fields, self.request_body.get("filter", None))
1172 208a6cff Michael Hanselmann
1173 208a6cff Michael Hanselmann
1174 26ff6ee2 Michael Hanselmann
class R_2_query_fields(baserlib.ResourceBase):
1175 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1176 208a6cff Michael Hanselmann

1177 208a6cff Michael Hanselmann
  """
1178 208a6cff Michael Hanselmann
  def GET(self):
1179 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1180 208a6cff Michael Hanselmann

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

1183 208a6cff Michael Hanselmann
    """
1184 208a6cff Michael Hanselmann
    try:
1185 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1186 208a6cff Michael Hanselmann
    except KeyError:
1187 208a6cff Michael Hanselmann
      fields = None
1188 208a6cff Michael Hanselmann
    else:
1189 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1190 208a6cff Michael Hanselmann
1191 be1ddd09 Michael Hanselmann
    return self.GetClient().QueryFields(self.items[0], fields).ToDict()
1192 208a6cff Michael Hanselmann
1193 208a6cff Michael Hanselmann
1194 460ef073 Michael Hanselmann
class _R_Tags(baserlib.OpcodeResource):
1195 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1196 441e7cfd Oleksiy Mishchenko

1197 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1198 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1199 441e7cfd Oleksiy Mishchenko

1200 441e7cfd Oleksiy Mishchenko
  """
1201 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1202 460ef073 Michael Hanselmann
  PUT_OPCODE = opcodes.OpTagsSet
1203 460ef073 Michael Hanselmann
  DELETE_OPCODE = opcodes.OpTagsDel
1204 18cb43a2 Oleksiy Mishchenko
1205 460ef073 Michael Hanselmann
  def __init__(self, items, queryargs, req, **kwargs):
1206 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1207 18cb43a2 Oleksiy Mishchenko

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

1210 18cb43a2 Oleksiy Mishchenko
    """
1211 460ef073 Michael Hanselmann
    baserlib.OpcodeResource.__init__(self, items, queryargs, req, **kwargs)
1212 18cb43a2 Oleksiy Mishchenko
1213 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1214 5313eed7 Michael Hanselmann
      self.name = None
1215 18cb43a2 Oleksiy Mishchenko
    else:
1216 5313eed7 Michael Hanselmann
      self.name = items[0]
1217 441e7cfd Oleksiy Mishchenko
1218 441e7cfd Oleksiy Mishchenko
  def GET(self):
1219 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1220 441e7cfd Oleksiy Mishchenko

1221 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1222 441e7cfd Oleksiy Mishchenko

1223 441e7cfd Oleksiy Mishchenko
    """
1224 f87ec53f Michael Hanselmann
    kind = self.TAG_LEVEL
1225 f87ec53f Michael Hanselmann
1226 f87ec53f Michael Hanselmann
    if kind in (constants.TAG_INSTANCE,
1227 f87ec53f Michael Hanselmann
                constants.TAG_NODEGROUP,
1228 f87ec53f Michael Hanselmann
                constants.TAG_NODE):
1229 f87ec53f Michael Hanselmann
      if not self.name:
1230 f87ec53f Michael Hanselmann
        raise http.HttpBadRequest("Missing name on tag request")
1231 f87ec53f Michael Hanselmann
1232 be1ddd09 Michael Hanselmann
      cl = self.GetClient()
1233 f87ec53f Michael Hanselmann
      if kind == constants.TAG_INSTANCE:
1234 f87ec53f Michael Hanselmann
        fn = cl.QueryInstances
1235 f87ec53f Michael Hanselmann
      elif kind == constants.TAG_NODEGROUP:
1236 f87ec53f Michael Hanselmann
        fn = cl.QueryGroups
1237 f87ec53f Michael Hanselmann
      else:
1238 f87ec53f Michael Hanselmann
        fn = cl.QueryNodes
1239 f87ec53f Michael Hanselmann
      result = fn(names=[self.name], fields=["tags"], use_locking=False)
1240 f87ec53f Michael Hanselmann
      if not result or not result[0]:
1241 f87ec53f Michael Hanselmann
        raise http.HttpBadGateway("Invalid response from tag query")
1242 f87ec53f Michael Hanselmann
      tags = result[0][0]
1243 f87ec53f Michael Hanselmann
1244 f87ec53f Michael Hanselmann
    elif kind == constants.TAG_CLUSTER:
1245 f87ec53f Michael Hanselmann
      assert not self.name
1246 f87ec53f Michael Hanselmann
      # TODO: Use query API?
1247 f87ec53f Michael Hanselmann
      ssc = ssconf.SimpleStore()
1248 f87ec53f Michael Hanselmann
      tags = ssc.GetClusterTags()
1249 f87ec53f Michael Hanselmann
1250 f87ec53f Michael Hanselmann
    return list(tags)
1251 441e7cfd Oleksiy Mishchenko
1252 460ef073 Michael Hanselmann
  def GetPutOpInput(self):
1253 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1254 441e7cfd Oleksiy Mishchenko

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

1258 441e7cfd Oleksiy Mishchenko
    """
1259 460ef073 Michael Hanselmann
    return ({}, {
1260 460ef073 Michael Hanselmann
      "kind": self.TAG_LEVEL,
1261 460ef073 Michael Hanselmann
      "name": self.name,
1262 460ef073 Michael Hanselmann
      "tags": self.queryargs.get("tag", []),
1263 460ef073 Michael Hanselmann
      "dry_run": self.dryRun(),
1264 460ef073 Michael Hanselmann
      })
1265 15fd9fd5 Oleksiy Mishchenko
1266 460ef073 Michael Hanselmann
  def GetDeleteOpInput(self):
1267 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1268 15fd9fd5 Oleksiy Mishchenko

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

1273 15fd9fd5 Oleksiy Mishchenko
    """
1274 460ef073 Michael Hanselmann
    # Re-use code
1275 460ef073 Michael Hanselmann
    return self.GetPutOpInput()
1276 18cb43a2 Oleksiy Mishchenko
1277 18cb43a2 Oleksiy Mishchenko
1278 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1279 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1280 18cb43a2 Oleksiy Mishchenko

1281 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1282 18cb43a2 Oleksiy Mishchenko

1283 18cb43a2 Oleksiy Mishchenko
  """
1284 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1285 18cb43a2 Oleksiy Mishchenko
1286 18cb43a2 Oleksiy Mishchenko
1287 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1288 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1289 18cb43a2 Oleksiy Mishchenko

1290 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1291 18cb43a2 Oleksiy Mishchenko

1292 18cb43a2 Oleksiy Mishchenko
  """
1293 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1294 18cb43a2 Oleksiy Mishchenko
1295 18cb43a2 Oleksiy Mishchenko
1296 414ebaf1 Michael Hanselmann
class R_2_groups_name_tags(_R_Tags):
1297 414ebaf1 Michael Hanselmann
  """ /2/groups/[group_name]/tags resource.
1298 414ebaf1 Michael Hanselmann

1299 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1300 414ebaf1 Michael Hanselmann

1301 414ebaf1 Michael Hanselmann
  """
1302 414ebaf1 Michael Hanselmann
  TAG_LEVEL = constants.TAG_NODEGROUP
1303 414ebaf1 Michael Hanselmann
1304 414ebaf1 Michael Hanselmann
1305 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1306 b58a4d16 Michael Hanselmann
  """ /2/tags resource.
1307 18cb43a2 Oleksiy Mishchenko

1308 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1309 18cb43a2 Oleksiy Mishchenko

1310 18cb43a2 Oleksiy Mishchenko
  """
1311 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER