Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 0dbaa9ca

History | View | Annotate | Download (38.7 kB)

1 10b207d4 Oleksiy Mishchenko
#
2 10b207d4 Oleksiy Mishchenko
#
3 10b207d4 Oleksiy Mishchenko
4 52194140 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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 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 0897dc97 Adeodato Simo
            "node_cnt", "node_list",
78 4edc512c Adeodato Simo
            "ctime", "mtime", "serial_no",
79 4edc512c Adeodato Simo
            ]  # "tags" is missing to be able to use _COMMON_FIELDS here.
80 0897dc97 Adeodato Simo
81 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
82 64dae8fc Michael Hanselmann
_NR_MASTER_CANDIATE = "master-candidate"
83 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
84 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
85 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
86 64dae8fc Michael Hanselmann
87 64dae8fc Michael Hanselmann
_NR_MAP = {
88 64dae8fc Michael Hanselmann
  "M": _NR_MASTER,
89 64dae8fc Michael Hanselmann
  "C": _NR_MASTER_CANDIATE,
90 64dae8fc Michael Hanselmann
  "D": _NR_DRAINED,
91 64dae8fc Michael Hanselmann
  "O": _NR_OFFLINE,
92 64dae8fc Michael Hanselmann
  "R": _NR_REGULAR,
93 64dae8fc Michael Hanselmann
  }
94 64dae8fc Michael Hanselmann
95 d975f482 Michael Hanselmann
# Request data version field
96 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
97 d975f482 Michael Hanselmann
98 6395cebb Michael Hanselmann
# Feature string for instance creation request data version 1
99 6395cebb Michael Hanselmann
_INST_CREATE_REQV1 = "instance-create-reqv1"
100 6395cebb Michael Hanselmann
101 c744425f Michael Hanselmann
# Feature string for instance reinstall request version 1
102 c744425f Michael Hanselmann
_INST_REINSTALL_REQV1 = "instance-reinstall-reqv1"
103 c744425f Michael Hanselmann
104 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
105 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
106 793a8f7c Michael Hanselmann
107 4e5a68f8 Oleksiy Mishchenko
108 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
109 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
110 4e5a68f8 Oleksiy Mishchenko

111 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
112 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
113 4e5a68f8 Oleksiy Mishchenko

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

119 4e5a68f8 Oleksiy Mishchenko
    """
120 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
121 4e5a68f8 Oleksiy Mishchenko
122 4e5a68f8 Oleksiy Mishchenko
123 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
124 4e5a68f8 Oleksiy Mishchenko
  """Cluster info.
125 4e5a68f8 Oleksiy Mishchenko

126 4e5a68f8 Oleksiy Mishchenko
  """
127 7e950d31 Iustin Pop
  @staticmethod
128 7e950d31 Iustin Pop
  def GET():
129 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
130 4e5a68f8 Oleksiy Mishchenko

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

139 7eac4a4d Michael Hanselmann
  """
140 7eac4a4d Michael Hanselmann
  @staticmethod
141 7eac4a4d Michael Hanselmann
  def GET():
142 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
143 7eac4a4d Michael Hanselmann

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

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

156 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
157 4e5a68f8 Oleksiy Mishchenko

158 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
159 4e5a68f8 Oleksiy Mishchenko

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

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

186 508e9b20 Michael Hanselmann
    """
187 508e9b20 Michael Hanselmann
    return baserlib.SubmitJob([opcodes.OpRedistributeConfig()])
188 508e9b20 Michael Hanselmann
189 508e9b20 Michael Hanselmann
190 10b207d4 Oleksiy Mishchenko
class R_2_jobs(baserlib.R_Generic):
191 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
192 10b207d4 Oleksiy Mishchenko

193 10b207d4 Oleksiy Mishchenko
  """
194 7e950d31 Iustin Pop
  @staticmethod
195 7e950d31 Iustin Pop
  def GET():
196 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
197 10b207d4 Oleksiy Mishchenko

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

200 10b207d4 Oleksiy Mishchenko
    """
201 10b207d4 Oleksiy Mishchenko
    fields = ["id"]
202 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
203 10b207d4 Oleksiy Mishchenko
    # Convert the list of lists to the list of ids
204 59b4eeef Iustin Pop
    result = [job_id for [job_id] in cl.QueryJobs(None, fields)]
205 9031ee8e Iustin Pop
    return baserlib.BuildUriList(result, "/2/jobs/%s",
206 9031ee8e Iustin Pop
                                 uri_fields=("id", "uri"))
207 10b207d4 Oleksiy Mishchenko
208 10b207d4 Oleksiy Mishchenko
209 10b207d4 Oleksiy Mishchenko
class R_2_jobs_id(baserlib.R_Generic):
210 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
211 10b207d4 Oleksiy Mishchenko

212 10b207d4 Oleksiy Mishchenko
  """
213 10b207d4 Oleksiy Mishchenko
  def GET(self):
214 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
215 10b207d4 Oleksiy Mishchenko

216 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
217 c41eea6e Iustin Pop
        The result includes:
218 c41eea6e Iustin Pop
            - id: job ID as a number
219 c41eea6e Iustin Pop
            - status: current job status as a string
220 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
221 c41eea6e Iustin Pop
              opcodes in the job
222 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
223 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
224 38206f3c Iustin Pop

225 10b207d4 Oleksiy Mishchenko
    """
226 ee69c97f Iustin Pop
    fields = ["id", "ops", "status", "summary",
227 ee69c97f Iustin Pop
              "opstatus", "opresult", "oplog",
228 ee69c97f Iustin Pop
              "received_ts", "start_ts", "end_ts",
229 ee69c97f Iustin Pop
              ]
230 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
231 59b4eeef Iustin Pop
    result = baserlib.GetClient().QueryJobs([job_id, ], fields)[0]
232 ee69c97f Iustin Pop
    if result is None:
233 ee69c97f Iustin Pop
      raise http.HttpNotFound()
234 10b207d4 Oleksiy Mishchenko
    return baserlib.MapFields(fields, result)
235 10b207d4 Oleksiy Mishchenko
236 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
237 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
238 c7f5f338 Oleksiy Mishchenko

239 c7f5f338 Oleksiy Mishchenko
    """
240 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
241 59b4eeef Iustin Pop
    result = baserlib.GetClient().CancelJob(job_id)
242 c7f5f338 Oleksiy Mishchenko
    return result
243 c7f5f338 Oleksiy Mishchenko
244 10b207d4 Oleksiy Mishchenko
245 793a8f7c Michael Hanselmann
class R_2_jobs_id_wait(baserlib.R_Generic):
246 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
247 793a8f7c Michael Hanselmann

248 793a8f7c Michael Hanselmann
  """
249 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
250 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
251 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
252 793a8f7c Michael Hanselmann
253 793a8f7c Michael Hanselmann
  def GET(self):
254 793a8f7c Michael Hanselmann
    """Waits for job changes.
255 793a8f7c Michael Hanselmann

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

297 10b207d4 Oleksiy Mishchenko
  """
298 10b207d4 Oleksiy Mishchenko
  def GET(self):
299 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
300 38206f3c Iustin Pop

301 10b207d4 Oleksiy Mishchenko
    """
302 59b4eeef Iustin Pop
    client = baserlib.GetClient()
303 38206f3c Iustin Pop
304 3d103742 Iustin Pop
    if self.useBulk():
305 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
306 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
307 9031ee8e Iustin Pop
    else:
308 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
309 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
310 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
311 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
312 441e7cfd Oleksiy Mishchenko
313 441e7cfd Oleksiy Mishchenko
314 4e5a68f8 Oleksiy Mishchenko
class R_2_nodes_name(baserlib.R_Generic):
315 4e5a68f8 Oleksiy Mishchenko
  """/2/nodes/[node_name] resources.
316 028c6b76 Oleksiy Mishchenko

317 028c6b76 Oleksiy Mishchenko
  """
318 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
319 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
320 4e5a68f8 Oleksiy Mishchenko

321 4e5a68f8 Oleksiy Mishchenko
    """
322 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
323 59b4eeef Iustin Pop
    client = baserlib.GetClient()
324 e8ebbd2b Michael Hanselmann
325 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
326 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
327 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
328 4e5a68f8 Oleksiy Mishchenko
329 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
330 028c6b76 Oleksiy Mishchenko
331 028c6b76 Oleksiy Mishchenko
332 64dae8fc Michael Hanselmann
class R_2_nodes_name_role(baserlib.R_Generic):
333 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
334 64dae8fc Michael Hanselmann

335 64dae8fc Michael Hanselmann
  """
336 64dae8fc Michael Hanselmann
  def GET(self):
337 64dae8fc Michael Hanselmann
    """Returns the current node role.
338 64dae8fc Michael Hanselmann

339 64dae8fc Michael Hanselmann
    @return: Node role
340 64dae8fc Michael Hanselmann

341 64dae8fc Michael Hanselmann
    """
342 64dae8fc Michael Hanselmann
    node_name = self.items[0]
343 64dae8fc Michael Hanselmann
    client = baserlib.GetClient()
344 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
345 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
346 64dae8fc Michael Hanselmann
347 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
348 64dae8fc Michael Hanselmann
349 64dae8fc Michael Hanselmann
  def PUT(self):
350 64dae8fc Michael Hanselmann
    """Sets the node role.
351 64dae8fc Michael Hanselmann

352 64dae8fc Michael Hanselmann
    @return: a job id
353 64dae8fc Michael Hanselmann

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

393 73452f12 Michael Hanselmann
  """
394 73452f12 Michael Hanselmann
  def POST(self):
395 73452f12 Michael Hanselmann
    """Evacuate all secondary instances off a node.
396 73452f12 Michael Hanselmann

397 73452f12 Michael Hanselmann
    """
398 73452f12 Michael Hanselmann
    node_name = self.items[0]
399 73452f12 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
400 73452f12 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
401 941b9309 Iustin Pop
    early_r = bool(self._checkIntVariable("early_release", default=0))
402 941b9309 Iustin Pop
    dry_run = bool(self.dryRun())
403 73452f12 Michael Hanselmann
404 941b9309 Iustin Pop
    cl = baserlib.GetClient()
405 73452f12 Michael Hanselmann
406 941b9309 Iustin Pop
    op = opcodes.OpNodeEvacuationStrategy(nodes=[node_name],
407 941b9309 Iustin Pop
                                          iallocator=iallocator,
408 941b9309 Iustin Pop
                                          remote_node=remote_node)
409 941b9309 Iustin Pop
410 941b9309 Iustin Pop
    job_id = baserlib.SubmitJob([op], cl)
411 941b9309 Iustin Pop
    # we use custom feedback function, instead of print we log the status
412 941b9309 Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
413 941b9309 Iustin Pop
414 941b9309 Iustin Pop
    jobs = []
415 941b9309 Iustin Pop
    for iname, node in result:
416 941b9309 Iustin Pop
      if dry_run:
417 941b9309 Iustin Pop
        jid = None
418 941b9309 Iustin Pop
      else:
419 941b9309 Iustin Pop
        op = opcodes.OpReplaceDisks(instance_name=iname,
420 941b9309 Iustin Pop
                                    remote_node=node, disks=[],
421 941b9309 Iustin Pop
                                    mode=constants.REPLACE_DISK_CHG,
422 941b9309 Iustin Pop
                                    early_release=early_r)
423 941b9309 Iustin Pop
        jid = baserlib.SubmitJob([op])
424 941b9309 Iustin Pop
      jobs.append((jid, iname, node))
425 941b9309 Iustin Pop
426 941b9309 Iustin Pop
    return jobs
427 73452f12 Michael Hanselmann
428 73452f12 Michael Hanselmann
429 1c482bab Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.R_Generic):
430 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
431 1c482bab Michael Hanselmann

432 1c482bab Michael Hanselmann
  """
433 1c482bab Michael Hanselmann
  def POST(self):
434 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
435 1c482bab Michael Hanselmann

436 1c482bab Michael Hanselmann
    """
437 1c482bab Michael Hanselmann
    node_name = self.items[0]
438 1c482bab Michael Hanselmann
439 52194140 Iustin Pop
    if "live" in self.queryargs and "mode" in self.queryargs:
440 52194140 Iustin Pop
      raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
441 52194140 Iustin Pop
                                " be passed")
442 52194140 Iustin Pop
    elif "live" in self.queryargs:
443 52194140 Iustin Pop
      if self._checkIntVariable("live", default=1):
444 52194140 Iustin Pop
        mode = constants.HT_MIGRATION_LIVE
445 52194140 Iustin Pop
      else:
446 52194140 Iustin Pop
        mode = constants.HT_MIGRATION_NONLIVE
447 52194140 Iustin Pop
    else:
448 52194140 Iustin Pop
      mode = self._checkStringVariable("mode", default=None)
449 52194140 Iustin Pop
450 52194140 Iustin Pop
    op = opcodes.OpMigrateNode(node_name=node_name, mode=mode)
451 1c482bab Michael Hanselmann
452 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
453 1c482bab Michael Hanselmann
454 1c482bab Michael Hanselmann
455 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
456 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/storage ressource.
457 7a95a954 Michael Hanselmann

458 7a95a954 Michael Hanselmann
  """
459 7a95a954 Michael Hanselmann
  # LUQueryNodeStorage acquires locks, hence restricting access to GET
460 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
461 7a95a954 Michael Hanselmann
462 7a95a954 Michael Hanselmann
  def GET(self):
463 7a95a954 Michael Hanselmann
    node_name = self.items[0]
464 7a95a954 Michael Hanselmann
465 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
466 7a95a954 Michael Hanselmann
    if not storage_type:
467 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
468 7a95a954 Michael Hanselmann
                                " parameter")
469 7a95a954 Michael Hanselmann
470 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
471 7a95a954 Michael Hanselmann
    if not output_fields:
472 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
473 7a95a954 Michael Hanselmann
                                " parameter")
474 7a95a954 Michael Hanselmann
475 7a95a954 Michael Hanselmann
    op = opcodes.OpQueryNodeStorage(nodes=[node_name],
476 7a95a954 Michael Hanselmann
                                    storage_type=storage_type,
477 7a95a954 Michael Hanselmann
                                    output_fields=output_fields.split(","))
478 7a95a954 Michael Hanselmann
    return baserlib.SubmitJob([op])
479 7a95a954 Michael Hanselmann
480 7a95a954 Michael Hanselmann
481 1e82bc80 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.R_Generic):
482 1e82bc80 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify ressource.
483 1e82bc80 Michael Hanselmann

484 1e82bc80 Michael Hanselmann
  """
485 1e82bc80 Michael Hanselmann
  def PUT(self):
486 1e82bc80 Michael Hanselmann
    node_name = self.items[0]
487 1e82bc80 Michael Hanselmann
488 1e82bc80 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
489 1e82bc80 Michael Hanselmann
    if not storage_type:
490 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
491 1e82bc80 Michael Hanselmann
                                " parameter")
492 1e82bc80 Michael Hanselmann
493 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
494 1e82bc80 Michael Hanselmann
    if not name:
495 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
496 1e82bc80 Michael Hanselmann
                                " parameter")
497 1e82bc80 Michael Hanselmann
498 1e82bc80 Michael Hanselmann
    changes = {}
499 1e82bc80 Michael Hanselmann
500 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
501 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
502 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
503 1e82bc80 Michael Hanselmann
504 1e82bc80 Michael Hanselmann
    op = opcodes.OpModifyNodeStorage(node_name=node_name,
505 1e82bc80 Michael Hanselmann
                                     storage_type=storage_type,
506 1e82bc80 Michael Hanselmann
                                     name=name,
507 1e82bc80 Michael Hanselmann
                                     changes=changes)
508 1e82bc80 Michael Hanselmann
    return baserlib.SubmitJob([op])
509 1e82bc80 Michael Hanselmann
510 1e82bc80 Michael Hanselmann
511 723f4565 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.R_Generic):
512 723f4565 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair ressource.
513 723f4565 Michael Hanselmann

514 723f4565 Michael Hanselmann
  """
515 723f4565 Michael Hanselmann
  def PUT(self):
516 723f4565 Michael Hanselmann
    node_name = self.items[0]
517 723f4565 Michael Hanselmann
518 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
519 723f4565 Michael Hanselmann
    if not storage_type:
520 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
521 723f4565 Michael Hanselmann
                                " parameter")
522 723f4565 Michael Hanselmann
523 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
524 723f4565 Michael Hanselmann
    if not name:
525 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
526 723f4565 Michael Hanselmann
                                " parameter")
527 723f4565 Michael Hanselmann
528 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
529 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
530 723f4565 Michael Hanselmann
                                     name=name)
531 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
532 723f4565 Michael Hanselmann
533 723f4565 Michael Hanselmann
534 0897dc97 Adeodato Simo
class R_2_groups(baserlib.R_Generic):
535 0897dc97 Adeodato Simo
  """/2/groups resource.
536 0897dc97 Adeodato Simo

537 0897dc97 Adeodato Simo
  """
538 0897dc97 Adeodato Simo
  def GET(self):
539 0897dc97 Adeodato Simo
    """Returns a list of all node groups.
540 0897dc97 Adeodato Simo

541 0897dc97 Adeodato Simo
    """
542 0897dc97 Adeodato Simo
    client = baserlib.GetClient()
543 0897dc97 Adeodato Simo
544 0897dc97 Adeodato Simo
    if self.useBulk():
545 0897dc97 Adeodato Simo
      bulkdata = client.QueryGroups([], G_FIELDS, False)
546 0897dc97 Adeodato Simo
      return baserlib.MapBulkFields(bulkdata, G_FIELDS)
547 0897dc97 Adeodato Simo
    else:
548 0897dc97 Adeodato Simo
      data = client.QueryGroups([], ["name"], False)
549 0897dc97 Adeodato Simo
      groupnames = [row[0] for row in data]
550 0897dc97 Adeodato Simo
      return baserlib.BuildUriList(groupnames, "/2/groups/%s",
551 0897dc97 Adeodato Simo
                                   uri_fields=("name", "uri"))
552 0897dc97 Adeodato Simo
553 0dbaa9ca Adeodato Simo
  def POST(self):
554 0dbaa9ca Adeodato Simo
    """Create a node group.
555 0dbaa9ca Adeodato Simo

556 0dbaa9ca Adeodato Simo
    @return: a job id
557 0dbaa9ca Adeodato Simo

558 0dbaa9ca Adeodato Simo
    """
559 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
560 0dbaa9ca Adeodato Simo
    group_name = baserlib.CheckParameter(self.request_body, "name")
561 0dbaa9ca Adeodato Simo
    op = opcodes.OpAddGroup(group_name=group_name, dry_run=self.dryRun())
562 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
563 0dbaa9ca Adeodato Simo
564 0897dc97 Adeodato Simo
565 0897dc97 Adeodato Simo
class R_2_groups_name(baserlib.R_Generic):
566 0897dc97 Adeodato Simo
  """/2/groups/[group_name] resources.
567 0897dc97 Adeodato Simo

568 0897dc97 Adeodato Simo
  """
569 0897dc97 Adeodato Simo
  def GET(self):
570 0897dc97 Adeodato Simo
    """Send information about a node group.
571 0897dc97 Adeodato Simo

572 0897dc97 Adeodato Simo
    """
573 0897dc97 Adeodato Simo
    group_name = self.items[0]
574 0897dc97 Adeodato Simo
    client = baserlib.GetClient()
575 0897dc97 Adeodato Simo
576 0897dc97 Adeodato Simo
    result = baserlib.HandleItemQueryErrors(client.QueryGroups,
577 0897dc97 Adeodato Simo
                                            names=[group_name], fields=G_FIELDS,
578 0897dc97 Adeodato Simo
                                            use_locking=self.useLocking())
579 0897dc97 Adeodato Simo
580 0897dc97 Adeodato Simo
    return baserlib.MapFields(G_FIELDS, result[0])
581 0897dc97 Adeodato Simo
582 0dbaa9ca Adeodato Simo
  def DELETE(self):
583 0dbaa9ca Adeodato Simo
    """Delete a node group.
584 0dbaa9ca Adeodato Simo

585 0dbaa9ca Adeodato Simo
    """
586 0dbaa9ca Adeodato Simo
    op = opcodes.OpRemoveGroup(group_name=self.items[0],
587 0dbaa9ca Adeodato Simo
                               dry_run=bool(self.dryRun()))
588 0dbaa9ca Adeodato Simo
589 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
590 0dbaa9ca Adeodato Simo
591 0dbaa9ca Adeodato Simo
592 0dbaa9ca Adeodato Simo
def _ParseRenameGroupRequest(name, data, dry_run):
593 0dbaa9ca Adeodato Simo
  """Parses a request for renaming a node group.
594 0dbaa9ca Adeodato Simo

595 0dbaa9ca Adeodato Simo
  @type name: string
596 0dbaa9ca Adeodato Simo
  @param name: name of the node group to rename
597 0dbaa9ca Adeodato Simo
  @type data: dict
598 0dbaa9ca Adeodato Simo
  @param data: the body received by the rename request
599 0dbaa9ca Adeodato Simo
  @type dry_run: bool
600 0dbaa9ca Adeodato Simo
  @param dry_run: whether to perform a dry run
601 0dbaa9ca Adeodato Simo

602 0dbaa9ca Adeodato Simo
  @rtype: L{opcodes.OpRenameGroup}
603 0dbaa9ca Adeodato Simo
  @return: Node group rename opcode
604 0dbaa9ca Adeodato Simo

605 0dbaa9ca Adeodato Simo
  """
606 0dbaa9ca Adeodato Simo
  old_name = name
607 0dbaa9ca Adeodato Simo
  new_name = baserlib.CheckParameter(data, "new_name")
608 0dbaa9ca Adeodato Simo
609 0dbaa9ca Adeodato Simo
  return opcodes.OpRenameGroup(old_name=old_name, new_name=new_name,
610 0dbaa9ca Adeodato Simo
                               dry_run=dry_run)
611 0dbaa9ca Adeodato Simo
612 0dbaa9ca Adeodato Simo
613 0dbaa9ca Adeodato Simo
class R_2_groups_name_rename(baserlib.R_Generic):
614 0dbaa9ca Adeodato Simo
  """/2/groups/[groupe_name]/rename resource.
615 0dbaa9ca Adeodato Simo

616 0dbaa9ca Adeodato Simo
  """
617 0dbaa9ca Adeodato Simo
  def PUT(self):
618 0dbaa9ca Adeodato Simo
    """Changes the name of a node group.
619 0dbaa9ca Adeodato Simo

620 0dbaa9ca Adeodato Simo
    @return: a job id
621 0dbaa9ca Adeodato Simo

622 0dbaa9ca Adeodato Simo
    """
623 0dbaa9ca Adeodato Simo
    baserlib.CheckType(self.request_body, dict, "Body contents")
624 0dbaa9ca Adeodato Simo
    op = _ParseRenameGroupRequest(self.items[0], self.request_body,
625 0dbaa9ca Adeodato Simo
                                  self.dryRun())
626 0dbaa9ca Adeodato Simo
    return baserlib.SubmitJob([op])
627 0897dc97 Adeodato Simo
628 0897dc97 Adeodato Simo
629 6395cebb Michael Hanselmann
def _ParseInstanceCreateRequestVersion1(data, dry_run):
630 6395cebb Michael Hanselmann
  """Parses an instance creation request version 1.
631 6395cebb Michael Hanselmann

632 6395cebb Michael Hanselmann
  @rtype: L{opcodes.OpCreateInstance}
633 6395cebb Michael Hanselmann
  @return: Instance creation opcode
634 6395cebb Michael Hanselmann

635 6395cebb Michael Hanselmann
  """
636 6395cebb Michael Hanselmann
  # Disks
637 6395cebb Michael Hanselmann
  disks_input = baserlib.CheckParameter(data, "disks", exptype=list)
638 6395cebb Michael Hanselmann
639 6395cebb Michael Hanselmann
  disks = []
640 6395cebb Michael Hanselmann
  for idx, i in enumerate(disks_input):
641 6395cebb Michael Hanselmann
    baserlib.CheckType(i, dict, "Disk %d specification" % idx)
642 6395cebb Michael Hanselmann
643 6395cebb Michael Hanselmann
    # Size is mandatory
644 6395cebb Michael Hanselmann
    try:
645 7be048f0 Michael Hanselmann
      size = i[constants.IDISK_SIZE]
646 6395cebb Michael Hanselmann
    except KeyError:
647 6395cebb Michael Hanselmann
      raise http.HttpBadRequest("Disk %d specification wrong: missing disk"
648 6395cebb Michael Hanselmann
                                " size" % idx)
649 6395cebb Michael Hanselmann
650 6395cebb Michael Hanselmann
    disk = {
651 7be048f0 Michael Hanselmann
      constants.IDISK_SIZE: size,
652 6395cebb Michael Hanselmann
      }
653 6395cebb Michael Hanselmann
654 6395cebb Michael Hanselmann
    # Optional disk access mode
655 6395cebb Michael Hanselmann
    try:
656 7be048f0 Michael Hanselmann
      disk_access = i[constants.IDISK_MODE]
657 6395cebb Michael Hanselmann
    except KeyError:
658 6395cebb Michael Hanselmann
      pass
659 6395cebb Michael Hanselmann
    else:
660 7be048f0 Michael Hanselmann
      disk[constants.IDISK_MODE] = disk_access
661 6395cebb Michael Hanselmann
662 6395cebb Michael Hanselmann
    disks.append(disk)
663 6395cebb Michael Hanselmann
664 6395cebb Michael Hanselmann
  assert len(disks_input) == len(disks)
665 6395cebb Michael Hanselmann
666 6395cebb Michael Hanselmann
  # Network interfaces
667 6395cebb Michael Hanselmann
  nics_input = baserlib.CheckParameter(data, "nics", exptype=list)
668 6395cebb Michael Hanselmann
669 6395cebb Michael Hanselmann
  nics = []
670 6395cebb Michael Hanselmann
  for idx, i in enumerate(nics_input):
671 6395cebb Michael Hanselmann
    baserlib.CheckType(i, dict, "NIC %d specification" % idx)
672 6395cebb Michael Hanselmann
673 6395cebb Michael Hanselmann
    nic = {}
674 6395cebb Michael Hanselmann
675 7be048f0 Michael Hanselmann
    for field in constants.INIC_PARAMS:
676 6395cebb Michael Hanselmann
      try:
677 6395cebb Michael Hanselmann
        value = i[field]
678 6395cebb Michael Hanselmann
      except KeyError:
679 6395cebb Michael Hanselmann
        continue
680 6395cebb Michael Hanselmann
681 6395cebb Michael Hanselmann
      nic[field] = value
682 6395cebb Michael Hanselmann
683 6395cebb Michael Hanselmann
    nics.append(nic)
684 6395cebb Michael Hanselmann
685 6395cebb Michael Hanselmann
  assert len(nics_input) == len(nics)
686 6395cebb Michael Hanselmann
687 6395cebb Michael Hanselmann
  # HV/BE parameters
688 6395cebb Michael Hanselmann
  hvparams = baserlib.CheckParameter(data, "hvparams", default={})
689 6395cebb Michael Hanselmann
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
690 6395cebb Michael Hanselmann
691 6395cebb Michael Hanselmann
  beparams = baserlib.CheckParameter(data, "beparams", default={})
692 6395cebb Michael Hanselmann
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
693 6395cebb Michael Hanselmann
694 6395cebb Michael Hanselmann
  return opcodes.OpCreateInstance(
695 6395cebb Michael Hanselmann
    mode=baserlib.CheckParameter(data, "mode"),
696 6395cebb Michael Hanselmann
    instance_name=baserlib.CheckParameter(data, "name"),
697 130f0966 Iustin Pop
    os_type=baserlib.CheckParameter(data, "os"),
698 130f0966 Iustin Pop
    osparams=baserlib.CheckParameter(data, "osparams", default={}),
699 6395cebb Michael Hanselmann
    force_variant=baserlib.CheckParameter(data, "force_variant",
700 6395cebb Michael Hanselmann
                                          default=False),
701 04a8865b Lance Albertson
    no_install=baserlib.CheckParameter(data, "no_install", default=False),
702 6395cebb Michael Hanselmann
    pnode=baserlib.CheckParameter(data, "pnode", default=None),
703 6395cebb Michael Hanselmann
    snode=baserlib.CheckParameter(data, "snode", default=None),
704 6395cebb Michael Hanselmann
    disk_template=baserlib.CheckParameter(data, "disk_template"),
705 6395cebb Michael Hanselmann
    disks=disks,
706 6395cebb Michael Hanselmann
    nics=nics,
707 6395cebb Michael Hanselmann
    src_node=baserlib.CheckParameter(data, "src_node", default=None),
708 6395cebb Michael Hanselmann
    src_path=baserlib.CheckParameter(data, "src_path", default=None),
709 6395cebb Michael Hanselmann
    start=baserlib.CheckParameter(data, "start", default=True),
710 6395cebb Michael Hanselmann
    wait_for_sync=True,
711 6395cebb Michael Hanselmann
    ip_check=baserlib.CheckParameter(data, "ip_check", default=True),
712 6395cebb Michael Hanselmann
    name_check=baserlib.CheckParameter(data, "name_check", default=True),
713 6395cebb Michael Hanselmann
    file_storage_dir=baserlib.CheckParameter(data, "file_storage_dir",
714 6395cebb Michael Hanselmann
                                             default=None),
715 6395cebb Michael Hanselmann
    file_driver=baserlib.CheckParameter(data, "file_driver",
716 6395cebb Michael Hanselmann
                                        default=constants.FD_LOOP),
717 ebeb600f Michael Hanselmann
    source_handshake=baserlib.CheckParameter(data, "source_handshake",
718 ebeb600f Michael Hanselmann
                                             default=None),
719 ebeb600f Michael Hanselmann
    source_x509_ca=baserlib.CheckParameter(data, "source_x509_ca",
720 ebeb600f Michael Hanselmann
                                           default=None),
721 ebeb600f Michael Hanselmann
    source_instance_name=baserlib.CheckParameter(data, "source_instance_name",
722 ebeb600f Michael Hanselmann
                                                 default=None),
723 6395cebb Michael Hanselmann
    iallocator=baserlib.CheckParameter(data, "iallocator", default=None),
724 6395cebb Michael Hanselmann
    hypervisor=baserlib.CheckParameter(data, "hypervisor", default=None),
725 6395cebb Michael Hanselmann
    hvparams=hvparams,
726 6395cebb Michael Hanselmann
    beparams=beparams,
727 6395cebb Michael Hanselmann
    dry_run=dry_run,
728 6395cebb Michael Hanselmann
    )
729 6395cebb Michael Hanselmann
730 6395cebb Michael Hanselmann
731 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
732 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
733 441e7cfd Oleksiy Mishchenko

734 441e7cfd Oleksiy Mishchenko
  """
735 441e7cfd Oleksiy Mishchenko
  def GET(self):
736 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
737 441e7cfd Oleksiy Mishchenko

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

754 6395cebb Michael Hanselmann
    Request data version 0 is deprecated and should not be used anymore.
755 2f7635f4 Oleksiy Mishchenko

756 d975f482 Michael Hanselmann
    @rtype: L{opcodes.OpCreateInstance}
757 d975f482 Michael Hanselmann
    @return: Instance creation opcode
758 6e99c5a0 Iustin Pop

759 2f7635f4 Oleksiy Mishchenko
    """
760 6395cebb Michael Hanselmann
    # Do not modify anymore, request data version 0 is deprecated
761 627ad739 Michael Hanselmann
    beparams = baserlib.MakeParamsDict(self.request_body,
762 6e99c5a0 Iustin Pop
                                       constants.BES_PARAMETERS)
763 627ad739 Michael Hanselmann
    hvparams = baserlib.MakeParamsDict(self.request_body,
764 6e99c5a0 Iustin Pop
                                       constants.HVS_PARAMETERS)
765 6e99c5a0 Iustin Pop
    fn = self.getBodyParameter
766 6e99c5a0 Iustin Pop
767 6e99c5a0 Iustin Pop
    # disk processing
768 6e99c5a0 Iustin Pop
    disk_data = fn('disks')
769 6e99c5a0 Iustin Pop
    if not isinstance(disk_data, list):
770 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("The 'disks' parameter should be a list")
771 6e99c5a0 Iustin Pop
    disks = []
772 6e99c5a0 Iustin Pop
    for idx, d in enumerate(disk_data):
773 6e99c5a0 Iustin Pop
      if not isinstance(d, int):
774 6e99c5a0 Iustin Pop
        raise http.HttpBadRequest("Disk %d specification wrong: should"
775 69b99987 Michael Hanselmann
                                  " be an integer" % idx)
776 6e99c5a0 Iustin Pop
      disks.append({"size": d})
777 d975f482 Michael Hanselmann
778 6e99c5a0 Iustin Pop
    # nic processing (one nic only)
779 495cfdf0 Guido Trotter
    nics = [{"mac": fn("mac", constants.VALUE_AUTO)}]
780 495cfdf0 Guido Trotter
    if fn("ip", None) is not None:
781 495cfdf0 Guido Trotter
      nics[0]["ip"] = fn("ip")
782 495cfdf0 Guido Trotter
    if fn("mode", None) is not None:
783 495cfdf0 Guido Trotter
      nics[0]["mode"] = fn("mode")
784 495cfdf0 Guido Trotter
    if fn("link", None) is not None:
785 495cfdf0 Guido Trotter
      nics[0]["link"] = fn("link")
786 495cfdf0 Guido Trotter
    if fn("bridge", None) is not None:
787 69b99987 Michael Hanselmann
      nics[0]["bridge"] = fn("bridge")
788 2f7635f4 Oleksiy Mishchenko
789 6395cebb Michael Hanselmann
    # Do not modify anymore, request data version 0 is deprecated
790 d975f482 Michael Hanselmann
    return opcodes.OpCreateInstance(
791 59b4eeef Iustin Pop
      mode=constants.INSTANCE_CREATE,
792 59b4eeef Iustin Pop
      instance_name=fn('name'),
793 59b4eeef Iustin Pop
      disks=disks,
794 59b4eeef Iustin Pop
      disk_template=fn('disk_template'),
795 59b4eeef Iustin Pop
      os_type=fn('os'),
796 59b4eeef Iustin Pop
      pnode=fn('pnode', None),
797 59b4eeef Iustin Pop
      snode=fn('snode', None),
798 59b4eeef Iustin Pop
      iallocator=fn('iallocator', None),
799 59b4eeef Iustin Pop
      nics=nics,
800 59b4eeef Iustin Pop
      start=fn('start', True),
801 59b4eeef Iustin Pop
      ip_check=fn('ip_check', True),
802 460d22be Iustin Pop
      name_check=fn('name_check', True),
803 59b4eeef Iustin Pop
      wait_for_sync=True,
804 59b4eeef Iustin Pop
      hypervisor=fn('hypervisor', None),
805 59b4eeef Iustin Pop
      hvparams=hvparams,
806 59b4eeef Iustin Pop
      beparams=beparams,
807 59b4eeef Iustin Pop
      file_storage_dir=fn('file_storage_dir', None),
808 6395cebb Michael Hanselmann
      file_driver=fn('file_driver', constants.FD_LOOP),
809 6f59b964 Iustin Pop
      dry_run=bool(self.dryRun()),
810 59b4eeef Iustin Pop
      )
811 59b4eeef Iustin Pop
812 d975f482 Michael Hanselmann
  def POST(self):
813 d975f482 Michael Hanselmann
    """Create an instance.
814 d975f482 Michael Hanselmann

815 d975f482 Michael Hanselmann
    @return: a job id
816 d975f482 Michael Hanselmann

817 d975f482 Michael Hanselmann
    """
818 1c54156d Luca Bigliardi
    if not isinstance(self.request_body, dict):
819 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
820 d975f482 Michael Hanselmann
821 d975f482 Michael Hanselmann
    # Default to request data version 0
822 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
823 d975f482 Michael Hanselmann
824 d975f482 Michael Hanselmann
    if data_version == 0:
825 d975f482 Michael Hanselmann
      op = self._ParseVersion0CreateRequest()
826 6395cebb Michael Hanselmann
    elif data_version == 1:
827 1c54156d Luca Bigliardi
      op = _ParseInstanceCreateRequestVersion1(self.request_body,
828 6395cebb Michael Hanselmann
                                               self.dryRun())
829 d975f482 Michael Hanselmann
    else:
830 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
831 12eff9b9 Michael Hanselmann
                                data_version)
832 d975f482 Michael Hanselmann
833 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
834 2f7635f4 Oleksiy Mishchenko
835 441e7cfd Oleksiy Mishchenko
836 4e5a68f8 Oleksiy Mishchenko
class R_2_instances_name(baserlib.R_Generic):
837 4e5a68f8 Oleksiy Mishchenko
  """/2/instances/[instance_name] resources.
838 028c6b76 Oleksiy Mishchenko

839 028c6b76 Oleksiy Mishchenko
  """
840 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
841 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
842 4e5a68f8 Oleksiy Mishchenko

843 4e5a68f8 Oleksiy Mishchenko
    """
844 59b4eeef Iustin Pop
    client = baserlib.GetClient()
845 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
846 e8ebbd2b Michael Hanselmann
847 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
848 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
849 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
850 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
851 4e5a68f8 Oleksiy Mishchenko
852 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
853 028c6b76 Oleksiy Mishchenko
854 6e99c5a0 Iustin Pop
  def DELETE(self):
855 6e99c5a0 Iustin Pop
    """Delete an instance.
856 6e99c5a0 Iustin Pop

857 6e99c5a0 Iustin Pop
    """
858 59b4eeef Iustin Pop
    op = opcodes.OpRemoveInstance(instance_name=self.items[0],
859 6f59b964 Iustin Pop
                                  ignore_failures=False,
860 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
861 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
862 6e99c5a0 Iustin Pop
863 028c6b76 Oleksiy Mishchenko
864 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
865 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
866 d8260842 Michael Hanselmann

867 d8260842 Michael Hanselmann
  """
868 d8260842 Michael Hanselmann
  def GET(self):
869 d8260842 Michael Hanselmann
    """Request detailed instance information.
870 d8260842 Michael Hanselmann

871 d8260842 Michael Hanselmann
    """
872 d8260842 Michael Hanselmann
    instance_name = self.items[0]
873 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
874 d8260842 Michael Hanselmann
875 d8260842 Michael Hanselmann
    op = opcodes.OpQueryInstanceData(instances=[instance_name],
876 d8260842 Michael Hanselmann
                                     static=static)
877 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
878 d8260842 Michael Hanselmann
879 d8260842 Michael Hanselmann
880 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
881 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
882 2276aa29 Oleksiy Mishchenko

883 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
884 2276aa29 Oleksiy Mishchenko

885 2276aa29 Oleksiy Mishchenko
  """
886 21f04e5e Oleksiy Mishchenko
  def POST(self):
887 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
888 2276aa29 Oleksiy Mishchenko

889 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
890 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
891 0c55c24b Oleksiy Mishchenko

892 2276aa29 Oleksiy Mishchenko
    """
893 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
894 0c55c24b Oleksiy Mishchenko
    reboot_type = self.queryargs.get('type',
895 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
896 94cdfa4a Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable('ignore_secondaries'))
897 59b4eeef Iustin Pop
    op = opcodes.OpRebootInstance(instance_name=instance_name,
898 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
899 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
900 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
901 2276aa29 Oleksiy Mishchenko
902 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
903 2276aa29 Oleksiy Mishchenko
904 2276aa29 Oleksiy Mishchenko
905 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
906 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
907 0c55c24b Oleksiy Mishchenko

908 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
909 0c55c24b Oleksiy Mishchenko

910 0c55c24b Oleksiy Mishchenko
  """
911 21f04e5e Oleksiy Mishchenko
  def PUT(self):
912 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
913 0c55c24b Oleksiy Mishchenko

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

917 0c55c24b Oleksiy Mishchenko
    """
918 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
919 94cdfa4a Iustin Pop
    force_startup = bool(self._checkIntVariable('force'))
920 59b4eeef Iustin Pop
    op = opcodes.OpStartupInstance(instance_name=instance_name,
921 6f59b964 Iustin Pop
                                   force=force_startup,
922 6f59b964 Iustin Pop
                                   dry_run=bool(self.dryRun()))
923 0c55c24b Oleksiy Mishchenko
924 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
925 0c55c24b Oleksiy Mishchenko
926 0c55c24b Oleksiy Mishchenko
927 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
928 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
929 0c55c24b Oleksiy Mishchenko

930 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
931 0c55c24b Oleksiy Mishchenko

932 0c55c24b Oleksiy Mishchenko
  """
933 21f04e5e Oleksiy Mishchenko
  def PUT(self):
934 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
935 0c55c24b Oleksiy Mishchenko

936 0c55c24b Oleksiy Mishchenko
    """
937 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
938 6f59b964 Iustin Pop
    op = opcodes.OpShutdownInstance(instance_name=instance_name,
939 6f59b964 Iustin Pop
                                    dry_run=bool(self.dryRun()))
940 0c55c24b Oleksiy Mishchenko
941 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
942 0c55c24b Oleksiy Mishchenko
943 0c55c24b Oleksiy Mishchenko
944 c744425f Michael Hanselmann
def _ParseInstanceReinstallRequest(name, data):
945 c744425f Michael Hanselmann
  """Parses a request for reinstalling an instance.
946 c744425f Michael Hanselmann

947 c744425f Michael Hanselmann
  """
948 c744425f Michael Hanselmann
  if not isinstance(data, dict):
949 c744425f Michael Hanselmann
    raise http.HttpBadRequest("Invalid body contents, not a dictionary")
950 c744425f Michael Hanselmann
951 c744425f Michael Hanselmann
  ostype = baserlib.CheckParameter(data, "os")
952 c744425f Michael Hanselmann
  start = baserlib.CheckParameter(data, "start", exptype=bool,
953 c744425f Michael Hanselmann
                                  default=True)
954 c744425f Michael Hanselmann
  osparams = baserlib.CheckParameter(data, "osparams", default=None)
955 c744425f Michael Hanselmann
956 c744425f Michael Hanselmann
  ops = [
957 c744425f Michael Hanselmann
    opcodes.OpShutdownInstance(instance_name=name),
958 c744425f Michael Hanselmann
    opcodes.OpReinstallInstance(instance_name=name, os_type=ostype,
959 c744425f Michael Hanselmann
                                osparams=osparams),
960 c744425f Michael Hanselmann
    ]
961 c744425f Michael Hanselmann
962 c744425f Michael Hanselmann
  if start:
963 c744425f Michael Hanselmann
    ops.append(opcodes.OpStartupInstance(instance_name=name, force=False))
964 c744425f Michael Hanselmann
965 c744425f Michael Hanselmann
  return ops
966 c744425f Michael Hanselmann
967 c744425f Michael Hanselmann
968 e5b7c4ca Iustin Pop
class R_2_instances_name_reinstall(baserlib.R_Generic):
969 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
970 e5b7c4ca Iustin Pop

971 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
972 e5b7c4ca Iustin Pop

973 e5b7c4ca Iustin Pop
  """
974 e5b7c4ca Iustin Pop
  def POST(self):
975 e5b7c4ca Iustin Pop
    """Reinstall an instance.
976 e5b7c4ca Iustin Pop

977 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
978 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
979 e5b7c4ca Iustin Pop
    automatically.
980 e5b7c4ca Iustin Pop

981 e5b7c4ca Iustin Pop
    """
982 c744425f Michael Hanselmann
    if self.request_body:
983 c744425f Michael Hanselmann
      if self.queryargs:
984 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Can't combine query and body parameters")
985 c744425f Michael Hanselmann
986 c744425f Michael Hanselmann
      body = self.request_body
987 c744425f Michael Hanselmann
    else:
988 c744425f Michael Hanselmann
      if not self.queryargs:
989 c744425f Michael Hanselmann
        raise http.HttpBadRequest("Missing query parameters")
990 c744425f Michael Hanselmann
      # Legacy interface, do not modify/extend
991 c744425f Michael Hanselmann
      body = {
992 c744425f Michael Hanselmann
        "os": self._checkStringVariable("os"),
993 c744425f Michael Hanselmann
        "start": not self._checkIntVariable("nostartup"),
994 c744425f Michael Hanselmann
        }
995 c744425f Michael Hanselmann
996 c744425f Michael Hanselmann
    ops = _ParseInstanceReinstallRequest(self.items[0], body)
997 c744425f Michael Hanselmann
998 e5b7c4ca Iustin Pop
    return baserlib.SubmitJob(ops)
999 e5b7c4ca Iustin Pop
1000 e5b7c4ca Iustin Pop
1001 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
1002 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
1003 4c98b915 Michael Hanselmann

1004 4c98b915 Michael Hanselmann
  """
1005 4c98b915 Michael Hanselmann
  def POST(self):
1006 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1007 4c98b915 Michael Hanselmann

1008 4c98b915 Michael Hanselmann
    """
1009 4c98b915 Michael Hanselmann
    instance_name = self.items[0]
1010 4c98b915 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
1011 4c98b915 Michael Hanselmann
    mode = self._checkStringVariable("mode", default=None)
1012 4c98b915 Michael Hanselmann
    raw_disks = self._checkStringVariable("disks", default=None)
1013 4c98b915 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
1014 4c98b915 Michael Hanselmann
1015 4c98b915 Michael Hanselmann
    if raw_disks:
1016 4c98b915 Michael Hanselmann
      try:
1017 4c98b915 Michael Hanselmann
        disks = [int(part) for part in raw_disks.split(",")]
1018 4c98b915 Michael Hanselmann
      except ValueError, err:
1019 4c98b915 Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
1020 4c98b915 Michael Hanselmann
    else:
1021 4c98b915 Michael Hanselmann
      disks = []
1022 4c98b915 Michael Hanselmann
1023 4c98b915 Michael Hanselmann
    op = opcodes.OpReplaceDisks(instance_name=instance_name,
1024 4c98b915 Michael Hanselmann
                                remote_node=remote_node,
1025 4c98b915 Michael Hanselmann
                                mode=mode,
1026 4c98b915 Michael Hanselmann
                                disks=disks,
1027 4c98b915 Michael Hanselmann
                                iallocator=iallocator)
1028 4c98b915 Michael Hanselmann
1029 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
1030 4c98b915 Michael Hanselmann
1031 4c98b915 Michael Hanselmann
1032 2197b66f René Nussbaumer
class R_2_instances_name_activate_disks(baserlib.R_Generic):
1033 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
1034 2197b66f René Nussbaumer

1035 2197b66f René Nussbaumer
  """
1036 2197b66f René Nussbaumer
  def PUT(self):
1037 2197b66f René Nussbaumer
    """Activate disks for an instance.
1038 2197b66f René Nussbaumer

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

1041 2197b66f René Nussbaumer
    """
1042 2197b66f René Nussbaumer
    instance_name = self.items[0]
1043 2197b66f René Nussbaumer
    ignore_size = bool(self._checkIntVariable('ignore_size'))
1044 2197b66f René Nussbaumer
1045 2197b66f René Nussbaumer
    op = opcodes.OpActivateInstanceDisks(instance_name=instance_name,
1046 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
1047 2197b66f René Nussbaumer
1048 2197b66f René Nussbaumer
    return baserlib.SubmitJob([op])
1049 2197b66f René Nussbaumer
1050 2197b66f René Nussbaumer
1051 0a37de5f René Nussbaumer
class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
1052 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
1053 0a37de5f René Nussbaumer

1054 0a37de5f René Nussbaumer
  """
1055 0a37de5f René Nussbaumer
  def PUT(self):
1056 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1057 0a37de5f René Nussbaumer

1058 0a37de5f René Nussbaumer
    """
1059 0a37de5f René Nussbaumer
    instance_name = self.items[0]
1060 0a37de5f René Nussbaumer
1061 2263aec2 René Nussbaumer
    op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
1062 0a37de5f René Nussbaumer
1063 0a37de5f René Nussbaumer
    return baserlib.SubmitJob([op])
1064 0a37de5f René Nussbaumer
1065 0a37de5f René Nussbaumer
1066 ebeb600f Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.R_Generic):
1067 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
1068 ebeb600f Michael Hanselmann

1069 ebeb600f Michael Hanselmann
  """
1070 ebeb600f Michael Hanselmann
  def PUT(self):
1071 ebeb600f Michael Hanselmann
    """Prepares an export for an instance.
1072 ebeb600f Michael Hanselmann

1073 ebeb600f Michael Hanselmann
    @return: a job id
1074 ebeb600f Michael Hanselmann

1075 ebeb600f Michael Hanselmann
    """
1076 ebeb600f Michael Hanselmann
    instance_name = self.items[0]
1077 ebeb600f Michael Hanselmann
    mode = self._checkStringVariable("mode")
1078 ebeb600f Michael Hanselmann
1079 ebeb600f Michael Hanselmann
    op = opcodes.OpPrepareExport(instance_name=instance_name,
1080 ebeb600f Michael Hanselmann
                                 mode=mode)
1081 ebeb600f Michael Hanselmann
1082 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1083 ebeb600f Michael Hanselmann
1084 ebeb600f Michael Hanselmann
1085 ebeb600f Michael Hanselmann
def _ParseExportInstanceRequest(name, data):
1086 ebeb600f Michael Hanselmann
  """Parses a request for an instance export.
1087 ebeb600f Michael Hanselmann

1088 ebeb600f Michael Hanselmann
  @rtype: L{opcodes.OpExportInstance}
1089 ebeb600f Michael Hanselmann
  @return: Instance export opcode
1090 ebeb600f Michael Hanselmann

1091 ebeb600f Michael Hanselmann
  """
1092 ebeb600f Michael Hanselmann
  mode = baserlib.CheckParameter(data, "mode",
1093 ebeb600f Michael Hanselmann
                                 default=constants.EXPORT_MODE_LOCAL)
1094 ebeb600f Michael Hanselmann
  target_node = baserlib.CheckParameter(data, "destination")
1095 ebeb600f Michael Hanselmann
  shutdown = baserlib.CheckParameter(data, "shutdown", exptype=bool)
1096 ebeb600f Michael Hanselmann
  remove_instance = baserlib.CheckParameter(data, "remove_instance",
1097 ebeb600f Michael Hanselmann
                                            exptype=bool, default=False)
1098 ebeb600f Michael Hanselmann
  x509_key_name = baserlib.CheckParameter(data, "x509_key_name", default=None)
1099 ebeb600f Michael Hanselmann
  destination_x509_ca = baserlib.CheckParameter(data, "destination_x509_ca",
1100 ebeb600f Michael Hanselmann
                                                default=None)
1101 ebeb600f Michael Hanselmann
1102 ebeb600f Michael Hanselmann
  return opcodes.OpExportInstance(instance_name=name,
1103 ebeb600f Michael Hanselmann
                                  mode=mode,
1104 ebeb600f Michael Hanselmann
                                  target_node=target_node,
1105 ebeb600f Michael Hanselmann
                                  shutdown=shutdown,
1106 ebeb600f Michael Hanselmann
                                  remove_instance=remove_instance,
1107 ebeb600f Michael Hanselmann
                                  x509_key_name=x509_key_name,
1108 ebeb600f Michael Hanselmann
                                  destination_x509_ca=destination_x509_ca)
1109 ebeb600f Michael Hanselmann
1110 ebeb600f Michael Hanselmann
1111 ebeb600f Michael Hanselmann
class R_2_instances_name_export(baserlib.R_Generic):
1112 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
1113 ebeb600f Michael Hanselmann

1114 ebeb600f Michael Hanselmann
  """
1115 ebeb600f Michael Hanselmann
  def PUT(self):
1116 ebeb600f Michael Hanselmann
    """Exports an instance.
1117 ebeb600f Michael Hanselmann

1118 ebeb600f Michael Hanselmann
    @return: a job id
1119 ebeb600f Michael Hanselmann

1120 ebeb600f Michael Hanselmann
    """
1121 ebeb600f Michael Hanselmann
    if not isinstance(self.request_body, dict):
1122 ebeb600f Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
1123 ebeb600f Michael Hanselmann
1124 ebeb600f Michael Hanselmann
    op = _ParseExportInstanceRequest(self.items[0], self.request_body)
1125 ebeb600f Michael Hanselmann
1126 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
1127 ebeb600f Michael Hanselmann
1128 ebeb600f Michael Hanselmann
1129 5823e0d2 Michael Hanselmann
def _ParseMigrateInstanceRequest(name, data):
1130 5823e0d2 Michael Hanselmann
  """Parses a request for an instance migration.
1131 5823e0d2 Michael Hanselmann

1132 5823e0d2 Michael Hanselmann
  @rtype: L{opcodes.OpMigrateInstance}
1133 5823e0d2 Michael Hanselmann
  @return: Instance migration opcode
1134 5823e0d2 Michael Hanselmann

1135 5823e0d2 Michael Hanselmann
  """
1136 5823e0d2 Michael Hanselmann
  mode = baserlib.CheckParameter(data, "mode", default=None)
1137 5823e0d2 Michael Hanselmann
  cleanup = baserlib.CheckParameter(data, "cleanup", exptype=bool,
1138 5823e0d2 Michael Hanselmann
                                    default=False)
1139 5823e0d2 Michael Hanselmann
1140 5823e0d2 Michael Hanselmann
  return opcodes.OpMigrateInstance(instance_name=name, mode=mode,
1141 5823e0d2 Michael Hanselmann
                                   cleanup=cleanup)
1142 5823e0d2 Michael Hanselmann
1143 5823e0d2 Michael Hanselmann
1144 5823e0d2 Michael Hanselmann
class R_2_instances_name_migrate(baserlib.R_Generic):
1145 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1146 5823e0d2 Michael Hanselmann

1147 5823e0d2 Michael Hanselmann
  """
1148 5823e0d2 Michael Hanselmann
  def PUT(self):
1149 5823e0d2 Michael Hanselmann
    """Migrates an instance.
1150 5823e0d2 Michael Hanselmann

1151 5823e0d2 Michael Hanselmann
    @return: a job id
1152 5823e0d2 Michael Hanselmann

1153 5823e0d2 Michael Hanselmann
    """
1154 5823e0d2 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1155 5823e0d2 Michael Hanselmann
1156 5823e0d2 Michael Hanselmann
    op = _ParseMigrateInstanceRequest(self.items[0], self.request_body)
1157 5823e0d2 Michael Hanselmann
1158 5823e0d2 Michael Hanselmann
    return baserlib.SubmitJob([op])
1159 5823e0d2 Michael Hanselmann
1160 5823e0d2 Michael Hanselmann
1161 d56e7dc7 Michael Hanselmann
def _ParseRenameInstanceRequest(name, data):
1162 d56e7dc7 Michael Hanselmann
  """Parses a request for renaming an instance.
1163 d56e7dc7 Michael Hanselmann

1164 d56e7dc7 Michael Hanselmann
  @rtype: L{opcodes.OpRenameInstance}
1165 d56e7dc7 Michael Hanselmann
  @return: Instance rename opcode
1166 d56e7dc7 Michael Hanselmann

1167 d56e7dc7 Michael Hanselmann
  """
1168 d56e7dc7 Michael Hanselmann
  new_name = baserlib.CheckParameter(data, "new_name")
1169 d56e7dc7 Michael Hanselmann
  ip_check = baserlib.CheckParameter(data, "ip_check", default=True)
1170 d56e7dc7 Michael Hanselmann
  name_check = baserlib.CheckParameter(data, "name_check", default=True)
1171 d56e7dc7 Michael Hanselmann
1172 d56e7dc7 Michael Hanselmann
  return opcodes.OpRenameInstance(instance_name=name, new_name=new_name,
1173 d56e7dc7 Michael Hanselmann
                                  name_check=name_check, ip_check=ip_check)
1174 d56e7dc7 Michael Hanselmann
1175 d56e7dc7 Michael Hanselmann
1176 d56e7dc7 Michael Hanselmann
class R_2_instances_name_rename(baserlib.R_Generic):
1177 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1178 d56e7dc7 Michael Hanselmann

1179 d56e7dc7 Michael Hanselmann
  """
1180 d56e7dc7 Michael Hanselmann
  def PUT(self):
1181 d56e7dc7 Michael Hanselmann
    """Changes the name of an instance.
1182 d56e7dc7 Michael Hanselmann

1183 d56e7dc7 Michael Hanselmann
    @return: a job id
1184 d56e7dc7 Michael Hanselmann

1185 d56e7dc7 Michael Hanselmann
    """
1186 d56e7dc7 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1187 d56e7dc7 Michael Hanselmann
1188 d56e7dc7 Michael Hanselmann
    op = _ParseRenameInstanceRequest(self.items[0], self.request_body)
1189 d56e7dc7 Michael Hanselmann
1190 d56e7dc7 Michael Hanselmann
    return baserlib.SubmitJob([op])
1191 d56e7dc7 Michael Hanselmann
1192 d56e7dc7 Michael Hanselmann
1193 3882937a Michael Hanselmann
def _ParseModifyInstanceRequest(name, data):
1194 3882937a Michael Hanselmann
  """Parses a request for modifying an instance.
1195 3882937a Michael Hanselmann

1196 3882937a Michael Hanselmann
  @rtype: L{opcodes.OpSetInstanceParams}
1197 3882937a Michael Hanselmann
  @return: Instance modify opcode
1198 3882937a Michael Hanselmann

1199 3882937a Michael Hanselmann
  """
1200 3882937a Michael Hanselmann
  osparams = baserlib.CheckParameter(data, "osparams", default={})
1201 3882937a Michael Hanselmann
  force = baserlib.CheckParameter(data, "force", default=False)
1202 3882937a Michael Hanselmann
  nics = baserlib.CheckParameter(data, "nics", default=[])
1203 3882937a Michael Hanselmann
  disks = baserlib.CheckParameter(data, "disks", default=[])
1204 3882937a Michael Hanselmann
  disk_template = baserlib.CheckParameter(data, "disk_template", default=None)
1205 3882937a Michael Hanselmann
  remote_node = baserlib.CheckParameter(data, "remote_node", default=None)
1206 3882937a Michael Hanselmann
  os_name = baserlib.CheckParameter(data, "os_name", default=None)
1207 3882937a Michael Hanselmann
  force_variant = baserlib.CheckParameter(data, "force_variant", default=False)
1208 3882937a Michael Hanselmann
1209 3882937a Michael Hanselmann
  # HV/BE parameters
1210 3882937a Michael Hanselmann
  hvparams = baserlib.CheckParameter(data, "hvparams", default={})
1211 3882937a Michael Hanselmann
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES,
1212 3882937a Michael Hanselmann
                      allowed_values=[constants.VALUE_DEFAULT])
1213 3882937a Michael Hanselmann
1214 3882937a Michael Hanselmann
  beparams = baserlib.CheckParameter(data, "beparams", default={})
1215 3882937a Michael Hanselmann
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES,
1216 3882937a Michael Hanselmann
                      allowed_values=[constants.VALUE_DEFAULT])
1217 3882937a Michael Hanselmann
1218 3882937a Michael Hanselmann
  return opcodes.OpSetInstanceParams(instance_name=name, hvparams=hvparams,
1219 3882937a Michael Hanselmann
                                     beparams=beparams, osparams=osparams,
1220 3882937a Michael Hanselmann
                                     force=force, nics=nics, disks=disks,
1221 3882937a Michael Hanselmann
                                     disk_template=disk_template,
1222 3882937a Michael Hanselmann
                                     remote_node=remote_node, os_name=os_name,
1223 3882937a Michael Hanselmann
                                     force_variant=force_variant)
1224 3882937a Michael Hanselmann
1225 3882937a Michael Hanselmann
1226 3882937a Michael Hanselmann
class R_2_instances_name_modify(baserlib.R_Generic):
1227 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1228 3882937a Michael Hanselmann

1229 3882937a Michael Hanselmann
  """
1230 3882937a Michael Hanselmann
  def PUT(self):
1231 3882937a Michael Hanselmann
    """Changes some parameters of an instance.
1232 3882937a Michael Hanselmann

1233 3882937a Michael Hanselmann
    @return: a job id
1234 3882937a Michael Hanselmann

1235 3882937a Michael Hanselmann
    """
1236 3882937a Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1237 3882937a Michael Hanselmann
1238 3882937a Michael Hanselmann
    op = _ParseModifyInstanceRequest(self.items[0], self.request_body)
1239 3882937a Michael Hanselmann
1240 3882937a Michael Hanselmann
    return baserlib.SubmitJob([op])
1241 3882937a Michael Hanselmann
1242 3882937a Michael Hanselmann
1243 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
1244 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1245 441e7cfd Oleksiy Mishchenko

1246 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1247 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1248 441e7cfd Oleksiy Mishchenko

1249 441e7cfd Oleksiy Mishchenko
  """
1250 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1251 18cb43a2 Oleksiy Mishchenko
1252 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
1253 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1254 18cb43a2 Oleksiy Mishchenko

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

1257 18cb43a2 Oleksiy Mishchenko
    """
1258 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
1259 18cb43a2 Oleksiy Mishchenko
1260 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1261 5313eed7 Michael Hanselmann
      self.name = None
1262 18cb43a2 Oleksiy Mishchenko
    else:
1263 5313eed7 Michael Hanselmann
      self.name = items[0]
1264 441e7cfd Oleksiy Mishchenko
1265 441e7cfd Oleksiy Mishchenko
  def GET(self):
1266 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1267 441e7cfd Oleksiy Mishchenko

1268 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1269 441e7cfd Oleksiy Mishchenko

1270 441e7cfd Oleksiy Mishchenko
    """
1271 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1272 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
1273 441e7cfd Oleksiy Mishchenko
1274 21f04e5e Oleksiy Mishchenko
  def PUT(self):
1275 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1276 441e7cfd Oleksiy Mishchenko

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

1280 441e7cfd Oleksiy Mishchenko
    """
1281 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1282 6e99c5a0 Iustin Pop
    if 'tag' not in self.queryargs:
1283 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
1284 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
1285 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
1286 6f59b964 Iustin Pop
                              self.queryargs['tag'], name=self.name,
1287 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
1288 15fd9fd5 Oleksiy Mishchenko
1289 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
1290 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1291 15fd9fd5 Oleksiy Mishchenko

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

1296 15fd9fd5 Oleksiy Mishchenko
    """
1297 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1298 15fd9fd5 Oleksiy Mishchenko
    if 'tag' not in self.queryargs:
1299 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
1300 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
1301 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
1302 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
1303 15fd9fd5 Oleksiy Mishchenko
                                 self.queryargs['tag'],
1304 6f59b964 Iustin Pop
                                 name=self.name,
1305 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
1306 18cb43a2 Oleksiy Mishchenko
1307 18cb43a2 Oleksiy Mishchenko
1308 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1309 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1310 18cb43a2 Oleksiy Mishchenko

1311 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1312 18cb43a2 Oleksiy Mishchenko

1313 18cb43a2 Oleksiy Mishchenko
  """
1314 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1315 18cb43a2 Oleksiy Mishchenko
1316 18cb43a2 Oleksiy Mishchenko
1317 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1318 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1319 18cb43a2 Oleksiy Mishchenko

1320 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1321 18cb43a2 Oleksiy Mishchenko

1322 18cb43a2 Oleksiy Mishchenko
  """
1323 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1324 18cb43a2 Oleksiy Mishchenko
1325 18cb43a2 Oleksiy Mishchenko
1326 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1327 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/tags resource.
1328 18cb43a2 Oleksiy Mishchenko

1329 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1330 18cb43a2 Oleksiy Mishchenko

1331 18cb43a2 Oleksiy Mishchenko
  """
1332 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER