Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / rlib2.py @ 460d22be

History | View | Annotate | Download (20.2 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 10b207d4 Oleksiy Mishchenko
"""
25 10b207d4 Oleksiy Mishchenko
26 59b4eeef Iustin Pop
from ganeti import opcodes
27 15fd9fd5 Oleksiy Mishchenko
from ganeti import http
28 15fd9fd5 Oleksiy Mishchenko
from ganeti import constants
29 59b4eeef Iustin Pop
from ganeti import cli
30 8381fa2d Michael Hanselmann
from ganeti import rapi
31 38206f3c Iustin Pop
from ganeti.rapi import baserlib
32 10b207d4 Oleksiy Mishchenko
33 4e5a68f8 Oleksiy Mishchenko
34 7118a0df Iustin Pop
_COMMON_FIELDS = ["ctime", "mtime", "uuid", "serial_no", "tags"]
35 9031ee8e Iustin Pop
I_FIELDS = ["name", "admin_state", "os",
36 9031ee8e Iustin Pop
            "pnode", "snodes",
37 9031ee8e Iustin Pop
            "disk_template",
38 82e186f8 Michael Hanselmann
            "nic.ips", "nic.macs", "nic.modes", "nic.links", "nic.bridges",
39 a8b16c4e Tim Boring
            "network_port",
40 024e157f Iustin Pop
            "disk.sizes", "disk_usage",
41 a5b9d725 Iustin Pop
            "beparams", "hvparams",
42 9031ee8e Iustin Pop
            "oper_state", "oper_ram", "status",
43 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
44 9031ee8e Iustin Pop
45 0b2454b9 Iustin Pop
N_FIELDS = ["name", "offline", "master_candidate", "drained",
46 9031ee8e Iustin Pop
            "dtotal", "dfree",
47 4e5a68f8 Oleksiy Mishchenko
            "mtotal", "mnode", "mfree",
48 7118a0df Iustin Pop
            "pinst_cnt", "sinst_cnt",
49 0105bad3 Iustin Pop
            "ctotal", "cnodes", "csockets",
50 7118a0df Iustin Pop
            "pip", "sip", "role",
51 93962b80 Iustin Pop
            "pinst_list", "sinst_list",
52 7118a0df Iustin Pop
            ] + _COMMON_FIELDS
53 4e5a68f8 Oleksiy Mishchenko
54 64dae8fc Michael Hanselmann
_NR_DRAINED = "drained"
55 64dae8fc Michael Hanselmann
_NR_MASTER_CANDIATE = "master-candidate"
56 64dae8fc Michael Hanselmann
_NR_MASTER = "master"
57 64dae8fc Michael Hanselmann
_NR_OFFLINE = "offline"
58 64dae8fc Michael Hanselmann
_NR_REGULAR = "regular"
59 64dae8fc Michael Hanselmann
60 64dae8fc Michael Hanselmann
_NR_MAP = {
61 64dae8fc Michael Hanselmann
  "M": _NR_MASTER,
62 64dae8fc Michael Hanselmann
  "C": _NR_MASTER_CANDIATE,
63 64dae8fc Michael Hanselmann
  "D": _NR_DRAINED,
64 64dae8fc Michael Hanselmann
  "O": _NR_OFFLINE,
65 64dae8fc Michael Hanselmann
  "R": _NR_REGULAR,
66 64dae8fc Michael Hanselmann
  }
67 64dae8fc Michael Hanselmann
68 4e5a68f8 Oleksiy Mishchenko
69 4e5a68f8 Oleksiy Mishchenko
class R_version(baserlib.R_Generic):
70 4e5a68f8 Oleksiy Mishchenko
  """/version resource.
71 4e5a68f8 Oleksiy Mishchenko

72 4e5a68f8 Oleksiy Mishchenko
  This resource should be used to determine the remote API version and
73 4e5a68f8 Oleksiy Mishchenko
  to adapt clients accordingly.
74 4e5a68f8 Oleksiy Mishchenko

75 4e5a68f8 Oleksiy Mishchenko
  """
76 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
77 4e5a68f8 Oleksiy Mishchenko
    """Returns the remote API version.
78 4e5a68f8 Oleksiy Mishchenko

79 4e5a68f8 Oleksiy Mishchenko
    """
80 4e5a68f8 Oleksiy Mishchenko
    return constants.RAPI_VERSION
81 4e5a68f8 Oleksiy Mishchenko
82 4e5a68f8 Oleksiy Mishchenko
83 4e5a68f8 Oleksiy Mishchenko
class R_2_info(baserlib.R_Generic):
84 4e5a68f8 Oleksiy Mishchenko
  """Cluster info.
85 4e5a68f8 Oleksiy Mishchenko

86 4e5a68f8 Oleksiy Mishchenko
  """
87 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
88 4e5a68f8 Oleksiy Mishchenko
    """Returns cluster information.
89 4e5a68f8 Oleksiy Mishchenko

90 4e5a68f8 Oleksiy Mishchenko
    """
91 59b4eeef Iustin Pop
    client = baserlib.GetClient()
92 9031ee8e Iustin Pop
    return client.QueryClusterInfo()
93 4e5a68f8 Oleksiy Mishchenko
94 4e5a68f8 Oleksiy Mishchenko
95 4e5a68f8 Oleksiy Mishchenko
class R_2_os(baserlib.R_Generic):
96 4e5a68f8 Oleksiy Mishchenko
  """/2/os resource.
97 4e5a68f8 Oleksiy Mishchenko

98 4e5a68f8 Oleksiy Mishchenko
  """
99 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
100 4e5a68f8 Oleksiy Mishchenko
    """Return a list of all OSes.
101 4e5a68f8 Oleksiy Mishchenko

102 4e5a68f8 Oleksiy Mishchenko
    Can return error 500 in case of a problem.
103 4e5a68f8 Oleksiy Mishchenko

104 4e5a68f8 Oleksiy Mishchenko
    Example: ["debian-etch"]
105 4e5a68f8 Oleksiy Mishchenko

106 4e5a68f8 Oleksiy Mishchenko
    """
107 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
108 e3ac208c Guido Trotter
    op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants"],
109 e3ac208c Guido Trotter
                              names=[])
110 59b4eeef Iustin Pop
    job_id = baserlib.SubmitJob([op], cl)
111 59b4eeef Iustin Pop
    # we use custom feedback function, instead of print we log the status
112 59b4eeef Iustin Pop
    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
113 59b4eeef Iustin Pop
    diagnose_data = result[0]
114 4e5a68f8 Oleksiy Mishchenko
115 4e5a68f8 Oleksiy Mishchenko
    if not isinstance(diagnose_data, list):
116 59b4eeef Iustin Pop
      raise http.HttpBadGateway(message="Can't get OS list")
117 4e5a68f8 Oleksiy Mishchenko
118 e3ac208c Guido Trotter
    os_names = []
119 e3ac208c Guido Trotter
    for (name, valid, variants) in diagnose_data:
120 e3ac208c Guido Trotter
      if valid:
121 e3ac208c Guido Trotter
        os_names.extend(cli.CalculateOSNames(name, variants))
122 e3ac208c Guido Trotter
123 e3ac208c Guido Trotter
    return os_names
124 51ee2f49 Oleksiy Mishchenko
125 10b207d4 Oleksiy Mishchenko
126 508e9b20 Michael Hanselmann
class R_2_redist_config(baserlib.R_Generic):
127 508e9b20 Michael Hanselmann
  """/2/redistribute-config resource.
128 508e9b20 Michael Hanselmann

129 508e9b20 Michael Hanselmann
  """
130 508e9b20 Michael Hanselmann
  def PUT(self):
131 508e9b20 Michael Hanselmann
    """Redistribute configuration to all nodes.
132 508e9b20 Michael Hanselmann

133 508e9b20 Michael Hanselmann
    """
134 508e9b20 Michael Hanselmann
    return baserlib.SubmitJob([opcodes.OpRedistributeConfig()])
135 508e9b20 Michael Hanselmann
136 508e9b20 Michael Hanselmann
137 10b207d4 Oleksiy Mishchenko
class R_2_jobs(baserlib.R_Generic):
138 10b207d4 Oleksiy Mishchenko
  """/2/jobs resource.
139 10b207d4 Oleksiy Mishchenko

140 10b207d4 Oleksiy Mishchenko
  """
141 10b207d4 Oleksiy Mishchenko
  def GET(self):
142 10b207d4 Oleksiy Mishchenko
    """Returns a dictionary of jobs.
143 10b207d4 Oleksiy Mishchenko

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

146 10b207d4 Oleksiy Mishchenko
    """
147 10b207d4 Oleksiy Mishchenko
    fields = ["id"]
148 59b4eeef Iustin Pop
    cl = baserlib.GetClient()
149 10b207d4 Oleksiy Mishchenko
    # Convert the list of lists to the list of ids
150 59b4eeef Iustin Pop
    result = [job_id for [job_id] in cl.QueryJobs(None, fields)]
151 9031ee8e Iustin Pop
    return baserlib.BuildUriList(result, "/2/jobs/%s",
152 9031ee8e Iustin Pop
                                 uri_fields=("id", "uri"))
153 10b207d4 Oleksiy Mishchenko
154 10b207d4 Oleksiy Mishchenko
155 10b207d4 Oleksiy Mishchenko
class R_2_jobs_id(baserlib.R_Generic):
156 10b207d4 Oleksiy Mishchenko
  """/2/jobs/[job_id] resource.
157 10b207d4 Oleksiy Mishchenko

158 10b207d4 Oleksiy Mishchenko
  """
159 10b207d4 Oleksiy Mishchenko
  def GET(self):
160 10b207d4 Oleksiy Mishchenko
    """Returns a job status.
161 10b207d4 Oleksiy Mishchenko

162 c41eea6e Iustin Pop
    @return: a dictionary with job parameters.
163 c41eea6e Iustin Pop
        The result includes:
164 c41eea6e Iustin Pop
            - id: job ID as a number
165 c41eea6e Iustin Pop
            - status: current job status as a string
166 c41eea6e Iustin Pop
            - ops: involved OpCodes as a list of dictionaries for each
167 c41eea6e Iustin Pop
              opcodes in the job
168 c41eea6e Iustin Pop
            - opstatus: OpCodes status as a list
169 c41eea6e Iustin Pop
            - opresult: OpCodes results as a list of lists
170 38206f3c Iustin Pop

171 10b207d4 Oleksiy Mishchenko
    """
172 ee69c97f Iustin Pop
    fields = ["id", "ops", "status", "summary",
173 ee69c97f Iustin Pop
              "opstatus", "opresult", "oplog",
174 ee69c97f Iustin Pop
              "received_ts", "start_ts", "end_ts",
175 ee69c97f Iustin Pop
              ]
176 10b207d4 Oleksiy Mishchenko
    job_id = self.items[0]
177 59b4eeef Iustin Pop
    result = baserlib.GetClient().QueryJobs([job_id, ], fields)[0]
178 ee69c97f Iustin Pop
    if result is None:
179 ee69c97f Iustin Pop
      raise http.HttpNotFound()
180 10b207d4 Oleksiy Mishchenko
    return baserlib.MapFields(fields, result)
181 10b207d4 Oleksiy Mishchenko
182 c7f5f338 Oleksiy Mishchenko
  def DELETE(self):
183 c7f5f338 Oleksiy Mishchenko
    """Cancel not-yet-started job.
184 c7f5f338 Oleksiy Mishchenko

185 c7f5f338 Oleksiy Mishchenko
    """
186 c7f5f338 Oleksiy Mishchenko
    job_id = self.items[0]
187 59b4eeef Iustin Pop
    result = baserlib.GetClient().CancelJob(job_id)
188 c7f5f338 Oleksiy Mishchenko
    return result
189 c7f5f338 Oleksiy Mishchenko
190 10b207d4 Oleksiy Mishchenko
191 10b207d4 Oleksiy Mishchenko
class R_2_nodes(baserlib.R_Generic):
192 10b207d4 Oleksiy Mishchenko
  """/2/nodes resource.
193 10b207d4 Oleksiy Mishchenko

194 10b207d4 Oleksiy Mishchenko
  """
195 10b207d4 Oleksiy Mishchenko
  def GET(self):
196 10b207d4 Oleksiy Mishchenko
    """Returns a list of all nodes.
197 38206f3c Iustin Pop

198 10b207d4 Oleksiy Mishchenko
    """
199 59b4eeef Iustin Pop
    client = baserlib.GetClient()
200 38206f3c Iustin Pop
201 3d103742 Iustin Pop
    if self.useBulk():
202 9031ee8e Iustin Pop
      bulkdata = client.QueryNodes([], N_FIELDS, False)
203 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, N_FIELDS)
204 9031ee8e Iustin Pop
    else:
205 9031ee8e Iustin Pop
      nodesdata = client.QueryNodes([], ["name"], False)
206 9031ee8e Iustin Pop
      nodeslist = [row[0] for row in nodesdata]
207 9031ee8e Iustin Pop
      return baserlib.BuildUriList(nodeslist, "/2/nodes/%s",
208 9031ee8e Iustin Pop
                                   uri_fields=("id", "uri"))
209 441e7cfd Oleksiy Mishchenko
210 441e7cfd Oleksiy Mishchenko
211 4e5a68f8 Oleksiy Mishchenko
class R_2_nodes_name(baserlib.R_Generic):
212 4e5a68f8 Oleksiy Mishchenko
  """/2/nodes/[node_name] resources.
213 028c6b76 Oleksiy Mishchenko

214 028c6b76 Oleksiy Mishchenko
  """
215 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
216 4e5a68f8 Oleksiy Mishchenko
    """Send information about a node.
217 4e5a68f8 Oleksiy Mishchenko

218 4e5a68f8 Oleksiy Mishchenko
    """
219 4e5a68f8 Oleksiy Mishchenko
    node_name = self.items[0]
220 59b4eeef Iustin Pop
    client = baserlib.GetClient()
221 9031ee8e Iustin Pop
    result = client.QueryNodes(names=[node_name], fields=N_FIELDS,
222 3d103742 Iustin Pop
                               use_locking=self.useLocking())
223 4e5a68f8 Oleksiy Mishchenko
224 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(N_FIELDS, result[0])
225 028c6b76 Oleksiy Mishchenko
226 028c6b76 Oleksiy Mishchenko
227 64dae8fc Michael Hanselmann
class R_2_nodes_name_role(baserlib.R_Generic):
228 64dae8fc Michael Hanselmann
  """ /2/nodes/[node_name]/role resource.
229 64dae8fc Michael Hanselmann

230 64dae8fc Michael Hanselmann
  """
231 64dae8fc Michael Hanselmann
  def GET(self):
232 64dae8fc Michael Hanselmann
    """Returns the current node role.
233 64dae8fc Michael Hanselmann

234 64dae8fc Michael Hanselmann
    @return: Node role
235 64dae8fc Michael Hanselmann

236 64dae8fc Michael Hanselmann
    """
237 64dae8fc Michael Hanselmann
    node_name = self.items[0]
238 64dae8fc Michael Hanselmann
    client = baserlib.GetClient()
239 64dae8fc Michael Hanselmann
    result = client.QueryNodes(names=[node_name], fields=["role"],
240 64dae8fc Michael Hanselmann
                               use_locking=self.useLocking())
241 64dae8fc Michael Hanselmann
242 64dae8fc Michael Hanselmann
    return _NR_MAP[result[0][0]]
243 64dae8fc Michael Hanselmann
244 64dae8fc Michael Hanselmann
  def PUT(self):
245 64dae8fc Michael Hanselmann
    """Sets the node role.
246 64dae8fc Michael Hanselmann

247 64dae8fc Michael Hanselmann
    @return: a job id
248 64dae8fc Michael Hanselmann

249 64dae8fc Michael Hanselmann
    """
250 64dae8fc Michael Hanselmann
    if not isinstance(self.req.request_body, basestring):
251 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Invalid body contents, not a string")
252 64dae8fc Michael Hanselmann
253 64dae8fc Michael Hanselmann
    node_name = self.items[0]
254 64dae8fc Michael Hanselmann
    role = self.req.request_body
255 64dae8fc Michael Hanselmann
256 64dae8fc Michael Hanselmann
    if role == _NR_REGULAR:
257 64dae8fc Michael Hanselmann
      candidate = False
258 64dae8fc Michael Hanselmann
      offline = False
259 64dae8fc Michael Hanselmann
      drained = False
260 64dae8fc Michael Hanselmann
261 64dae8fc Michael Hanselmann
    elif role == _NR_MASTER_CANDIATE:
262 64dae8fc Michael Hanselmann
      candidate = True
263 64dae8fc Michael Hanselmann
      offline = drained = None
264 64dae8fc Michael Hanselmann
265 64dae8fc Michael Hanselmann
    elif role == _NR_DRAINED:
266 64dae8fc Michael Hanselmann
      drained = True
267 64dae8fc Michael Hanselmann
      candidate = offline = None
268 64dae8fc Michael Hanselmann
269 64dae8fc Michael Hanselmann
    elif role == _NR_OFFLINE:
270 64dae8fc Michael Hanselmann
      offline = True
271 64dae8fc Michael Hanselmann
      candidate = drained = None
272 64dae8fc Michael Hanselmann
273 64dae8fc Michael Hanselmann
    else:
274 64dae8fc Michael Hanselmann
      raise http.HttpBadRequest("Can't set '%s' role" % role)
275 64dae8fc Michael Hanselmann
276 64dae8fc Michael Hanselmann
    op = opcodes.OpSetNodeParams(node_name=node_name,
277 64dae8fc Michael Hanselmann
                                 master_candidate=candidate,
278 64dae8fc Michael Hanselmann
                                 offline=offline,
279 64dae8fc Michael Hanselmann
                                 drained=drained,
280 64dae8fc Michael Hanselmann
                                 force=bool(self.useForce()))
281 64dae8fc Michael Hanselmann
282 64dae8fc Michael Hanselmann
    return baserlib.SubmitJob([op])
283 64dae8fc Michael Hanselmann
284 64dae8fc Michael Hanselmann
285 73452f12 Michael Hanselmann
class R_2_nodes_name_evacuate(baserlib.R_Generic):
286 73452f12 Michael Hanselmann
  """/2/nodes/[node_name]/evacuate resource.
287 73452f12 Michael Hanselmann

288 73452f12 Michael Hanselmann
  """
289 73452f12 Michael Hanselmann
  def POST(self):
290 73452f12 Michael Hanselmann
    """Evacuate all secondary instances off a node.
291 73452f12 Michael Hanselmann

292 73452f12 Michael Hanselmann
    """
293 73452f12 Michael Hanselmann
    node_name = self.items[0]
294 73452f12 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
295 73452f12 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
296 73452f12 Michael Hanselmann
297 73452f12 Michael Hanselmann
    op = opcodes.OpEvacuateNode(node_name=node_name,
298 73452f12 Michael Hanselmann
                                remote_node=remote_node,
299 73452f12 Michael Hanselmann
                                iallocator=iallocator)
300 73452f12 Michael Hanselmann
301 73452f12 Michael Hanselmann
    return baserlib.SubmitJob([op])
302 73452f12 Michael Hanselmann
303 73452f12 Michael Hanselmann
304 1c482bab Michael Hanselmann
class R_2_nodes_name_migrate(baserlib.R_Generic):
305 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/migrate resource.
306 1c482bab Michael Hanselmann

307 1c482bab Michael Hanselmann
  """
308 1c482bab Michael Hanselmann
  def POST(self):
309 1c482bab Michael Hanselmann
    """Migrate all primary instances from a node.
310 1c482bab Michael Hanselmann

311 1c482bab Michael Hanselmann
    """
312 1c482bab Michael Hanselmann
    node_name = self.items[0]
313 1c482bab Michael Hanselmann
    live = bool(self._checkIntVariable("live", default=1))
314 1c482bab Michael Hanselmann
315 1c482bab Michael Hanselmann
    op = opcodes.OpMigrateNode(node_name=node_name, live=live)
316 1c482bab Michael Hanselmann
317 1c482bab Michael Hanselmann
    return baserlib.SubmitJob([op])
318 1c482bab Michael Hanselmann
319 1c482bab Michael Hanselmann
320 7a95a954 Michael Hanselmann
class R_2_nodes_name_storage(baserlib.R_Generic):
321 7a95a954 Michael Hanselmann
  """/2/nodes/[node_name]/storage ressource.
322 7a95a954 Michael Hanselmann

323 7a95a954 Michael Hanselmann
  """
324 7a95a954 Michael Hanselmann
  # LUQueryNodeStorage acquires locks, hence restricting access to GET
325 7a95a954 Michael Hanselmann
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
326 7a95a954 Michael Hanselmann
327 7a95a954 Michael Hanselmann
  def GET(self):
328 7a95a954 Michael Hanselmann
    node_name = self.items[0]
329 7a95a954 Michael Hanselmann
330 7a95a954 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
331 7a95a954 Michael Hanselmann
    if not storage_type:
332 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
333 7a95a954 Michael Hanselmann
                                " parameter")
334 7a95a954 Michael Hanselmann
335 7a95a954 Michael Hanselmann
    output_fields = self._checkStringVariable("output_fields", None)
336 7a95a954 Michael Hanselmann
    if not output_fields:
337 7a95a954 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'output_fields'"
338 7a95a954 Michael Hanselmann
                                " parameter")
339 7a95a954 Michael Hanselmann
340 7a95a954 Michael Hanselmann
    op = opcodes.OpQueryNodeStorage(nodes=[node_name],
341 7a95a954 Michael Hanselmann
                                    storage_type=storage_type,
342 7a95a954 Michael Hanselmann
                                    output_fields=output_fields.split(","))
343 7a95a954 Michael Hanselmann
    return baserlib.SubmitJob([op])
344 7a95a954 Michael Hanselmann
345 7a95a954 Michael Hanselmann
346 1e82bc80 Michael Hanselmann
class R_2_nodes_name_storage_modify(baserlib.R_Generic):
347 1e82bc80 Michael Hanselmann
  """/2/nodes/[node_name]/storage/modify ressource.
348 1e82bc80 Michael Hanselmann

349 1e82bc80 Michael Hanselmann
  """
350 1e82bc80 Michael Hanselmann
  def PUT(self):
351 1e82bc80 Michael Hanselmann
    node_name = self.items[0]
352 1e82bc80 Michael Hanselmann
353 1e82bc80 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
354 1e82bc80 Michael Hanselmann
    if not storage_type:
355 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
356 1e82bc80 Michael Hanselmann
                                " parameter")
357 1e82bc80 Michael Hanselmann
358 1e82bc80 Michael Hanselmann
    name = self._checkStringVariable("name", None)
359 1e82bc80 Michael Hanselmann
    if not name:
360 1e82bc80 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
361 1e82bc80 Michael Hanselmann
                                " parameter")
362 1e82bc80 Michael Hanselmann
363 1e82bc80 Michael Hanselmann
    changes = {}
364 1e82bc80 Michael Hanselmann
365 1e82bc80 Michael Hanselmann
    if "allocatable" in self.queryargs:
366 1e82bc80 Michael Hanselmann
      changes[constants.SF_ALLOCATABLE] = \
367 1e82bc80 Michael Hanselmann
        bool(self._checkIntVariable("allocatable", default=1))
368 1e82bc80 Michael Hanselmann
369 1e82bc80 Michael Hanselmann
    op = opcodes.OpModifyNodeStorage(node_name=node_name,
370 1e82bc80 Michael Hanselmann
                                     storage_type=storage_type,
371 1e82bc80 Michael Hanselmann
                                     name=name,
372 1e82bc80 Michael Hanselmann
                                     changes=changes)
373 1e82bc80 Michael Hanselmann
    return baserlib.SubmitJob([op])
374 1e82bc80 Michael Hanselmann
375 1e82bc80 Michael Hanselmann
376 723f4565 Michael Hanselmann
class R_2_nodes_name_storage_repair(baserlib.R_Generic):
377 723f4565 Michael Hanselmann
  """/2/nodes/[node_name]/storage/repair ressource.
378 723f4565 Michael Hanselmann

379 723f4565 Michael Hanselmann
  """
380 723f4565 Michael Hanselmann
  def PUT(self):
381 723f4565 Michael Hanselmann
    node_name = self.items[0]
382 723f4565 Michael Hanselmann
383 723f4565 Michael Hanselmann
    storage_type = self._checkStringVariable("storage_type", None)
384 723f4565 Michael Hanselmann
    if not storage_type:
385 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'storage_type'"
386 723f4565 Michael Hanselmann
                                " parameter")
387 723f4565 Michael Hanselmann
388 723f4565 Michael Hanselmann
    name = self._checkStringVariable("name", None)
389 723f4565 Michael Hanselmann
    if not name:
390 723f4565 Michael Hanselmann
      raise http.HttpBadRequest("Missing the required 'name'"
391 723f4565 Michael Hanselmann
                                " parameter")
392 723f4565 Michael Hanselmann
393 723f4565 Michael Hanselmann
    op = opcodes.OpRepairNodeStorage(node_name=node_name,
394 723f4565 Michael Hanselmann
                                     storage_type=storage_type,
395 723f4565 Michael Hanselmann
                                     name=name)
396 723f4565 Michael Hanselmann
    return baserlib.SubmitJob([op])
397 723f4565 Michael Hanselmann
398 723f4565 Michael Hanselmann
399 441e7cfd Oleksiy Mishchenko
class R_2_instances(baserlib.R_Generic):
400 441e7cfd Oleksiy Mishchenko
  """/2/instances resource.
401 441e7cfd Oleksiy Mishchenko

402 441e7cfd Oleksiy Mishchenko
  """
403 441e7cfd Oleksiy Mishchenko
  def GET(self):
404 441e7cfd Oleksiy Mishchenko
    """Returns a list of all available instances.
405 441e7cfd Oleksiy Mishchenko

406 441e7cfd Oleksiy Mishchenko
    """
407 59b4eeef Iustin Pop
    client = baserlib.GetClient()
408 441e7cfd Oleksiy Mishchenko
409 3d103742 Iustin Pop
    use_locking = self.useLocking()
410 3d103742 Iustin Pop
    if self.useBulk():
411 3d103742 Iustin Pop
      bulkdata = client.QueryInstances([], I_FIELDS, use_locking)
412 a0dcf7c2 Oleksiy Mishchenko
      return baserlib.MapBulkFields(bulkdata, I_FIELDS)
413 441e7cfd Oleksiy Mishchenko
    else:
414 3d103742 Iustin Pop
      instancesdata = client.QueryInstances([], ["name"], use_locking)
415 9031ee8e Iustin Pop
      instanceslist = [row[0] for row in instancesdata]
416 441e7cfd Oleksiy Mishchenko
      return baserlib.BuildUriList(instanceslist, "/2/instances/%s",
417 441e7cfd Oleksiy Mishchenko
                                   uri_fields=("id", "uri"))
418 441e7cfd Oleksiy Mishchenko
419 21f04e5e Oleksiy Mishchenko
  def POST(self):
420 2f7635f4 Oleksiy Mishchenko
    """Create an instance.
421 2f7635f4 Oleksiy Mishchenko

422 5fcc718f Iustin Pop
    @return: a job id
423 2f7635f4 Oleksiy Mishchenko

424 2f7635f4 Oleksiy Mishchenko
    """
425 6e99c5a0 Iustin Pop
    if not isinstance(self.req.request_body, dict):
426 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Invalid body contents, not a dictionary")
427 6e99c5a0 Iustin Pop
428 6e99c5a0 Iustin Pop
    beparams = baserlib.MakeParamsDict(self.req.request_body,
429 6e99c5a0 Iustin Pop
                                       constants.BES_PARAMETERS)
430 6e99c5a0 Iustin Pop
    hvparams = baserlib.MakeParamsDict(self.req.request_body,
431 6e99c5a0 Iustin Pop
                                       constants.HVS_PARAMETERS)
432 6e99c5a0 Iustin Pop
    fn = self.getBodyParameter
433 6e99c5a0 Iustin Pop
434 6e99c5a0 Iustin Pop
    # disk processing
435 6e99c5a0 Iustin Pop
    disk_data = fn('disks')
436 6e99c5a0 Iustin Pop
    if not isinstance(disk_data, list):
437 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("The 'disks' parameter should be a list")
438 6e99c5a0 Iustin Pop
    disks = []
439 6e99c5a0 Iustin Pop
    for idx, d in enumerate(disk_data):
440 6e99c5a0 Iustin Pop
      if not isinstance(d, int):
441 6e99c5a0 Iustin Pop
        raise http.HttpBadRequest("Disk %d specification wrong: should"
442 69b99987 Michael Hanselmann
                                  " be an integer" % idx)
443 6e99c5a0 Iustin Pop
      disks.append({"size": d})
444 6e99c5a0 Iustin Pop
    # nic processing (one nic only)
445 495cfdf0 Guido Trotter
    nics = [{"mac": fn("mac", constants.VALUE_AUTO)}]
446 495cfdf0 Guido Trotter
    if fn("ip", None) is not None:
447 495cfdf0 Guido Trotter
      nics[0]["ip"] = fn("ip")
448 495cfdf0 Guido Trotter
    if fn("mode", None) is not None:
449 495cfdf0 Guido Trotter
      nics[0]["mode"] = fn("mode")
450 495cfdf0 Guido Trotter
    if fn("link", None) is not None:
451 495cfdf0 Guido Trotter
      nics[0]["link"] = fn("link")
452 495cfdf0 Guido Trotter
    if fn("bridge", None) is not None:
453 69b99987 Michael Hanselmann
      nics[0]["bridge"] = fn("bridge")
454 2f7635f4 Oleksiy Mishchenko
455 59b4eeef Iustin Pop
    op = opcodes.OpCreateInstance(
456 59b4eeef Iustin Pop
      mode=constants.INSTANCE_CREATE,
457 59b4eeef Iustin Pop
      instance_name=fn('name'),
458 59b4eeef Iustin Pop
      disks=disks,
459 59b4eeef Iustin Pop
      disk_template=fn('disk_template'),
460 59b4eeef Iustin Pop
      os_type=fn('os'),
461 59b4eeef Iustin Pop
      pnode=fn('pnode', None),
462 59b4eeef Iustin Pop
      snode=fn('snode', None),
463 59b4eeef Iustin Pop
      iallocator=fn('iallocator', None),
464 59b4eeef Iustin Pop
      nics=nics,
465 59b4eeef Iustin Pop
      start=fn('start', True),
466 59b4eeef Iustin Pop
      ip_check=fn('ip_check', True),
467 460d22be Iustin Pop
      name_check=fn('name_check', True),
468 59b4eeef Iustin Pop
      wait_for_sync=True,
469 59b4eeef Iustin Pop
      hypervisor=fn('hypervisor', None),
470 59b4eeef Iustin Pop
      hvparams=hvparams,
471 59b4eeef Iustin Pop
      beparams=beparams,
472 59b4eeef Iustin Pop
      file_storage_dir=fn('file_storage_dir', None),
473 59b4eeef Iustin Pop
      file_driver=fn('file_driver', 'loop'),
474 6f59b964 Iustin Pop
      dry_run=bool(self.dryRun()),
475 59b4eeef Iustin Pop
      )
476 59b4eeef Iustin Pop
477 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
478 2f7635f4 Oleksiy Mishchenko
479 441e7cfd Oleksiy Mishchenko
480 4e5a68f8 Oleksiy Mishchenko
class R_2_instances_name(baserlib.R_Generic):
481 4e5a68f8 Oleksiy Mishchenko
  """/2/instances/[instance_name] resources.
482 028c6b76 Oleksiy Mishchenko

483 028c6b76 Oleksiy Mishchenko
  """
484 4e5a68f8 Oleksiy Mishchenko
  def GET(self):
485 4e5a68f8 Oleksiy Mishchenko
    """Send information about an instance.
486 4e5a68f8 Oleksiy Mishchenko

487 4e5a68f8 Oleksiy Mishchenko
    """
488 59b4eeef Iustin Pop
    client = baserlib.GetClient()
489 4e5a68f8 Oleksiy Mishchenko
    instance_name = self.items[0]
490 9031ee8e Iustin Pop
    result = client.QueryInstances(names=[instance_name], fields=I_FIELDS,
491 3d103742 Iustin Pop
                                   use_locking=self.useLocking())
492 4e5a68f8 Oleksiy Mishchenko
493 4e5a68f8 Oleksiy Mishchenko
    return baserlib.MapFields(I_FIELDS, result[0])
494 028c6b76 Oleksiy Mishchenko
495 6e99c5a0 Iustin Pop
  def DELETE(self):
496 6e99c5a0 Iustin Pop
    """Delete an instance.
497 6e99c5a0 Iustin Pop

498 6e99c5a0 Iustin Pop
    """
499 59b4eeef Iustin Pop
    op = opcodes.OpRemoveInstance(instance_name=self.items[0],
500 6f59b964 Iustin Pop
                                  ignore_failures=False,
501 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
502 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
503 6e99c5a0 Iustin Pop
504 028c6b76 Oleksiy Mishchenko
505 d8260842 Michael Hanselmann
class R_2_instances_name_info(baserlib.R_Generic):
506 d8260842 Michael Hanselmann
  """/2/instances/[instance_name]/info resource.
507 d8260842 Michael Hanselmann

508 d8260842 Michael Hanselmann
  """
509 d8260842 Michael Hanselmann
  def GET(self):
510 d8260842 Michael Hanselmann
    """Request detailed instance information.
511 d8260842 Michael Hanselmann

512 d8260842 Michael Hanselmann
    """
513 d8260842 Michael Hanselmann
    instance_name = self.items[0]
514 d8260842 Michael Hanselmann
    static = bool(self._checkIntVariable("static", default=0))
515 d8260842 Michael Hanselmann
516 d8260842 Michael Hanselmann
    op = opcodes.OpQueryInstanceData(instances=[instance_name],
517 d8260842 Michael Hanselmann
                                     static=static)
518 d8260842 Michael Hanselmann
    return baserlib.SubmitJob([op])
519 d8260842 Michael Hanselmann
520 d8260842 Michael Hanselmann
521 2276aa29 Oleksiy Mishchenko
class R_2_instances_name_reboot(baserlib.R_Generic):
522 2276aa29 Oleksiy Mishchenko
  """/2/instances/[instance_name]/reboot resource.
523 2276aa29 Oleksiy Mishchenko

524 2276aa29 Oleksiy Mishchenko
  Implements an instance reboot.
525 2276aa29 Oleksiy Mishchenko

526 2276aa29 Oleksiy Mishchenko
  """
527 21f04e5e Oleksiy Mishchenko
  def POST(self):
528 2276aa29 Oleksiy Mishchenko
    """Reboot an instance.
529 2276aa29 Oleksiy Mishchenko

530 0c55c24b Oleksiy Mishchenko
    The URI takes type=[hard|soft|full] and
531 0c55c24b Oleksiy Mishchenko
    ignore_secondaries=[False|True] parameters.
532 0c55c24b Oleksiy Mishchenko

533 2276aa29 Oleksiy Mishchenko
    """
534 2276aa29 Oleksiy Mishchenko
    instance_name = self.items[0]
535 0c55c24b Oleksiy Mishchenko
    reboot_type = self.queryargs.get('type',
536 0c55c24b Oleksiy Mishchenko
                                     [constants.INSTANCE_REBOOT_HARD])[0]
537 94cdfa4a Iustin Pop
    ignore_secondaries = bool(self._checkIntVariable('ignore_secondaries'))
538 59b4eeef Iustin Pop
    op = opcodes.OpRebootInstance(instance_name=instance_name,
539 59b4eeef Iustin Pop
                                  reboot_type=reboot_type,
540 6f59b964 Iustin Pop
                                  ignore_secondaries=ignore_secondaries,
541 6f59b964 Iustin Pop
                                  dry_run=bool(self.dryRun()))
542 2276aa29 Oleksiy Mishchenko
543 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
544 2276aa29 Oleksiy Mishchenko
545 2276aa29 Oleksiy Mishchenko
546 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_startup(baserlib.R_Generic):
547 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/startup resource.
548 0c55c24b Oleksiy Mishchenko

549 0c55c24b Oleksiy Mishchenko
  Implements an instance startup.
550 0c55c24b Oleksiy Mishchenko

551 0c55c24b Oleksiy Mishchenko
  """
552 21f04e5e Oleksiy Mishchenko
  def PUT(self):
553 0c55c24b Oleksiy Mishchenko
    """Startup an instance.
554 0c55c24b Oleksiy Mishchenko

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

558 0c55c24b Oleksiy Mishchenko
    """
559 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
560 94cdfa4a Iustin Pop
    force_startup = bool(self._checkIntVariable('force'))
561 59b4eeef Iustin Pop
    op = opcodes.OpStartupInstance(instance_name=instance_name,
562 6f59b964 Iustin Pop
                                   force=force_startup,
563 6f59b964 Iustin Pop
                                   dry_run=bool(self.dryRun()))
564 0c55c24b Oleksiy Mishchenko
565 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
566 0c55c24b Oleksiy Mishchenko
567 0c55c24b Oleksiy Mishchenko
568 0c55c24b Oleksiy Mishchenko
class R_2_instances_name_shutdown(baserlib.R_Generic):
569 0c55c24b Oleksiy Mishchenko
  """/2/instances/[instance_name]/shutdown resource.
570 0c55c24b Oleksiy Mishchenko

571 0c55c24b Oleksiy Mishchenko
  Implements an instance shutdown.
572 0c55c24b Oleksiy Mishchenko

573 0c55c24b Oleksiy Mishchenko
  """
574 21f04e5e Oleksiy Mishchenko
  def PUT(self):
575 0c55c24b Oleksiy Mishchenko
    """Shutdown an instance.
576 0c55c24b Oleksiy Mishchenko

577 0c55c24b Oleksiy Mishchenko
    """
578 0c55c24b Oleksiy Mishchenko
    instance_name = self.items[0]
579 6f59b964 Iustin Pop
    op = opcodes.OpShutdownInstance(instance_name=instance_name,
580 6f59b964 Iustin Pop
                                    dry_run=bool(self.dryRun()))
581 0c55c24b Oleksiy Mishchenko
582 59b4eeef Iustin Pop
    return baserlib.SubmitJob([op])
583 0c55c24b Oleksiy Mishchenko
584 0c55c24b Oleksiy Mishchenko
585 e5b7c4ca Iustin Pop
class R_2_instances_name_reinstall(baserlib.R_Generic):
586 e5b7c4ca Iustin Pop
  """/2/instances/[instance_name]/reinstall resource.
587 e5b7c4ca Iustin Pop

588 e5b7c4ca Iustin Pop
  Implements an instance reinstall.
589 e5b7c4ca Iustin Pop

590 e5b7c4ca Iustin Pop
  """
591 e5b7c4ca Iustin Pop
  def POST(self):
592 e5b7c4ca Iustin Pop
    """Reinstall an instance.
593 e5b7c4ca Iustin Pop

594 e5b7c4ca Iustin Pop
    The URI takes os=name and nostartup=[0|1] optional
595 e5b7c4ca Iustin Pop
    parameters. By default, the instance will be started
596 e5b7c4ca Iustin Pop
    automatically.
597 e5b7c4ca Iustin Pop

598 e5b7c4ca Iustin Pop
    """
599 e5b7c4ca Iustin Pop
    instance_name = self.items[0]
600 e5b7c4ca Iustin Pop
    ostype = self._checkStringVariable('os')
601 e5b7c4ca Iustin Pop
    nostartup = self._checkIntVariable('nostartup')
602 e5b7c4ca Iustin Pop
    ops = [
603 e5b7c4ca Iustin Pop
      opcodes.OpShutdownInstance(instance_name=instance_name),
604 e5b7c4ca Iustin Pop
      opcodes.OpReinstallInstance(instance_name=instance_name, os_type=ostype),
605 e5b7c4ca Iustin Pop
      ]
606 e5b7c4ca Iustin Pop
    if not nostartup:
607 e5b7c4ca Iustin Pop
      ops.append(opcodes.OpStartupInstance(instance_name=instance_name,
608 e5b7c4ca Iustin Pop
                                           force=False))
609 e5b7c4ca Iustin Pop
    return baserlib.SubmitJob(ops)
610 e5b7c4ca Iustin Pop
611 e5b7c4ca Iustin Pop
612 4c98b915 Michael Hanselmann
class R_2_instances_name_replace_disks(baserlib.R_Generic):
613 4c98b915 Michael Hanselmann
  """/2/instances/[instance_name]/replace-disks resource.
614 4c98b915 Michael Hanselmann

615 4c98b915 Michael Hanselmann
  """
616 4c98b915 Michael Hanselmann
  def POST(self):
617 4c98b915 Michael Hanselmann
    """Replaces disks on an instance.
618 4c98b915 Michael Hanselmann

619 4c98b915 Michael Hanselmann
    """
620 4c98b915 Michael Hanselmann
    instance_name = self.items[0]
621 4c98b915 Michael Hanselmann
    remote_node = self._checkStringVariable("remote_node", default=None)
622 4c98b915 Michael Hanselmann
    mode = self._checkStringVariable("mode", default=None)
623 4c98b915 Michael Hanselmann
    raw_disks = self._checkStringVariable("disks", default=None)
624 4c98b915 Michael Hanselmann
    iallocator = self._checkStringVariable("iallocator", default=None)
625 4c98b915 Michael Hanselmann
626 4c98b915 Michael Hanselmann
    if raw_disks:
627 4c98b915 Michael Hanselmann
      try:
628 4c98b915 Michael Hanselmann
        disks = [int(part) for part in raw_disks.split(",")]
629 4c98b915 Michael Hanselmann
      except ValueError, err:
630 4c98b915 Michael Hanselmann
        raise http.HttpBadRequest("Invalid disk index passed: %s" % str(err))
631 4c98b915 Michael Hanselmann
    else:
632 4c98b915 Michael Hanselmann
      disks = []
633 4c98b915 Michael Hanselmann
634 4c98b915 Michael Hanselmann
    op = opcodes.OpReplaceDisks(instance_name=instance_name,
635 4c98b915 Michael Hanselmann
                                remote_node=remote_node,
636 4c98b915 Michael Hanselmann
                                mode=mode,
637 4c98b915 Michael Hanselmann
                                disks=disks,
638 4c98b915 Michael Hanselmann
                                iallocator=iallocator)
639 4c98b915 Michael Hanselmann
640 4c98b915 Michael Hanselmann
    return baserlib.SubmitJob([op])
641 4c98b915 Michael Hanselmann
642 4c98b915 Michael Hanselmann
643 18cb43a2 Oleksiy Mishchenko
class _R_Tags(baserlib.R_Generic):
644 18cb43a2 Oleksiy Mishchenko
  """ Quasiclass for tagging resources
645 441e7cfd Oleksiy Mishchenko

646 c8e0a534 Iustin Pop
  Manages tags. When inheriting this class you must define the
647 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL for it.
648 441e7cfd Oleksiy Mishchenko

649 441e7cfd Oleksiy Mishchenko
  """
650 7a6b9510 Iustin Pop
  TAG_LEVEL = None
651 18cb43a2 Oleksiy Mishchenko
652 18cb43a2 Oleksiy Mishchenko
  def __init__(self, items, queryargs, req):
653 18cb43a2 Oleksiy Mishchenko
    """A tag resource constructor.
654 18cb43a2 Oleksiy Mishchenko

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

657 18cb43a2 Oleksiy Mishchenko
    """
658 18cb43a2 Oleksiy Mishchenko
    baserlib.R_Generic.__init__(self, items, queryargs, req)
659 18cb43a2 Oleksiy Mishchenko
660 18cb43a2 Oleksiy Mishchenko
    if self.TAG_LEVEL != constants.TAG_CLUSTER:
661 18cb43a2 Oleksiy Mishchenko
      self.name = items[0]
662 18cb43a2 Oleksiy Mishchenko
    else:
663 18cb43a2 Oleksiy Mishchenko
      self.name = ""
664 441e7cfd Oleksiy Mishchenko
665 441e7cfd Oleksiy Mishchenko
  def GET(self):
666 18cb43a2 Oleksiy Mishchenko
    """Returns a list of tags.
667 441e7cfd Oleksiy Mishchenko

668 441e7cfd Oleksiy Mishchenko
    Example: ["tag1", "tag2", "tag3"]
669 441e7cfd Oleksiy Mishchenko

670 441e7cfd Oleksiy Mishchenko
    """
671 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_GET(self.TAG_LEVEL, name=self.name)
672 441e7cfd Oleksiy Mishchenko
673 21f04e5e Oleksiy Mishchenko
  def PUT(self):
674 18cb43a2 Oleksiy Mishchenko
    """Add a set of tags.
675 441e7cfd Oleksiy Mishchenko

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

679 441e7cfd Oleksiy Mishchenko
    """
680 6e99c5a0 Iustin Pop
    if 'tag' not in self.queryargs:
681 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Please specify tag(s) to add using the"
682 6e99c5a0 Iustin Pop
                                " the 'tag' parameter")
683 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_PUT(self.TAG_LEVEL,
684 6f59b964 Iustin Pop
                              self.queryargs['tag'], name=self.name,
685 6f59b964 Iustin Pop
                              dry_run=bool(self.dryRun()))
686 15fd9fd5 Oleksiy Mishchenko
687 15fd9fd5 Oleksiy Mishchenko
  def DELETE(self):
688 15fd9fd5 Oleksiy Mishchenko
    """Delete a tag.
689 15fd9fd5 Oleksiy Mishchenko

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

694 15fd9fd5 Oleksiy Mishchenko
    """
695 15fd9fd5 Oleksiy Mishchenko
    if 'tag' not in self.queryargs:
696 18cb43a2 Oleksiy Mishchenko
      # no we not gonna delete all tags
697 6e99c5a0 Iustin Pop
      raise http.HttpBadRequest("Cannot delete all tags - please specify"
698 6e99c5a0 Iustin Pop
                                " tag(s) using the 'tag' parameter")
699 18cb43a2 Oleksiy Mishchenko
    return baserlib._Tags_DELETE(self.TAG_LEVEL,
700 15fd9fd5 Oleksiy Mishchenko
                                 self.queryargs['tag'],
701 6f59b964 Iustin Pop
                                 name=self.name,
702 6f59b964 Iustin Pop
                                 dry_run=bool(self.dryRun()))
703 18cb43a2 Oleksiy Mishchenko
704 18cb43a2 Oleksiy Mishchenko
705 18cb43a2 Oleksiy Mishchenko
class R_2_instances_name_tags(_R_Tags):
706 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/[instance_name]/tags resource.
707 18cb43a2 Oleksiy Mishchenko

708 18cb43a2 Oleksiy Mishchenko
  Manages per-instance tags.
709 18cb43a2 Oleksiy Mishchenko

710 18cb43a2 Oleksiy Mishchenko
  """
711 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_INSTANCE
712 18cb43a2 Oleksiy Mishchenko
713 18cb43a2 Oleksiy Mishchenko
714 18cb43a2 Oleksiy Mishchenko
class R_2_nodes_name_tags(_R_Tags):
715 18cb43a2 Oleksiy Mishchenko
  """ /2/nodes/[node_name]/tags resource.
716 18cb43a2 Oleksiy Mishchenko

717 18cb43a2 Oleksiy Mishchenko
  Manages per-node tags.
718 18cb43a2 Oleksiy Mishchenko

719 18cb43a2 Oleksiy Mishchenko
  """
720 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_NODE
721 18cb43a2 Oleksiy Mishchenko
722 18cb43a2 Oleksiy Mishchenko
723 18cb43a2 Oleksiy Mishchenko
class R_2_tags(_R_Tags):
724 18cb43a2 Oleksiy Mishchenko
  """ /2/instances/tags resource.
725 18cb43a2 Oleksiy Mishchenko

726 18cb43a2 Oleksiy Mishchenko
  Manages cluster tags.
727 18cb43a2 Oleksiy Mishchenko

728 18cb43a2 Oleksiy Mishchenko
  """
729 18cb43a2 Oleksiy Mishchenko
  TAG_LEVEL = constants.TAG_CLUSTER