Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ d0c8c01d

History | View | Annotate | Download (36.2 kB)

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

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

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

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

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

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

127 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
128 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
129 4e5a68f8 Oleksiy Mishchenko

130 4e5a68f8 Oleksiy Mishchenko
  """
131 7e950d31 Iustin Pop
  @staticmethod
132 7e950d31 Iustin Pop
  def GET():
133 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
134 4e5a68f8 Oleksiy Mishchenko

135 4e5a68f8 Oleksiy Mishchenko
    """
136 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
137 4e5a68f8 Oleksiy Mishchenko
138 4e5a68f8 Oleksiy Mishchenko
139 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
140 b58a4d16 Michael Hanselmann
  """/2/info resource.
141 4e5a68f8 Oleksiy Mishchenko

142 4e5a68f8 Oleksiy Mishchenko
  """
143 7e950d31 Iustin Pop
  @staticmethod
144 7e950d31 Iustin Pop
  def GET():
145 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
146 4e5a68f8 Oleksiy Mishchenko

147 4e5a68f8 Oleksiy Mishchenko
    """
148 59b4eeef Iustin Pop
    client = baserlib.GetClient()
149 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
150 4e5a68f8 Oleksiy Mishchenko
151 4e5a68f8 Oleksiy Mishchenko
152 7eac4a4d Michael Hanselmann
class R_2_features(baserlib.R_Generic):
153 7eac4a4d Michael Hanselmann
  """/2/features resource.
154 7eac4a4d Michael Hanselmann

155 7eac4a4d Michael Hanselmann
  """
156 7eac4a4d Michael Hanselmann
  @staticmethod
157 7eac4a4d Michael Hanselmann
  def GET():
158 7eac4a4d Michael Hanselmann
    """Returns list of optional RAPI features implemented.
159 7eac4a4d Michael Hanselmann

160 7eac4a4d Michael Hanselmann
    """
161 b4fcee5b Michael Hanselmann
    return list(ALL_FEATURES)
162 7eac4a4d Michael Hanselmann
163 7eac4a4d Michael Hanselmann
164 4e5a68f8 Oleksiy Mishchenko
class R_2_os(baserlib.R_Generic):
165 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
166 4e5a68f8 Oleksiy Mishchenko

167 4e5a68f8 Oleksiy Mishchenko
  """
168 7e950d31 Iustin Pop
  @staticmethod
169 7e950d31 Iustin Pop
  def GET():
170 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
171 4e5a68f8 Oleksiy Mishchenko

172 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
173 4e5a68f8 Oleksiy Mishchenko

174 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
175 4e5a68f8 Oleksiy Mishchenko

176 4e5a68f8 Oleksiy Mishchenko
    """
177 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
178 da2d02e7 Iustin Pop
    op = opcodes.OpOsDiagnose(output_fields=["name", "variants"], names=[])
179 59b4eeef Iustin Pop
    job_id = baserlib.SubmitJob([op], cl)
180 59b4eeef Iustin Pop
    # we use custom feedback function, instead of print we log the status
181 59b4eeef Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
182 59b4eeef Iustin Pop
    diagnose_data = result[0]
183 4e5a68f8 Oleksiy Mishchenko
184 4e5a68f8 Oleksiy Mishchenko
    if not isinstance(diagnose_data, list):
185 59b4eeef Iustin Pop
      raise http.HttpBadGateway(message="Can't get OS list")
186 4e5a68f8 Oleksiy Mishchenko
187 e3ac208c Guido Trotter
    os_names = []
188 d22dfef7 Iustin Pop
    for (name, variants) in diagnose_data:
189 d22dfef7 Iustin Pop
      os_names.extend(cli.CalculateOSNames(name, variants))
190 e3ac208c Guido Trotter
191 e3ac208c Guido Trotter
    return os_names
192 51ee2f49 Oleksiy Mishchenko
193 10b207d4 Oleksiy Mishchenko
194 508e9b20 Michael Hanselmann
class R_2_redist_config(baserlib.R_Generic):
195 508e9b20 Michael Hanselmann
  """/2/redistribute-config resource.
196 508e9b20 Michael Hanselmann

197 508e9b20 Michael Hanselmann
  """
198 7e950d31 Iustin Pop
  @staticmethod
199 7e950d31 Iustin Pop
  def PUT():
200 508e9b20 Michael Hanselmann
    """Redistribute configuration to all nodes.
201 508e9b20 Michael Hanselmann

202 508e9b20 Michael Hanselmann
    """
203 d1240007 Iustin Pop
    return baserlib.SubmitJob([opcodes.OpClusterRedistConf()])
204 508e9b20 Michael Hanselmann
205 508e9b20 Michael Hanselmann
206 62e999a5 Michael Hanselmann
class R_2_cluster_modify(baserlib.R_Generic):
207 62e999a5 Michael Hanselmann
  """/2/modify resource.
208 62e999a5 Michael Hanselmann

209 62e999a5 Michael Hanselmann
  """
210 62e999a5 Michael Hanselmann
  def PUT(self):
211 62e999a5 Michael Hanselmann
    """Modifies cluster parameters.
212 62e999a5 Michael Hanselmann

213 62e999a5 Michael Hanselmann
    @return: a job id
214 62e999a5 Michael Hanselmann

215 62e999a5 Michael Hanselmann
    """
216 a6682fdc Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpClusterSetParams, self.request_body,
217 62e999a5 Michael Hanselmann
                             None)
218 62e999a5 Michael Hanselmann
219 62e999a5 Michael Hanselmann
    return baserlib.SubmitJob([op])
220 62e999a5 Michael Hanselmann
221 62e999a5 Michael Hanselmann
222 10b207d4 Oleksiy Mishchenko
class R_2_jobs(baserlib.R_Generic):
223 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
224 10b207d4 Oleksiy Mishchenko

225 10b207d4 Oleksiy Mishchenko
  """
226 7e950d31 Iustin Pop
  @staticmethod
227 7e950d31 Iustin Pop
  def GET():
228 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
229 10b207d4 Oleksiy Mishchenko

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

232 10b207d4 Oleksiy Mishchenko
    """
233 10b207d4 Oleksiy Mishchenko
    fields = ["id"]
234 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
235 10b207d4 Oleksiy Mishchenko
    # Convert the list of lists to the list of ids
236 59b4eeef Iustin Pop
    result = [job_id for [job_id] in cl.QueryJobs(None, fields)]
237 9031ee8e Iustin Pop
    return baserlib.BuildUriList(result, "/2/jobs/%s",
238 9031ee8e Iustin Pop
                                 uri_fields=("id", "uri"))
239 10b207d4 Oleksiy Mishchenko
240 10b207d4 Oleksiy Mishchenko
241 10b207d4 Oleksiy Mishchenko
class R_2_jobs_id(baserlib.R_Generic):
242 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
243 10b207d4 Oleksiy Mishchenko

244 10b207d4 Oleksiy Mishchenko
  """
245 10b207d4 Oleksiy Mishchenko
  def GET(self):
246 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
247 10b207d4 Oleksiy Mishchenko

248 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
249 c41eea6e Iustin Pop
        The result includes:
250 c41eea6e Iustin Pop
            - id: job ID as a number
251 c41eea6e Iustin Pop
            - status: current job status as a string
252 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
253 c41eea6e Iustin Pop
              opcodes in the job
254 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
255 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
256 38206f3c Iustin Pop

257 10b207d4 Oleksiy Mishchenko
    """
258 ee69c97f Iustin Pop
    fields = ["id", "ops", "status", "summary",
259 ee69c97f Iustin Pop
              "opstatus", "opresult", "oplog",
260 ee69c97f Iustin Pop
              "received_ts", "start_ts", "end_ts",
261 ee69c97f Iustin Pop
              ]
262 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
263 59b4eeef Iustin Pop
    result = baserlib.GetClient().QueryJobs([job_id, ], fields)[0]
264 ee69c97f Iustin Pop
    if result is None:
265 ee69c97f Iustin Pop
      raise http.HttpNotFound()
266 10b207d4 Oleksiy Mishchenko
    return baserlib.MapFields(fields, result)
267 10b207d4 Oleksiy Mishchenko
268 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
269 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
270 c7f5f338 Oleksiy Mishchenko

271 c7f5f338 Oleksiy Mishchenko
    """
272 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
273 59b4eeef Iustin Pop
    result = baserlib.GetClient().CancelJob(job_id)
274 c7f5f338 Oleksiy Mishchenko
    return result
275 c7f5f338 Oleksiy Mishchenko
276 10b207d4 Oleksiy Mishchenko
277 793a8f7c Michael Hanselmann
class R_2_jobs_id_wait(baserlib.R_Generic):
278 793a8f7c Michael Hanselmann
  """/2/jobs/[job_id]/wait resource.
279 793a8f7c Michael Hanselmann

280 793a8f7c Michael Hanselmann
  """
281 793a8f7c Michael Hanselmann
  # WaitForJobChange provides access to sensitive information and blocks
282 793a8f7c Michael Hanselmann
  # machine resources (it's a blocking RAPI call), hence restricting access.
283 793a8f7c Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
284 793a8f7c Michael Hanselmann
285 793a8f7c Michael Hanselmann
  def GET(self):
286 793a8f7c Michael Hanselmann
    """Waits for job changes.
287 793a8f7c Michael Hanselmann

288 793a8f7c Michael Hanselmann
    """
289 793a8f7c Michael Hanselmann
    job_id = self.items[0]
290 793a8f7c Michael Hanselmann
291 793a8f7c Michael Hanselmann
    fields = self.getBodyParameter("fields")
292 793a8f7c Michael Hanselmann
    prev_job_info = self.getBodyParameter("previous_job_info", None)
293 793a8f7c Michael Hanselmann
    prev_log_serial = self.getBodyParameter("previous_log_serial", None)
294 793a8f7c Michael Hanselmann
295 793a8f7c Michael Hanselmann
    if not isinstance(fields, list):
296 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'fields' parameter should be a list")
297 793a8f7c Michael Hanselmann
298 793a8f7c Michael Hanselmann
    if not (prev_job_info is None or isinstance(prev_job_info, list)):
299 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_job_info' parameter should"
300 793a8f7c Michael Hanselmann
                                " be a list")
301 793a8f7c Michael Hanselmann
302 793a8f7c Michael Hanselmann
    if not (prev_log_serial is None or
303 793a8f7c Michael Hanselmann
            isinstance(prev_log_serial, (int, long))):
304 793a8f7c Michael Hanselmann
      raise http.HttpBadRequest("The 'previous_log_serial' parameter should"
305 793a8f7c Michael Hanselmann
                                " be a number")
306 793a8f7c Michael Hanselmann
307 793a8f7c Michael Hanselmann
    client = baserlib.GetClient()
308 793a8f7c Michael Hanselmann
    result = client.WaitForJobChangeOnce(job_id, fields,
309 793a8f7c Michael Hanselmann
                                         prev_job_info, prev_log_serial,
310 793a8f7c Michael Hanselmann
                                         timeout=_WFJC_TIMEOUT)
311 793a8f7c Michael Hanselmann
    if not result:
312 793a8f7c Michael Hanselmann
      raise http.HttpNotFound()
313 793a8f7c Michael Hanselmann
314 793a8f7c Michael Hanselmann
    if result == constants.JOB_NOTCHANGED:
315 793a8f7c Michael Hanselmann
      # No changes
316 793a8f7c Michael Hanselmann
      return None
317 793a8f7c Michael Hanselmann
318 793a8f7c Michael Hanselmann
    (job_info, log_entries) = result
319 793a8f7c Michael Hanselmann
320 793a8f7c Michael Hanselmann
    return {
321 793a8f7c Michael Hanselmann
      "job_info": job_info,
322 793a8f7c Michael Hanselmann
      "log_entries": log_entries,
323 793a8f7c Michael Hanselmann
      }
324 793a8f7c Michael Hanselmann
325 793a8f7c Michael Hanselmann
326 10b207d4 Oleksiy Mishchenko
class R_2_nodes(baserlib.R_Generic):
327 10b207d4 Oleksiy Mishchenko
  """/2/nodes resource.
328 10b207d4 Oleksiy Mishchenko

329 10b207d4 Oleksiy Mishchenko
  """
330 10b207d4 Oleksiy Mishchenko
  def GET(self):
331 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
332 38206f3c Iustin Pop

333 10b207d4 Oleksiy Mishchenko
    """
334 59b4eeef Iustin Pop
    client = baserlib.GetClient()
335 38206f3c Iustin Pop
336 3d103742 Iustin Pop
    if self.useBulk():
337 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
338 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
339 9031ee8e Iustin Pop
    else:
340 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
341 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
342 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
343 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
344 441e7cfd Oleksiy Mishchenko
345 441e7cfd Oleksiy Mishchenko
346 4e5a68f8 Oleksiy Mishchenko
class R_2_nodes_name(baserlib.R_Generic):
347 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name] resource.
348 028c6b76 Oleksiy Mishchenko

349 028c6b76 Oleksiy Mishchenko
  """
350 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
351 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
352 4e5a68f8 Oleksiy Mishchenko

353 4e5a68f8 Oleksiy Mishchenko
    """
354 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
355 59b4eeef Iustin Pop
    client = baserlib.GetClient()
356 e8ebbd2b Michael Hanselmann
357 e8ebbd2b Michael Hanselmann
    result = baserlib.HandleItemQueryErrors(client.QueryNodes,
358 e8ebbd2b Michael Hanselmann
                                            names=[node_name], fields=N_FIELDS,
359 e8ebbd2b Michael Hanselmann
                                            use_locking=self.useLocking())
360 4e5a68f8 Oleksiy Mishchenko
361 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
362 028c6b76 Oleksiy Mishchenko
363 028c6b76 Oleksiy Mishchenko
364 64dae8fc Michael Hanselmann
class R_2_nodes_name_role(baserlib.R_Generic):
365 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
366 64dae8fc Michael Hanselmann

367 64dae8fc Michael Hanselmann
  """
368 64dae8fc Michael Hanselmann
  def GET(self):
369 64dae8fc Michael Hanselmann
    """Returns the current node role.
370 64dae8fc Michael Hanselmann

371 64dae8fc Michael Hanselmann
    @return: Node role
372 64dae8fc Michael Hanselmann

373 64dae8fc Michael Hanselmann
    """
374 64dae8fc Michael Hanselmann
    node_name = self.items[0]
375 64dae8fc Michael Hanselmann
    client = baserlib.GetClient()
376 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
377 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
378 64dae8fc Michael Hanselmann
379 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
380 64dae8fc Michael Hanselmann
381 64dae8fc Michael Hanselmann
  def PUT(self):
382 64dae8fc Michael Hanselmann
    """Sets the node role.
383 64dae8fc Michael Hanselmann

384 64dae8fc Michael Hanselmann
    @return: a job id
385 64dae8fc Michael Hanselmann

386 64dae8fc Michael Hanselmann
    """
387 627ad739 Michael Hanselmann
    if not isinstance(self.request_body, basestring):
388 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a string")
389 64dae8fc Michael Hanselmann
390 64dae8fc Michael Hanselmann
    node_name = self.items[0]
391 627ad739 Michael Hanselmann
    role = self.request_body
392 64dae8fc Michael Hanselmann
393 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
394 64dae8fc Michael Hanselmann
      candidate = False
395 64dae8fc Michael Hanselmann
      offline = False
396 64dae8fc Michael Hanselmann
      drained = False
397 64dae8fc Michael Hanselmann
398 64dae8fc Michael Hanselmann
    elif role == _NR_MASTER_CANDIATE:
399 64dae8fc Michael Hanselmann
      candidate = True
400 64dae8fc Michael Hanselmann
      offline = drained = None
401 64dae8fc Michael Hanselmann
402 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
403 64dae8fc Michael Hanselmann
      drained = True
404 64dae8fc Michael Hanselmann
      candidate = offline = None
405 64dae8fc Michael Hanselmann
406 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
407 64dae8fc Michael Hanselmann
      offline = True
408 64dae8fc Michael Hanselmann
      candidate = drained = None
409 64dae8fc Michael Hanselmann
410 64dae8fc Michael Hanselmann
    else:
411 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
412 64dae8fc Michael Hanselmann
413 f13973c4 Iustin Pop
    op = opcodes.OpNodeSetParams(node_name=node_name,
414 64dae8fc Michael Hanselmann
                                 master_candidate=candidate,
415 64dae8fc Michael Hanselmann
                                 offline=offline,
416 64dae8fc Michael Hanselmann
                                 drained=drained,
417 64dae8fc Michael Hanselmann
                                 force=bool(self.useForce()))
418 64dae8fc Michael Hanselmann
419 64dae8fc Michael Hanselmann
    return baserlib.SubmitJob([op])
420 64dae8fc Michael Hanselmann
421 64dae8fc Michael Hanselmann
422 73452f12 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.R_Generic):
423 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
424 73452f12 Michael Hanselmann

425 73452f12 Michael Hanselmann
  """
426 73452f12 Michael Hanselmann
  def POST(self):
427 de40437a Michael Hanselmann
    """Evacuate all instances off a node.
428 73452f12 Michael Hanselmann

429 73452f12 Michael Hanselmann
    """
430 de40437a Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeEvacuate, self.request_body, {
431 de40437a Michael Hanselmann
      "node_name": self.items[0],
432 de40437a Michael Hanselmann
      "dry_run": self.dryRun(),
433 de40437a Michael Hanselmann
      })
434 941b9309 Iustin Pop
435 de40437a Michael Hanselmann
    return baserlib.SubmitJob([op])
436 73452f12 Michael Hanselmann
437 73452f12 Michael Hanselmann
438 1c482bab Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.R_Generic):
439 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
440 1c482bab Michael Hanselmann

441 1c482bab Michael Hanselmann
  """
442 1c482bab Michael Hanselmann
  def POST(self):
443 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
444 1c482bab Michael Hanselmann

445 1c482bab Michael Hanselmann
    """
446 1c482bab Michael Hanselmann
    node_name = self.items[0]
447 1c482bab Michael Hanselmann
448 b7a1c816 Michael Hanselmann
    if self.queryargs:
449 b7a1c816 Michael Hanselmann
      # Support old-style requests
450 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs and "mode" in self.queryargs:
451 b7a1c816 Michael Hanselmann
        raise http.HttpBadRequest("Only one of 'live' and 'mode' should"
452 b7a1c816 Michael Hanselmann
                                  " be passed")
453 b7a1c816 Michael Hanselmann
454 b7a1c816 Michael Hanselmann
      if "live" in self.queryargs:
455 b7a1c816 Michael Hanselmann
        if self._checkIntVariable("live", default=1):
456 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_LIVE
457 b7a1c816 Michael Hanselmann
        else:
458 b7a1c816 Michael Hanselmann
          mode = constants.HT_MIGRATION_NONLIVE
459 52194140 Iustin Pop
      else:
460 b7a1c816 Michael Hanselmann
        mode = self._checkStringVariable("mode", default=None)
461 b7a1c816 Michael Hanselmann
462 b7a1c816 Michael Hanselmann
      data = {
463 b7a1c816 Michael Hanselmann
        "mode": mode,
464 b7a1c816 Michael Hanselmann
        }
465 52194140 Iustin Pop
    else:
466 b7a1c816 Michael Hanselmann
      data = self.request_body
467 52194140 Iustin Pop
468 b7a1c816 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpNodeMigrate, data, {
469 b7a1c816 Michael Hanselmann
      "node_name": node_name,
470 b7a1c816 Michael Hanselmann
      })
471 1c482bab Michael Hanselmann
472 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
473 1c482bab Michael Hanselmann
474 1c482bab Michael Hanselmann
475 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
476 b58a4d16 Michael Hanselmann
  """/2/nodes/[node_name]/storage resource.
477 7a95a954 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

878 7fa310f6 René Nussbaumer
  @rtype: L{opcodes.OpInstanceShutdown}
879 7fa310f6 René Nussbaumer
  @return: Instance shutdown opcode
880 7fa310f6 René Nussbaumer

881 7fa310f6 René Nussbaumer
  """
882 7fa310f6 René Nussbaumer
  return baserlib.FillOpcode(opcodes.OpInstanceShutdown, data, {
883 7fa310f6 René Nussbaumer
    "instance_name": name,
884 7fa310f6 René Nussbaumer
    "dry_run": dry_run,
885 6aac5aef Iustin Pop
    "no_remember": no_remember,
886 7fa310f6 René Nussbaumer
    })
887 7fa310f6 René Nussbaumer
888 7fa310f6 René Nussbaumer
889 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
890 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
891 0c55c24b Oleksiy Mishchenko

892 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
893 0c55c24b Oleksiy Mishchenko

894 0c55c24b Oleksiy Mishchenko
  """
895 21f04e5e Oleksiy Mishchenko
  def PUT(self):
896 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
897 0c55c24b Oleksiy Mishchenko

898 7fa310f6 René Nussbaumer
    @return: a job id
899 7fa310f6 René Nussbaumer

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

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

937 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
938 e5b7c4ca Iustin Pop

939 e5b7c4ca Iustin Pop
  """
940 e5b7c4ca Iustin Pop
  def POST(self):
941 e5b7c4ca Iustin Pop
    """Reinstall an instance.
942 e5b7c4ca Iustin Pop

943 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
944 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
945 e5b7c4ca Iustin Pop
    automatically.
946 e5b7c4ca Iustin Pop

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

970 d1c172de Michael Hanselmann
  @rtype: L{opcodes.OpInstanceReplaceDisks}
971 d1c172de Michael Hanselmann
  @return: Instance export opcode
972 d1c172de Michael Hanselmann

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

997 4c98b915 Michael Hanselmann
  """
998 4c98b915 Michael Hanselmann
  def POST(self):
999 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
1000 4c98b915 Michael Hanselmann

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

1010 2197b66f René Nussbaumer
  """
1011 2197b66f René Nussbaumer
  def PUT(self):
1012 2197b66f René Nussbaumer
    """Activate disks for an instance.
1013 2197b66f René Nussbaumer

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

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

1029 0a37de5f René Nussbaumer
  """
1030 0a37de5f René Nussbaumer
  def PUT(self):
1031 0a37de5f René Nussbaumer
    """Deactivate disks for an instance.
1032 0a37de5f René Nussbaumer

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

1044 ebeb600f Michael Hanselmann
  """
1045 ebeb600f Michael Hanselmann
  def PUT(self):
1046 ebeb600f Michael Hanselmann
    """Prepares an export for an instance.
1047 ebeb600f Michael Hanselmann

1048 ebeb600f Michael Hanselmann
    @return: a job id
1049 ebeb600f Michael Hanselmann

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

1063 4ff922a2 Iustin Pop
  @rtype: L{opcodes.OpBackupExport}
1064 ebeb600f Michael Hanselmann
  @return: Instance export opcode
1065 ebeb600f Michael Hanselmann

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

1081 ebeb600f Michael Hanselmann
  """
1082 ebeb600f Michael Hanselmann
  def PUT(self):
1083 ebeb600f Michael Hanselmann
    """Exports an instance.
1084 ebeb600f Michael Hanselmann

1085 ebeb600f Michael Hanselmann
    @return: a job id
1086 ebeb600f Michael Hanselmann

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

1099 75c866c2 Iustin Pop
  @rtype: L{opcodes.OpInstanceMigrate}
1100 5823e0d2 Michael Hanselmann
  @return: Instance migration opcode
1101 5823e0d2 Michael Hanselmann

1102 5823e0d2 Michael Hanselmann
  """
1103 c1a27c9a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceMigrate, data, {
1104 c1a27c9a Michael Hanselmann
    "instance_name": name,
1105 c1a27c9a Michael Hanselmann
    })
1106 5823e0d2 Michael Hanselmann
1107 5823e0d2 Michael Hanselmann
1108 5823e0d2 Michael Hanselmann
class R_2_instances_name_migrate(baserlib.R_Generic):
1109 5823e0d2 Michael Hanselmann
  """/2/instances/[instance_name]/migrate resource.
1110 5823e0d2 Michael Hanselmann

1111 5823e0d2 Michael Hanselmann
  """
1112 5823e0d2 Michael Hanselmann
  def PUT(self):
1113 5823e0d2 Michael Hanselmann
    """Migrates an instance.
1114 5823e0d2 Michael Hanselmann

1115 5823e0d2 Michael Hanselmann
    @return: a job id
1116 5823e0d2 Michael Hanselmann

1117 5823e0d2 Michael Hanselmann
    """
1118 5823e0d2 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1119 5823e0d2 Michael Hanselmann
1120 5823e0d2 Michael Hanselmann
    op = _ParseMigrateInstanceRequest(self.items[0], self.request_body)
1121 5823e0d2 Michael Hanselmann
1122 5823e0d2 Michael Hanselmann
    return baserlib.SubmitJob([op])
1123 5823e0d2 Michael Hanselmann
1124 5823e0d2 Michael Hanselmann
1125 c0a146a1 Michael Hanselmann
class R_2_instances_name_failover(baserlib.R_Generic):
1126 c0a146a1 Michael Hanselmann
  """/2/instances/[instance_name]/failover resource.
1127 c0a146a1 Michael Hanselmann

1128 c0a146a1 Michael Hanselmann
  """
1129 c0a146a1 Michael Hanselmann
  def PUT(self):
1130 c0a146a1 Michael Hanselmann
    """Does a failover of an instance.
1131 c0a146a1 Michael Hanselmann

1132 c0a146a1 Michael Hanselmann
    @return: a job id
1133 c0a146a1 Michael Hanselmann

1134 c0a146a1 Michael Hanselmann
    """
1135 c0a146a1 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1136 c0a146a1 Michael Hanselmann
1137 c0a146a1 Michael Hanselmann
    op = baserlib.FillOpcode(opcodes.OpInstanceFailover, self.request_body, {
1138 c0a146a1 Michael Hanselmann
      "instance_name": self.items[0],
1139 c0a146a1 Michael Hanselmann
      })
1140 c0a146a1 Michael Hanselmann
1141 c0a146a1 Michael Hanselmann
    return baserlib.SubmitJob([op])
1142 c0a146a1 Michael Hanselmann
1143 c0a146a1 Michael Hanselmann
1144 d56e7dc7 Michael Hanselmann
def _ParseRenameInstanceRequest(name, data):
1145 d56e7dc7 Michael Hanselmann
  """Parses a request for renaming an instance.
1146 d56e7dc7 Michael Hanselmann

1147 5659e2e2 Iustin Pop
  @rtype: L{opcodes.OpInstanceRename}
1148 d56e7dc7 Michael Hanselmann
  @return: Instance rename opcode
1149 d56e7dc7 Michael Hanselmann

1150 d56e7dc7 Michael Hanselmann
  """
1151 88bc199a Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceRename, data, {
1152 88bc199a Michael Hanselmann
    "instance_name": name,
1153 88bc199a Michael Hanselmann
    })
1154 d56e7dc7 Michael Hanselmann
1155 d56e7dc7 Michael Hanselmann
1156 d56e7dc7 Michael Hanselmann
class R_2_instances_name_rename(baserlib.R_Generic):
1157 d56e7dc7 Michael Hanselmann
  """/2/instances/[instance_name]/rename resource.
1158 d56e7dc7 Michael Hanselmann

1159 d56e7dc7 Michael Hanselmann
  """
1160 d56e7dc7 Michael Hanselmann
  def PUT(self):
1161 d56e7dc7 Michael Hanselmann
    """Changes the name of an instance.
1162 d56e7dc7 Michael Hanselmann

1163 d56e7dc7 Michael Hanselmann
    @return: a job id
1164 d56e7dc7 Michael Hanselmann

1165 d56e7dc7 Michael Hanselmann
    """
1166 d56e7dc7 Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1167 d56e7dc7 Michael Hanselmann
1168 d56e7dc7 Michael Hanselmann
    op = _ParseRenameInstanceRequest(self.items[0], self.request_body)
1169 d56e7dc7 Michael Hanselmann
1170 d56e7dc7 Michael Hanselmann
    return baserlib.SubmitJob([op])
1171 d56e7dc7 Michael Hanselmann
1172 d56e7dc7 Michael Hanselmann
1173 3882937a Michael Hanselmann
def _ParseModifyInstanceRequest(name, data):
1174 3882937a Michael Hanselmann
  """Parses a request for modifying an instance.
1175 3882937a Michael Hanselmann

1176 9a3cc7ae Iustin Pop
  @rtype: L{opcodes.OpInstanceSetParams}
1177 3882937a Michael Hanselmann
  @return: Instance modify opcode
1178 3882937a Michael Hanselmann

1179 3882937a Michael Hanselmann
  """
1180 ee5549c7 Michael Hanselmann
  return baserlib.FillOpcode(opcodes.OpInstanceSetParams, data, {
1181 ee5549c7 Michael Hanselmann
    "instance_name": name,
1182 ee5549c7 Michael Hanselmann
    })
1183 3882937a Michael Hanselmann
1184 3882937a Michael Hanselmann
1185 3882937a Michael Hanselmann
class R_2_instances_name_modify(baserlib.R_Generic):
1186 3882937a Michael Hanselmann
  """/2/instances/[instance_name]/modify resource.
1187 3882937a Michael Hanselmann

1188 3882937a Michael Hanselmann
  """
1189 3882937a Michael Hanselmann
  def PUT(self):
1190 3882937a Michael Hanselmann
    """Changes some parameters of an instance.
1191 3882937a Michael Hanselmann

1192 3882937a Michael Hanselmann
    @return: a job id
1193 3882937a Michael Hanselmann

1194 3882937a Michael Hanselmann
    """
1195 3882937a Michael Hanselmann
    baserlib.CheckType(self.request_body, dict, "Body contents")
1196 3882937a Michael Hanselmann
1197 3882937a Michael Hanselmann
    op = _ParseModifyInstanceRequest(self.items[0], self.request_body)
1198 3882937a Michael Hanselmann
1199 3882937a Michael Hanselmann
    return baserlib.SubmitJob([op])
1200 3882937a Michael Hanselmann
1201 3882937a Michael Hanselmann
1202 e23881ed Michael Hanselmann
class R_2_instances_name_disk_grow(baserlib.R_Generic):
1203 b58a4d16 Michael Hanselmann
  """/2/instances/[instance_name]/disk/[disk_index]/grow resource.
1204 e23881ed Michael Hanselmann

1205 e23881ed Michael Hanselmann
  """
1206 e23881ed Michael Hanselmann
  def POST(self):
1207 e23881ed Michael Hanselmann
    """Increases the size of an instance disk.
1208 e23881ed Michael Hanselmann

1209 e23881ed Michael Hanselmann
    @return: a job id
1210 e23881ed Michael Hanselmann

1211 e23881ed Michael Hanselmann
    """
1212 60472d29 Iustin Pop
    op = baserlib.FillOpcode(opcodes.OpInstanceGrowDisk, self.request_body, {
1213 e23881ed Michael Hanselmann
      "instance_name": self.items[0],
1214 e23881ed Michael Hanselmann
      "disk": int(self.items[1]),
1215 e23881ed Michael Hanselmann
      })
1216 e23881ed Michael Hanselmann
1217 e23881ed Michael Hanselmann
    return baserlib.SubmitJob([op])
1218 e23881ed Michael Hanselmann
1219 e23881ed Michael Hanselmann
1220 b82d4c5e Michael Hanselmann
class R_2_instances_name_console(baserlib.R_Generic):
1221 b82d4c5e Michael Hanselmann
  """/2/instances/[instance_name]/console resource.
1222 b82d4c5e Michael Hanselmann

1223 b82d4c5e Michael Hanselmann
  """
1224 b82d4c5e Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1225 b82d4c5e Michael Hanselmann
1226 b82d4c5e Michael Hanselmann
  def GET(self):
1227 b82d4c5e Michael Hanselmann
    """Request information for connecting to instance's console.
1228 b82d4c5e Michael Hanselmann

1229 b82d4c5e Michael Hanselmann
    @return: Serialized instance console description, see
1230 b82d4c5e Michael Hanselmann
             L{objects.InstanceConsole}
1231 b82d4c5e Michael Hanselmann

1232 b82d4c5e Michael Hanselmann
    """
1233 b82d4c5e Michael Hanselmann
    client = baserlib.GetClient()
1234 b82d4c5e Michael Hanselmann
1235 b82d4c5e Michael Hanselmann
    ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False)
1236 b82d4c5e Michael Hanselmann
1237 b82d4c5e Michael Hanselmann
    if console is None:
1238 b82d4c5e Michael Hanselmann
      raise http.HttpServiceUnavailable("Instance console unavailable")
1239 b82d4c5e Michael Hanselmann
1240 b82d4c5e Michael Hanselmann
    assert isinstance(console, dict)
1241 b82d4c5e Michael Hanselmann
    return console
1242 b82d4c5e Michael Hanselmann
1243 b82d4c5e Michael Hanselmann
1244 208a6cff Michael Hanselmann
def _GetQueryFields(args):
1245 208a6cff Michael Hanselmann
  """
1246 208a6cff Michael Hanselmann

1247 208a6cff Michael Hanselmann
  """
1248 208a6cff Michael Hanselmann
  try:
1249 208a6cff Michael Hanselmann
    fields = args["fields"]
1250 208a6cff Michael Hanselmann
  except KeyError:
1251 208a6cff Michael Hanselmann
    raise http.HttpBadRequest("Missing 'fields' query argument")
1252 208a6cff Michael Hanselmann
1253 208a6cff Michael Hanselmann
  return _SplitQueryFields(fields[0])
1254 208a6cff Michael Hanselmann
1255 208a6cff Michael Hanselmann
1256 208a6cff Michael Hanselmann
def _SplitQueryFields(fields):
1257 208a6cff Michael Hanselmann
  """
1258 208a6cff Michael Hanselmann

1259 208a6cff Michael Hanselmann
  """
1260 208a6cff Michael Hanselmann
  return [i.strip() for i in fields.split(",")]
1261 208a6cff Michael Hanselmann
1262 208a6cff Michael Hanselmann
1263 208a6cff Michael Hanselmann
class R_2_query(baserlib.R_Generic):
1264 208a6cff Michael Hanselmann
  """/2/query/[resource] resource.
1265 208a6cff Michael Hanselmann

1266 208a6cff Michael Hanselmann
  """
1267 208a6cff Michael Hanselmann
  # Results might contain sensitive information
1268 208a6cff Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
1269 208a6cff Michael Hanselmann
1270 208a6cff Michael Hanselmann
  def _Query(self, fields, filter_):
1271 208a6cff Michael Hanselmann
    return baserlib.GetClient().Query(self.items[0], fields, filter_).ToDict()
1272 208a6cff Michael Hanselmann
1273 208a6cff Michael Hanselmann
  def GET(self):
1274 208a6cff Michael Hanselmann
    """Returns resource information.
1275 208a6cff Michael Hanselmann

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

1278 208a6cff Michael Hanselmann
    """
1279 208a6cff Michael Hanselmann
    return self._Query(_GetQueryFields(self.queryargs), None)
1280 208a6cff Michael Hanselmann
1281 208a6cff Michael Hanselmann
  def PUT(self):
1282 208a6cff Michael Hanselmann
    """Submits job querying for resources.
1283 208a6cff Michael Hanselmann

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

1286 208a6cff Michael Hanselmann
    """
1287 208a6cff Michael Hanselmann
    body = self.request_body
1288 208a6cff Michael Hanselmann
1289 208a6cff Michael Hanselmann
    baserlib.CheckType(body, dict, "Body contents")
1290 208a6cff Michael Hanselmann
1291 208a6cff Michael Hanselmann
    try:
1292 208a6cff Michael Hanselmann
      fields = body["fields"]
1293 208a6cff Michael Hanselmann
    except KeyError:
1294 208a6cff Michael Hanselmann
      fields = _GetQueryFields(self.queryargs)
1295 208a6cff Michael Hanselmann
1296 208a6cff Michael Hanselmann
    return self._Query(fields, self.request_body.get("filter", None))
1297 208a6cff Michael Hanselmann
1298 208a6cff Michael Hanselmann
1299 208a6cff Michael Hanselmann
class R_2_query_fields(baserlib.R_Generic):
1300 208a6cff Michael Hanselmann
  """/2/query/[resource]/fields resource.
1301 208a6cff Michael Hanselmann

1302 208a6cff Michael Hanselmann
  """
1303 208a6cff Michael Hanselmann
  def GET(self):
1304 208a6cff Michael Hanselmann
    """Retrieves list of available fields for a resource.
1305 208a6cff Michael Hanselmann

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

1308 208a6cff Michael Hanselmann
    """
1309 208a6cff Michael Hanselmann
    try:
1310 208a6cff Michael Hanselmann
      raw_fields = self.queryargs["fields"]
1311 208a6cff Michael Hanselmann
    except KeyError:
1312 208a6cff Michael Hanselmann
      fields = None
1313 208a6cff Michael Hanselmann
    else:
1314 208a6cff Michael Hanselmann
      fields = _SplitQueryFields(raw_fields[0])
1315 208a6cff Michael Hanselmann
1316 208a6cff Michael Hanselmann
    return baserlib.GetClient().QueryFields(self.items[0], fields).ToDict()
1317 208a6cff Michael Hanselmann
1318 208a6cff Michael Hanselmann
1319 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
1320 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
1321 441e7cfd Oleksiy Mishchenko

1322 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
1323 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
1324 441e7cfd Oleksiy Mishchenko

1325 441e7cfd Oleksiy Mishchenko
  """
1326 7a6b9510 Iustin Pop
  TAG_LEVEL = None
1327 18cb43a2 Oleksiy Mishchenko
1328 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
1329 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
1330 18cb43a2 Oleksiy Mishchenko

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

1333 18cb43a2 Oleksiy Mishchenko
    """
1334 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
1335 18cb43a2 Oleksiy Mishchenko
1336 5313eed7 Michael Hanselmann
    if self.TAG_LEVEL == constants.TAG_CLUSTER:
1337 5313eed7 Michael Hanselmann
      self.name = None
1338 18cb43a2 Oleksiy Mishchenko
    else:
1339 5313eed7 Michael Hanselmann
      self.name = items[0]
1340 441e7cfd Oleksiy Mishchenko
1341 441e7cfd Oleksiy Mishchenko
  def GET(self):
1342 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
1343 441e7cfd Oleksiy Mishchenko

1344 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
1345 441e7cfd Oleksiy Mishchenko

1346 441e7cfd Oleksiy Mishchenko
    """
1347 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1348 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
1349 441e7cfd Oleksiy Mishchenko
1350 21f04e5e Oleksiy Mishchenko
  def PUT(self):
1351 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
1352 441e7cfd Oleksiy Mishchenko

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

1356 441e7cfd Oleksiy Mishchenko
    """
1357 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1358 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1359 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
1360 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
1361 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
1362 d0c8c01d Iustin Pop
                              self.queryargs["tag"], name=self.name,
1363 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
1364 15fd9fd5 Oleksiy Mishchenko
1365 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
1366 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
1367 15fd9fd5 Oleksiy Mishchenko

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

1372 15fd9fd5 Oleksiy Mishchenko
    """
1373 7260cfbe Iustin Pop
    # pylint: disable-msg=W0212
1374 d0c8c01d Iustin Pop
    if "tag" not in self.queryargs:
1375 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
1376 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
1377 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
1378 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
1379 d0c8c01d Iustin Pop
                                 self.queryargs["tag"],
1380 6f59b964 Iustin Pop
                                 name=self.name,
1381 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
1382 18cb43a2 Oleksiy Mishchenko
1383 18cb43a2 Oleksiy Mishchenko
1384 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
1385 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
1386 18cb43a2 Oleksiy Mishchenko

1387 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
1388 18cb43a2 Oleksiy Mishchenko

1389 18cb43a2 Oleksiy Mishchenko
  """
1390 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
1391 18cb43a2 Oleksiy Mishchenko
1392 18cb43a2 Oleksiy Mishchenko
1393 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
1394 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
1395 18cb43a2 Oleksiy Mishchenko

1396 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
1397 18cb43a2 Oleksiy Mishchenko

1398 18cb43a2 Oleksiy Mishchenko
  """
1399 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
1400 18cb43a2 Oleksiy Mishchenko
1401 18cb43a2 Oleksiy Mishchenko
1402 414ebaf1 Michael Hanselmann
class R_2_groups_name_tags(_R_Tags):
1403 414ebaf1 Michael Hanselmann
  """ /2/groups/[group_name]/tags resource.
1404 414ebaf1 Michael Hanselmann

1405 414ebaf1 Michael Hanselmann
  Manages per-nodegroup tags.
1406 414ebaf1 Michael Hanselmann

1407 414ebaf1 Michael Hanselmann
  """
1408 414ebaf1 Michael Hanselmann
  TAG_LEVEL = constants.TAG_NODEGROUP
1409 414ebaf1 Michael Hanselmann
1410 414ebaf1 Michael Hanselmann
1411 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
1412 b58a4d16 Michael Hanselmann
  """ /2/tags resource.
1413 18cb43a2 Oleksiy Mishchenko

1414 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
1415 18cb43a2 Oleksiy Mishchenko

1416 18cb43a2 Oleksiy Mishchenko
  """
1417 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER