Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 2652b363

History | View | Annotate | Download (27.8 kB)

1 10b207d4 Oleksiy Mishchenko
#
2 10b207d4 Oleksiy Mishchenko
#
3 10b207d4 Oleksiy Mishchenko
4 10b207d4 Oleksiy Mishchenko
# Copyright (C) 2006, 2007, 2008 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 6395cebb Michael Hanselmann
from ganeti import utils
49 8381fa2d Michael Hanselmann
from ganeti import rapi
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 9031ee8e Iustin Pop
            "oper_state", "oper_ram", "status",
62 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
63 9031ee8e Iustin Pop
64 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
65 9031ee8e Iustin Pop
            "dtotal", "dfree",
66 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
67 7118a0df Iustin Pop
            "pinst_cnt", "sinst_cnt",
68 0105bad3 Iustin Pop
            "ctotal", "cnodes", "csockets",
69 7118a0df Iustin Pop
            "pip", "sip", "role",
70 93962b80 Iustin Pop
            "pinst_list", "sinst_list",
71 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
72 4e5a68f8 Oleksiy Mishchenko
73 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
74 64dae8fc Michael Hanselmann
_NR_MASTER_CANDIATE = "master-candidate"
75 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
76 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
77 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
78 64dae8fc Michael Hanselmann
79 64dae8fc Michael Hanselmann
_NR_MAP = {
80 64dae8fc Michael Hanselmann
  "M": _NR_MASTER,
81 64dae8fc Michael Hanselmann
  "C": _NR_MASTER_CANDIATE,
82 64dae8fc Michael Hanselmann
  "D": _NR_DRAINED,
83 64dae8fc Michael Hanselmann
  "O": _NR_OFFLINE,
84 64dae8fc Michael Hanselmann
  "R": _NR_REGULAR,
85 64dae8fc Michael Hanselmann
  }
86 64dae8fc Michael Hanselmann
87 d975f482 Michael Hanselmann
# Request data version field
88 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
89 d975f482 Michael Hanselmann
90 6395cebb Michael Hanselmann
# Feature string for instance creation request data version 1
91 6395cebb Michael Hanselmann
_INST_CREATE_REQV1 = "instance-create-reqv1"
92 6395cebb Michael Hanselmann
93 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
94 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
95 793a8f7c Michael Hanselmann
96 4e5a68f8 Oleksiy Mishchenko
97 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
98 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
99 4e5a68f8 Oleksiy Mishchenko

100 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
101 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
102 4e5a68f8 Oleksiy Mishchenko

103 4e5a68f8 Oleksiy Mishchenko
  """
104 7e950d31 Iustin Pop
  @staticmethod
105 7e950d31 Iustin Pop
  def GET():
106 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
107 4e5a68f8 Oleksiy Mishchenko

108 4e5a68f8 Oleksiy Mishchenko
    """
109 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
110 4e5a68f8 Oleksiy Mishchenko
111 4e5a68f8 Oleksiy Mishchenko
112 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
113 4e5a68f8 Oleksiy Mishchenko
  """Cluster info.
114 4e5a68f8 Oleksiy Mishchenko

115 4e5a68f8 Oleksiy Mishchenko
  """
116 7e950d31 Iustin Pop
  @staticmethod
117 7e950d31 Iustin Pop
  def GET():
118 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
119 4e5a68f8 Oleksiy Mishchenko

120 4e5a68f8 Oleksiy Mishchenko
    """
121 59b4eeef Iustin Pop
    client = baserlib.GetClient()
122 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
123 4e5a68f8 Oleksiy Mishchenko
124 4e5a68f8 Oleksiy Mishchenko
125 7eac4a4d Michael Hanselmann
class R_2_features(baserlib.R_Generic):
126 7eac4a4d Michael Hanselmann
  """/2/features resource.
127 7eac4a4d Michael Hanselmann

128 7eac4a4d Michael Hanselmann
  """
129 7eac4a4d Michael Hanselmann
  @staticmethod
130 7eac4a4d Michael Hanselmann
  def GET():
131 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
132 7eac4a4d Michael Hanselmann

133 7eac4a4d Michael Hanselmann
    """
134 6395cebb Michael Hanselmann
    return [_INST_CREATE_REQV1]
135 7eac4a4d Michael Hanselmann
136 7eac4a4d Michael Hanselmann
137 4e5a68f8 Oleksiy Mishchenko
class R_2_os(baserlib.R_Generic):
138 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
139 4e5a68f8 Oleksiy Mishchenko

140 4e5a68f8 Oleksiy Mishchenko
  """
141 7e950d31 Iustin Pop
  @staticmethod
142 7e950d31 Iustin Pop
  def GET():
143 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
144 4e5a68f8 Oleksiy Mishchenko

145 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
146 4e5a68f8 Oleksiy Mishchenko

147 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
148 4e5a68f8 Oleksiy Mishchenko

149 4e5a68f8 Oleksiy Mishchenko
    """
150 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
151 e3ac208c Guido Trotter
    op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants"],
152 e3ac208c Guido Trotter
                              names=[])
153 59b4eeef Iustin Pop
    job_id = baserlib.SubmitJob([op], cl)
154 59b4eeef Iustin Pop
    # we use custom feedback function, instead of print we log the status
155 59b4eeef Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
156 59b4eeef Iustin Pop
    diagnose_data = result[0]
157 4e5a68f8 Oleksiy Mishchenko
158 4e5a68f8 Oleksiy Mishchenko
    if not isinstance(diagnose_data, list):
159 59b4eeef Iustin Pop
      raise http.HttpBadGateway(message="Can't get OS list")
160 4e5a68f8 Oleksiy Mishchenko
161 e3ac208c Guido Trotter
    os_names = []
162 e3ac208c Guido Trotter
    for (name, valid, variants) in diagnose_data:
163 e3ac208c Guido Trotter
      if valid:
164 e3ac208c Guido Trotter
        os_names.extend(cli.CalculateOSNames(name, variants))
165 e3ac208c Guido Trotter
166 e3ac208c Guido Trotter
    return os_names
167 51ee2f49 Oleksiy Mishchenko
168 10b207d4 Oleksiy Mishchenko
169 508e9b20 Michael Hanselmann
class R_2_redist_config(baserlib.R_Generic):
170 508e9b20 Michael Hanselmann
  """/2/redistribute-config resource.
171 508e9b20 Michael Hanselmann

172 508e9b20 Michael Hanselmann
  """
173 7e950d31 Iustin Pop
  @staticmethod
174 7e950d31 Iustin Pop
  def PUT():
175 508e9b20 Michael Hanselmann
    """Redistribute configuration to all nodes.
176 508e9b20 Michael Hanselmann

177 508e9b20 Michael Hanselmann
    """
178 508e9b20 Michael Hanselmann
    return baserlib.SubmitJob([opcodes.OpRedistributeConfig()])
179 508e9b20 Michael Hanselmann
180 508e9b20 Michael Hanselmann
181 10b207d4 Oleksiy Mishchenko
class R_2_jobs(baserlib.R_Generic):
182 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
183 10b207d4 Oleksiy Mishchenko

184 10b207d4 Oleksiy Mishchenko
  """
185 7e950d31 Iustin Pop
  @staticmethod
186 7e950d31 Iustin Pop
  def GET():
187 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
188 10b207d4 Oleksiy Mishchenko

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

191 10b207d4 Oleksiy Mishchenko
    """
192 10b207d4 Oleksiy Mishchenko
    fields = ["id"]
193 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
194 10b207d4 Oleksiy Mishchenko
    # Convert the list of lists to the list of ids
195 59b4eeef Iustin Pop
    result = [job_id for [job_id] in cl.QueryJobs(None, fields)]
196 9031ee8e Iustin Pop
    return baserlib.BuildUriList(result, "/2/jobs/%s",
197 9031ee8e Iustin Pop
                                 uri_fields=("id", "uri"))
198 10b207d4 Oleksiy Mishchenko
199 10b207d4 Oleksiy Mishchenko
200 10b207d4 Oleksiy Mishchenko
class R_2_jobs_id(baserlib.R_Generic):
201 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
202 10b207d4 Oleksiy Mishchenko

203 10b207d4 Oleksiy Mishchenko
  """
204 10b207d4 Oleksiy Mishchenko
  def GET(self):
205 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
206 10b207d4 Oleksiy Mishchenko

207 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
208 c41eea6e Iustin Pop
        The result includes:
209 c41eea6e Iustin Pop
            - id: job ID as a number
210 c41eea6e Iustin Pop
            - status: current job status as a string
211 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
212 c41eea6e Iustin Pop
              opcodes in the job
213 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
214 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
215 38206f3c Iustin Pop

216 10b207d4 Oleksiy Mishchenko
    """
217 ee69c97f Iustin Pop
    fields = ["id", "ops", "status", "summary",
218 ee69c97f Iustin Pop
              "opstatus", "opresult", "oplog",
219 ee69c97f Iustin Pop
              "received_ts", "start_ts", "end_ts",
220 ee69c97f Iustin Pop
              ]
221 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
222 59b4eeef Iustin Pop
    result = baserlib.GetClient().QueryJobs([job_id, ], fields)[0]
223 ee69c97f Iustin Pop
    if result is None:
224 ee69c97f Iustin Pop
      raise http.HttpNotFound()
225 10b207d4 Oleksiy Mishchenko
    return baserlib.MapFields(fields, result)
226 10b207d4 Oleksiy Mishchenko
227 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
228 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
229 c7f5f338 Oleksiy Mishchenko

230 c7f5f338 Oleksiy Mishchenko
    """
231 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
232 59b4eeef Iustin Pop
    result = baserlib.GetClient().CancelJob(job_id)
233 c7f5f338 Oleksiy Mishchenko
    return result
234 c7f5f338 Oleksiy Mishchenko
235 10b207d4 Oleksiy Mishchenko
236 793a8f7c Michael Hanselmann
class R_2_jobs_id_wait(baserlib.R_Generic):
237 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
238 793a8f7c Michael Hanselmann

239 793a8f7c Michael Hanselmann
  """
240 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
241 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
242 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
243 793a8f7c Michael Hanselmann
244 793a8f7c Michael Hanselmann
  def GET(self):
245 793a8f7c Michael Hanselmann
    """Waits for job changes.
246 793a8f7c Michael Hanselmann

247 793a8f7c Michael Hanselmann
    """
248 793a8f7c Michael Hanselmann
    job_id = self.items[0]
249 793a8f7c Michael Hanselmann
250 793a8f7c Michael Hanselmann
    fields = self.getBodyParameter("fields")
251 793a8f7c Michael Hanselmann
    prev_job_info = self.getBodyParameter("previous_job_info", None)
252 793a8f7c Michael Hanselmann
    prev_log_serial = self.getBodyParameter("previous_log_serial", None)
253 793a8f7c Michael Hanselmann
254 793a8f7c Michael Hanselmann
    if not isinstance(fields, list):
255 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'fields' parameter should be a list")
256 793a8f7c Michael Hanselmann
257 793a8f7c Michael Hanselmann
    if not (prev_job_info is None or isinstance(prev_job_info, list)):
258 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_job_info' parameter should"
259 793a8f7c Michael Hanselmann
                                " be a list")
260 793a8f7c Michael Hanselmann
261 793a8f7c Michael Hanselmann
    if not (prev_log_serial is None or
262 793a8f7c Michael Hanselmann
            isinstance(prev_log_serial, (int, long))):
263 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_log_serial' parameter should"
264 793a8f7c Michael Hanselmann
                                " be a number")
265 793a8f7c Michael Hanselmann
266 793a8f7c Michael Hanselmann
    client = baserlib.GetClient()
267 793a8f7c Michael Hanselmann
    result = client.WaitForJobChangeOnce(job_id, fields,
268 793a8f7c Michael Hanselmann
                                         prev_job_info, prev_log_serial,
269 793a8f7c Michael Hanselmann
                                         timeout=_WFJC_TIMEOUT)
270 793a8f7c Michael Hanselmann
    if not result:
271 793a8f7c Michael Hanselmann
      raise http.HttpNotFound()
272 793a8f7c Michael Hanselmann
273 793a8f7c Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
274 793a8f7c Michael Hanselmann
      # No changes
275 793a8f7c Michael Hanselmann
      return None
276 793a8f7c Michael Hanselmann
277 793a8f7c Michael Hanselmann
    (job_info, log_entries) = result
278 793a8f7c Michael Hanselmann
279 793a8f7c Michael Hanselmann
    return {
280 793a8f7c Michael Hanselmann
      "job_info": job_info,
281 793a8f7c Michael Hanselmann
      "log_entries": log_entries,
282 793a8f7c Michael Hanselmann
      }
283 793a8f7c Michael Hanselmann
284 793a8f7c Michael Hanselmann
285 10b207d4 Oleksiy Mishchenko
class R_2_nodes(baserlib.R_Generic):
286 10b207d4 Oleksiy Mishchenko
  """/2/nodes resource.
287 10b207d4 Oleksiy Mishchenko

288 10b207d4 Oleksiy Mishchenko
  """
289 10b207d4 Oleksiy Mishchenko
  def GET(self):
290 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
291 38206f3c Iustin Pop

292 10b207d4 Oleksiy Mishchenko
    """
293 59b4eeef Iustin Pop
    client = baserlib.GetClient()
294 38206f3c Iustin Pop
295 3d103742 Iustin Pop
    if self.useBulk():
296 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
297 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
298 9031ee8e Iustin Pop
    else:
299 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
300 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
301 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
302 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
303 441e7cfd Oleksiy Mishchenko
304 441e7cfd Oleksiy Mishchenko
305 4e5a68f8 Oleksiy Mishchenko
class R_2_nodes_name(baserlib.R_Generic):
306 4e5a68f8 Oleksiy Mishchenko
  """/2/nodes/[node_name] resources.
307 028c6b76 Oleksiy Mishchenko

308 028c6b76 Oleksiy Mishchenko
  """
309 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
310 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
311 4e5a68f8 Oleksiy Mishchenko

312 4e5a68f8 Oleksiy Mishchenko
    """
313 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
314 59b4eeef Iustin Pop
    client = baserlib.GetClient()
315 e8ebbd2b Michael Hanselmann
316 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
317 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
318 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
319 4e5a68f8 Oleksiy Mishchenko
320 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
321 028c6b76 Oleksiy Mishchenko
322 028c6b76 Oleksiy Mishchenko
323 64dae8fc Michael Hanselmann
class R_2_nodes_name_role(baserlib.R_Generic):
324 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
325 64dae8fc Michael Hanselmann

326 64dae8fc Michael Hanselmann
  """
327 64dae8fc Michael Hanselmann
  def GET(self):
328 64dae8fc Michael Hanselmann
    """Returns the current node role.
329 64dae8fc Michael Hanselmann

330 64dae8fc Michael Hanselmann
    @return: Node role
331 64dae8fc Michael Hanselmann

332 64dae8fc Michael Hanselmann
    """
333 64dae8fc Michael Hanselmann
    node_name = self.items[0]
334 64dae8fc Michael Hanselmann
    client = baserlib.GetClient()
335 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
336 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
337 64dae8fc Michael Hanselmann
338 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
339 64dae8fc Michael Hanselmann
340 64dae8fc Michael Hanselmann
  def PUT(self):
341 64dae8fc Michael Hanselmann
    """Sets the node role.
342 64dae8fc Michael Hanselmann

343 64dae8fc Michael Hanselmann
    @return: a job id
344 64dae8fc Michael Hanselmann

345 64dae8fc Michael Hanselmann
    """
346 64dae8fc Michael Hanselmann
    if not isinstance(self.req.request_body, basestring):
347 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a string")
348 64dae8fc Michael Hanselmann
349 64dae8fc Michael Hanselmann
    node_name = self.items[0]
350 64dae8fc Michael Hanselmann
    role = self.req.request_body
351 64dae8fc Michael Hanselmann
352 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
353 64dae8fc Michael Hanselmann
      candidate = False
354 64dae8fc Michael Hanselmann
      offline = False
355 64dae8fc Michael Hanselmann
      drained = False
356 64dae8fc Michael Hanselmann
357 64dae8fc Michael Hanselmann
    elif role == _NR_MASTER_CANDIATE:
358 64dae8fc Michael Hanselmann
      candidate = True
359 64dae8fc Michael Hanselmann
      offline = drained = None
360 64dae8fc Michael Hanselmann
361 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
362 64dae8fc Michael Hanselmann
      drained = True
363 64dae8fc Michael Hanselmann
      candidate = offline = None
364 64dae8fc Michael Hanselmann
365 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
366 64dae8fc Michael Hanselmann
      offline = True
367 64dae8fc Michael Hanselmann
      candidate = drained = None
368 64dae8fc Michael Hanselmann
369 64dae8fc Michael Hanselmann
    else:
370 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
371 64dae8fc Michael Hanselmann
372 64dae8fc Michael Hanselmann
    op = opcodes.OpSetNodeParams(node_name=node_name,
373 64dae8fc Michael Hanselmann
                                 master_candidate=candidate,
374 64dae8fc Michael Hanselmann
                                 offline=offline,
375 64dae8fc Michael Hanselmann
                                 drained=drained,
376 64dae8fc Michael Hanselmann
                                 force=bool(self.useForce()))
377 64dae8fc Michael Hanselmann
378 64dae8fc Michael Hanselmann
    return baserlib.SubmitJob([op])
379 64dae8fc Michael Hanselmann
380 64dae8fc Michael Hanselmann
381 73452f12 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.R_Generic):
382 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
383 73452f12 Michael Hanselmann

384 73452f12 Michael Hanselmann
  """
385 73452f12 Michael Hanselmann
  def POST(self):
386 73452f12 Michael Hanselmann
    """Evacuate all secondary instances off a node.
387 73452f12 Michael Hanselmann

388 73452f12 Michael Hanselmann
    """
389 73452f12 Michael Hanselmann
    node_name = self.items[0]
390 73452f12 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
391 73452f12 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
392 73452f12 Michael Hanselmann
393 73452f12 Michael Hanselmann
    op = opcodes.OpEvacuateNode(node_name=node_name,
394 73452f12 Michael Hanselmann
                                remote_node=remote_node,
395 73452f12 Michael Hanselmann
                                iallocator=iallocator)
396 73452f12 Michael Hanselmann
397 73452f12 Michael Hanselmann
    return baserlib.SubmitJob([op])
398 73452f12 Michael Hanselmann
399 73452f12 Michael Hanselmann
400 1c482bab Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.R_Generic):
401 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
402 1c482bab Michael Hanselmann

403 1c482bab Michael Hanselmann
  """
404 1c482bab Michael Hanselmann
  def POST(self):
405 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
406 1c482bab Michael Hanselmann

407 1c482bab Michael Hanselmann
    """
408 1c482bab Michael Hanselmann
    node_name = self.items[0]
409 1c482bab Michael Hanselmann
    live = bool(self._checkIntVariable("live", default=1))
410 1c482bab Michael Hanselmann
411 1c482bab Michael Hanselmann
    op = opcodes.OpMigrateNode(node_name=node_name, live=live)
412 1c482bab Michael Hanselmann
413 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
414 1c482bab Michael Hanselmann
415 1c482bab Michael Hanselmann
416 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
417 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/storage ressource.
418 7a95a954 Michael Hanselmann

419 7a95a954 Michael Hanselmann
  """
420 7a95a954 Michael Hanselmann
  # LUQueryNodeStorage acquires locks, hence restricting access to GET
421 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
422 7a95a954 Michael Hanselmann
423 7a95a954 Michael Hanselmann
  def GET(self):
424 7a95a954 Michael Hanselmann
    node_name = self.items[0]
425 7a95a954 Michael Hanselmann
426 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
427 7a95a954 Michael Hanselmann
    if not storage_type:
428 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
429 7a95a954 Michael Hanselmann
                                " parameter")
430 7a95a954 Michael Hanselmann
431 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
432 7a95a954 Michael Hanselmann
    if not output_fields:
433 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
434 7a95a954 Michael Hanselmann
                                " parameter")
435 7a95a954 Michael Hanselmann
436 7a95a954 Michael Hanselmann
    op = opcodes.OpQueryNodeStorage(nodes=[node_name],
437 7a95a954 Michael Hanselmann
                                    storage_type=storage_type,
438 7a95a954 Michael Hanselmann
                                    output_fields=output_fields.split(","))
439 7a95a954 Michael Hanselmann
    return baserlib.SubmitJob([op])
440 7a95a954 Michael Hanselmann
441 7a95a954 Michael Hanselmann
442 1e82bc80 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.R_Generic):
443 1e82bc80 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify ressource.
444 1e82bc80 Michael Hanselmann

445 1e82bc80 Michael Hanselmann
  """
446 1e82bc80 Michael Hanselmann
  def PUT(self):
447 1e82bc80 Michael Hanselmann
    node_name = self.items[0]
448 1e82bc80 Michael Hanselmann
449 1e82bc80 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
450 1e82bc80 Michael Hanselmann
    if not storage_type:
451 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
452 1e82bc80 Michael Hanselmann
                                " parameter")
453 1e82bc80 Michael Hanselmann
454 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
455 1e82bc80 Michael Hanselmann
    if not name:
456 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
457 1e82bc80 Michael Hanselmann
                                " parameter")
458 1e82bc80 Michael Hanselmann
459 1e82bc80 Michael Hanselmann
    changes = {}
460 1e82bc80 Michael Hanselmann
461 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
462 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
463 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
464 1e82bc80 Michael Hanselmann
465 1e82bc80 Michael Hanselmann
    op = opcodes.OpModifyNodeStorage(node_name=node_name,
466 1e82bc80 Michael Hanselmann
                                     storage_type=storage_type,
467 1e82bc80 Michael Hanselmann
                                     name=name,
468 1e82bc80 Michael Hanselmann
                                     changes=changes)
469 1e82bc80 Michael Hanselmann
    return baserlib.SubmitJob([op])
470 1e82bc80 Michael Hanselmann
471 1e82bc80 Michael Hanselmann
472 723f4565 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.R_Generic):
473 723f4565 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair ressource.
474 723f4565 Michael Hanselmann

475 723f4565 Michael Hanselmann
  """
476 723f4565 Michael Hanselmann
  def PUT(self):
477 723f4565 Michael Hanselmann
    node_name = self.items[0]
478 723f4565 Michael Hanselmann
479 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
480 723f4565 Michael Hanselmann
    if not storage_type:
481 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
482 723f4565 Michael Hanselmann
                                " parameter")
483 723f4565 Michael Hanselmann
484 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
485 723f4565 Michael Hanselmann
    if not name:
486 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
487 723f4565 Michael Hanselmann
                                " parameter")
488 723f4565 Michael Hanselmann
489 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
490 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
491 723f4565 Michael Hanselmann
                                     name=name)
492 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
493 723f4565 Michael Hanselmann
494 723f4565 Michael Hanselmann
495 6395cebb Michael Hanselmann
def _ParseInstanceCreateRequestVersion1(data, dry_run):
496 6395cebb Michael Hanselmann
  """Parses an instance creation request version 1.
497 6395cebb Michael Hanselmann

498 6395cebb Michael Hanselmann
  @rtype: L{opcodes.OpCreateInstance}
499 6395cebb Michael Hanselmann
  @return: Instance creation opcode
500 6395cebb Michael Hanselmann

501 6395cebb Michael Hanselmann
  """
502 6395cebb Michael Hanselmann
  # Disks
503 6395cebb Michael Hanselmann
  disks_input = baserlib.CheckParameter(data, "disks", exptype=list)
504 6395cebb Michael Hanselmann
505 6395cebb Michael Hanselmann
  disks = []
506 6395cebb Michael Hanselmann
  for idx, i in enumerate(disks_input):
507 6395cebb Michael Hanselmann
    baserlib.CheckType(i, dict, "Disk %d specification" % idx)
508 6395cebb Michael Hanselmann
509 6395cebb Michael Hanselmann
    # Size is mandatory
510 6395cebb Michael Hanselmann
    try:
511 6395cebb Michael Hanselmann
      size = i["size"]
512 6395cebb Michael Hanselmann
    except KeyError:
513 6395cebb Michael Hanselmann
      raise http.HttpBadRequest("Disk %d specification wrong: missing disk"
514 6395cebb Michael Hanselmann
                                " size" % idx)
515 6395cebb Michael Hanselmann
516 6395cebb Michael Hanselmann
    disk = {
517 6395cebb Michael Hanselmann
      "size": size,
518 6395cebb Michael Hanselmann
      }
519 6395cebb Michael Hanselmann
520 6395cebb Michael Hanselmann
    # Optional disk access mode
521 6395cebb Michael Hanselmann
    try:
522 6395cebb Michael Hanselmann
      disk_access = i["mode"]
523 6395cebb Michael Hanselmann
    except KeyError:
524 6395cebb Michael Hanselmann
      pass
525 6395cebb Michael Hanselmann
    else:
526 6395cebb Michael Hanselmann
      disk["mode"] = disk_access
527 6395cebb Michael Hanselmann
528 6395cebb Michael Hanselmann
    disks.append(disk)
529 6395cebb Michael Hanselmann
530 6395cebb Michael Hanselmann
  assert len(disks_input) == len(disks)
531 6395cebb Michael Hanselmann
532 6395cebb Michael Hanselmann
  # Network interfaces
533 6395cebb Michael Hanselmann
  nics_input = baserlib.CheckParameter(data, "nics", exptype=list)
534 6395cebb Michael Hanselmann
535 6395cebb Michael Hanselmann
  nics = []
536 6395cebb Michael Hanselmann
  for idx, i in enumerate(nics_input):
537 6395cebb Michael Hanselmann
    baserlib.CheckType(i, dict, "NIC %d specification" % idx)
538 6395cebb Michael Hanselmann
539 6395cebb Michael Hanselmann
    nic = {}
540 6395cebb Michael Hanselmann
541 6395cebb Michael Hanselmann
    for field in ["mode", "ip", "link", "bridge"]:
542 6395cebb Michael Hanselmann
      try:
543 6395cebb Michael Hanselmann
        value = i[field]
544 6395cebb Michael Hanselmann
      except KeyError:
545 6395cebb Michael Hanselmann
        continue
546 6395cebb Michael Hanselmann
547 6395cebb Michael Hanselmann
      nic[field] = value
548 6395cebb Michael Hanselmann
549 6395cebb Michael Hanselmann
    nics.append(nic)
550 6395cebb Michael Hanselmann
551 6395cebb Michael Hanselmann
  assert len(nics_input) == len(nics)
552 6395cebb Michael Hanselmann
553 6395cebb Michael Hanselmann
  # HV/BE parameters
554 6395cebb Michael Hanselmann
  hvparams = baserlib.CheckParameter(data, "hvparams", default={})
555 6395cebb Michael Hanselmann
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
556 6395cebb Michael Hanselmann
557 6395cebb Michael Hanselmann
  beparams = baserlib.CheckParameter(data, "beparams", default={})
558 6395cebb Michael Hanselmann
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
559 6395cebb Michael Hanselmann
560 6395cebb Michael Hanselmann
  return opcodes.OpCreateInstance(
561 6395cebb Michael Hanselmann
    mode=baserlib.CheckParameter(data, "mode"),
562 6395cebb Michael Hanselmann
    instance_name=baserlib.CheckParameter(data, "name"),
563 6395cebb Michael Hanselmann
    os_type=baserlib.CheckParameter(data, "os", default=None),
564 6395cebb Michael Hanselmann
    force_variant=baserlib.CheckParameter(data, "force_variant",
565 6395cebb Michael Hanselmann
                                          default=False),
566 6395cebb Michael Hanselmann
    pnode=baserlib.CheckParameter(data, "pnode", default=None),
567 6395cebb Michael Hanselmann
    snode=baserlib.CheckParameter(data, "snode", default=None),
568 6395cebb Michael Hanselmann
    disk_template=baserlib.CheckParameter(data, "disk_template"),
569 6395cebb Michael Hanselmann
    disks=disks,
570 6395cebb Michael Hanselmann
    nics=nics,
571 6395cebb Michael Hanselmann
    src_node=baserlib.CheckParameter(data, "src_node", default=None),
572 6395cebb Michael Hanselmann
    src_path=baserlib.CheckParameter(data, "src_path", default=None),
573 6395cebb Michael Hanselmann
    start=baserlib.CheckParameter(data, "start", default=True),
574 6395cebb Michael Hanselmann
    wait_for_sync=True,
575 6395cebb Michael Hanselmann
    ip_check=baserlib.CheckParameter(data, "ip_check", default=True),
576 6395cebb Michael Hanselmann
    name_check=baserlib.CheckParameter(data, "name_check", default=True),
577 6395cebb Michael Hanselmann
    file_storage_dir=baserlib.CheckParameter(data, "file_storage_dir",
578 6395cebb Michael Hanselmann
                                             default=None),
579 6395cebb Michael Hanselmann
    file_driver=baserlib.CheckParameter(data, "file_driver",
580 6395cebb Michael Hanselmann
                                        default=constants.FD_LOOP),
581 6395cebb Michael Hanselmann
    iallocator=baserlib.CheckParameter(data, "iallocator", default=None),
582 6395cebb Michael Hanselmann
    hypervisor=baserlib.CheckParameter(data, "hypervisor", default=None),
583 6395cebb Michael Hanselmann
    hvparams=hvparams,
584 6395cebb Michael Hanselmann
    beparams=beparams,
585 6395cebb Michael Hanselmann
    dry_run=dry_run,
586 6395cebb Michael Hanselmann
    )
587 6395cebb Michael Hanselmann
588 6395cebb Michael Hanselmann
589 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
590 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
591 441e7cfd Oleksiy Mishchenko

592 441e7cfd Oleksiy Mishchenko
  """
593 441e7cfd Oleksiy Mishchenko
  def GET(self):
594 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
595 441e7cfd Oleksiy Mishchenko

596 441e7cfd Oleksiy Mishchenko
    """
597 59b4eeef Iustin Pop
    client = baserlib.GetClient()
598 441e7cfd Oleksiy Mishchenko
599 3d103742 Iustin Pop
    use_locking = self.useLocking()
600 3d103742 Iustin Pop
    if self.useBulk():
601 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
602 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
603 441e7cfd Oleksiy Mishchenko
    else:
604 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
605 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
606 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
607 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
608 441e7cfd Oleksiy Mishchenko
609 d975f482 Michael Hanselmann
  def _ParseVersion0CreateRequest(self):
610 d975f482 Michael Hanselmann
    """Parses an instance creation request version 0.
611 2f7635f4 Oleksiy Mishchenko

612 6395cebb Michael Hanselmann
    Request data version 0 is deprecated and should not be used anymore.
613 6395cebb Michael Hanselmann

614 d975f482 Michael Hanselmann
    @rtype: L{opcodes.OpCreateInstance}
615 d975f482 Michael Hanselmann
    @return: Instance creation opcode
616 2f7635f4 Oleksiy Mishchenko

617 2f7635f4 Oleksiy Mishchenko
    """
618 6395cebb Michael Hanselmann
    # Do not modify anymore, request data version 0 is deprecated
619 6e99c5a0 Iustin Pop
    beparams = baserlib.MakeParamsDict(self.req.request_body,
620 6e99c5a0 Iustin Pop
                                       constants.BES_PARAMETERS)
621 6e99c5a0 Iustin Pop
    hvparams = baserlib.MakeParamsDict(self.req.request_body,
622 6e99c5a0 Iustin Pop
                                       constants.HVS_PARAMETERS)
623 6e99c5a0 Iustin Pop
    fn = self.getBodyParameter
624 6e99c5a0 Iustin Pop
625 6e99c5a0 Iustin Pop
    # disk processing
626 6e99c5a0 Iustin Pop
    disk_data = fn('disks')
627 6e99c5a0 Iustin Pop
    if not isinstance(disk_data, list):
628 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("The 'disks' parameter should be a list")
629 6e99c5a0 Iustin Pop
    disks = []
630 6e99c5a0 Iustin Pop
    for idx, d in enumerate(disk_data):
631 6e99c5a0 Iustin Pop
      if not isinstance(d, int):
632 6e99c5a0 Iustin Pop
        raise http.HttpBadRequest("Disk %d specification wrong: should"
633 69b99987 Michael Hanselmann
                                  " be an integer" % idx)
634 6e99c5a0 Iustin Pop
      disks.append({"size": d})
635 d975f482 Michael Hanselmann
636 6e99c5a0 Iustin Pop
    # nic processing (one nic only)
637 495cfdf0 Guido Trotter
    nics = [{"mac": fn("mac", constants.VALUE_AUTO)}]
638 495cfdf0 Guido Trotter
    if fn("ip", None) is not None:
639 495cfdf0 Guido Trotter
      nics[0]["ip"] = fn("ip")
640 495cfdf0 Guido Trotter
    if fn("mode", None) is not None:
641 495cfdf0 Guido Trotter
      nics[0]["mode"] = fn("mode")
642 495cfdf0 Guido Trotter
    if fn("link", None) is not None:
643 495cfdf0 Guido Trotter
      nics[0]["link"] = fn("link")
644 495cfdf0 Guido Trotter
    if fn("bridge", None) is not None:
645 69b99987 Michael Hanselmann
      nics[0]["bridge"] = fn("bridge")
646 2f7635f4 Oleksiy Mishchenko
647 6395cebb Michael Hanselmann
    # Do not modify anymore, request data version 0 is deprecated
648 d975f482 Michael Hanselmann
    return opcodes.OpCreateInstance(
649 59b4eeef Iustin Pop
      mode=constants.INSTANCE_CREATE,
650 59b4eeef Iustin Pop
      instance_name=fn('name'),
651 59b4eeef Iustin Pop
      disks=disks,
652 59b4eeef Iustin Pop
      disk_template=fn('disk_template'),
653 59b4eeef Iustin Pop
      os_type=fn('os'),
654 59b4eeef Iustin Pop
      pnode=fn('pnode', None),
655 59b4eeef Iustin Pop
      snode=fn('snode', None),
656 59b4eeef Iustin Pop
      iallocator=fn('iallocator', None),
657 59b4eeef Iustin Pop
      nics=nics,
658 59b4eeef Iustin Pop
      start=fn('start', True),
659 59b4eeef Iustin Pop
      ip_check=fn('ip_check', True),
660 460d22be Iustin Pop
      name_check=fn('name_check', True),
661 59b4eeef Iustin Pop
      wait_for_sync=True,
662 59b4eeef Iustin Pop
      hypervisor=fn('hypervisor', None),
663 59b4eeef Iustin Pop
      hvparams=hvparams,
664 59b4eeef Iustin Pop
      beparams=beparams,
665 59b4eeef Iustin Pop
      file_storage_dir=fn('file_storage_dir', None),
666 6395cebb Michael Hanselmann
      file_driver=fn('file_driver', constants.FD_LOOP),
667 6f59b964 Iustin Pop
      dry_run=bool(self.dryRun()),
668 59b4eeef Iustin Pop
      )
669 59b4eeef Iustin Pop
670 d975f482 Michael Hanselmann
  def POST(self):
671 d975f482 Michael Hanselmann
    """Create an instance.
672 d975f482 Michael Hanselmann

673 d975f482 Michael Hanselmann
    @return: a job id
674 d975f482 Michael Hanselmann

675 d975f482 Michael Hanselmann
    """
676 d975f482 Michael Hanselmann
    if not isinstance(self.req.request_body, dict):
677 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
678 d975f482 Michael Hanselmann
679 d975f482 Michael Hanselmann
    # Default to request data version 0
680 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
681 d975f482 Michael Hanselmann
682 d975f482 Michael Hanselmann
    if data_version == 0:
683 d975f482 Michael Hanselmann
      op = self._ParseVersion0CreateRequest()
684 6395cebb Michael Hanselmann
    elif data_version == 1:
685 6395cebb Michael Hanselmann
      op = _ParseInstanceCreateRequestVersion1(self.req.request_body,
686 6395cebb Michael Hanselmann
                                               self.dryRun())
687 d975f482 Michael Hanselmann
    else:
688 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
689 12eff9b9 Michael Hanselmann
                                data_version)
690 d975f482 Michael Hanselmann
691 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
692 2f7635f4 Oleksiy Mishchenko
693 441e7cfd Oleksiy Mishchenko
694 4e5a68f8 Oleksiy Mishchenko
class R_2_instances_name(baserlib.R_Generic):
695 4e5a68f8 Oleksiy Mishchenko
  """/2/instances/[instance_name] resources.
696 028c6b76 Oleksiy Mishchenko

697 028c6b76 Oleksiy Mishchenko
  """
698 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
699 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
700 4e5a68f8 Oleksiy Mishchenko

701 4e5a68f8 Oleksiy Mishchenko
    """
702 59b4eeef Iustin Pop
    client = baserlib.GetClient()
703 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
704 e8ebbd2b Michael Hanselmann
705 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
706 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
707 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
708 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
709 4e5a68f8 Oleksiy Mishchenko
710 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
711 028c6b76 Oleksiy Mishchenko
712 6e99c5a0 Iustin Pop
  def DELETE(self):
713 6e99c5a0 Iustin Pop
    """Delete an instance.
714 6e99c5a0 Iustin Pop

715 6e99c5a0 Iustin Pop
    """
716 59b4eeef Iustin Pop
    op = opcodes.OpRemoveInstance(instance_name=self.items[0],
717 6f59b964 Iustin Pop
                                  ignore_failures=False,
718 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
719 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
720 6e99c5a0 Iustin Pop
721 028c6b76 Oleksiy Mishchenko
722 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
723 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
724 d8260842 Michael Hanselmann

725 d8260842 Michael Hanselmann
  """
726 d8260842 Michael Hanselmann
  def GET(self):
727 d8260842 Michael Hanselmann
    """Request detailed instance information.
728 d8260842 Michael Hanselmann

729 d8260842 Michael Hanselmann
    """
730 d8260842 Michael Hanselmann
    instance_name = self.items[0]
731 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
732 d8260842 Michael Hanselmann
733 d8260842 Michael Hanselmann
    op = opcodes.OpQueryInstanceData(instances=[instance_name],
734 d8260842 Michael Hanselmann
                                     static=static)
735 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
736 d8260842 Michael Hanselmann
737 d8260842 Michael Hanselmann
738 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
739 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
740 2276aa29 Oleksiy Mishchenko

741 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
742 2276aa29 Oleksiy Mishchenko

743 2276aa29 Oleksiy Mishchenko
  """
744 21f04e5e Oleksiy Mishchenko
  def POST(self):
745 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
746 2276aa29 Oleksiy Mishchenko

747 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
748 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
749 0c55c24b Oleksiy Mishchenko

750 2276aa29 Oleksiy Mishchenko
    """
751 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
752 0c55c24b Oleksiy Mishchenko
    reboot_type = self.queryargs.get('type',
753 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
754 94cdfa4a Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable('ignore_secondaries'))
755 59b4eeef Iustin Pop
    op = opcodes.OpRebootInstance(instance_name=instance_name,
756 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
757 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
758 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
759 2276aa29 Oleksiy Mishchenko
760 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
761 2276aa29 Oleksiy Mishchenko
762 2276aa29 Oleksiy Mishchenko
763 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
764 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
765 0c55c24b Oleksiy Mishchenko

766 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
767 0c55c24b Oleksiy Mishchenko

768 0c55c24b Oleksiy Mishchenko
  """
769 21f04e5e Oleksiy Mishchenko
  def PUT(self):
770 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
771 0c55c24b Oleksiy Mishchenko

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

775 0c55c24b Oleksiy Mishchenko
    """
776 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
777 94cdfa4a Iustin Pop
    force_startup = bool(self._checkIntVariable('force'))
778 59b4eeef Iustin Pop
    op = opcodes.OpStartupInstance(instance_name=instance_name,
779 6f59b964 Iustin Pop
                                   force=force_startup,
780 6f59b964 Iustin Pop
                                   dry_run=bool(self.dryRun()))
781 0c55c24b Oleksiy Mishchenko
782 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
783 0c55c24b Oleksiy Mishchenko
784 0c55c24b Oleksiy Mishchenko
785 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
786 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
787 0c55c24b Oleksiy Mishchenko

788 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
789 0c55c24b Oleksiy Mishchenko

790 0c55c24b Oleksiy Mishchenko
  """
791 21f04e5e Oleksiy Mishchenko
  def PUT(self):
792 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
793 0c55c24b Oleksiy Mishchenko

794 0c55c24b Oleksiy Mishchenko
    """
795 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
796 6f59b964 Iustin Pop
    op = opcodes.OpShutdownInstance(instance_name=instance_name,
797 6f59b964 Iustin Pop
                                    dry_run=bool(self.dryRun()))
798 0c55c24b Oleksiy Mishchenko
799 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
800 0c55c24b Oleksiy Mishchenko
801 0c55c24b Oleksiy Mishchenko
802 e5b7c4ca Iustin Pop
class R_2_instances_name_reinstall(baserlib.R_Generic):
803 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
804 e5b7c4ca Iustin Pop

805 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
806 e5b7c4ca Iustin Pop

807 e5b7c4ca Iustin Pop
  """
808 e5b7c4ca Iustin Pop
  def POST(self):
809 e5b7c4ca Iustin Pop
    """Reinstall an instance.
810 e5b7c4ca Iustin Pop

811 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
812 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
813 e5b7c4ca Iustin Pop
    automatically.
814 e5b7c4ca Iustin Pop

815 e5b7c4ca Iustin Pop
    """
816 e5b7c4ca Iustin Pop
    instance_name = self.items[0]
817 e5b7c4ca Iustin Pop
    ostype = self._checkStringVariable('os')
818 e5b7c4ca Iustin Pop
    nostartup = self._checkIntVariable('nostartup')
819 e5b7c4ca Iustin Pop
    ops = [
820 e5b7c4ca Iustin Pop
      opcodes.OpShutdownInstance(instance_name=instance_name),
821 e5b7c4ca Iustin Pop
      opcodes.OpReinstallInstance(instance_name=instance_name, os_type=ostype),
822 e5b7c4ca Iustin Pop
      ]
823 e5b7c4ca Iustin Pop
    if not nostartup:
824 e5b7c4ca Iustin Pop
      ops.append(opcodes.OpStartupInstance(instance_name=instance_name,
825 e5b7c4ca Iustin Pop
                                           force=False))
826 e5b7c4ca Iustin Pop
    return baserlib.SubmitJob(ops)
827 e5b7c4ca Iustin Pop
828 e5b7c4ca Iustin Pop
829 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
830 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
831 4c98b915 Michael Hanselmann

832 4c98b915 Michael Hanselmann
  """
833 4c98b915 Michael Hanselmann
  def POST(self):
834 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
835 4c98b915 Michael Hanselmann

836 4c98b915 Michael Hanselmann
    """
837 4c98b915 Michael Hanselmann
    instance_name = self.items[0]
838 4c98b915 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
839 4c98b915 Michael Hanselmann
    mode = self._checkStringVariable("mode", default=None)
840 4c98b915 Michael Hanselmann
    raw_disks = self._checkStringVariable("disks", default=None)
841 4c98b915 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
842 4c98b915 Michael Hanselmann
843 4c98b915 Michael Hanselmann
    if raw_disks:
844 4c98b915 Michael Hanselmann
      try:
845 4c98b915 Michael Hanselmann
        disks = [int(part) for part in raw_disks.split(",")]
846 4c98b915 Michael Hanselmann
      except ValueError, err:
847 4c98b915 Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
848 4c98b915 Michael Hanselmann
    else:
849 4c98b915 Michael Hanselmann
      disks = []
850 4c98b915 Michael Hanselmann
851 4c98b915 Michael Hanselmann
    op = opcodes.OpReplaceDisks(instance_name=instance_name,
852 4c98b915 Michael Hanselmann
                                remote_node=remote_node,
853 4c98b915 Michael Hanselmann
                                mode=mode,
854 4c98b915 Michael Hanselmann
                                disks=disks,
855 4c98b915 Michael Hanselmann
                                iallocator=iallocator)
856 4c98b915 Michael Hanselmann
857 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
858 4c98b915 Michael Hanselmann
859 4c98b915 Michael Hanselmann
860 2197b66f René Nussbaumer
class R_2_instances_name_activate_disks(baserlib.R_Generic):
861 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
862 2197b66f René Nussbaumer

863 2197b66f René Nussbaumer
  """
864 2197b66f René Nussbaumer
  def PUT(self):
865 2197b66f René Nussbaumer
    """Activate disks for an instance.
866 2197b66f René Nussbaumer

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

869 2197b66f René Nussbaumer
    """
870 2197b66f René Nussbaumer
    instance_name = self.items[0]
871 2197b66f René Nussbaumer
    ignore_size = bool(self._checkIntVariable('ignore_size'))
872 2197b66f René Nussbaumer
873 2197b66f René Nussbaumer
    op = opcodes.OpActivateInstanceDisks(instance_name=instance_name,
874 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
875 2197b66f René Nussbaumer
876 2197b66f René Nussbaumer
    return baserlib.SubmitJob([op])
877 2197b66f René Nussbaumer
878 2197b66f René Nussbaumer
879 0a37de5f René Nussbaumer
class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
880 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
881 0a37de5f René Nussbaumer

882 0a37de5f René Nussbaumer
  """
883 0a37de5f René Nussbaumer
  def PUT(self):
884 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
885 0a37de5f René Nussbaumer

886 0a37de5f René Nussbaumer
    """
887 0a37de5f René Nussbaumer
    instance_name = self.items[0]
888 0a37de5f René Nussbaumer
889 2263aec2 René Nussbaumer
    op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
890 0a37de5f René Nussbaumer
891 0a37de5f René Nussbaumer
    return baserlib.SubmitJob([op])
892 0a37de5f René Nussbaumer
893 0a37de5f René Nussbaumer
894 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
895 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
896 441e7cfd Oleksiy Mishchenko

897 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
898 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
899 441e7cfd Oleksiy Mishchenko

900 441e7cfd Oleksiy Mishchenko
  """
901 7a6b9510 Iustin Pop
  TAG_LEVEL = None
902 18cb43a2 Oleksiy Mishchenko
903 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
904 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
905 18cb43a2 Oleksiy Mishchenko

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

908 18cb43a2 Oleksiy Mishchenko
    """
909 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
910 18cb43a2 Oleksiy Mishchenko
911 18cb43a2 Oleksiy Mishchenko
    if self.TAG_LEVEL != constants.TAG_CLUSTER:
912 18cb43a2 Oleksiy Mishchenko
      self.name = items[0]
913 18cb43a2 Oleksiy Mishchenko
    else:
914 18cb43a2 Oleksiy Mishchenko
      self.name = ""
915 441e7cfd Oleksiy Mishchenko
916 441e7cfd Oleksiy Mishchenko
  def GET(self):
917 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
918 441e7cfd Oleksiy Mishchenko

919 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
920 441e7cfd Oleksiy Mishchenko

921 441e7cfd Oleksiy Mishchenko
    """
922 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
923 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
924 441e7cfd Oleksiy Mishchenko
925 21f04e5e Oleksiy Mishchenko
  def PUT(self):
926 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
927 441e7cfd Oleksiy Mishchenko

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

931 441e7cfd Oleksiy Mishchenko
    """
932 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
933 6e99c5a0 Iustin Pop
    if 'tag' not in self.queryargs:
934 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
935 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
936 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
937 6f59b964 Iustin Pop
                              self.queryargs['tag'], name=self.name,
938 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
939 15fd9fd5 Oleksiy Mishchenko
940 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
941 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
942 15fd9fd5 Oleksiy Mishchenko

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

947 15fd9fd5 Oleksiy Mishchenko
    """
948 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
949 15fd9fd5 Oleksiy Mishchenko
    if 'tag' not in self.queryargs:
950 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
951 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
952 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
953 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
954 15fd9fd5 Oleksiy Mishchenko
                                 self.queryargs['tag'],
955 6f59b964 Iustin Pop
                                 name=self.name,
956 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
957 18cb43a2 Oleksiy Mishchenko
958 18cb43a2 Oleksiy Mishchenko
959 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
960 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
961 18cb43a2 Oleksiy Mishchenko

962 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
963 18cb43a2 Oleksiy Mishchenko

964 18cb43a2 Oleksiy Mishchenko
  """
965 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
966 18cb43a2 Oleksiy Mishchenko
967 18cb43a2 Oleksiy Mishchenko
968 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
969 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
970 18cb43a2 Oleksiy Mishchenko

971 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
972 18cb43a2 Oleksiy Mishchenko

973 18cb43a2 Oleksiy Mishchenko
  """
974 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
975 18cb43a2 Oleksiy Mishchenko
976 18cb43a2 Oleksiy Mishchenko
977 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
978 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/tags resource.
979 18cb43a2 Oleksiy Mishchenko

980 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
981 18cb43a2 Oleksiy Mishchenko

982 18cb43a2 Oleksiy Mishchenko
  """
983 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER