Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (24.1 kB)

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

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

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

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

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

38 10b207d4 Oleksiy Mishchenko
"""
39 10b207d4 Oleksiy Mishchenko
40 fe267188 Iustin Pop
# pylint: disable-msg=C0103
41 fe267188 Iustin Pop
42 fe267188 Iustin Pop
# C0103: Invalid name, since the R_* names are not conforming
43 fe267188 Iustin Pop
44 59b4eeef Iustin Pop
from ganeti import opcodes
45 15fd9fd5 Oleksiy Mishchenko
from ganeti import http
46 15fd9fd5 Oleksiy Mishchenko
from ganeti import constants
47 59b4eeef Iustin Pop
from ganeti import cli
48 8381fa2d Michael Hanselmann
from ganeti import rapi
49 38206f3c Iustin Pop
from ganeti.rapi import baserlib
50 10b207d4 Oleksiy Mishchenko
51 4e5a68f8 Oleksiy Mishchenko
52 7118a0df Iustin Pop
_COMMON_FIELDS = ["ctime", "mtime", "uuid", "serial_no", "tags"]
53 9031ee8e Iustin Pop
I_FIELDS = ["name", "admin_state", "os",
54 9031ee8e Iustin Pop
            "pnode", "snodes",
55 9031ee8e Iustin Pop
            "disk_template",
56 82e186f8 Michael Hanselmann
            "nic.ips", "nic.macs", "nic.modes", "nic.links", "nic.bridges",
57 a8b16c4e Tim Boring
            "network_port",
58 024e157f Iustin Pop
            "disk.sizes", "disk_usage",
59 a5b9d725 Iustin Pop
            "beparams", "hvparams",
60 9031ee8e Iustin Pop
            "oper_state", "oper_ram", "status",
61 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
62 9031ee8e Iustin Pop
63 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
64 9031ee8e Iustin Pop
            "dtotal", "dfree",
65 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
66 7118a0df Iustin Pop
            "pinst_cnt", "sinst_cnt",
67 0105bad3 Iustin Pop
            "ctotal", "cnodes", "csockets",
68 7118a0df Iustin Pop
            "pip", "sip", "role",
69 93962b80 Iustin Pop
            "pinst_list", "sinst_list",
70 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
71 4e5a68f8 Oleksiy Mishchenko
72 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
73 64dae8fc Michael Hanselmann
_NR_MASTER_CANDIATE = "master-candidate"
74 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
75 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
76 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
77 64dae8fc Michael Hanselmann
78 64dae8fc Michael Hanselmann
_NR_MAP = {
79 64dae8fc Michael Hanselmann
  "M": _NR_MASTER,
80 64dae8fc Michael Hanselmann
  "C": _NR_MASTER_CANDIATE,
81 64dae8fc Michael Hanselmann
  "D": _NR_DRAINED,
82 64dae8fc Michael Hanselmann
  "O": _NR_OFFLINE,
83 64dae8fc Michael Hanselmann
  "R": _NR_REGULAR,
84 64dae8fc Michael Hanselmann
  }
85 64dae8fc Michael Hanselmann
86 d975f482 Michael Hanselmann
# Request data version field
87 d975f482 Michael Hanselmann
_REQ_DATA_VERSION = "__version__"
88 d975f482 Michael Hanselmann
89 793a8f7c Michael Hanselmann
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
90 793a8f7c Michael Hanselmann
_WFJC_TIMEOUT = 10
91 793a8f7c Michael Hanselmann
92 4e5a68f8 Oleksiy Mishchenko
93 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
94 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
95 4e5a68f8 Oleksiy Mishchenko

96 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
97 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
98 4e5a68f8 Oleksiy Mishchenko

99 4e5a68f8 Oleksiy Mishchenko
  """
100 7e950d31 Iustin Pop
  @staticmethod
101 7e950d31 Iustin Pop
  def GET():
102 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
103 4e5a68f8 Oleksiy Mishchenko

104 4e5a68f8 Oleksiy Mishchenko
    """
105 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
106 4e5a68f8 Oleksiy Mishchenko
107 4e5a68f8 Oleksiy Mishchenko
108 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
109 4e5a68f8 Oleksiy Mishchenko
  """Cluster info.
110 4e5a68f8 Oleksiy Mishchenko

111 4e5a68f8 Oleksiy Mishchenko
  """
112 7e950d31 Iustin Pop
  @staticmethod
113 7e950d31 Iustin Pop
  def GET():
114 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
115 4e5a68f8 Oleksiy Mishchenko

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

124 7eac4a4d Michael Hanselmann
  """
125 7eac4a4d Michael Hanselmann
  @staticmethod
126 7eac4a4d Michael Hanselmann
  def GET():
127 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
128 7eac4a4d Michael Hanselmann

129 7eac4a4d Michael Hanselmann
    """
130 7eac4a4d Michael Hanselmann
    return []
131 7eac4a4d Michael Hanselmann
132 7eac4a4d Michael Hanselmann
133 4e5a68f8 Oleksiy Mishchenko
class R_2_os(baserlib.R_Generic):
134 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
135 4e5a68f8 Oleksiy Mishchenko

136 4e5a68f8 Oleksiy Mishchenko
  """
137 7e950d31 Iustin Pop
  @staticmethod
138 7e950d31 Iustin Pop
  def GET():
139 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
140 4e5a68f8 Oleksiy Mishchenko

141 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
142 4e5a68f8 Oleksiy Mishchenko

143 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
144 4e5a68f8 Oleksiy Mishchenko

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

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

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

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

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

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

199 10b207d4 Oleksiy Mishchenko
  """
200 10b207d4 Oleksiy Mishchenko
  def GET(self):
201 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
202 10b207d4 Oleksiy Mishchenko

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

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

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

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

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

284 10b207d4 Oleksiy Mishchenko
  """
285 10b207d4 Oleksiy Mishchenko
  def GET(self):
286 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
287 38206f3c Iustin Pop

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

304 028c6b76 Oleksiy Mishchenko
  """
305 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
306 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
307 4e5a68f8 Oleksiy Mishchenko

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

320 64dae8fc Michael Hanselmann
  """
321 64dae8fc Michael Hanselmann
  def GET(self):
322 64dae8fc Michael Hanselmann
    """Returns the current node role.
323 64dae8fc Michael Hanselmann

324 64dae8fc Michael Hanselmann
    @return: Node role
325 64dae8fc Michael Hanselmann

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

337 64dae8fc Michael Hanselmann
    @return: a job id
338 64dae8fc Michael Hanselmann

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

378 73452f12 Michael Hanselmann
  """
379 73452f12 Michael Hanselmann
  def POST(self):
380 73452f12 Michael Hanselmann
    """Evacuate all secondary instances off a node.
381 73452f12 Michael Hanselmann

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

397 1c482bab Michael Hanselmann
  """
398 1c482bab Michael Hanselmann
  def POST(self):
399 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
400 1c482bab Michael Hanselmann

401 1c482bab Michael Hanselmann
    """
402 1c482bab Michael Hanselmann
    node_name = self.items[0]
403 1c482bab Michael Hanselmann
    live = bool(self._checkIntVariable("live", default=1))
404 1c482bab Michael Hanselmann
405 1c482bab Michael Hanselmann
    op = opcodes.OpMigrateNode(node_name=node_name, live=live)
406 1c482bab Michael Hanselmann
407 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
408 1c482bab Michael Hanselmann
409 1c482bab Michael Hanselmann
410 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
411 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/storage ressource.
412 7a95a954 Michael Hanselmann

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

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

469 723f4565 Michael Hanselmann
  """
470 723f4565 Michael Hanselmann
  def PUT(self):
471 723f4565 Michael Hanselmann
    node_name = self.items[0]
472 723f4565 Michael Hanselmann
473 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
474 723f4565 Michael Hanselmann
    if not storage_type:
475 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
476 723f4565 Michael Hanselmann
                                " parameter")
477 723f4565 Michael Hanselmann
478 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
479 723f4565 Michael Hanselmann
    if not name:
480 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
481 723f4565 Michael Hanselmann
                                " parameter")
482 723f4565 Michael Hanselmann
483 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
484 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
485 723f4565 Michael Hanselmann
                                     name=name)
486 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
487 723f4565 Michael Hanselmann
488 723f4565 Michael Hanselmann
489 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
490 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
491 441e7cfd Oleksiy Mishchenko

492 441e7cfd Oleksiy Mishchenko
  """
493 441e7cfd Oleksiy Mishchenko
  def GET(self):
494 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
495 441e7cfd Oleksiy Mishchenko

496 441e7cfd Oleksiy Mishchenko
    """
497 59b4eeef Iustin Pop
    client = baserlib.GetClient()
498 441e7cfd Oleksiy Mishchenko
499 3d103742 Iustin Pop
    use_locking = self.useLocking()
500 3d103742 Iustin Pop
    if self.useBulk():
501 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
502 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
503 441e7cfd Oleksiy Mishchenko
    else:
504 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
505 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
506 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
507 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
508 441e7cfd Oleksiy Mishchenko
509 d975f482 Michael Hanselmann
  def _ParseVersion0CreateRequest(self):
510 d975f482 Michael Hanselmann
    """Parses an instance creation request version 0.
511 2f7635f4 Oleksiy Mishchenko

512 d975f482 Michael Hanselmann
    @rtype: L{opcodes.OpCreateInstance}
513 d975f482 Michael Hanselmann
    @return: Instance creation opcode
514 2f7635f4 Oleksiy Mishchenko

515 2f7635f4 Oleksiy Mishchenko
    """
516 6e99c5a0 Iustin Pop
    beparams = baserlib.MakeParamsDict(self.req.request_body,
517 6e99c5a0 Iustin Pop
                                       constants.BES_PARAMETERS)
518 6e99c5a0 Iustin Pop
    hvparams = baserlib.MakeParamsDict(self.req.request_body,
519 6e99c5a0 Iustin Pop
                                       constants.HVS_PARAMETERS)
520 6e99c5a0 Iustin Pop
    fn = self.getBodyParameter
521 6e99c5a0 Iustin Pop
522 6e99c5a0 Iustin Pop
    # disk processing
523 6e99c5a0 Iustin Pop
    disk_data = fn('disks')
524 6e99c5a0 Iustin Pop
    if not isinstance(disk_data, list):
525 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("The 'disks' parameter should be a list")
526 6e99c5a0 Iustin Pop
    disks = []
527 6e99c5a0 Iustin Pop
    for idx, d in enumerate(disk_data):
528 6e99c5a0 Iustin Pop
      if not isinstance(d, int):
529 6e99c5a0 Iustin Pop
        raise http.HttpBadRequest("Disk %d specification wrong: should"
530 69b99987 Michael Hanselmann
                                  " be an integer" % idx)
531 6e99c5a0 Iustin Pop
      disks.append({"size": d})
532 d975f482 Michael Hanselmann
533 6e99c5a0 Iustin Pop
    # nic processing (one nic only)
534 495cfdf0 Guido Trotter
    nics = [{"mac": fn("mac", constants.VALUE_AUTO)}]
535 495cfdf0 Guido Trotter
    if fn("ip", None) is not None:
536 495cfdf0 Guido Trotter
      nics[0]["ip"] = fn("ip")
537 495cfdf0 Guido Trotter
    if fn("mode", None) is not None:
538 495cfdf0 Guido Trotter
      nics[0]["mode"] = fn("mode")
539 495cfdf0 Guido Trotter
    if fn("link", None) is not None:
540 495cfdf0 Guido Trotter
      nics[0]["link"] = fn("link")
541 495cfdf0 Guido Trotter
    if fn("bridge", None) is not None:
542 69b99987 Michael Hanselmann
      nics[0]["bridge"] = fn("bridge")
543 2f7635f4 Oleksiy Mishchenko
544 d975f482 Michael Hanselmann
    return opcodes.OpCreateInstance(
545 59b4eeef Iustin Pop
      mode=constants.INSTANCE_CREATE,
546 59b4eeef Iustin Pop
      instance_name=fn('name'),
547 59b4eeef Iustin Pop
      disks=disks,
548 59b4eeef Iustin Pop
      disk_template=fn('disk_template'),
549 59b4eeef Iustin Pop
      os_type=fn('os'),
550 59b4eeef Iustin Pop
      pnode=fn('pnode', None),
551 59b4eeef Iustin Pop
      snode=fn('snode', None),
552 59b4eeef Iustin Pop
      iallocator=fn('iallocator', None),
553 59b4eeef Iustin Pop
      nics=nics,
554 59b4eeef Iustin Pop
      start=fn('start', True),
555 59b4eeef Iustin Pop
      ip_check=fn('ip_check', True),
556 460d22be Iustin Pop
      name_check=fn('name_check', True),
557 59b4eeef Iustin Pop
      wait_for_sync=True,
558 59b4eeef Iustin Pop
      hypervisor=fn('hypervisor', None),
559 59b4eeef Iustin Pop
      hvparams=hvparams,
560 59b4eeef Iustin Pop
      beparams=beparams,
561 59b4eeef Iustin Pop
      file_storage_dir=fn('file_storage_dir', None),
562 59b4eeef Iustin Pop
      file_driver=fn('file_driver', 'loop'),
563 6f59b964 Iustin Pop
      dry_run=bool(self.dryRun()),
564 59b4eeef Iustin Pop
      )
565 59b4eeef Iustin Pop
566 d975f482 Michael Hanselmann
  def POST(self):
567 d975f482 Michael Hanselmann
    """Create an instance.
568 d975f482 Michael Hanselmann

569 d975f482 Michael Hanselmann
    @return: a job id
570 d975f482 Michael Hanselmann

571 d975f482 Michael Hanselmann
    """
572 d975f482 Michael Hanselmann
    if not isinstance(self.req.request_body, dict):
573 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
574 d975f482 Michael Hanselmann
575 d975f482 Michael Hanselmann
    # Default to request data version 0
576 d975f482 Michael Hanselmann
    data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0)
577 d975f482 Michael Hanselmann
578 d975f482 Michael Hanselmann
    if data_version == 0:
579 d975f482 Michael Hanselmann
      op = self._ParseVersion0CreateRequest()
580 d975f482 Michael Hanselmann
    else:
581 d975f482 Michael Hanselmann
      raise http.HttpBadRequest("Unsupported request data version %s" %
582 12eff9b9 Michael Hanselmann
                                data_version)
583 d975f482 Michael Hanselmann
584 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
585 2f7635f4 Oleksiy Mishchenko
586 441e7cfd Oleksiy Mishchenko
587 4e5a68f8 Oleksiy Mishchenko
class R_2_instances_name(baserlib.R_Generic):
588 4e5a68f8 Oleksiy Mishchenko
  """/2/instances/[instance_name] resources.
589 028c6b76 Oleksiy Mishchenko

590 028c6b76 Oleksiy Mishchenko
  """
591 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
592 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
593 4e5a68f8 Oleksiy Mishchenko

594 4e5a68f8 Oleksiy Mishchenko
    """
595 59b4eeef Iustin Pop
    client = baserlib.GetClient()
596 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
597 9031ee8e Iustin Pop
    result = client.QueryInstances(names=[instance_name], fields=I_FIELDS,
598 3d103742 Iustin Pop
                                   use_locking=self.useLocking())
599 4e5a68f8 Oleksiy Mishchenko
600 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
601 028c6b76 Oleksiy Mishchenko
602 6e99c5a0 Iustin Pop
  def DELETE(self):
603 6e99c5a0 Iustin Pop
    """Delete an instance.
604 6e99c5a0 Iustin Pop

605 6e99c5a0 Iustin Pop
    """
606 59b4eeef Iustin Pop
    op = opcodes.OpRemoveInstance(instance_name=self.items[0],
607 6f59b964 Iustin Pop
                                  ignore_failures=False,
608 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
609 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
610 6e99c5a0 Iustin Pop
611 028c6b76 Oleksiy Mishchenko
612 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
613 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
614 d8260842 Michael Hanselmann

615 d8260842 Michael Hanselmann
  """
616 d8260842 Michael Hanselmann
  def GET(self):
617 d8260842 Michael Hanselmann
    """Request detailed instance information.
618 d8260842 Michael Hanselmann

619 d8260842 Michael Hanselmann
    """
620 d8260842 Michael Hanselmann
    instance_name = self.items[0]
621 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
622 d8260842 Michael Hanselmann
623 d8260842 Michael Hanselmann
    op = opcodes.OpQueryInstanceData(instances=[instance_name],
624 d8260842 Michael Hanselmann
                                     static=static)
625 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
626 d8260842 Michael Hanselmann
627 d8260842 Michael Hanselmann
628 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
629 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
630 2276aa29 Oleksiy Mishchenko

631 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
632 2276aa29 Oleksiy Mishchenko

633 2276aa29 Oleksiy Mishchenko
  """
634 21f04e5e Oleksiy Mishchenko
  def POST(self):
635 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
636 2276aa29 Oleksiy Mishchenko

637 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
638 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
639 0c55c24b Oleksiy Mishchenko

640 2276aa29 Oleksiy Mishchenko
    """
641 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
642 0c55c24b Oleksiy Mishchenko
    reboot_type = self.queryargs.get('type',
643 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
644 94cdfa4a Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable('ignore_secondaries'))
645 59b4eeef Iustin Pop
    op = opcodes.OpRebootInstance(instance_name=instance_name,
646 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
647 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
648 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
649 2276aa29 Oleksiy Mishchenko
650 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
651 2276aa29 Oleksiy Mishchenko
652 2276aa29 Oleksiy Mishchenko
653 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
654 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
655 0c55c24b Oleksiy Mishchenko

656 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
657 0c55c24b Oleksiy Mishchenko

658 0c55c24b Oleksiy Mishchenko
  """
659 21f04e5e Oleksiy Mishchenko
  def PUT(self):
660 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
661 0c55c24b Oleksiy Mishchenko

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

665 0c55c24b Oleksiy Mishchenko
    """
666 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
667 94cdfa4a Iustin Pop
    force_startup = bool(self._checkIntVariable('force'))
668 59b4eeef Iustin Pop
    op = opcodes.OpStartupInstance(instance_name=instance_name,
669 6f59b964 Iustin Pop
                                   force=force_startup,
670 6f59b964 Iustin Pop
                                   dry_run=bool(self.dryRun()))
671 0c55c24b Oleksiy Mishchenko
672 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
673 0c55c24b Oleksiy Mishchenko
674 0c55c24b Oleksiy Mishchenko
675 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
676 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
677 0c55c24b Oleksiy Mishchenko

678 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
679 0c55c24b Oleksiy Mishchenko

680 0c55c24b Oleksiy Mishchenko
  """
681 21f04e5e Oleksiy Mishchenko
  def PUT(self):
682 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
683 0c55c24b Oleksiy Mishchenko

684 0c55c24b Oleksiy Mishchenko
    """
685 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
686 6f59b964 Iustin Pop
    op = opcodes.OpShutdownInstance(instance_name=instance_name,
687 6f59b964 Iustin Pop
                                    dry_run=bool(self.dryRun()))
688 0c55c24b Oleksiy Mishchenko
689 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
690 0c55c24b Oleksiy Mishchenko
691 0c55c24b Oleksiy Mishchenko
692 e5b7c4ca Iustin Pop
class R_2_instances_name_reinstall(baserlib.R_Generic):
693 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
694 e5b7c4ca Iustin Pop

695 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
696 e5b7c4ca Iustin Pop

697 e5b7c4ca Iustin Pop
  """
698 e5b7c4ca Iustin Pop
  def POST(self):
699 e5b7c4ca Iustin Pop
    """Reinstall an instance.
700 e5b7c4ca Iustin Pop

701 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
702 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
703 e5b7c4ca Iustin Pop
    automatically.
704 e5b7c4ca Iustin Pop

705 e5b7c4ca Iustin Pop
    """
706 e5b7c4ca Iustin Pop
    instance_name = self.items[0]
707 e5b7c4ca Iustin Pop
    ostype = self._checkStringVariable('os')
708 e5b7c4ca Iustin Pop
    nostartup = self._checkIntVariable('nostartup')
709 e5b7c4ca Iustin Pop
    ops = [
710 e5b7c4ca Iustin Pop
      opcodes.OpShutdownInstance(instance_name=instance_name),
711 e5b7c4ca Iustin Pop
      opcodes.OpReinstallInstance(instance_name=instance_name, os_type=ostype),
712 e5b7c4ca Iustin Pop
      ]
713 e5b7c4ca Iustin Pop
    if not nostartup:
714 e5b7c4ca Iustin Pop
      ops.append(opcodes.OpStartupInstance(instance_name=instance_name,
715 e5b7c4ca Iustin Pop
                                           force=False))
716 e5b7c4ca Iustin Pop
    return baserlib.SubmitJob(ops)
717 e5b7c4ca Iustin Pop
718 e5b7c4ca Iustin Pop
719 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
720 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
721 4c98b915 Michael Hanselmann

722 4c98b915 Michael Hanselmann
  """
723 4c98b915 Michael Hanselmann
  def POST(self):
724 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
725 4c98b915 Michael Hanselmann

726 4c98b915 Michael Hanselmann
    """
727 4c98b915 Michael Hanselmann
    instance_name = self.items[0]
728 4c98b915 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
729 4c98b915 Michael Hanselmann
    mode = self._checkStringVariable("mode", default=None)
730 4c98b915 Michael Hanselmann
    raw_disks = self._checkStringVariable("disks", default=None)
731 4c98b915 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
732 4c98b915 Michael Hanselmann
733 4c98b915 Michael Hanselmann
    if raw_disks:
734 4c98b915 Michael Hanselmann
      try:
735 4c98b915 Michael Hanselmann
        disks = [int(part) for part in raw_disks.split(",")]
736 4c98b915 Michael Hanselmann
      except ValueError, err:
737 4c98b915 Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
738 4c98b915 Michael Hanselmann
    else:
739 4c98b915 Michael Hanselmann
      disks = []
740 4c98b915 Michael Hanselmann
741 4c98b915 Michael Hanselmann
    op = opcodes.OpReplaceDisks(instance_name=instance_name,
742 4c98b915 Michael Hanselmann
                                remote_node=remote_node,
743 4c98b915 Michael Hanselmann
                                mode=mode,
744 4c98b915 Michael Hanselmann
                                disks=disks,
745 4c98b915 Michael Hanselmann
                                iallocator=iallocator)
746 4c98b915 Michael Hanselmann
747 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
748 4c98b915 Michael Hanselmann
749 4c98b915 Michael Hanselmann
750 2197b66f René Nussbaumer
class R_2_instances_name_activate_disks(baserlib.R_Generic):
751 2197b66f René Nussbaumer
  """/2/instances/[instance_name]/activate-disks resource.
752 2197b66f René Nussbaumer

753 2197b66f René Nussbaumer
  """
754 2197b66f René Nussbaumer
  def PUT(self):
755 2197b66f René Nussbaumer
    """Activate disks for an instance.
756 2197b66f René Nussbaumer

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

759 2197b66f René Nussbaumer
    """
760 2197b66f René Nussbaumer
    instance_name = self.items[0]
761 2197b66f René Nussbaumer
    ignore_size = bool(self._checkIntVariable('ignore_size'))
762 2197b66f René Nussbaumer
763 2197b66f René Nussbaumer
    op = opcodes.OpActivateInstanceDisks(instance_name=instance_name,
764 2197b66f René Nussbaumer
                                         ignore_size=ignore_size)
765 2197b66f René Nussbaumer
766 2197b66f René Nussbaumer
    return baserlib.SubmitJob([op])
767 2197b66f René Nussbaumer
768 2197b66f René Nussbaumer
769 0a37de5f René Nussbaumer
class R_2_instances_name_deactivate_disks(baserlib.R_Generic):
770 0a37de5f René Nussbaumer
  """/2/instances/[instance_name]/deactivate-disks resource.
771 0a37de5f René Nussbaumer

772 0a37de5f René Nussbaumer
  """
773 0a37de5f René Nussbaumer
  def PUT(self):
774 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
775 0a37de5f René Nussbaumer

776 0a37de5f René Nussbaumer
    """
777 0a37de5f René Nussbaumer
    instance_name = self.items[0]
778 0a37de5f René Nussbaumer
779 2263aec2 René Nussbaumer
    op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
780 0a37de5f René Nussbaumer
781 0a37de5f René Nussbaumer
    return baserlib.SubmitJob([op])
782 0a37de5f René Nussbaumer
783 0a37de5f René Nussbaumer
784 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
785 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
786 441e7cfd Oleksiy Mishchenko

787 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
788 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
789 441e7cfd Oleksiy Mishchenko

790 441e7cfd Oleksiy Mishchenko
  """
791 7a6b9510 Iustin Pop
  TAG_LEVEL = None
792 18cb43a2 Oleksiy Mishchenko
793 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
794 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
795 18cb43a2 Oleksiy Mishchenko

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

798 18cb43a2 Oleksiy Mishchenko
    """
799 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
800 18cb43a2 Oleksiy Mishchenko
801 18cb43a2 Oleksiy Mishchenko
    if self.TAG_LEVEL != constants.TAG_CLUSTER:
802 18cb43a2 Oleksiy Mishchenko
      self.name = items[0]
803 18cb43a2 Oleksiy Mishchenko
    else:
804 18cb43a2 Oleksiy Mishchenko
      self.name = ""
805 441e7cfd Oleksiy Mishchenko
806 441e7cfd Oleksiy Mishchenko
  def GET(self):
807 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
808 441e7cfd Oleksiy Mishchenko

809 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
810 441e7cfd Oleksiy Mishchenko

811 441e7cfd Oleksiy Mishchenko
    """
812 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
813 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
814 441e7cfd Oleksiy Mishchenko
815 21f04e5e Oleksiy Mishchenko
  def PUT(self):
816 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
817 441e7cfd Oleksiy Mishchenko

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

821 441e7cfd Oleksiy Mishchenko
    """
822 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
823 6e99c5a0 Iustin Pop
    if 'tag' not in self.queryargs:
824 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
825 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
826 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
827 6f59b964 Iustin Pop
                              self.queryargs['tag'], name=self.name,
828 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
829 15fd9fd5 Oleksiy Mishchenko
830 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
831 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
832 15fd9fd5 Oleksiy Mishchenko

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

837 15fd9fd5 Oleksiy Mishchenko
    """
838 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
839 15fd9fd5 Oleksiy Mishchenko
    if 'tag' not in self.queryargs:
840 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
841 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
842 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
843 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
844 15fd9fd5 Oleksiy Mishchenko
                                 self.queryargs['tag'],
845 6f59b964 Iustin Pop
                                 name=self.name,
846 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
847 18cb43a2 Oleksiy Mishchenko
848 18cb43a2 Oleksiy Mishchenko
849 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
850 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
851 18cb43a2 Oleksiy Mishchenko

852 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
853 18cb43a2 Oleksiy Mishchenko

854 18cb43a2 Oleksiy Mishchenko
  """
855 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
856 18cb43a2 Oleksiy Mishchenko
857 18cb43a2 Oleksiy Mishchenko
858 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
859 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
860 18cb43a2 Oleksiy Mishchenko

861 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
862 18cb43a2 Oleksiy Mishchenko

863 18cb43a2 Oleksiy Mishchenko
  """
864 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
865 18cb43a2 Oleksiy Mishchenko
866 18cb43a2 Oleksiy Mishchenko
867 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
868 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/tags resource.
869 18cb43a2 Oleksiy Mishchenko

870 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
871 18cb43a2 Oleksiy Mishchenko

872 18cb43a2 Oleksiy Mishchenko
  """
873 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER