Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 7fa310f6

History | View | Annotate | Download (35.9 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 10b207d4 Oleksiy Mishchenko
"""Remote API version 2 baserlib.library.
23 10b207d4 Oleksiy Mishchenko

24 88394aa7 René Nussbaumer
  PUT or POST?
25 bb579a7d René Nussbaumer
  ============
26 88394aa7 René Nussbaumer

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

31 88394aa7 René Nussbaumer
  To be in context of this module for instance creation POST on
32 88394aa7 René Nussbaumer
  /2/instances is legitim while PUT would be not, due to it does create a
33 88394aa7 René Nussbaumer
  new entity and not just replace /2/instances with it.
34 88394aa7 René Nussbaumer

35 88394aa7 René Nussbaumer
  So when adding new methods, if they are operating on the URI entity itself,
36 88394aa7 René Nussbaumer
  PUT should be prefered over POST.
37 88394aa7 René Nussbaumer

38 10b207d4 Oleksiy Mishchenko
"""
39 10b207d4 Oleksiy Mishchenko
40 fe267188 Iustin Pop
# pylint: disable-msg=C0103
41 fe267188 Iustin Pop
42 fe267188 Iustin Pop
# C0103: Invalid name, since the R_* names are not conforming
43 fe267188 Iustin Pop
44 59b4eeef Iustin Pop
from ganeti import opcodes
45 15fd9fd5 Oleksiy Mishchenko
from ganeti import http
46 15fd9fd5 Oleksiy Mishchenko
from ganeti import constants
47 59b4eeef Iustin Pop
from ganeti import cli
48 8381fa2d Michael Hanselmann
from ganeti import rapi
49 d1c172de Michael Hanselmann
from ganeti import ht
50 38206f3c Iustin Pop
from ganeti.rapi import baserlib
51 10b207d4 Oleksiy Mishchenko
52 4e5a68f8 Oleksiy Mishchenko
53 7118a0df Iustin Pop
_COMMON_FIELDS = ["ctime", "mtime", "uuid", "serial_no", "tags"]
54 9031ee8e Iustin Pop
I_FIELDS = ["name", "admin_state", "os",
55 9031ee8e Iustin Pop
            "pnode", "snodes",
56 9031ee8e Iustin Pop
            "disk_template",
57 82e186f8 Michael Hanselmann
            "nic.ips", "nic.macs", "nic.modes", "nic.links", "nic.bridges",
58 a8b16c4e Tim Boring
            "network_port",
59 024e157f Iustin Pop
            "disk.sizes", "disk_usage",
60 a5b9d725 Iustin Pop
            "beparams", "hvparams",
61 4ea3de4e Balazs Lecz
            "oper_state", "oper_ram", "oper_vcpus", "status",
62 90224407 Iustin Pop
            "custom_hvparams", "custom_beparams", "custom_nicparams",
63 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
64 9031ee8e Iustin Pop
65 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
66 9031ee8e Iustin Pop
            "dtotal", "dfree",
67 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
68 7118a0df Iustin Pop
            "pinst_cnt", "sinst_cnt",
69 0105bad3 Iustin Pop
            "ctotal", "cnodes", "csockets",
70 7118a0df Iustin Pop
            "pip", "sip", "role",
71 93962b80 Iustin Pop
            "pinst_list", "sinst_list",
72 c190e817 Iustin Pop
            "master_capable", "vm_capable",
73 fd254195 Iustin Pop
            "group.uuid",
74 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
75 4e5a68f8 Oleksiy Mishchenko
76 0897dc97 Adeodato Simo
G_FIELDS = ["name", "uuid",
77 90e99856 Adeodato Simo
            "alloc_policy",
78 0897dc97 Adeodato Simo
            "node_cnt", "node_list",
79 4edc512c Adeodato Simo
            "ctime", "mtime", "serial_no",
80 4edc512c Adeodato Simo
            ]  # "tags" is missing to be able to use _COMMON_FIELDS here.
81 0897dc97 Adeodato Simo
82 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
83 64dae8fc Michael Hanselmann
_NR_MASTER_CANDIATE = "master-candidate"
84 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
85 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
86 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
87 64dae8fc Michael Hanselmann
88 64dae8fc Michael Hanselmann
_NR_MAP = {
89 1e28e3b8 Michael Hanselmann
  constants.NR_MASTER: _NR_MASTER,
90 1e28e3b8 Michael Hanselmann
  constants.NR_MCANDIDATE: _NR_MASTER_CANDIATE,
91 1e28e3b8 Michael Hanselmann
  constants.NR_DRAINED: _NR_DRAINED,
92 1e28e3b8 Michael Hanselmann
  constants.NR_OFFLINE: _NR_OFFLINE,
93 1e28e3b8 Michael Hanselmann
  constants.NR_REGULAR: _NR_REGULAR,
94 64dae8fc Michael Hanselmann
  }
95 64dae8fc Michael Hanselmann
96 1e28e3b8 Michael Hanselmann
assert frozenset(_NR_MAP.keys()) == constants.NR_ALL
97 1e28e3b8 Michael Hanselmann
98 d975f482 Michael Hanselmann
# Request data version field
99 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
100 d975f482 Michael Hanselmann
101 6395cebb Michael Hanselmann
# Feature string for instance creation request data version 1
102 6395cebb Michael Hanselmann
_INST_CREATE_REQV1 = "instance-create-reqv1"
103 6395cebb Michael Hanselmann
104 c744425f Michael Hanselmann
# Feature string for instance reinstall request version 1
105 c744425f Michael Hanselmann
_INST_REINSTALL_REQV1 = "instance-reinstall-reqv1"
106 c744425f Michael Hanselmann
107 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
108 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
109 793a8f7c Michael Hanselmann
110 4e5a68f8 Oleksiy Mishchenko
111 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
112 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
113 4e5a68f8 Oleksiy Mishchenko

114 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
115 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
116 4e5a68f8 Oleksiy Mishchenko

117 4e5a68f8 Oleksiy Mishchenko
  """
118 7e950d31 Iustin Pop
  @staticmethod
119 7e950d31 Iustin Pop
  def GET():
120 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
121 4e5a68f8 Oleksiy Mishchenko

122 4e5a68f8 Oleksiy Mishchenko
    """
123 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
124 4e5a68f8 Oleksiy Mishchenko
125 4e5a68f8 Oleksiy Mishchenko
126 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
127 b58a4d16 Michael Hanselmann
  """/2/info resource.
128 4e5a68f8 Oleksiy Mishchenko

129 4e5a68f8 Oleksiy Mishchenko
  """
130 7e950d31 Iustin Pop
  @staticmethod
131 7e950d31 Iustin Pop
  def GET():
132 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
133 4e5a68f8 Oleksiy Mishchenko

134 4e5a68f8 Oleksiy Mishchenko
    """
135 59b4eeef Iustin Pop
    client = baserlib.GetClient()
136 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
137 4e5a68f8 Oleksiy Mishchenko
138 4e5a68f8 Oleksiy Mishchenko
139 7eac4a4d Michael Hanselmann
class R_2_features(baserlib.R_Generic):
140 7eac4a4d Michael Hanselmann
  """/2/features resource.
141 7eac4a4d Michael Hanselmann

142 7eac4a4d Michael Hanselmann
  """
143 7eac4a4d Michael Hanselmann
  @staticmethod
144 7eac4a4d Michael Hanselmann
  def GET():
145 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
146 7eac4a4d Michael Hanselmann

147 7eac4a4d Michael Hanselmann
    """
148 c744425f Michael Hanselmann
    return [_INST_CREATE_REQV1, _INST_REINSTALL_REQV1]
149 7eac4a4d Michael Hanselmann
150 7eac4a4d Michael Hanselmann
151 4e5a68f8 Oleksiy Mishchenko
class R_2_os(baserlib.R_Generic):
152 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
153 4e5a68f8 Oleksiy Mishchenko

154 4e5a68f8 Oleksiy Mishchenko
  """
155 7e950d31 Iustin Pop
  @staticmethod
156 7e950d31 Iustin Pop
  def GET():
157 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
158 4e5a68f8 Oleksiy Mishchenko

159 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
160 4e5a68f8 Oleksiy Mishchenko

161 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
162 4e5a68f8 Oleksiy Mishchenko

163 4e5a68f8 Oleksiy Mishchenko
    """
164 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
165 da2d02e7 Iustin Pop
    op = opcodes.OpOsDiagnose(output_fields=["name", "variants"], names=[])
166 59b4eeef Iustin Pop
    job_id = baserlib.SubmitJob([op], cl)
167 59b4eeef Iustin Pop
    # we use custom feedback function, instead of print we log the status
168 59b4eeef Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
169 59b4eeef Iustin Pop
    diagnose_data = result[0]
170 4e5a68f8 Oleksiy Mishchenko
171 4e5a68f8 Oleksiy Mishchenko
    if not isinstance(diagnose_data, list):
172 59b4eeef Iustin Pop
      raise http.HttpBadGateway(message="Can't get OS list")
173 4e5a68f8 Oleksiy Mishchenko
174 e3ac208c Guido Trotter
    os_names = []
175 d22dfef7 Iustin Pop
    for (name, variants) in diagnose_data:
176 d22dfef7 Iustin Pop
      os_names.extend(cli.CalculateOSNames(name, variants))
177 e3ac208c Guido Trotter
178 e3ac208c Guido Trotter
    return os_names
179 51ee2f49 Oleksiy Mishchenko
180 10b207d4 Oleksiy Mishchenko
181 508e9b20 Michael Hanselmann
class R_2_redist_config(baserlib.R_Generic):
182 508e9b20 Michael Hanselmann
  """/2/redistribute-config resource.
183 508e9b20 Michael Hanselmann

184 508e9b20 Michael Hanselmann
  """
185 7e950d31 Iustin Pop
  @staticmethod
186 7e950d31 Iustin Pop
  def PUT():
187 508e9b20 Michael Hanselmann
    """Redistribute configuration to all nodes.
188 508e9b20 Michael Hanselmann

189 508e9b20 Michael Hanselmann
    """
190 d1240007 Iustin Pop
    return baserlib.SubmitJob([opcodes.OpClusterRedistConf()])
191 508e9b20 Michael Hanselmann
192 508e9b20 Michael Hanselmann
193 62e999a5 Michael Hanselmann
class R_2_cluster_modify(baserlib.R_Generic):
194 62e999a5 Michael Hanselmann
  """/2/modify resource.
195 62e999a5 Michael Hanselmann

196 62e999a5 Michael Hanselmann
  """
197 62e999a5 Michael Hanselmann
  def PUT(self):
198 62e999a5 Michael Hanselmann
    """Modifies cluster parameters.
199 62e999a5 Michael Hanselmann

200 62e999a5 Michael Hanselmann
    @return: a job id
201 62e999a5 Michael Hanselmann

202 62e999a5 Michael Hanselmann
    """
203 a6682fdc Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpClusterSetParams, self.request_body,
204 62e999a5 Michael Hanselmann
                             None)
205 62e999a5 Michael Hanselmann
206 62e999a5 Michael Hanselmann
    return baserlib.SubmitJob([op])
207 62e999a5 Michael Hanselmann
208 62e999a5 Michael Hanselmann
209 10b207d4 Oleksiy Mishchenko
class R_2_jobs(baserlib.R_Generic):
210 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
211 10b207d4 Oleksiy Mishchenko

212 10b207d4 Oleksiy Mishchenko
  """
213 7e950d31 Iustin Pop
  @staticmethod
214 7e950d31 Iustin Pop
  def GET():
215 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
216 10b207d4 Oleksiy Mishchenko

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

219 10b207d4 Oleksiy Mishchenko
    """
220 10b207d4 Oleksiy Mishchenko
    fields = ["id"]
221 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
222 10b207d4 Oleksiy Mishchenko
    # Convert the list of lists to the list of ids
223 59b4eeef Iustin Pop
    result = [job_id for [job_id] in cl.QueryJobs(None, fields)]
224 9031ee8e Iustin Pop
    return baserlib.BuildUriList(result, "/2/jobs/%s",
225 9031ee8e Iustin Pop
                                 uri_fields=("id", "uri"))
226 10b207d4 Oleksiy Mishchenko
227 10b207d4 Oleksiy Mishchenko
228 10b207d4 Oleksiy Mishchenko
class R_2_jobs_id(baserlib.R_Generic):
229 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
230 10b207d4 Oleksiy Mishchenko

231 10b207d4 Oleksiy Mishchenko
  """
232 10b207d4 Oleksiy Mishchenko
  def GET(self):
233 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
234 10b207d4 Oleksiy Mishchenko

235 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
236 c41eea6e Iustin Pop
        The result includes:
237 c41eea6e Iustin Pop
            - id: job ID as a number
238 c41eea6e Iustin Pop
            - status: current job status as a string
239 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
240 c41eea6e Iustin Pop
              opcodes in the job
241 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
242 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
243 38206f3c Iustin Pop

244 10b207d4 Oleksiy Mishchenko
    """
245 ee69c97f Iustin Pop
    fields = ["id", "ops", "status", "summary",
246 ee69c97f Iustin Pop
              "opstatus", "opresult", "oplog",
247 ee69c97f Iustin Pop
              "received_ts", "start_ts", "end_ts",
248 ee69c97f Iustin Pop
              ]
249 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
250 59b4eeef Iustin Pop
    result = baserlib.GetClient().QueryJobs([job_id, ], fields)[0]
251 ee69c97f Iustin Pop
    if result is None:
252 ee69c97f Iustin Pop
      raise http.HttpNotFound()
253 10b207d4 Oleksiy Mishchenko
    return baserlib.MapFields(fields, result)
254 10b207d4 Oleksiy Mishchenko
255 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
256 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
257 c7f5f338 Oleksiy Mishchenko

258 c7f5f338 Oleksiy Mishchenko
    """
259 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
260 59b4eeef Iustin Pop
    result = baserlib.GetClient().CancelJob(job_id)
261 c7f5f338 Oleksiy Mishchenko
    return result
262 c7f5f338 Oleksiy Mishchenko
263 10b207d4 Oleksiy Mishchenko
264 793a8f7c Michael Hanselmann
class R_2_jobs_id_wait(baserlib.R_Generic):
265 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
266 793a8f7c Michael Hanselmann

267 793a8f7c Michael Hanselmann
  """
268 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
269 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
270 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
271 793a8f7c Michael Hanselmann
272 793a8f7c Michael Hanselmann
  def GET(self):
273 793a8f7c Michael Hanselmann
    """Waits for job changes.
274 793a8f7c Michael Hanselmann

275 793a8f7c Michael Hanselmann
    """
276 793a8f7c Michael Hanselmann
    job_id = self.items[0]
277 793a8f7c Michael Hanselmann
278 793a8f7c Michael Hanselmann
    fields = self.getBodyParameter("fields")
279 793a8f7c Michael Hanselmann
    prev_job_info = self.getBodyParameter("previous_job_info", None)
280 793a8f7c Michael Hanselmann
    prev_log_serial = self.getBodyParameter("previous_log_serial", None)
281 793a8f7c Michael Hanselmann
282 793a8f7c Michael Hanselmann
    if not isinstance(fields, list):
283 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'fields' parameter should be a list")
284 793a8f7c Michael Hanselmann
285 793a8f7c Michael Hanselmann
    if not (prev_job_info is None or isinstance(prev_job_info, list)):
286 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_job_info' parameter should"
287 793a8f7c Michael Hanselmann
                                " be a list")
288 793a8f7c Michael Hanselmann
289 793a8f7c Michael Hanselmann
    if not (prev_log_serial is None or
290 793a8f7c Michael Hanselmann
            isinstance(prev_log_serial, (int, long))):
291 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_log_serial' parameter should"
292 793a8f7c Michael Hanselmann
                                " be a number")
293 793a8f7c Michael Hanselmann
294 793a8f7c Michael Hanselmann
    client = baserlib.GetClient()
295 793a8f7c Michael Hanselmann
    result = client.WaitForJobChangeOnce(job_id, fields,
296 793a8f7c Michael Hanselmann
                                         prev_job_info, prev_log_serial,
297 793a8f7c Michael Hanselmann
                                         timeout=_WFJC_TIMEOUT)
298 793a8f7c Michael Hanselmann
    if not result:
299 793a8f7c Michael Hanselmann
      raise http.HttpNotFound()
300 793a8f7c Michael Hanselmann
301 793a8f7c Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
302 793a8f7c Michael Hanselmann
      # No changes
303 793a8f7c Michael Hanselmann
      return None
304 793a8f7c Michael Hanselmann
305 793a8f7c Michael Hanselmann
    (job_info, log_entries) = result
306 793a8f7c Michael Hanselmann
307 793a8f7c Michael Hanselmann
    return {
308 793a8f7c Michael Hanselmann
      "job_info": job_info,
309 793a8f7c Michael Hanselmann
      "log_entries": log_entries,
310 793a8f7c Michael Hanselmann
      }
311 793a8f7c Michael Hanselmann
312 793a8f7c Michael Hanselmann
313 10b207d4 Oleksiy Mishchenko
class R_2_nodes(baserlib.R_Generic):
314 10b207d4 Oleksiy Mishchenko
  """/2/nodes resource.
315 10b207d4 Oleksiy Mishchenko

316 10b207d4 Oleksiy Mishchenko
  """
317 10b207d4 Oleksiy Mishchenko
  def GET(self):
318 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
319 38206f3c Iustin Pop

320 10b207d4 Oleksiy Mishchenko
    """
321 59b4eeef Iustin Pop
    client = baserlib.GetClient()
322 38206f3c Iustin Pop
323 3d103742 Iustin Pop
    if self.useBulk():
324 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
325 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
326 9031ee8e Iustin Pop
    else:
327 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
328 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
329 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
330 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
331 441e7cfd Oleksiy Mishchenko
332 441e7cfd Oleksiy Mishchenko
333 4e5a68f8 Oleksiy Mishchenko
class R_2_nodes_name(baserlib.R_Generic):
334 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name] resource.
335 028c6b76 Oleksiy Mishchenko

336 028c6b76 Oleksiy Mishchenko
  """
337 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
338 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
339 4e5a68f8 Oleksiy Mishchenko

340 4e5a68f8 Oleksiy Mishchenko
    """
341 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
342 59b4eeef Iustin Pop
    client = baserlib.GetClient()
343 e8ebbd2b Michael Hanselmann
344 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
345 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
346 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
347 4e5a68f8 Oleksiy Mishchenko
348 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
349 028c6b76 Oleksiy Mishchenko
350 028c6b76 Oleksiy Mishchenko
351 64dae8fc Michael Hanselmann
class R_2_nodes_name_role(baserlib.R_Generic):
352 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
353 64dae8fc Michael Hanselmann

354 64dae8fc Michael Hanselmann
  """
355 64dae8fc Michael Hanselmann
  def GET(self):
356 64dae8fc Michael Hanselmann
    """Returns the current node role.
357 64dae8fc Michael Hanselmann

358 64dae8fc Michael Hanselmann
    @return: Node role
359 64dae8fc Michael Hanselmann

360 64dae8fc Michael Hanselmann
    """
361 64dae8fc Michael Hanselmann
    node_name = self.items[0]
362 64dae8fc Michael Hanselmann
    client = baserlib.GetClient()
363 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
364 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
365 64dae8fc Michael Hanselmann
366 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
367 64dae8fc Michael Hanselmann
368 64dae8fc Michael Hanselmann
  def PUT(self):
369 64dae8fc Michael Hanselmann
    """Sets the node role.
370 64dae8fc Michael Hanselmann

371 64dae8fc Michael Hanselmann
    @return: a job id
372 64dae8fc Michael Hanselmann

373 64dae8fc Michael Hanselmann
    """
374 627ad739 Michael Hanselmann
    if not isinstance(self.request_body, basestring):
375 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a string")
376 64dae8fc Michael Hanselmann
377 64dae8fc Michael Hanselmann
    node_name = self.items[0]
378 627ad739 Michael Hanselmann
    role = self.request_body
379 64dae8fc Michael Hanselmann
380 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
381 64dae8fc Michael Hanselmann
      candidate = False
382 64dae8fc Michael Hanselmann
      offline = False
383 64dae8fc Michael Hanselmann
      drained = False
384 64dae8fc Michael Hanselmann
385 64dae8fc Michael Hanselmann
    elif role == _NR_MASTER_CANDIATE:
386 64dae8fc Michael Hanselmann
      candidate = True
387 64dae8fc Michael Hanselmann
      offline = drained = None
388 64dae8fc Michael Hanselmann
389 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
390 64dae8fc Michael Hanselmann
      drained = True
391 64dae8fc Michael Hanselmann
      candidate = offline = None
392 64dae8fc Michael Hanselmann
393 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
394 64dae8fc Michael Hanselmann
      offline = True
395 64dae8fc Michael Hanselmann
      candidate = drained = None
396 64dae8fc Michael Hanselmann
397 64dae8fc Michael Hanselmann
    else:
398 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
399 64dae8fc Michael Hanselmann
400 f13973c4 Iustin Pop
    op = opcodes.OpNodeSetParams(node_name=node_name,
401 64dae8fc Michael Hanselmann
                                 master_candidate=candidate,
402 64dae8fc Michael Hanselmann
                                 offline=offline,
403 64dae8fc Michael Hanselmann
                                 drained=drained,
404 64dae8fc Michael Hanselmann
                                 force=bool(self.useForce()))
405 64dae8fc Michael Hanselmann
406 64dae8fc Michael Hanselmann
    return baserlib.SubmitJob([op])
407 64dae8fc Michael Hanselmann
408 64dae8fc Michael Hanselmann
409 73452f12 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.R_Generic):
410 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
411 73452f12 Michael Hanselmann

412 73452f12 Michael Hanselmann
  """
413 73452f12 Michael Hanselmann
  def POST(self):
414 73452f12 Michael Hanselmann
    """Evacuate all secondary instances off a node.
415 73452f12 Michael Hanselmann

416 73452f12 Michael Hanselmann
    """
417 73452f12 Michael Hanselmann
    node_name = self.items[0]
418 73452f12 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
419 73452f12 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
420 941b9309 Iustin Pop
    early_r = bool(self._checkIntVariable("early_release", default=0))
421 941b9309 Iustin Pop
    dry_run = bool(self.dryRun())
422 73452f12 Michael Hanselmann
423 941b9309 Iustin Pop
    cl = baserlib.GetClient()
424 73452f12 Michael Hanselmann
425 0ae89533 Iustin Pop
    op = opcodes.OpNodeEvacStrategy(nodes=[node_name],
426 0ae89533 Iustin Pop
                                    iallocator=iallocator,
427 0ae89533 Iustin Pop
                                    remote_node=remote_node)
428 941b9309 Iustin Pop
429 941b9309 Iustin Pop
    job_id = baserlib.SubmitJob([op], cl)
430 941b9309 Iustin Pop
    # we use custom feedback function, instead of print we log the status
431 941b9309 Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
432 941b9309 Iustin Pop
433 941b9309 Iustin Pop
    jobs = []
434 63ea9789 Iustin Pop
    for iname, node in result[0]:
435 941b9309 Iustin Pop
      if dry_run:
436 941b9309 Iustin Pop
        jid = None
437 941b9309 Iustin Pop
      else:
438 668f755d Iustin Pop
        op = opcodes.OpInstanceReplaceDisks(instance_name=iname,
439 668f755d Iustin Pop
                                            remote_node=node, disks=[],
440 668f755d Iustin Pop
                                            mode=constants.REPLACE_DISK_CHG,
441 668f755d Iustin Pop
                                            early_release=early_r)
442 941b9309 Iustin Pop
        jid = baserlib.SubmitJob([op])
443 941b9309 Iustin Pop
      jobs.append((jid, iname, node))
444 941b9309 Iustin Pop
445 941b9309 Iustin Pop
    return jobs
446 73452f12 Michael Hanselmann
447 73452f12 Michael Hanselmann
448 1c482bab Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.R_Generic):
449 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
450 1c482bab Michael Hanselmann

451 1c482bab Michael Hanselmann
  """
452 1c482bab Michael Hanselmann
  def POST(self):
453 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
454 1c482bab Michael Hanselmann

455 1c482bab Michael Hanselmann
    """
456 1c482bab Michael Hanselmann
    node_name = self.items[0]
457 1c482bab Michael Hanselmann
458 52194140 Iustin Pop
    if "live" in self.queryargs and "mode" in self.queryargs:
459 52194140 Iustin Pop
      raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
460 52194140 Iustin Pop
                                " be passed")
461 52194140 Iustin Pop
    elif "live" in self.queryargs:
462 52194140 Iustin Pop
      if self._checkIntVariable("live", default=1):
463 52194140 Iustin Pop
        mode = constants.HT_MIGRATION_LIVE
464 52194140 Iustin Pop
      else:
465 52194140 Iustin Pop
        mode = constants.HT_MIGRATION_NONLIVE
466 52194140 Iustin Pop
    else:
467 52194140 Iustin Pop
      mode = self._checkStringVariable("mode", default=None)
468 52194140 Iustin Pop
469 5b14a488 Iustin Pop
    op = opcodes.OpNodeMigrate(node_name=node_name, mode=mode)
470 1c482bab Michael Hanselmann
471 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
472 1c482bab Michael Hanselmann
473 1c482bab Michael Hanselmann
474 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
475 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
476 7a95a954 Michael Hanselmann

477 7a95a954 Michael Hanselmann
  """
478 ad8d0595 Iustin Pop
  # LUNodeQueryStorage acquires locks, hence restricting access to GET
479 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
480 7a95a954 Michael Hanselmann
481 7a95a954 Michael Hanselmann
  def GET(self):
482 7a95a954 Michael Hanselmann
    node_name = self.items[0]
483 7a95a954 Michael Hanselmann
484 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
485 7a95a954 Michael Hanselmann
    if not storage_type:
486 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
487 7a95a954 Michael Hanselmann
                                " parameter")
488 7a95a954 Michael Hanselmann
489 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
490 7a95a954 Michael Hanselmann
    if not output_fields:
491 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
492 7a95a954 Michael Hanselmann
                                " parameter")
493 7a95a954 Michael Hanselmann
494 ad8d0595 Iustin Pop
    op = opcodes.OpNodeQueryStorage(nodes=[node_name],
495 7a95a954 Michael Hanselmann
                                    storage_type=storage_type,
496 7a95a954 Michael Hanselmann
                                    output_fields=output_fields.split(","))
497 7a95a954 Michael Hanselmann
    return baserlib.SubmitJob([op])
498 7a95a954 Michael Hanselmann
499 7a95a954 Michael Hanselmann
500 1e82bc80 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.R_Generic):
501 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify resource.
502 1e82bc80 Michael Hanselmann

503 1e82bc80 Michael Hanselmann
  """
504 1e82bc80 Michael Hanselmann
  def PUT(self):
505 1e82bc80 Michael Hanselmann
    node_name = self.items[0]
506 1e82bc80 Michael Hanselmann
507 1e82bc80 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
508 1e82bc80 Michael Hanselmann
    if not storage_type:
509 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
510 1e82bc80 Michael Hanselmann
                                " parameter")
511 1e82bc80 Michael Hanselmann
512 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
513 1e82bc80 Michael Hanselmann
    if not name:
514 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
515 1e82bc80 Michael Hanselmann
                                " parameter")
516 1e82bc80 Michael Hanselmann
517 1e82bc80 Michael Hanselmann
    changes = {}
518 1e82bc80 Michael Hanselmann
519 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
520 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
521 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
522 1e82bc80 Michael Hanselmann
523 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
524 1e82bc80 Michael Hanselmann
                                     storage_type=storage_type,
525 1e82bc80 Michael Hanselmann
                                     name=name,
526 1e82bc80 Michael Hanselmann
                                     changes=changes)
527 1e82bc80 Michael Hanselmann
    return baserlib.SubmitJob([op])
528 1e82bc80 Michael Hanselmann
529 1e82bc80 Michael Hanselmann
530 723f4565 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.R_Generic):
531 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair resource.
532 723f4565 Michael Hanselmann

533 723f4565 Michael Hanselmann
  """
534 723f4565 Michael Hanselmann
  def PUT(self):
535 723f4565 Michael Hanselmann
    node_name = self.items[0]
536 723f4565 Michael Hanselmann
537 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
538 723f4565 Michael Hanselmann
    if not storage_type:
539 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
540 723f4565 Michael Hanselmann
                                " parameter")
541 723f4565 Michael Hanselmann
542 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
543 723f4565 Michael Hanselmann
    if not name:
544 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
545 723f4565 Michael Hanselmann
                                " parameter")
546 723f4565 Michael Hanselmann
547 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
548 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
549 723f4565 Michael Hanselmann
                                     name=name)
550 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
551 723f4565 Michael Hanselmann
552 723f4565 Michael Hanselmann
553 90e99856 Adeodato Simo
def _ParseCreateGroupRequest(data, dry_run):
554 90e99856 Adeodato Simo
  """Parses a request for creating a node group.
555 90e99856 Adeodato Simo

556 fabf1731 Iustin Pop
  @rtype: L{opcodes.OpGroupAdd}
557 90e99856 Adeodato Simo
  @return: Group creation opcode
558 90e99856 Adeodato Simo

559 90e99856 Adeodato Simo
  """
560 527fbde8 Michael Hanselmann
  override = {
561 527fbde8 Michael Hanselmann
    "dry_run": dry_run,
562 527fbde8 Michael Hanselmann
    }
563 90e99856 Adeodato Simo
564 527fbde8 Michael Hanselmann
  rename = {
565 527fbde8 Michael Hanselmann
    "name": "group_name",
566 527fbde8 Michael Hanselmann
    }
567 527fbde8 Michael Hanselmann
568 527fbde8 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupAdd, data, override,
569 527fbde8 Michael Hanselmann
                             rename=rename)
570 90e99856 Adeodato Simo
571 90e99856 Adeodato Simo
572 0897dc97 Adeodato Simo
class R_2_groups(baserlib.R_Generic):
573 0897dc97 Adeodato Simo
  """/2/groups resource.
574 0897dc97 Adeodato Simo

575 0897dc97 Adeodato Simo
  """
576 0897dc97 Adeodato Simo
  def GET(self):
577 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
578 0897dc97 Adeodato Simo

579 0897dc97 Adeodato Simo
    """
580 0897dc97 Adeodato Simo
    client = baserlib.GetClient()
581 0897dc97 Adeodato Simo
582 0897dc97 Adeodato Simo
    if self.useBulk():
583 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
584 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
585 0897dc97 Adeodato Simo
    else:
586 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
587 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
588 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
589 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
590 0897dc97 Adeodato Simo
591 0dbaa9ca Adeodato Simo
  def POST(self):
592 0dbaa9ca Adeodato Simo
    """Create a node group.
593 0dbaa9ca Adeodato Simo

594 0dbaa9ca Adeodato Simo
    @return: a job id
595 0dbaa9ca Adeodato Simo

596 0dbaa9ca Adeodato Simo
    """
597 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
598 90e99856 Adeodato Simo
    op = _ParseCreateGroupRequest(self.request_body, self.dryRun())
599 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
600 0dbaa9ca Adeodato Simo
601 0897dc97 Adeodato Simo
602 0897dc97 Adeodato Simo
class R_2_groups_name(baserlib.R_Generic):
603 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name] resource.
604 0897dc97 Adeodato Simo

605 0897dc97 Adeodato Simo
  """
606 0897dc97 Adeodato Simo
  def GET(self):
607 0897dc97 Adeodato Simo
    """Send information about a node group.
608 0897dc97 Adeodato Simo

609 0897dc97 Adeodato Simo
    """
610 0897dc97 Adeodato Simo
    group_name = self.items[0]
611 0897dc97 Adeodato Simo
    client = baserlib.GetClient()
612 0897dc97 Adeodato Simo
613 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
614 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
615 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
616 0897dc97 Adeodato Simo
617 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
618 0897dc97 Adeodato Simo
619 0dbaa9ca Adeodato Simo
  def DELETE(self):
620 0dbaa9ca Adeodato Simo
    """Delete a node group.
621 0dbaa9ca Adeodato Simo

622 0dbaa9ca Adeodato Simo
    """
623 4d1baa51 Iustin Pop
    op = opcodes.OpGroupRemove(group_name=self.items[0],
624 0dbaa9ca Adeodato Simo
                               dry_run=bool(self.dryRun()))
625 0dbaa9ca Adeodato Simo
626 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
627 0dbaa9ca Adeodato Simo
628 0dbaa9ca Adeodato Simo
629 f18fab7d Adeodato Simo
def _ParseModifyGroupRequest(name, data):
630 f18fab7d Adeodato Simo
  """Parses a request for modifying a node group.
631 f18fab7d Adeodato Simo

632 7cbf74f0 Iustin Pop
  @rtype: L{opcodes.OpGroupSetParams}
633 f18fab7d Adeodato Simo
  @return: Group modify opcode
634 f18fab7d Adeodato Simo

635 f18fab7d Adeodato Simo
  """
636 df340fae Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupSetParams, data, {
637 df340fae Michael Hanselmann
    "group_name": name,
638 df340fae Michael Hanselmann
    })
639 df340fae Michael Hanselmann
640 f18fab7d Adeodato Simo
641 f18fab7d Adeodato Simo
642 f18fab7d Adeodato Simo
class R_2_groups_name_modify(baserlib.R_Generic):
643 f18fab7d Adeodato Simo
  """/2/groups/[group_name]/modify resource.
644 f18fab7d Adeodato Simo

645 f18fab7d Adeodato Simo
  """
646 f18fab7d Adeodato Simo
  def PUT(self):
647 f18fab7d Adeodato Simo
    """Changes some parameters of node group.
648 f18fab7d Adeodato Simo

649 f18fab7d Adeodato Simo
    @return: a job id
650 f18fab7d Adeodato Simo

651 f18fab7d Adeodato Simo
    """
652 f18fab7d Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
653 f18fab7d Adeodato Simo
654 f18fab7d Adeodato Simo
    op = _ParseModifyGroupRequest(self.items[0], self.request_body)
655 f18fab7d Adeodato Simo
656 f18fab7d Adeodato Simo
    return baserlib.SubmitJob([op])
657 f18fab7d Adeodato Simo
658 f18fab7d Adeodato Simo
659 0dbaa9ca Adeodato Simo
def _ParseRenameGroupRequest(name, data, dry_run):
660 0dbaa9ca Adeodato Simo
  """Parses a request for renaming a node group.
661 0dbaa9ca Adeodato Simo

662 0dbaa9ca Adeodato Simo
  @type name: string
663 0dbaa9ca Adeodato Simo
  @param name: name of the node group to rename
664 0dbaa9ca Adeodato Simo
  @type data: dict
665 0dbaa9ca Adeodato Simo
  @param data: the body received by the rename request
666 0dbaa9ca Adeodato Simo
  @type dry_run: bool
667 0dbaa9ca Adeodato Simo
  @param dry_run: whether to perform a dry run
668 0dbaa9ca Adeodato Simo

669 a8173e82 Iustin Pop
  @rtype: L{opcodes.OpGroupRename}
670 0dbaa9ca Adeodato Simo
  @return: Node group rename opcode
671 0dbaa9ca Adeodato Simo

672 0dbaa9ca Adeodato Simo
  """
673 8a08be3b Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpGroupRename, data, {
674 8a08be3b Michael Hanselmann
    "group_name": name,
675 8a08be3b Michael Hanselmann
    "dry_run": dry_run,
676 8a08be3b Michael Hanselmann
    })
677 0dbaa9ca Adeodato Simo
678 0dbaa9ca Adeodato Simo
679 0dbaa9ca Adeodato Simo
class R_2_groups_name_rename(baserlib.R_Generic):
680 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/rename resource.
681 0dbaa9ca Adeodato Simo

682 0dbaa9ca Adeodato Simo
  """
683 0dbaa9ca Adeodato Simo
  def PUT(self):
684 0dbaa9ca Adeodato Simo
    """Changes the name of a node group.
685 0dbaa9ca Adeodato Simo

686 0dbaa9ca Adeodato Simo
    @return: a job id
687 0dbaa9ca Adeodato Simo

688 0dbaa9ca Adeodato Simo
    """
689 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
690 0dbaa9ca Adeodato Simo
    op = _ParseRenameGroupRequest(self.items[0], self.request_body,
691 0dbaa9ca Adeodato Simo
                                  self.dryRun())
692 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
693 0897dc97 Adeodato Simo
694 0897dc97 Adeodato Simo
695 4245446f Adeodato Simo
class R_2_groups_name_assign_nodes(baserlib.R_Generic):
696 b58a4d16 Michael Hanselmann
  """/2/groups/[group_name]/assign-nodes resource.
697 4245446f Adeodato Simo

698 4245446f Adeodato Simo
  """
699 4245446f Adeodato Simo
  def PUT(self):
700 4245446f Adeodato Simo
    """Assigns nodes to a group.
701 4245446f Adeodato Simo

702 4245446f Adeodato Simo
    @return: a job id
703 4245446f Adeodato Simo

704 4245446f Adeodato Simo
    """
705 934704ae Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpGroupAssignNodes, self.request_body, {
706 4245446f Adeodato Simo
      "group_name": self.items[0],
707 4245446f Adeodato Simo
      "dry_run": self.dryRun(),
708 4245446f Adeodato Simo
      "force": self.useForce(),
709 4245446f Adeodato Simo
      })
710 4245446f Adeodato Simo
711 4245446f Adeodato Simo
    return baserlib.SubmitJob([op])
712 4245446f Adeodato Simo
713 4245446f Adeodato Simo
714 6395cebb Michael Hanselmann
def _ParseInstanceCreateRequestVersion1(data, dry_run):
715 6395cebb Michael Hanselmann
  """Parses an instance creation request version 1.
716 6395cebb Michael Hanselmann

717 e1530b10 Iustin Pop
  @rtype: L{opcodes.OpInstanceCreate}
718 6395cebb Michael Hanselmann
  @return: Instance creation opcode
719 6395cebb Michael Hanselmann

720 6395cebb Michael Hanselmann
  """
721 526a662a Michael Hanselmann
  override = {
722 526a662a Michael Hanselmann
    "dry_run": dry_run,
723 526a662a Michael Hanselmann
    }
724 6395cebb Michael Hanselmann
725 526a662a Michael Hanselmann
  rename = {
726 526a662a Michael Hanselmann
    "os": "os_type",
727 526a662a Michael Hanselmann
    "name": "instance_name",
728 526a662a Michael Hanselmann
    }
729 526a662a Michael Hanselmann
730 526a662a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceCreate, data, override,
731 526a662a Michael Hanselmann
                             rename=rename)
732 6395cebb Michael Hanselmann
733 6395cebb Michael Hanselmann
734 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
735 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
736 441e7cfd Oleksiy Mishchenko

737 441e7cfd Oleksiy Mishchenko
  """
738 441e7cfd Oleksiy Mishchenko
  def GET(self):
739 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
740 441e7cfd Oleksiy Mishchenko

741 441e7cfd Oleksiy Mishchenko
    """
742 59b4eeef Iustin Pop
    client = baserlib.GetClient()
743 441e7cfd Oleksiy Mishchenko
744 3d103742 Iustin Pop
    use_locking = self.useLocking()
745 3d103742 Iustin Pop
    if self.useBulk():
746 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
747 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
748 441e7cfd Oleksiy Mishchenko
    else:
749 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
750 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
751 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
752 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
753 441e7cfd Oleksiy Mishchenko
754 d975f482 Michael Hanselmann
  def POST(self):
755 d975f482 Michael Hanselmann
    """Create an instance.
756 d975f482 Michael Hanselmann

757 d975f482 Michael Hanselmann
    @return: a job id
758 d975f482 Michael Hanselmann

759 d975f482 Michael Hanselmann
    """
760 1c54156d Luca Bigliardi
    if not isinstance(self.request_body, dict):
761 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
762 d975f482 Michael Hanselmann
763 d975f482 Michael Hanselmann
    # Default to request data version 0
764 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
765 d975f482 Michael Hanselmann
766 d975f482 Michael Hanselmann
    if data_version == 0:
767 3fd7f652 Michael Hanselmann
      raise http.HttpBadRequest("Instance creation request version 0 is no"
768 3fd7f652 Michael Hanselmann
                                " longer supported")
769 6395cebb Michael Hanselmann
    elif data_version == 1:
770 4b163794 Michael Hanselmann
      data = self.request_body.copy()
771 4b163794 Michael Hanselmann
      # Remove "__version__"
772 4b163794 Michael Hanselmann
      data.pop(_REQ_DATA_VERSION, None)
773 4b163794 Michael Hanselmann
      op = _ParseInstanceCreateRequestVersion1(data, self.dryRun())
774 d975f482 Michael Hanselmann
    else:
775 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
776 12eff9b9 Michael Hanselmann
                                data_version)
777 d975f482 Michael Hanselmann
778 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
779 2f7635f4 Oleksiy Mishchenko
780 441e7cfd Oleksiy Mishchenko
781 4e5a68f8 Oleksiy Mishchenko
class R_2_instances_name(baserlib.R_Generic):
782 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name] resource.
783 028c6b76 Oleksiy Mishchenko

784 028c6b76 Oleksiy Mishchenko
  """
785 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
786 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
787 4e5a68f8 Oleksiy Mishchenko

788 4e5a68f8 Oleksiy Mishchenko
    """
789 59b4eeef Iustin Pop
    client = baserlib.GetClient()
790 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
791 e8ebbd2b Michael Hanselmann
792 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
793 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
794 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
795 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
796 4e5a68f8 Oleksiy Mishchenko
797 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
798 028c6b76 Oleksiy Mishchenko
799 6e99c5a0 Iustin Pop
  def DELETE(self):
800 6e99c5a0 Iustin Pop
    """Delete an instance.
801 6e99c5a0 Iustin Pop

802 6e99c5a0 Iustin Pop
    """
803 3cd2d4b1 Iustin Pop
    op = opcodes.OpInstanceRemove(instance_name=self.items[0],
804 6f59b964 Iustin Pop
                                  ignore_failures=False,
805 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
806 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
807 6e99c5a0 Iustin Pop
808 028c6b76 Oleksiy Mishchenko
809 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
810 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
811 d8260842 Michael Hanselmann

812 d8260842 Michael Hanselmann
  """
813 d8260842 Michael Hanselmann
  def GET(self):
814 d8260842 Michael Hanselmann
    """Request detailed instance information.
815 d8260842 Michael Hanselmann

816 d8260842 Michael Hanselmann
    """
817 d8260842 Michael Hanselmann
    instance_name = self.items[0]
818 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
819 d8260842 Michael Hanselmann
820 dc28c4e4 Iustin Pop
    op = opcodes.OpInstanceQueryData(instances=[instance_name],
821 d8260842 Michael Hanselmann
                                     static=static)
822 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
823 d8260842 Michael Hanselmann
824 d8260842 Michael Hanselmann
825 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
826 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
827 2276aa29 Oleksiy Mishchenko

828 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
829 2276aa29 Oleksiy Mishchenko

830 2276aa29 Oleksiy Mishchenko
  """
831 21f04e5e Oleksiy Mishchenko
  def POST(self):
832 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
833 2276aa29 Oleksiy Mishchenko

834 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
835 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
836 0c55c24b Oleksiy Mishchenko

837 2276aa29 Oleksiy Mishchenko
    """
838 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
839 0c55c24b Oleksiy Mishchenko
    reboot_type = self.queryargs.get('type',
840 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
841 94cdfa4a Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable('ignore_secondaries'))
842 90ab1a95 Iustin Pop
    op = opcodes.OpInstanceReboot(instance_name=instance_name,
843 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
844 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
845 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
846 2276aa29 Oleksiy Mishchenko
847 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
848 2276aa29 Oleksiy Mishchenko
849 2276aa29 Oleksiy Mishchenko
850 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
851 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
852 0c55c24b Oleksiy Mishchenko

853 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
854 0c55c24b Oleksiy Mishchenko

855 0c55c24b Oleksiy Mishchenko
  """
856 21f04e5e Oleksiy Mishchenko
  def PUT(self):
857 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
858 0c55c24b Oleksiy Mishchenko

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

862 0c55c24b Oleksiy Mishchenko
    """
863 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
864 94cdfa4a Iustin Pop
    force_startup = bool(self._checkIntVariable('force'))
865 c873d91c Iustin Pop
    op = opcodes.OpInstanceStartup(instance_name=instance_name,
866 6f59b964 Iustin Pop
                                   force=force_startup,
867 6f59b964 Iustin Pop
                                   dry_run=bool(self.dryRun()))
868 0c55c24b Oleksiy Mishchenko
869 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
870 0c55c24b Oleksiy Mishchenko
871 0c55c24b Oleksiy Mishchenko
872 7fa310f6 René Nussbaumer
def _ParseShutdownInstanceRequest(name, data, dry_run):
873 7fa310f6 René Nussbaumer
  """Parses a request for an instance shutdown.
874 7fa310f6 René Nussbaumer

875 7fa310f6 René Nussbaumer
  @rtype: L{opcodes.OpInstanceShutdown}
876 7fa310f6 René Nussbaumer
  @return: Instance shutdown opcode
877 7fa310f6 René Nussbaumer

878 7fa310f6 René Nussbaumer
  """
879 7fa310f6 René Nussbaumer
  return baserlib.FillOpcode(opcodes.OpInstanceShutdown, data, {
880 7fa310f6 René Nussbaumer
    "instance_name": name,
881 7fa310f6 René Nussbaumer
    "dry_run": dry_run,
882 7fa310f6 René Nussbaumer
    })
883 7fa310f6 René Nussbaumer
884 7fa310f6 René Nussbaumer
885 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
886 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
887 0c55c24b Oleksiy Mishchenko

888 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
889 0c55c24b Oleksiy Mishchenko

890 0c55c24b Oleksiy Mishchenko
  """
891 21f04e5e Oleksiy Mishchenko
  def PUT(self):
892 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
893 0c55c24b Oleksiy Mishchenko

894 7fa310f6 René Nussbaumer
    @return: a job id
895 7fa310f6 René Nussbaumer

896 0c55c24b Oleksiy Mishchenko
    """
897 7fa310f6 René Nussbaumer
    baserlib.CheckType(self.request_body, dict, "Body contents")
898 7fa310f6 René Nussbaumer
899 7fa310f6 René Nussbaumer
    op = _ParseShutdownInstanceRequest(self.items[0], self.request_body,
900 7fa310f6 René Nussbaumer
                                       bool(self.dryRun()))
901 0c55c24b Oleksiy Mishchenko
902 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
903 0c55c24b Oleksiy Mishchenko
904 0c55c24b Oleksiy Mishchenko
905 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
906 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
907 c744425f Michael Hanselmann

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

932 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
933 e5b7c4ca Iustin Pop

934 e5b7c4ca Iustin Pop
  """
935 e5b7c4ca Iustin Pop
  def POST(self):
936 e5b7c4ca Iustin Pop
    """Reinstall an instance.
937 e5b7c4ca Iustin Pop

938 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
939 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
940 e5b7c4ca Iustin Pop
    automatically.
941 e5b7c4ca Iustin Pop

942 e5b7c4ca Iustin Pop
    """
943 c744425f Michael Hanselmann
    if self.request_body:
944 c744425f Michael Hanselmann
      if self.queryargs:
945 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
946 c744425f Michael Hanselmann
947 c744425f Michael Hanselmann
      body = self.request_body
948 bd0807fe Guido Trotter
    elif self.queryargs:
949 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
950 c744425f Michael Hanselmann
      body = {
951 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
952 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
953 c744425f Michael Hanselmann
        }
954 bd0807fe Guido Trotter
    else:
955 bd0807fe Guido Trotter
      body = {}
956 c744425f Michael Hanselmann
957 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
958 c744425f Michael Hanselmann
959 e5b7c4ca Iustin Pop
    return baserlib.SubmitJob(ops)
960 e5b7c4ca Iustin Pop
961 e5b7c4ca Iustin Pop
962 d1c172de Michael Hanselmann
def _ParseInstanceReplaceDisksRequest(name, data):
963 d1c172de Michael Hanselmann
  """Parses a request for an instance export.
964 d1c172de Michael Hanselmann

965 d1c172de Michael Hanselmann
  @rtype: L{opcodes.OpInstanceReplaceDisks}
966 d1c172de Michael Hanselmann
  @return: Instance export opcode
967 d1c172de Michael Hanselmann

968 d1c172de Michael Hanselmann
  """
969 d1c172de Michael Hanselmann
  override = {
970 d1c172de Michael Hanselmann
    "instance_name": name,
971 d1c172de Michael Hanselmann
    }
972 d1c172de Michael Hanselmann
973 d1c172de Michael Hanselmann
  # Parse disks
974 d1c172de Michael Hanselmann
  try:
975 d1c172de Michael Hanselmann
    raw_disks = data["disks"]
976 d1c172de Michael Hanselmann
  except KeyError:
977 d1c172de Michael Hanselmann
    pass
978 d1c172de Michael Hanselmann
  else:
979 d1c172de Michael Hanselmann
    if not ht.TListOf(ht.TInt)(raw_disks): # pylint: disable-msg=E1102
980 d1c172de Michael Hanselmann
      # Backwards compatibility for strings of the format "1, 2, 3"
981 d1c172de Michael Hanselmann
      try:
982 d1c172de Michael Hanselmann
        data["disks"] = [int(part) for part in raw_disks.split(",")]
983 d1c172de Michael Hanselmann
      except (TypeError, ValueError), err:
984 d1c172de Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
985 d1c172de Michael Hanselmann
986 d1c172de Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceReplaceDisks, data, override)
987 d1c172de Michael Hanselmann
988 d1c172de Michael Hanselmann
989 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
990 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
991 4c98b915 Michael Hanselmann

992 4c98b915 Michael Hanselmann
  """
993 4c98b915 Michael Hanselmann
  def POST(self):
994 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
995 4c98b915 Michael Hanselmann

996 4c98b915 Michael Hanselmann
    """
997 d1c172de Michael Hanselmann
    op = _ParseInstanceReplaceDisksRequest(self.items[0], self.request_body)
998 4c98b915 Michael Hanselmann
999 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
1000 4c98b915 Michael Hanselmann
1001 4c98b915 Michael Hanselmann
1002 2197b66f René Nussbaumer
class R_2_instances_name_activate_disks(baserlib.R_Generic):
1003 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1004 2197b66f René Nussbaumer

1005 2197b66f René Nussbaumer
  """
1006 2197b66f René Nussbaumer
  def PUT(self):
1007 2197b66f René Nussbaumer
    """Activate disks for an instance.
1008 2197b66f René Nussbaumer

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

1011 2197b66f René Nussbaumer
    """
1012 2197b66f René Nussbaumer
    instance_name = self.items[0]
1013 2197b66f René Nussbaumer
    ignore_size = bool(self._checkIntVariable('ignore_size'))
1014 2197b66f René Nussbaumer
1015 83f5d475 Iustin Pop
    op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
1016 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
1017 2197b66f René Nussbaumer
1018 2197b66f René Nussbaumer
    return baserlib.SubmitJob([op])
1019 2197b66f René Nussbaumer
1020 2197b66f René Nussbaumer
1021 0a37de5f René Nussbaumer
class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
1022 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1023 0a37de5f René Nussbaumer

1024 0a37de5f René Nussbaumer
  """
1025 0a37de5f René Nussbaumer
  def PUT(self):
1026 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1027 0a37de5f René Nussbaumer

1028 0a37de5f René Nussbaumer
    """
1029 0a37de5f René Nussbaumer
    instance_name = self.items[0]
1030 0a37de5f René Nussbaumer
1031 e176281f Iustin Pop
    op = opcodes.OpInstanceDeactivateDisks(instance_name=instance_name)
1032 0a37de5f René Nussbaumer
1033 0a37de5f René Nussbaumer
    return baserlib.SubmitJob([op])
1034 0a37de5f René Nussbaumer
1035 0a37de5f René Nussbaumer
1036 ebeb600f Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.R_Generic):
1037 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1038 ebeb600f Michael Hanselmann

1039 ebeb600f Michael Hanselmann
  """
1040 ebeb600f Michael Hanselmann
  def PUT(self):
1041 ebeb600f Michael Hanselmann
    """Prepares an export for an instance.
1042 ebeb600f Michael Hanselmann

1043 ebeb600f Michael Hanselmann
    @return: a job id
1044 ebeb600f Michael Hanselmann

1045 ebeb600f Michael Hanselmann
    """
1046 ebeb600f Michael Hanselmann
    instance_name = self.items[0]
1047 ebeb600f Michael Hanselmann
    mode = self._checkStringVariable("mode")
1048 ebeb600f Michael Hanselmann
1049 71910715 Iustin Pop
    op = opcodes.OpBackupPrepare(instance_name=instance_name,
1050 ebeb600f Michael Hanselmann
                                 mode=mode)
1051 ebeb600f Michael Hanselmann
1052 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1053 ebeb600f Michael Hanselmann
1054 ebeb600f Michael Hanselmann
1055 ebeb600f Michael Hanselmann
def _ParseExportInstanceRequest(name, data):
1056 ebeb600f Michael Hanselmann
  """Parses a request for an instance export.
1057 ebeb600f Michael Hanselmann

1058 4ff922a2 Iustin Pop
  @rtype: L{opcodes.OpBackupExport}
1059 ebeb600f Michael Hanselmann
  @return: Instance export opcode
1060 ebeb600f Michael Hanselmann

1061 ebeb600f Michael Hanselmann
  """
1062 07ce3e70 Michael Hanselmann
  # Rename "destination" to "target_node"
1063 07ce3e70 Michael Hanselmann
  try:
1064 07ce3e70 Michael Hanselmann
    data["target_node"] = data.pop("destination")
1065 07ce3e70 Michael Hanselmann
  except KeyError:
1066 07ce3e70 Michael Hanselmann
    pass
1067 07ce3e70 Michael Hanselmann
1068 07ce3e70 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpBackupExport, data, {
1069 07ce3e70 Michael Hanselmann
    "instance_name": name,
1070 07ce3e70 Michael Hanselmann
    })
1071 ebeb600f Michael Hanselmann
1072 ebeb600f Michael Hanselmann
1073 ebeb600f Michael Hanselmann
class R_2_instances_name_export(baserlib.R_Generic):
1074 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1075 ebeb600f Michael Hanselmann

1076 ebeb600f Michael Hanselmann
  """
1077 ebeb600f Michael Hanselmann
  def PUT(self):
1078 ebeb600f Michael Hanselmann
    """Exports an instance.
1079 ebeb600f Michael Hanselmann

1080 ebeb600f Michael Hanselmann
    @return: a job id
1081 ebeb600f Michael Hanselmann

1082 ebeb600f Michael Hanselmann
    """
1083 ebeb600f Michael Hanselmann
    if not isinstance(self.request_body, dict):
1084 ebeb600f Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
1085 ebeb600f Michael Hanselmann
1086 ebeb600f Michael Hanselmann
    op = _ParseExportInstanceRequest(self.items[0], self.request_body)
1087 ebeb600f Michael Hanselmann
1088 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1089 ebeb600f Michael Hanselmann
1090 ebeb600f Michael Hanselmann
1091 5823e0d2 Michael Hanselmann
def _ParseMigrateInstanceRequest(name, data):
1092 5823e0d2 Michael Hanselmann
  """Parses a request for an instance migration.
1093 5823e0d2 Michael Hanselmann

1094 75c866c2 Iustin Pop
  @rtype: L{opcodes.OpInstanceMigrate}
1095 5823e0d2 Michael Hanselmann
  @return: Instance migration opcode
1096 5823e0d2 Michael Hanselmann

1097 5823e0d2 Michael Hanselmann
  """
1098 c1a27c9a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceMigrate, data, {
1099 c1a27c9a Michael Hanselmann
    "instance_name": name,
1100 c1a27c9a Michael Hanselmann
    })
1101 5823e0d2 Michael Hanselmann
1102 5823e0d2 Michael Hanselmann
1103 5823e0d2 Michael Hanselmann
class R_2_instances_name_migrate(baserlib.R_Generic):
1104 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1105 5823e0d2 Michael Hanselmann

1106 5823e0d2 Michael Hanselmann
  """
1107 5823e0d2 Michael Hanselmann
  def PUT(self):
1108 5823e0d2 Michael Hanselmann
    """Migrates an instance.
1109 5823e0d2 Michael Hanselmann

1110 5823e0d2 Michael Hanselmann
    @return: a job id
1111 5823e0d2 Michael Hanselmann

1112 5823e0d2 Michael Hanselmann
    """
1113 5823e0d2 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1114 5823e0d2 Michael Hanselmann
1115 5823e0d2 Michael Hanselmann
    op = _ParseMigrateInstanceRequest(self.items[0], self.request_body)
1116 5823e0d2 Michael Hanselmann
1117 5823e0d2 Michael Hanselmann
    return baserlib.SubmitJob([op])
1118 5823e0d2 Michael Hanselmann
1119 5823e0d2 Michael Hanselmann
1120 d56e7dc7 Michael Hanselmann
def _ParseRenameInstanceRequest(name, data):
1121 d56e7dc7 Michael Hanselmann
  """Parses a request for renaming an instance.
1122 d56e7dc7 Michael Hanselmann

1123 5659e2e2 Iustin Pop
  @rtype: L{opcodes.OpInstanceRename}
1124 d56e7dc7 Michael Hanselmann
  @return: Instance rename opcode
1125 d56e7dc7 Michael Hanselmann

1126 d56e7dc7 Michael Hanselmann
  """
1127 88bc199a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceRename, data, {
1128 88bc199a Michael Hanselmann
    "instance_name": name,
1129 88bc199a Michael Hanselmann
    })
1130 d56e7dc7 Michael Hanselmann
1131 d56e7dc7 Michael Hanselmann
1132 d56e7dc7 Michael Hanselmann
class R_2_instances_name_rename(baserlib.R_Generic):
1133 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1134 d56e7dc7 Michael Hanselmann

1135 d56e7dc7 Michael Hanselmann
  """
1136 d56e7dc7 Michael Hanselmann
  def PUT(self):
1137 d56e7dc7 Michael Hanselmann
    """Changes the name of an instance.
1138 d56e7dc7 Michael Hanselmann

1139 d56e7dc7 Michael Hanselmann
    @return: a job id
1140 d56e7dc7 Michael Hanselmann

1141 d56e7dc7 Michael Hanselmann
    """
1142 d56e7dc7 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1143 d56e7dc7 Michael Hanselmann
1144 d56e7dc7 Michael Hanselmann
    op = _ParseRenameInstanceRequest(self.items[0], self.request_body)
1145 d56e7dc7 Michael Hanselmann
1146 d56e7dc7 Michael Hanselmann
    return baserlib.SubmitJob([op])
1147 d56e7dc7 Michael Hanselmann
1148 d56e7dc7 Michael Hanselmann
1149 3882937a Michael Hanselmann
def _ParseModifyInstanceRequest(name, data):
1150 3882937a Michael Hanselmann
  """Parses a request for modifying an instance.
1151 3882937a Michael Hanselmann

1152 9a3cc7ae Iustin Pop
  @rtype: L{opcodes.OpInstanceSetParams}
1153 3882937a Michael Hanselmann
  @return: Instance modify opcode
1154 3882937a Michael Hanselmann

1155 3882937a Michael Hanselmann
  """
1156 ee5549c7 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceSetParams, data, {
1157 ee5549c7 Michael Hanselmann
    "instance_name": name,
1158 ee5549c7 Michael Hanselmann
    })
1159 3882937a Michael Hanselmann
1160 3882937a Michael Hanselmann
1161 3882937a Michael Hanselmann
class R_2_instances_name_modify(baserlib.R_Generic):
1162 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1163 3882937a Michael Hanselmann

1164 3882937a Michael Hanselmann
  """
1165 3882937a Michael Hanselmann
  def PUT(self):
1166 3882937a Michael Hanselmann
    """Changes some parameters of an instance.
1167 3882937a Michael Hanselmann

1168 3882937a Michael Hanselmann
    @return: a job id
1169 3882937a Michael Hanselmann

1170 3882937a Michael Hanselmann
    """
1171 3882937a Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1172 3882937a Michael Hanselmann
1173 3882937a Michael Hanselmann
    op = _ParseModifyInstanceRequest(self.items[0], self.request_body)
1174 3882937a Michael Hanselmann
1175 3882937a Michael Hanselmann
    return baserlib.SubmitJob([op])
1176 3882937a Michael Hanselmann
1177 3882937a Michael Hanselmann
1178 e23881ed Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.R_Generic):
1179 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1180 e23881ed Michael Hanselmann

1181 e23881ed Michael Hanselmann
  """
1182 e23881ed Michael Hanselmann
  def POST(self):
1183 e23881ed Michael Hanselmann
    """Increases the size of an instance disk.
1184 e23881ed Michael Hanselmann

1185 e23881ed Michael Hanselmann
    @return: a job id
1186 e23881ed Michael Hanselmann

1187 e23881ed Michael Hanselmann
    """
1188 60472d29 Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpInstanceGrowDisk, self.request_body, {
1189 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1190 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1191 e23881ed Michael Hanselmann
      })
1192 e23881ed Michael Hanselmann
1193 e23881ed Michael Hanselmann
    return baserlib.SubmitJob([op])
1194 e23881ed Michael Hanselmann
1195 e23881ed Michael Hanselmann
1196 b82d4c5e Michael Hanselmann
class R_2_instances_name_console(baserlib.R_Generic):
1197 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1198 b82d4c5e Michael Hanselmann

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

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

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

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

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

1242 208a6cff Michael Hanselmann
  """
1243 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1244 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1245 208a6cff Michael Hanselmann
1246 208a6cff Michael Hanselmann
  def _Query(self, fields, filter_):
1247 208a6cff Michael Hanselmann
    return baserlib.GetClient().Query(self.items[0], fields, filter_).ToDict()
1248 208a6cff Michael Hanselmann
1249 208a6cff Michael Hanselmann
  def GET(self):
1250 208a6cff Michael Hanselmann
    """Returns resource information.
1251 208a6cff Michael Hanselmann

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

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

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

1262 208a6cff Michael Hanselmann
    """
1263 208a6cff Michael Hanselmann
    body = self.request_body
1264 208a6cff Michael Hanselmann
1265 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1266 208a6cff Michael Hanselmann
1267 208a6cff Michael Hanselmann
    try:
1268 208a6cff Michael Hanselmann
      fields = body["fields"]
1269 208a6cff Michael Hanselmann
    except KeyError:
1270 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1271 208a6cff Michael Hanselmann
1272 208a6cff Michael Hanselmann
    return self._Query(fields, self.request_body.get("filter", None))
1273 208a6cff Michael Hanselmann
1274 208a6cff Michael Hanselmann
1275 208a6cff Michael Hanselmann
class R_2_query_fields(baserlib.R_Generic):
1276 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1277 208a6cff Michael Hanselmann

1278 208a6cff Michael Hanselmann
  """
1279 208a6cff Michael Hanselmann
  def GET(self):
1280 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1281 208a6cff Michael Hanselmann

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

1284 208a6cff Michael Hanselmann
    """
1285 208a6cff Michael Hanselmann
    try:
1286 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1287 208a6cff Michael Hanselmann
    except KeyError:
1288 208a6cff Michael Hanselmann
      fields = None
1289 208a6cff Michael Hanselmann
    else:
1290 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1291 208a6cff Michael Hanselmann
1292 208a6cff Michael Hanselmann
    return baserlib.GetClient().QueryFields(self.items[0], fields).ToDict()
1293 208a6cff Michael Hanselmann
1294 208a6cff Michael Hanselmann
1295 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
1296 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1297 441e7cfd Oleksiy Mishchenko

1298 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1299 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1300 441e7cfd Oleksiy Mishchenko

1301 441e7cfd Oleksiy Mishchenko
  """
1302 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1303 18cb43a2 Oleksiy Mishchenko
1304 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
1305 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1306 18cb43a2 Oleksiy Mishchenko

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

1309 18cb43a2 Oleksiy Mishchenko
    """
1310 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
1311 18cb43a2 Oleksiy Mishchenko
1312 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1313 5313eed7 Michael Hanselmann
      self.name = None
1314 18cb43a2 Oleksiy Mishchenko
    else:
1315 5313eed7 Michael Hanselmann
      self.name = items[0]
1316 441e7cfd Oleksiy Mishchenko
1317 441e7cfd Oleksiy Mishchenko
  def GET(self):
1318 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1319 441e7cfd Oleksiy Mishchenko

1320 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1321 441e7cfd Oleksiy Mishchenko

1322 441e7cfd Oleksiy Mishchenko
    """
1323 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1324 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
1325 441e7cfd Oleksiy Mishchenko
1326 21f04e5e Oleksiy Mishchenko
  def PUT(self):
1327 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1328 441e7cfd Oleksiy Mishchenko

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

1332 441e7cfd Oleksiy Mishchenko
    """
1333 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1334 6e99c5a0 Iustin Pop
    if 'tag' not in self.queryargs:
1335 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
1336 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
1337 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
1338 6f59b964 Iustin Pop
                              self.queryargs['tag'], name=self.name,
1339 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
1340 15fd9fd5 Oleksiy Mishchenko
1341 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
1342 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1343 15fd9fd5 Oleksiy Mishchenko

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

1348 15fd9fd5 Oleksiy Mishchenko
    """
1349 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1350 15fd9fd5 Oleksiy Mishchenko
    if 'tag' not in self.queryargs:
1351 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
1352 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
1353 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
1354 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
1355 15fd9fd5 Oleksiy Mishchenko
                                 self.queryargs['tag'],
1356 6f59b964 Iustin Pop
                                 name=self.name,
1357 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
1358 18cb43a2 Oleksiy Mishchenko
1359 18cb43a2 Oleksiy Mishchenko
1360 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1361 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1362 18cb43a2 Oleksiy Mishchenko

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

1365 18cb43a2 Oleksiy Mishchenko
  """
1366 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1367 18cb43a2 Oleksiy Mishchenko
1368 18cb43a2 Oleksiy Mishchenko
1369 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1370 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1371 18cb43a2 Oleksiy Mishchenko

1372 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1373 18cb43a2 Oleksiy Mishchenko

1374 18cb43a2 Oleksiy Mishchenko
  """
1375 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1376 18cb43a2 Oleksiy Mishchenko
1377 18cb43a2 Oleksiy Mishchenko
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