Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 4b63dc7a

History | View | Annotate | Download (35 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 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
73 4e5a68f8 Oleksiy Mishchenko
74 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
75 64dae8fc Michael Hanselmann
_NR_MASTER_CANDIATE = "master-candidate"
76 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
77 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
78 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
79 64dae8fc Michael Hanselmann
80 64dae8fc Michael Hanselmann
_NR_MAP = {
81 64dae8fc Michael Hanselmann
  "M": _NR_MASTER,
82 64dae8fc Michael Hanselmann
  "C": _NR_MASTER_CANDIATE,
83 64dae8fc Michael Hanselmann
  "D": _NR_DRAINED,
84 64dae8fc Michael Hanselmann
  "O": _NR_OFFLINE,
85 64dae8fc Michael Hanselmann
  "R": _NR_REGULAR,
86 64dae8fc Michael Hanselmann
  }
87 64dae8fc Michael Hanselmann
88 d975f482 Michael Hanselmann
# Request data version field
89 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
90 d975f482 Michael Hanselmann
91 6395cebb Michael Hanselmann
# Feature string for instance creation request data version 1
92 6395cebb Michael Hanselmann
_INST_CREATE_REQV1 = "instance-create-reqv1"
93 6395cebb Michael Hanselmann
94 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
95 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
96 793a8f7c Michael Hanselmann
97 4e5a68f8 Oleksiy Mishchenko
98 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
99 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
100 4e5a68f8 Oleksiy Mishchenko

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

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

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

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

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

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

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

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

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

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

150 4e5a68f8 Oleksiy Mishchenko
    """
151 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
152 d22dfef7 Iustin Pop
    op = opcodes.OpDiagnoseOS(output_fields=["name", "variants"], 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 d22dfef7 Iustin Pop
    for (name, variants) in diagnose_data:
163 d22dfef7 Iustin Pop
      os_names.extend(cli.CalculateOSNames(name, variants))
164 e3ac208c Guido Trotter
165 e3ac208c Guido Trotter
    return os_names
166 51ee2f49 Oleksiy Mishchenko
167 10b207d4 Oleksiy Mishchenko
168 508e9b20 Michael Hanselmann
class R_2_redist_config(baserlib.R_Generic):
169 508e9b20 Michael Hanselmann
  """/2/redistribute-config resource.
170 508e9b20 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

422 1c482bab Michael Hanselmann
  """
423 1c482bab Michael Hanselmann
  def POST(self):
424 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
425 1c482bab Michael Hanselmann

426 1c482bab Michael Hanselmann
    """
427 1c482bab Michael Hanselmann
    node_name = self.items[0]
428 1c482bab Michael Hanselmann
429 52194140 Iustin Pop
    if "live" in self.queryargs and "mode" in self.queryargs:
430 52194140 Iustin Pop
      raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
431 52194140 Iustin Pop
                                " be passed")
432 52194140 Iustin Pop
    elif "live" in self.queryargs:
433 52194140 Iustin Pop
      if self._checkIntVariable("live", default=1):
434 52194140 Iustin Pop
        mode = constants.HT_MIGRATION_LIVE
435 52194140 Iustin Pop
      else:
436 52194140 Iustin Pop
        mode = constants.HT_MIGRATION_NONLIVE
437 52194140 Iustin Pop
    else:
438 52194140 Iustin Pop
      mode = self._checkStringVariable("mode", default=None)
439 52194140 Iustin Pop
440 52194140 Iustin Pop
    op = opcodes.OpMigrateNode(node_name=node_name, mode=mode)
441 1c482bab Michael Hanselmann
442 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
443 1c482bab Michael Hanselmann
444 1c482bab Michael Hanselmann
445 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
446 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/storage ressource.
447 7a95a954 Michael Hanselmann

448 7a95a954 Michael Hanselmann
  """
449 7a95a954 Michael Hanselmann
  # LUQueryNodeStorage acquires locks, hence restricting access to GET
450 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
451 7a95a954 Michael Hanselmann
452 7a95a954 Michael Hanselmann
  def GET(self):
453 7a95a954 Michael Hanselmann
    node_name = self.items[0]
454 7a95a954 Michael Hanselmann
455 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
456 7a95a954 Michael Hanselmann
    if not storage_type:
457 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
458 7a95a954 Michael Hanselmann
                                " parameter")
459 7a95a954 Michael Hanselmann
460 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
461 7a95a954 Michael Hanselmann
    if not output_fields:
462 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
463 7a95a954 Michael Hanselmann
                                " parameter")
464 7a95a954 Michael Hanselmann
465 7a95a954 Michael Hanselmann
    op = opcodes.OpQueryNodeStorage(nodes=[node_name],
466 7a95a954 Michael Hanselmann
                                    storage_type=storage_type,
467 7a95a954 Michael Hanselmann
                                    output_fields=output_fields.split(","))
468 7a95a954 Michael Hanselmann
    return baserlib.SubmitJob([op])
469 7a95a954 Michael Hanselmann
470 7a95a954 Michael Hanselmann
471 1e82bc80 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.R_Generic):
472 1e82bc80 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify ressource.
473 1e82bc80 Michael Hanselmann

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

504 723f4565 Michael Hanselmann
  """
505 723f4565 Michael Hanselmann
  def PUT(self):
506 723f4565 Michael Hanselmann
    node_name = self.items[0]
507 723f4565 Michael Hanselmann
508 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
509 723f4565 Michael Hanselmann
    if not storage_type:
510 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
511 723f4565 Michael Hanselmann
                                " parameter")
512 723f4565 Michael Hanselmann
513 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
514 723f4565 Michael Hanselmann
    if not name:
515 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
516 723f4565 Michael Hanselmann
                                " parameter")
517 723f4565 Michael Hanselmann
518 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
519 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
520 723f4565 Michael Hanselmann
                                     name=name)
521 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
522 723f4565 Michael Hanselmann
523 723f4565 Michael Hanselmann
524 6395cebb Michael Hanselmann
def _ParseInstanceCreateRequestVersion1(data, dry_run):
525 6395cebb Michael Hanselmann
  """Parses an instance creation request version 1.
526 6395cebb Michael Hanselmann

527 6395cebb Michael Hanselmann
  @rtype: L{opcodes.OpCreateInstance}
528 6395cebb Michael Hanselmann
  @return: Instance creation opcode
529 6395cebb Michael Hanselmann

530 6395cebb Michael Hanselmann
  """
531 6395cebb Michael Hanselmann
  # Disks
532 6395cebb Michael Hanselmann
  disks_input = baserlib.CheckParameter(data, "disks", exptype=list)
533 6395cebb Michael Hanselmann
534 6395cebb Michael Hanselmann
  disks = []
535 6395cebb Michael Hanselmann
  for idx, i in enumerate(disks_input):
536 6395cebb Michael Hanselmann
    baserlib.CheckType(i, dict, "Disk %d specification" % idx)
537 6395cebb Michael Hanselmann
538 6395cebb Michael Hanselmann
    # Size is mandatory
539 6395cebb Michael Hanselmann
    try:
540 7be048f0 Michael Hanselmann
      size = i[constants.IDISK_SIZE]
541 6395cebb Michael Hanselmann
    except KeyError:
542 6395cebb Michael Hanselmann
      raise http.HttpBadRequest("Disk %d specification wrong: missing disk"
543 6395cebb Michael Hanselmann
                                " size" % idx)
544 6395cebb Michael Hanselmann
545 6395cebb Michael Hanselmann
    disk = {
546 7be048f0 Michael Hanselmann
      constants.IDISK_SIZE: size,
547 6395cebb Michael Hanselmann
      }
548 6395cebb Michael Hanselmann
549 6395cebb Michael Hanselmann
    # Optional disk access mode
550 6395cebb Michael Hanselmann
    try:
551 7be048f0 Michael Hanselmann
      disk_access = i[constants.IDISK_MODE]
552 6395cebb Michael Hanselmann
    except KeyError:
553 6395cebb Michael Hanselmann
      pass
554 6395cebb Michael Hanselmann
    else:
555 7be048f0 Michael Hanselmann
      disk[constants.IDISK_MODE] = disk_access
556 6395cebb Michael Hanselmann
557 6395cebb Michael Hanselmann
    disks.append(disk)
558 6395cebb Michael Hanselmann
559 6395cebb Michael Hanselmann
  assert len(disks_input) == len(disks)
560 6395cebb Michael Hanselmann
561 6395cebb Michael Hanselmann
  # Network interfaces
562 6395cebb Michael Hanselmann
  nics_input = baserlib.CheckParameter(data, "nics", exptype=list)
563 6395cebb Michael Hanselmann
564 6395cebb Michael Hanselmann
  nics = []
565 6395cebb Michael Hanselmann
  for idx, i in enumerate(nics_input):
566 6395cebb Michael Hanselmann
    baserlib.CheckType(i, dict, "NIC %d specification" % idx)
567 6395cebb Michael Hanselmann
568 6395cebb Michael Hanselmann
    nic = {}
569 6395cebb Michael Hanselmann
570 7be048f0 Michael Hanselmann
    for field in constants.INIC_PARAMS:
571 6395cebb Michael Hanselmann
      try:
572 6395cebb Michael Hanselmann
        value = i[field]
573 6395cebb Michael Hanselmann
      except KeyError:
574 6395cebb Michael Hanselmann
        continue
575 6395cebb Michael Hanselmann
576 6395cebb Michael Hanselmann
      nic[field] = value
577 6395cebb Michael Hanselmann
578 6395cebb Michael Hanselmann
    nics.append(nic)
579 6395cebb Michael Hanselmann
580 6395cebb Michael Hanselmann
  assert len(nics_input) == len(nics)
581 6395cebb Michael Hanselmann
582 6395cebb Michael Hanselmann
  # HV/BE parameters
583 6395cebb Michael Hanselmann
  hvparams = baserlib.CheckParameter(data, "hvparams", default={})
584 6395cebb Michael Hanselmann
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES)
585 6395cebb Michael Hanselmann
586 6395cebb Michael Hanselmann
  beparams = baserlib.CheckParameter(data, "beparams", default={})
587 6395cebb Michael Hanselmann
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
588 6395cebb Michael Hanselmann
589 6395cebb Michael Hanselmann
  return opcodes.OpCreateInstance(
590 6395cebb Michael Hanselmann
    mode=baserlib.CheckParameter(data, "mode"),
591 6395cebb Michael Hanselmann
    instance_name=baserlib.CheckParameter(data, "name"),
592 130f0966 Iustin Pop
    os_type=baserlib.CheckParameter(data, "os"),
593 130f0966 Iustin Pop
    osparams=baserlib.CheckParameter(data, "osparams", default={}),
594 6395cebb Michael Hanselmann
    force_variant=baserlib.CheckParameter(data, "force_variant",
595 6395cebb Michael Hanselmann
                                          default=False),
596 6395cebb Michael Hanselmann
    pnode=baserlib.CheckParameter(data, "pnode", default=None),
597 6395cebb Michael Hanselmann
    snode=baserlib.CheckParameter(data, "snode", default=None),
598 6395cebb Michael Hanselmann
    disk_template=baserlib.CheckParameter(data, "disk_template"),
599 6395cebb Michael Hanselmann
    disks=disks,
600 6395cebb Michael Hanselmann
    nics=nics,
601 6395cebb Michael Hanselmann
    src_node=baserlib.CheckParameter(data, "src_node", default=None),
602 6395cebb Michael Hanselmann
    src_path=baserlib.CheckParameter(data, "src_path", default=None),
603 6395cebb Michael Hanselmann
    start=baserlib.CheckParameter(data, "start", default=True),
604 6395cebb Michael Hanselmann
    wait_for_sync=True,
605 6395cebb Michael Hanselmann
    ip_check=baserlib.CheckParameter(data, "ip_check", default=True),
606 6395cebb Michael Hanselmann
    name_check=baserlib.CheckParameter(data, "name_check", default=True),
607 6395cebb Michael Hanselmann
    file_storage_dir=baserlib.CheckParameter(data, "file_storage_dir",
608 6395cebb Michael Hanselmann
                                             default=None),
609 6395cebb Michael Hanselmann
    file_driver=baserlib.CheckParameter(data, "file_driver",
610 6395cebb Michael Hanselmann
                                        default=constants.FD_LOOP),
611 ebeb600f Michael Hanselmann
    source_handshake=baserlib.CheckParameter(data, "source_handshake",
612 ebeb600f Michael Hanselmann
                                             default=None),
613 ebeb600f Michael Hanselmann
    source_x509_ca=baserlib.CheckParameter(data, "source_x509_ca",
614 ebeb600f Michael Hanselmann
                                           default=None),
615 ebeb600f Michael Hanselmann
    source_instance_name=baserlib.CheckParameter(data, "source_instance_name",
616 ebeb600f Michael Hanselmann
                                                 default=None),
617 6395cebb Michael Hanselmann
    iallocator=baserlib.CheckParameter(data, "iallocator", default=None),
618 6395cebb Michael Hanselmann
    hypervisor=baserlib.CheckParameter(data, "hypervisor", default=None),
619 6395cebb Michael Hanselmann
    hvparams=hvparams,
620 6395cebb Michael Hanselmann
    beparams=beparams,
621 6395cebb Michael Hanselmann
    dry_run=dry_run,
622 6395cebb Michael Hanselmann
    )
623 6395cebb Michael Hanselmann
624 6395cebb Michael Hanselmann
625 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
626 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
627 441e7cfd Oleksiy Mishchenko

628 441e7cfd Oleksiy Mishchenko
  """
629 441e7cfd Oleksiy Mishchenko
  def GET(self):
630 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
631 441e7cfd Oleksiy Mishchenko

632 441e7cfd Oleksiy Mishchenko
    """
633 59b4eeef Iustin Pop
    client = baserlib.GetClient()
634 441e7cfd Oleksiy Mishchenko
635 3d103742 Iustin Pop
    use_locking = self.useLocking()
636 3d103742 Iustin Pop
    if self.useBulk():
637 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
638 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
639 441e7cfd Oleksiy Mishchenko
    else:
640 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
641 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
642 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
643 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
644 441e7cfd Oleksiy Mishchenko
645 d975f482 Michael Hanselmann
  def _ParseVersion0CreateRequest(self):
646 d975f482 Michael Hanselmann
    """Parses an instance creation request version 0.
647 2f7635f4 Oleksiy Mishchenko

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

650 d975f482 Michael Hanselmann
    @rtype: L{opcodes.OpCreateInstance}
651 d975f482 Michael Hanselmann
    @return: Instance creation opcode
652 6e99c5a0 Iustin Pop

653 2f7635f4 Oleksiy Mishchenko
    """
654 6395cebb Michael Hanselmann
    # Do not modify anymore, request data version 0 is deprecated
655 627ad739 Michael Hanselmann
    beparams = baserlib.MakeParamsDict(self.request_body,
656 6e99c5a0 Iustin Pop
                                       constants.BES_PARAMETERS)
657 627ad739 Michael Hanselmann
    hvparams = baserlib.MakeParamsDict(self.request_body,
658 6e99c5a0 Iustin Pop
                                       constants.HVS_PARAMETERS)
659 6e99c5a0 Iustin Pop
    fn = self.getBodyParameter
660 6e99c5a0 Iustin Pop
661 6e99c5a0 Iustin Pop
    # disk processing
662 6e99c5a0 Iustin Pop
    disk_data = fn('disks')
663 6e99c5a0 Iustin Pop
    if not isinstance(disk_data, list):
664 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("The 'disks' parameter should be a list")
665 6e99c5a0 Iustin Pop
    disks = []
666 6e99c5a0 Iustin Pop
    for idx, d in enumerate(disk_data):
667 6e99c5a0 Iustin Pop
      if not isinstance(d, int):
668 6e99c5a0 Iustin Pop
        raise http.HttpBadRequest("Disk %d specification wrong: should"
669 69b99987 Michael Hanselmann
                                  " be an integer" % idx)
670 6e99c5a0 Iustin Pop
      disks.append({"size": d})
671 d975f482 Michael Hanselmann
672 6e99c5a0 Iustin Pop
    # nic processing (one nic only)
673 495cfdf0 Guido Trotter
    nics = [{"mac": fn("mac", constants.VALUE_AUTO)}]
674 495cfdf0 Guido Trotter
    if fn("ip", None) is not None:
675 495cfdf0 Guido Trotter
      nics[0]["ip"] = fn("ip")
676 495cfdf0 Guido Trotter
    if fn("mode", None) is not None:
677 495cfdf0 Guido Trotter
      nics[0]["mode"] = fn("mode")
678 495cfdf0 Guido Trotter
    if fn("link", None) is not None:
679 495cfdf0 Guido Trotter
      nics[0]["link"] = fn("link")
680 495cfdf0 Guido Trotter
    if fn("bridge", None) is not None:
681 69b99987 Michael Hanselmann
      nics[0]["bridge"] = fn("bridge")
682 2f7635f4 Oleksiy Mishchenko
683 6395cebb Michael Hanselmann
    # Do not modify anymore, request data version 0 is deprecated
684 d975f482 Michael Hanselmann
    return opcodes.OpCreateInstance(
685 59b4eeef Iustin Pop
      mode=constants.INSTANCE_CREATE,
686 59b4eeef Iustin Pop
      instance_name=fn('name'),
687 59b4eeef Iustin Pop
      disks=disks,
688 59b4eeef Iustin Pop
      disk_template=fn('disk_template'),
689 59b4eeef Iustin Pop
      os_type=fn('os'),
690 59b4eeef Iustin Pop
      pnode=fn('pnode', None),
691 59b4eeef Iustin Pop
      snode=fn('snode', None),
692 59b4eeef Iustin Pop
      iallocator=fn('iallocator', None),
693 59b4eeef Iustin Pop
      nics=nics,
694 59b4eeef Iustin Pop
      start=fn('start', True),
695 59b4eeef Iustin Pop
      ip_check=fn('ip_check', True),
696 460d22be Iustin Pop
      name_check=fn('name_check', True),
697 59b4eeef Iustin Pop
      wait_for_sync=True,
698 59b4eeef Iustin Pop
      hypervisor=fn('hypervisor', None),
699 59b4eeef Iustin Pop
      hvparams=hvparams,
700 59b4eeef Iustin Pop
      beparams=beparams,
701 59b4eeef Iustin Pop
      file_storage_dir=fn('file_storage_dir', None),
702 6395cebb Michael Hanselmann
      file_driver=fn('file_driver', constants.FD_LOOP),
703 6f59b964 Iustin Pop
      dry_run=bool(self.dryRun()),
704 59b4eeef Iustin Pop
      )
705 59b4eeef Iustin Pop
706 d975f482 Michael Hanselmann
  def POST(self):
707 d975f482 Michael Hanselmann
    """Create an instance.
708 d975f482 Michael Hanselmann

709 d975f482 Michael Hanselmann
    @return: a job id
710 d975f482 Michael Hanselmann

711 d975f482 Michael Hanselmann
    """
712 1c54156d Luca Bigliardi
    if not isinstance(self.request_body, dict):
713 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
714 d975f482 Michael Hanselmann
715 d975f482 Michael Hanselmann
    # Default to request data version 0
716 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
717 d975f482 Michael Hanselmann
718 d975f482 Michael Hanselmann
    if data_version == 0:
719 d975f482 Michael Hanselmann
      op = self._ParseVersion0CreateRequest()
720 6395cebb Michael Hanselmann
    elif data_version == 1:
721 1c54156d Luca Bigliardi
      op = _ParseInstanceCreateRequestVersion1(self.request_body,
722 6395cebb Michael Hanselmann
                                               self.dryRun())
723 d975f482 Michael Hanselmann
    else:
724 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
725 12eff9b9 Michael Hanselmann
                                data_version)
726 d975f482 Michael Hanselmann
727 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
728 2f7635f4 Oleksiy Mishchenko
729 441e7cfd Oleksiy Mishchenko
730 4e5a68f8 Oleksiy Mishchenko
class R_2_instances_name(baserlib.R_Generic):
731 4e5a68f8 Oleksiy Mishchenko
  """/2/instances/[instance_name] resources.
732 028c6b76 Oleksiy Mishchenko

733 028c6b76 Oleksiy Mishchenko
  """
734 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
735 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
736 4e5a68f8 Oleksiy Mishchenko

737 4e5a68f8 Oleksiy Mishchenko
    """
738 59b4eeef Iustin Pop
    client = baserlib.GetClient()
739 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
740 e8ebbd2b Michael Hanselmann
741 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryInstances,
742 e8ebbd2b Michael Hanselmann
                                            names=[instance_name],
743 e8ebbd2b Michael Hanselmann
                                            fields=I_FIELDS,
744 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
745 4e5a68f8 Oleksiy Mishchenko
746 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
747 028c6b76 Oleksiy Mishchenko
748 6e99c5a0 Iustin Pop
  def DELETE(self):
749 6e99c5a0 Iustin Pop
    """Delete an instance.
750 6e99c5a0 Iustin Pop

751 6e99c5a0 Iustin Pop
    """
752 59b4eeef Iustin Pop
    op = opcodes.OpRemoveInstance(instance_name=self.items[0],
753 6f59b964 Iustin Pop
                                  ignore_failures=False,
754 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
755 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
756 6e99c5a0 Iustin Pop
757 028c6b76 Oleksiy Mishchenko
758 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
759 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
760 d8260842 Michael Hanselmann

761 d8260842 Michael Hanselmann
  """
762 d8260842 Michael Hanselmann
  def GET(self):
763 d8260842 Michael Hanselmann
    """Request detailed instance information.
764 d8260842 Michael Hanselmann

765 d8260842 Michael Hanselmann
    """
766 d8260842 Michael Hanselmann
    instance_name = self.items[0]
767 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
768 d8260842 Michael Hanselmann
769 d8260842 Michael Hanselmann
    op = opcodes.OpQueryInstanceData(instances=[instance_name],
770 d8260842 Michael Hanselmann
                                     static=static)
771 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
772 d8260842 Michael Hanselmann
773 d8260842 Michael Hanselmann
774 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
775 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
776 2276aa29 Oleksiy Mishchenko

777 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
778 2276aa29 Oleksiy Mishchenko

779 2276aa29 Oleksiy Mishchenko
  """
780 21f04e5e Oleksiy Mishchenko
  def POST(self):
781 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
782 2276aa29 Oleksiy Mishchenko

783 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
784 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
785 0c55c24b Oleksiy Mishchenko

786 2276aa29 Oleksiy Mishchenko
    """
787 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
788 0c55c24b Oleksiy Mishchenko
    reboot_type = self.queryargs.get('type',
789 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
790 94cdfa4a Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable('ignore_secondaries'))
791 59b4eeef Iustin Pop
    op = opcodes.OpRebootInstance(instance_name=instance_name,
792 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
793 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
794 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
795 2276aa29 Oleksiy Mishchenko
796 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
797 2276aa29 Oleksiy Mishchenko
798 2276aa29 Oleksiy Mishchenko
799 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
800 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
801 0c55c24b Oleksiy Mishchenko

802 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
803 0c55c24b Oleksiy Mishchenko

804 0c55c24b Oleksiy Mishchenko
  """
805 21f04e5e Oleksiy Mishchenko
  def PUT(self):
806 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
807 0c55c24b Oleksiy Mishchenko

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

811 0c55c24b Oleksiy Mishchenko
    """
812 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
813 94cdfa4a Iustin Pop
    force_startup = bool(self._checkIntVariable('force'))
814 59b4eeef Iustin Pop
    op = opcodes.OpStartupInstance(instance_name=instance_name,
815 6f59b964 Iustin Pop
                                   force=force_startup,
816 6f59b964 Iustin Pop
                                   dry_run=bool(self.dryRun()))
817 0c55c24b Oleksiy Mishchenko
818 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
819 0c55c24b Oleksiy Mishchenko
820 0c55c24b Oleksiy Mishchenko
821 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
822 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
823 0c55c24b Oleksiy Mishchenko

824 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
825 0c55c24b Oleksiy Mishchenko

826 0c55c24b Oleksiy Mishchenko
  """
827 21f04e5e Oleksiy Mishchenko
  def PUT(self):
828 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
829 0c55c24b Oleksiy Mishchenko

830 0c55c24b Oleksiy Mishchenko
    """
831 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
832 6f59b964 Iustin Pop
    op = opcodes.OpShutdownInstance(instance_name=instance_name,
833 6f59b964 Iustin Pop
                                    dry_run=bool(self.dryRun()))
834 0c55c24b Oleksiy Mishchenko
835 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
836 0c55c24b Oleksiy Mishchenko
837 0c55c24b Oleksiy Mishchenko
838 e5b7c4ca Iustin Pop
class R_2_instances_name_reinstall(baserlib.R_Generic):
839 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
840 e5b7c4ca Iustin Pop

841 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
842 e5b7c4ca Iustin Pop

843 e5b7c4ca Iustin Pop
  """
844 e5b7c4ca Iustin Pop
  def POST(self):
845 e5b7c4ca Iustin Pop
    """Reinstall an instance.
846 e5b7c4ca Iustin Pop

847 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
848 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
849 e5b7c4ca Iustin Pop
    automatically.
850 e5b7c4ca Iustin Pop

851 e5b7c4ca Iustin Pop
    """
852 e5b7c4ca Iustin Pop
    instance_name = self.items[0]
853 e5b7c4ca Iustin Pop
    ostype = self._checkStringVariable('os')
854 e5b7c4ca Iustin Pop
    nostartup = self._checkIntVariable('nostartup')
855 e5b7c4ca Iustin Pop
    ops = [
856 e5b7c4ca Iustin Pop
      opcodes.OpShutdownInstance(instance_name=instance_name),
857 e5b7c4ca Iustin Pop
      opcodes.OpReinstallInstance(instance_name=instance_name, os_type=ostype),
858 e5b7c4ca Iustin Pop
      ]
859 e5b7c4ca Iustin Pop
    if not nostartup:
860 e5b7c4ca Iustin Pop
      ops.append(opcodes.OpStartupInstance(instance_name=instance_name,
861 e5b7c4ca Iustin Pop
                                           force=False))
862 e5b7c4ca Iustin Pop
    return baserlib.SubmitJob(ops)
863 e5b7c4ca Iustin Pop
864 e5b7c4ca Iustin Pop
865 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
866 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
867 4c98b915 Michael Hanselmann

868 4c98b915 Michael Hanselmann
  """
869 4c98b915 Michael Hanselmann
  def POST(self):
870 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
871 4c98b915 Michael Hanselmann

872 4c98b915 Michael Hanselmann
    """
873 4c98b915 Michael Hanselmann
    instance_name = self.items[0]
874 4c98b915 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
875 4c98b915 Michael Hanselmann
    mode = self._checkStringVariable("mode", default=None)
876 4c98b915 Michael Hanselmann
    raw_disks = self._checkStringVariable("disks", default=None)
877 4c98b915 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
878 4c98b915 Michael Hanselmann
879 4c98b915 Michael Hanselmann
    if raw_disks:
880 4c98b915 Michael Hanselmann
      try:
881 4c98b915 Michael Hanselmann
        disks = [int(part) for part in raw_disks.split(",")]
882 4c98b915 Michael Hanselmann
      except ValueError, err:
883 4c98b915 Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
884 4c98b915 Michael Hanselmann
    else:
885 4c98b915 Michael Hanselmann
      disks = []
886 4c98b915 Michael Hanselmann
887 4c98b915 Michael Hanselmann
    op = opcodes.OpReplaceDisks(instance_name=instance_name,
888 4c98b915 Michael Hanselmann
                                remote_node=remote_node,
889 4c98b915 Michael Hanselmann
                                mode=mode,
890 4c98b915 Michael Hanselmann
                                disks=disks,
891 4c98b915 Michael Hanselmann
                                iallocator=iallocator)
892 4c98b915 Michael Hanselmann
893 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
894 4c98b915 Michael Hanselmann
895 4c98b915 Michael Hanselmann
896 2197b66f René Nussbaumer
class R_2_instances_name_activate_disks(baserlib.R_Generic):
897 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
898 2197b66f René Nussbaumer

899 2197b66f René Nussbaumer
  """
900 2197b66f René Nussbaumer
  def PUT(self):
901 2197b66f René Nussbaumer
    """Activate disks for an instance.
902 2197b66f René Nussbaumer

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

905 2197b66f René Nussbaumer
    """
906 2197b66f René Nussbaumer
    instance_name = self.items[0]
907 2197b66f René Nussbaumer
    ignore_size = bool(self._checkIntVariable('ignore_size'))
908 2197b66f René Nussbaumer
909 2197b66f René Nussbaumer
    op = opcodes.OpActivateInstanceDisks(instance_name=instance_name,
910 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
911 2197b66f René Nussbaumer
912 2197b66f René Nussbaumer
    return baserlib.SubmitJob([op])
913 2197b66f René Nussbaumer
914 2197b66f René Nussbaumer
915 0a37de5f René Nussbaumer
class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
916 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
917 0a37de5f René Nussbaumer

918 0a37de5f René Nussbaumer
  """
919 0a37de5f René Nussbaumer
  def PUT(self):
920 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
921 0a37de5f René Nussbaumer

922 0a37de5f René Nussbaumer
    """
923 0a37de5f René Nussbaumer
    instance_name = self.items[0]
924 0a37de5f René Nussbaumer
925 2263aec2 René Nussbaumer
    op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
926 0a37de5f René Nussbaumer
927 0a37de5f René Nussbaumer
    return baserlib.SubmitJob([op])
928 0a37de5f René Nussbaumer
929 0a37de5f René Nussbaumer
930 ebeb600f Michael Hanselmann
class R_2_instances_name_prepare_export(baserlib.R_Generic):
931 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/prepare-export resource.
932 ebeb600f Michael Hanselmann

933 ebeb600f Michael Hanselmann
  """
934 ebeb600f Michael Hanselmann
  def PUT(self):
935 ebeb600f Michael Hanselmann
    """Prepares an export for an instance.
936 ebeb600f Michael Hanselmann

937 ebeb600f Michael Hanselmann
    @return: a job id
938 ebeb600f Michael Hanselmann

939 ebeb600f Michael Hanselmann
    """
940 ebeb600f Michael Hanselmann
    instance_name = self.items[0]
941 ebeb600f Michael Hanselmann
    mode = self._checkStringVariable("mode")
942 ebeb600f Michael Hanselmann
943 ebeb600f Michael Hanselmann
    op = opcodes.OpPrepareExport(instance_name=instance_name,
944 ebeb600f Michael Hanselmann
                                 mode=mode)
945 ebeb600f Michael Hanselmann
946 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
947 ebeb600f Michael Hanselmann
948 ebeb600f Michael Hanselmann
949 ebeb600f Michael Hanselmann
def _ParseExportInstanceRequest(name, data):
950 ebeb600f Michael Hanselmann
  """Parses a request for an instance export.
951 ebeb600f Michael Hanselmann

952 ebeb600f Michael Hanselmann
  @rtype: L{opcodes.OpExportInstance}
953 ebeb600f Michael Hanselmann
  @return: Instance export opcode
954 ebeb600f Michael Hanselmann

955 ebeb600f Michael Hanselmann
  """
956 ebeb600f Michael Hanselmann
  mode = baserlib.CheckParameter(data, "mode",
957 ebeb600f Michael Hanselmann
                                 default=constants.EXPORT_MODE_LOCAL)
958 ebeb600f Michael Hanselmann
  target_node = baserlib.CheckParameter(data, "destination")
959 ebeb600f Michael Hanselmann
  shutdown = baserlib.CheckParameter(data, "shutdown", exptype=bool)
960 ebeb600f Michael Hanselmann
  remove_instance = baserlib.CheckParameter(data, "remove_instance",
961 ebeb600f Michael Hanselmann
                                            exptype=bool, default=False)
962 ebeb600f Michael Hanselmann
  x509_key_name = baserlib.CheckParameter(data, "x509_key_name", default=None)
963 ebeb600f Michael Hanselmann
  destination_x509_ca = baserlib.CheckParameter(data, "destination_x509_ca",
964 ebeb600f Michael Hanselmann
                                                default=None)
965 ebeb600f Michael Hanselmann
966 ebeb600f Michael Hanselmann
  return opcodes.OpExportInstance(instance_name=name,
967 ebeb600f Michael Hanselmann
                                  mode=mode,
968 ebeb600f Michael Hanselmann
                                  target_node=target_node,
969 ebeb600f Michael Hanselmann
                                  shutdown=shutdown,
970 ebeb600f Michael Hanselmann
                                  remove_instance=remove_instance,
971 ebeb600f Michael Hanselmann
                                  x509_key_name=x509_key_name,
972 ebeb600f Michael Hanselmann
                                  destination_x509_ca=destination_x509_ca)
973 ebeb600f Michael Hanselmann
974 ebeb600f Michael Hanselmann
975 ebeb600f Michael Hanselmann
class R_2_instances_name_export(baserlib.R_Generic):
976 ebeb600f Michael Hanselmann
  """/2/instances/[instance_name]/export resource.
977 ebeb600f Michael Hanselmann

978 ebeb600f Michael Hanselmann
  """
979 ebeb600f Michael Hanselmann
  def PUT(self):
980 ebeb600f Michael Hanselmann
    """Exports an instance.
981 ebeb600f Michael Hanselmann

982 ebeb600f Michael Hanselmann
    @return: a job id
983 ebeb600f Michael Hanselmann

984 ebeb600f Michael Hanselmann
    """
985 ebeb600f Michael Hanselmann
    if not isinstance(self.request_body, dict):
986 ebeb600f Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
987 ebeb600f Michael Hanselmann
988 ebeb600f Michael Hanselmann
    op = _ParseExportInstanceRequest(self.items[0], self.request_body)
989 ebeb600f Michael Hanselmann
990 ebeb600f Michael Hanselmann
    return baserlib.SubmitJob([op])
991 ebeb600f Michael Hanselmann
992 ebeb600f Michael Hanselmann
993 5823e0d2 Michael Hanselmann
def _ParseMigrateInstanceRequest(name, data):
994 5823e0d2 Michael Hanselmann
  """Parses a request for an instance migration.
995 5823e0d2 Michael Hanselmann

996 5823e0d2 Michael Hanselmann
  @rtype: L{opcodes.OpMigrateInstance}
997 5823e0d2 Michael Hanselmann
  @return: Instance migration opcode
998 5823e0d2 Michael Hanselmann

999 5823e0d2 Michael Hanselmann
  """
1000 5823e0d2 Michael Hanselmann
  mode = baserlib.CheckParameter(data, "mode", default=None)
1001 5823e0d2 Michael Hanselmann
  cleanup = baserlib.CheckParameter(data, "cleanup", exptype=bool,
1002 5823e0d2 Michael Hanselmann
                                    default=False)
1003 5823e0d2 Michael Hanselmann
1004 5823e0d2 Michael Hanselmann
  return opcodes.OpMigrateInstance(instance_name=name, mode=mode,
1005 5823e0d2 Michael Hanselmann
                                   cleanup=cleanup)
1006 5823e0d2 Michael Hanselmann
1007 5823e0d2 Michael Hanselmann
1008 5823e0d2 Michael Hanselmann
class R_2_instances_name_migrate(baserlib.R_Generic):
1009 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1010 5823e0d2 Michael Hanselmann

1011 5823e0d2 Michael Hanselmann
  """
1012 5823e0d2 Michael Hanselmann
  def PUT(self):
1013 5823e0d2 Michael Hanselmann
    """Migrates an instance.
1014 5823e0d2 Michael Hanselmann

1015 5823e0d2 Michael Hanselmann
    @return: a job id
1016 5823e0d2 Michael Hanselmann

1017 5823e0d2 Michael Hanselmann
    """
1018 5823e0d2 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1019 5823e0d2 Michael Hanselmann
1020 5823e0d2 Michael Hanselmann
    op = _ParseMigrateInstanceRequest(self.items[0], self.request_body)
1021 5823e0d2 Michael Hanselmann
1022 5823e0d2 Michael Hanselmann
    return baserlib.SubmitJob([op])
1023 5823e0d2 Michael Hanselmann
1024 5823e0d2 Michael Hanselmann
1025 d56e7dc7 Michael Hanselmann
def _ParseRenameInstanceRequest(name, data):
1026 d56e7dc7 Michael Hanselmann
  """Parses a request for renaming an instance.
1027 d56e7dc7 Michael Hanselmann

1028 d56e7dc7 Michael Hanselmann
  @rtype: L{opcodes.OpRenameInstance}
1029 d56e7dc7 Michael Hanselmann
  @return: Instance rename opcode
1030 d56e7dc7 Michael Hanselmann

1031 d56e7dc7 Michael Hanselmann
  """
1032 d56e7dc7 Michael Hanselmann
  new_name = baserlib.CheckParameter(data, "new_name")
1033 d56e7dc7 Michael Hanselmann
  ip_check = baserlib.CheckParameter(data, "ip_check", default=True)
1034 d56e7dc7 Michael Hanselmann
  name_check = baserlib.CheckParameter(data, "name_check", default=True)
1035 d56e7dc7 Michael Hanselmann
1036 d56e7dc7 Michael Hanselmann
  return opcodes.OpRenameInstance(instance_name=name, new_name=new_name,
1037 d56e7dc7 Michael Hanselmann
                                  name_check=name_check, ip_check=ip_check)
1038 d56e7dc7 Michael Hanselmann
1039 d56e7dc7 Michael Hanselmann
1040 d56e7dc7 Michael Hanselmann
class R_2_instances_name_rename(baserlib.R_Generic):
1041 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1042 d56e7dc7 Michael Hanselmann

1043 d56e7dc7 Michael Hanselmann
  """
1044 d56e7dc7 Michael Hanselmann
  def PUT(self):
1045 d56e7dc7 Michael Hanselmann
    """Changes the name of an instance.
1046 d56e7dc7 Michael Hanselmann

1047 d56e7dc7 Michael Hanselmann
    @return: a job id
1048 d56e7dc7 Michael Hanselmann

1049 d56e7dc7 Michael Hanselmann
    """
1050 d56e7dc7 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1051 d56e7dc7 Michael Hanselmann
1052 d56e7dc7 Michael Hanselmann
    op = _ParseRenameInstanceRequest(self.items[0], self.request_body)
1053 d56e7dc7 Michael Hanselmann
1054 d56e7dc7 Michael Hanselmann
    return baserlib.SubmitJob([op])
1055 d56e7dc7 Michael Hanselmann
1056 d56e7dc7 Michael Hanselmann
1057 3882937a Michael Hanselmann
def _ParseModifyInstanceRequest(name, data):
1058 3882937a Michael Hanselmann
  """Parses a request for modifying an instance.
1059 3882937a Michael Hanselmann

1060 3882937a Michael Hanselmann
  @rtype: L{opcodes.OpSetInstanceParams}
1061 3882937a Michael Hanselmann
  @return: Instance modify opcode
1062 3882937a Michael Hanselmann

1063 3882937a Michael Hanselmann
  """
1064 3882937a Michael Hanselmann
  osparams = baserlib.CheckParameter(data, "osparams", default={})
1065 3882937a Michael Hanselmann
  force = baserlib.CheckParameter(data, "force", default=False)
1066 3882937a Michael Hanselmann
  nics = baserlib.CheckParameter(data, "nics", default=[])
1067 3882937a Michael Hanselmann
  disks = baserlib.CheckParameter(data, "disks", default=[])
1068 3882937a Michael Hanselmann
  disk_template = baserlib.CheckParameter(data, "disk_template", default=None)
1069 3882937a Michael Hanselmann
  remote_node = baserlib.CheckParameter(data, "remote_node", default=None)
1070 3882937a Michael Hanselmann
  os_name = baserlib.CheckParameter(data, "os_name", default=None)
1071 3882937a Michael Hanselmann
  force_variant = baserlib.CheckParameter(data, "force_variant", default=False)
1072 3882937a Michael Hanselmann
1073 3882937a Michael Hanselmann
  # HV/BE parameters
1074 3882937a Michael Hanselmann
  hvparams = baserlib.CheckParameter(data, "hvparams", default={})
1075 3882937a Michael Hanselmann
  utils.ForceDictType(hvparams, constants.HVS_PARAMETER_TYPES,
1076 3882937a Michael Hanselmann
                      allowed_values=[constants.VALUE_DEFAULT])
1077 3882937a Michael Hanselmann
1078 3882937a Michael Hanselmann
  beparams = baserlib.CheckParameter(data, "beparams", default={})
1079 3882937a Michael Hanselmann
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES,
1080 3882937a Michael Hanselmann
                      allowed_values=[constants.VALUE_DEFAULT])
1081 3882937a Michael Hanselmann
1082 3882937a Michael Hanselmann
  return opcodes.OpSetInstanceParams(instance_name=name, hvparams=hvparams,
1083 3882937a Michael Hanselmann
                                     beparams=beparams, osparams=osparams,
1084 3882937a Michael Hanselmann
                                     force=force, nics=nics, disks=disks,
1085 3882937a Michael Hanselmann
                                     disk_template=disk_template,
1086 3882937a Michael Hanselmann
                                     remote_node=remote_node, os_name=os_name,
1087 3882937a Michael Hanselmann
                                     force_variant=force_variant)
1088 3882937a Michael Hanselmann
1089 3882937a Michael Hanselmann
1090 3882937a Michael Hanselmann
class R_2_instances_name_modify(baserlib.R_Generic):
1091 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1092 3882937a Michael Hanselmann

1093 3882937a Michael Hanselmann
  """
1094 3882937a Michael Hanselmann
  def PUT(self):
1095 3882937a Michael Hanselmann
    """Changes some parameters of an instance.
1096 3882937a Michael Hanselmann

1097 3882937a Michael Hanselmann
    @return: a job id
1098 3882937a Michael Hanselmann

1099 3882937a Michael Hanselmann
    """
1100 3882937a Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1101 3882937a Michael Hanselmann
1102 3882937a Michael Hanselmann
    op = _ParseModifyInstanceRequest(self.items[0], self.request_body)
1103 3882937a Michael Hanselmann
1104 3882937a Michael Hanselmann
    return baserlib.SubmitJob([op])
1105 3882937a Michael Hanselmann
1106 3882937a Michael Hanselmann
1107 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
1108 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1109 441e7cfd Oleksiy Mishchenko

1110 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1111 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1112 441e7cfd Oleksiy Mishchenko

1113 441e7cfd Oleksiy Mishchenko
  """
1114 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1115 18cb43a2 Oleksiy Mishchenko
1116 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
1117 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1118 18cb43a2 Oleksiy Mishchenko

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

1121 18cb43a2 Oleksiy Mishchenko
    """
1122 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
1123 18cb43a2 Oleksiy Mishchenko
1124 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1125 5313eed7 Michael Hanselmann
      self.name = None
1126 18cb43a2 Oleksiy Mishchenko
    else:
1127 5313eed7 Michael Hanselmann
      self.name = items[0]
1128 441e7cfd Oleksiy Mishchenko
1129 441e7cfd Oleksiy Mishchenko
  def GET(self):
1130 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1131 441e7cfd Oleksiy Mishchenko

1132 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1133 441e7cfd Oleksiy Mishchenko

1134 441e7cfd Oleksiy Mishchenko
    """
1135 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1136 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
1137 441e7cfd Oleksiy Mishchenko
1138 21f04e5e Oleksiy Mishchenko
  def PUT(self):
1139 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1140 441e7cfd Oleksiy Mishchenko

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

1144 441e7cfd Oleksiy Mishchenko
    """
1145 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1146 6e99c5a0 Iustin Pop
    if 'tag' not in self.queryargs:
1147 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
1148 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
1149 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
1150 6f59b964 Iustin Pop
                              self.queryargs['tag'], name=self.name,
1151 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
1152 15fd9fd5 Oleksiy Mishchenko
1153 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
1154 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1155 15fd9fd5 Oleksiy Mishchenko

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

1160 15fd9fd5 Oleksiy Mishchenko
    """
1161 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1162 15fd9fd5 Oleksiy Mishchenko
    if 'tag' not in self.queryargs:
1163 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
1164 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
1165 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
1166 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
1167 15fd9fd5 Oleksiy Mishchenko
                                 self.queryargs['tag'],
1168 6f59b964 Iustin Pop
                                 name=self.name,
1169 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
1170 18cb43a2 Oleksiy Mishchenko
1171 18cb43a2 Oleksiy Mishchenko
1172 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1173 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1174 18cb43a2 Oleksiy Mishchenko

1175 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1176 18cb43a2 Oleksiy Mishchenko

1177 18cb43a2 Oleksiy Mishchenko
  """
1178 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1179 18cb43a2 Oleksiy Mishchenko
1180 18cb43a2 Oleksiy Mishchenko
1181 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1182 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1183 18cb43a2 Oleksiy Mishchenko

1184 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1185 18cb43a2 Oleksiy Mishchenko

1186 18cb43a2 Oleksiy Mishchenko
  """
1187 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1188 18cb43a2 Oleksiy Mishchenko
1189 18cb43a2 Oleksiy Mishchenko
1190 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1191 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/tags resource.
1192 18cb43a2 Oleksiy Mishchenko

1193 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1194 18cb43a2 Oleksiy Mishchenko

1195 18cb43a2 Oleksiy Mishchenko
  """
1196 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER