Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / logic / rapi.py @ 883c1f94

History | View | Annotate | Download (52.7 kB)

1 e5e20779 Faidon Liambotis
#
2 e5e20779 Faidon Liambotis
#
3 e5e20779 Faidon Liambotis
4 a3ad611d Dimitris Aragiorgis
# Copyright (C) 2010, 2011 Google Inc.
5 b4135a1b Christos Stavrakakis
# Copyright (C) 2013, GRNET S.A.
6 e5e20779 Faidon Liambotis
#
7 e5e20779 Faidon Liambotis
# This program is free software; you can redistribute it and/or modify
8 e5e20779 Faidon Liambotis
# it under the terms of the GNU General Public License as published by
9 e5e20779 Faidon Liambotis
# the Free Software Foundation; either version 2 of the License, or
10 e5e20779 Faidon Liambotis
# (at your option) any later version.
11 e5e20779 Faidon Liambotis
#
12 e5e20779 Faidon Liambotis
# This program is distributed in the hope that it will be useful, but
13 e5e20779 Faidon Liambotis
# WITHOUT ANY WARRANTY; without even the implied warranty of
14 e5e20779 Faidon Liambotis
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 e5e20779 Faidon Liambotis
# General Public License for more details.
16 e5e20779 Faidon Liambotis
#
17 e5e20779 Faidon Liambotis
# You should have received a copy of the GNU General Public License
18 e5e20779 Faidon Liambotis
# along with this program; if not, write to the Free Software
19 e5e20779 Faidon Liambotis
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 e5e20779 Faidon Liambotis
# 02110-1301, USA.
21 e5e20779 Faidon Liambotis
22 e5e20779 Faidon Liambotis
23 b4135a1b Christos Stavrakakis
"""Ganeti RAPI client."""
24 e5e20779 Faidon Liambotis
25 e5e20779 Faidon Liambotis
# No Ganeti-specific modules should be imported. The RAPI client is supposed to
26 e5e20779 Faidon Liambotis
# be standalone.
27 e5e20779 Faidon Liambotis
28 b4135a1b Christos Stavrakakis
import requests
29 9e98ba3c Giorgos Verigakis
import logging
30 a3ad611d Dimitris Aragiorgis
import simplejson
31 a3ad611d Dimitris Aragiorgis
import time
32 3481786b Faidon Liambotis
33 e5e20779 Faidon Liambotis
GANETI_RAPI_PORT = 5080
34 e5e20779 Faidon Liambotis
GANETI_RAPI_VERSION = 2
35 e5e20779 Faidon Liambotis
36 e5e20779 Faidon Liambotis
HTTP_DELETE = "DELETE"
37 e5e20779 Faidon Liambotis
HTTP_GET = "GET"
38 e5e20779 Faidon Liambotis
HTTP_PUT = "PUT"
39 e5e20779 Faidon Liambotis
HTTP_POST = "POST"
40 e5e20779 Faidon Liambotis
HTTP_OK = 200
41 e5e20779 Faidon Liambotis
HTTP_NOT_FOUND = 404
42 e5e20779 Faidon Liambotis
HTTP_APP_JSON = "application/json"
43 e5e20779 Faidon Liambotis
44 e5e20779 Faidon Liambotis
REPLACE_DISK_PRI = "replace_on_primary"
45 e5e20779 Faidon Liambotis
REPLACE_DISK_SECONDARY = "replace_on_secondary"
46 e5e20779 Faidon Liambotis
REPLACE_DISK_CHG = "replace_new_secondary"
47 e5e20779 Faidon Liambotis
REPLACE_DISK_AUTO = "replace_auto"
48 e5e20779 Faidon Liambotis
49 a3ad611d Dimitris Aragiorgis
NODE_EVAC_PRI = "primary-only"
50 a3ad611d Dimitris Aragiorgis
NODE_EVAC_SEC = "secondary-only"
51 a3ad611d Dimitris Aragiorgis
NODE_EVAC_ALL = "all"
52 a3ad611d Dimitris Aragiorgis
53 e5e20779 Faidon Liambotis
NODE_ROLE_DRAINED = "drained"
54 e5e20779 Faidon Liambotis
NODE_ROLE_MASTER_CANDIATE = "master-candidate"
55 e5e20779 Faidon Liambotis
NODE_ROLE_MASTER = "master"
56 e5e20779 Faidon Liambotis
NODE_ROLE_OFFLINE = "offline"
57 e5e20779 Faidon Liambotis
NODE_ROLE_REGULAR = "regular"
58 e5e20779 Faidon Liambotis
59 a3ad611d Dimitris Aragiorgis
JOB_STATUS_QUEUED = "queued"
60 a3ad611d Dimitris Aragiorgis
JOB_STATUS_WAITING = "waiting"
61 a3ad611d Dimitris Aragiorgis
JOB_STATUS_CANCELING = "canceling"
62 a3ad611d Dimitris Aragiorgis
JOB_STATUS_RUNNING = "running"
63 a3ad611d Dimitris Aragiorgis
JOB_STATUS_CANCELED = "canceled"
64 a3ad611d Dimitris Aragiorgis
JOB_STATUS_SUCCESS = "success"
65 a3ad611d Dimitris Aragiorgis
JOB_STATUS_ERROR = "error"
66 a3ad611d Dimitris Aragiorgis
JOB_STATUS_FINALIZED = frozenset([
67 a3ad611d Dimitris Aragiorgis
  JOB_STATUS_CANCELED,
68 a3ad611d Dimitris Aragiorgis
  JOB_STATUS_SUCCESS,
69 a3ad611d Dimitris Aragiorgis
  JOB_STATUS_ERROR,
70 a3ad611d Dimitris Aragiorgis
  ])
71 a3ad611d Dimitris Aragiorgis
JOB_STATUS_ALL = frozenset([
72 a3ad611d Dimitris Aragiorgis
  JOB_STATUS_QUEUED,
73 a3ad611d Dimitris Aragiorgis
  JOB_STATUS_WAITING,
74 a3ad611d Dimitris Aragiorgis
  JOB_STATUS_CANCELING,
75 a3ad611d Dimitris Aragiorgis
  JOB_STATUS_RUNNING,
76 a3ad611d Dimitris Aragiorgis
  ]) | JOB_STATUS_FINALIZED
77 a3ad611d Dimitris Aragiorgis
78 a3ad611d Dimitris Aragiorgis
# Legacy name
79 a3ad611d Dimitris Aragiorgis
JOB_STATUS_WAITLOCK = JOB_STATUS_WAITING
80 a3ad611d Dimitris Aragiorgis
81 e5e20779 Faidon Liambotis
# Internal constants
82 e5e20779 Faidon Liambotis
_REQ_DATA_VERSION_FIELD = "__version__"
83 a3ad611d Dimitris Aragiorgis
_QPARAM_DRY_RUN = "dry-run"
84 a3ad611d Dimitris Aragiorgis
_QPARAM_FORCE = "force"
85 a3ad611d Dimitris Aragiorgis
86 a3ad611d Dimitris Aragiorgis
# Feature strings
87 a3ad611d Dimitris Aragiorgis
INST_CREATE_REQV1 = "instance-create-reqv1"
88 a3ad611d Dimitris Aragiorgis
INST_REINSTALL_REQV1 = "instance-reinstall-reqv1"
89 a3ad611d Dimitris Aragiorgis
NODE_MIGRATE_REQV1 = "node-migrate-reqv1"
90 a3ad611d Dimitris Aragiorgis
NODE_EVAC_RES1 = "node-evac-res1"
91 a3ad611d Dimitris Aragiorgis
92 a3ad611d Dimitris Aragiorgis
# Old feature constant names in case they're references by users of this module
93 a3ad611d Dimitris Aragiorgis
_INST_CREATE_REQV1 = INST_CREATE_REQV1
94 a3ad611d Dimitris Aragiorgis
_INST_REINSTALL_REQV1 = INST_REINSTALL_REQV1
95 a3ad611d Dimitris Aragiorgis
_NODE_MIGRATE_REQV1 = NODE_MIGRATE_REQV1
96 a3ad611d Dimitris Aragiorgis
_NODE_EVAC_RES1 = NODE_EVAC_RES1
97 e5e20779 Faidon Liambotis
98 aee560b0 Christos Stavrakakis
#: Not enough resources (iallocator failure, disk space, memory, etc.)
99 aee560b0 Christos Stavrakakis
ECODE_NORES = "insufficient_resources"
100 aee560b0 Christos Stavrakakis
101 aee560b0 Christos Stavrakakis
#: Temporarily out of resources; operation can be tried again
102 aee560b0 Christos Stavrakakis
ECODE_TEMP_NORES = "temp_insufficient_resources"
103 e5e20779 Faidon Liambotis
104 e5e20779 Faidon Liambotis
105 e5e20779 Faidon Liambotis
class Error(Exception):
106 e5e20779 Faidon Liambotis
  """Base error class for this module.
107 e5e20779 Faidon Liambotis

108 e5e20779 Faidon Liambotis
  """
109 e5e20779 Faidon Liambotis
  pass
110 e5e20779 Faidon Liambotis
111 e5e20779 Faidon Liambotis
112 a3ad611d Dimitris Aragiorgis
class GanetiApiError(Error):
113 a3ad611d Dimitris Aragiorgis
  """Generic error raised from Ganeti API.
114 a3ad611d Dimitris Aragiorgis

115 a3ad611d Dimitris Aragiorgis
  """
116 a3ad611d Dimitris Aragiorgis
  def __init__(self, msg, code=None):
117 a3ad611d Dimitris Aragiorgis
    Error.__init__(self, msg)
118 a3ad611d Dimitris Aragiorgis
    self.code = code
119 a3ad611d Dimitris Aragiorgis
120 a3ad611d Dimitris Aragiorgis
121 a3ad611d Dimitris Aragiorgis
class CertificateError(GanetiApiError):
122 e5e20779 Faidon Liambotis
  """Raised when a problem is found with the SSL certificate.
123 e5e20779 Faidon Liambotis

124 e5e20779 Faidon Liambotis
  """
125 e5e20779 Faidon Liambotis
  pass
126 e5e20779 Faidon Liambotis
127 e5e20779 Faidon Liambotis
128 a3ad611d Dimitris Aragiorgis
def _AppendIf(container, condition, value):
129 a3ad611d Dimitris Aragiorgis
  """Appends to a list if a condition evaluates to truth.
130 e5e20779 Faidon Liambotis

131 e5e20779 Faidon Liambotis
  """
132 a3ad611d Dimitris Aragiorgis
  if condition:
133 a3ad611d Dimitris Aragiorgis
    container.append(value)
134 a3ad611d Dimitris Aragiorgis
135 a3ad611d Dimitris Aragiorgis
  return condition
136 a3ad611d Dimitris Aragiorgis
137 a3ad611d Dimitris Aragiorgis
138 a3ad611d Dimitris Aragiorgis
def _AppendDryRunIf(container, condition):
139 a3ad611d Dimitris Aragiorgis
  """Appends a "dry-run" parameter if a condition evaluates to truth.
140 a3ad611d Dimitris Aragiorgis

141 a3ad611d Dimitris Aragiorgis
  """
142 a3ad611d Dimitris Aragiorgis
  return _AppendIf(container, condition, (_QPARAM_DRY_RUN, 1))
143 a3ad611d Dimitris Aragiorgis
144 a3ad611d Dimitris Aragiorgis
145 a3ad611d Dimitris Aragiorgis
def _AppendForceIf(container, condition):
146 a3ad611d Dimitris Aragiorgis
  """Appends a "force" parameter if a condition evaluates to truth.
147 a3ad611d Dimitris Aragiorgis

148 a3ad611d Dimitris Aragiorgis
  """
149 a3ad611d Dimitris Aragiorgis
  return _AppendIf(container, condition, (_QPARAM_FORCE, 1))
150 a3ad611d Dimitris Aragiorgis
151 a3ad611d Dimitris Aragiorgis
152 a3ad611d Dimitris Aragiorgis
def _SetItemIf(container, condition, item, value):
153 a3ad611d Dimitris Aragiorgis
  """Sets an item if a condition evaluates to truth.
154 a3ad611d Dimitris Aragiorgis

155 a3ad611d Dimitris Aragiorgis
  """
156 a3ad611d Dimitris Aragiorgis
  if condition:
157 a3ad611d Dimitris Aragiorgis
    container[item] = value
158 a3ad611d Dimitris Aragiorgis
159 a3ad611d Dimitris Aragiorgis
  return condition
160 e5e20779 Faidon Liambotis
161 e5e20779 Faidon Liambotis
162 a3ad611d Dimitris Aragiorgis
class GanetiRapiClient(object): # pylint: disable=R0904
163 e5e20779 Faidon Liambotis
  """Ganeti RAPI client.
164 e5e20779 Faidon Liambotis

165 e5e20779 Faidon Liambotis
  """
166 e5e20779 Faidon Liambotis
  USER_AGENT = "Ganeti RAPI Client"
167 a3ad611d Dimitris Aragiorgis
  _json_encoder = simplejson.JSONEncoder(sort_keys=True)
168 e5e20779 Faidon Liambotis
169 e5e20779 Faidon Liambotis
  def __init__(self, host, port=GANETI_RAPI_PORT,
170 b4135a1b Christos Stavrakakis
               username=None, password=None, logger=logging):
171 e5e20779 Faidon Liambotis
    """Initializes this class.
172 e5e20779 Faidon Liambotis

173 e5e20779 Faidon Liambotis
    @type host: string
174 e5e20779 Faidon Liambotis
    @param host: the ganeti cluster master to interact with
175 e5e20779 Faidon Liambotis
    @type port: int
176 e5e20779 Faidon Liambotis
    @param port: the port on which the RAPI is running (default is 5080)
177 e5e20779 Faidon Liambotis
    @type username: string
178 e5e20779 Faidon Liambotis
    @param username: the username to connect with
179 e5e20779 Faidon Liambotis
    @type password: string
180 e5e20779 Faidon Liambotis
    @param password: the password to connect with
181 e5e20779 Faidon Liambotis
    @param logger: Logging object
182 e5e20779 Faidon Liambotis

183 e5e20779 Faidon Liambotis
    """
184 e5e20779 Faidon Liambotis
    self._logger = logger
185 b4135a1b Christos Stavrakakis
    self._base_url = "https://%s:%s" % (host, port)
186 e5e20779 Faidon Liambotis
187 e5e20779 Faidon Liambotis
    if username is not None:
188 e5e20779 Faidon Liambotis
      if password is None:
189 e5e20779 Faidon Liambotis
        raise Error("Password not specified")
190 e5e20779 Faidon Liambotis
    elif password:
191 e5e20779 Faidon Liambotis
      raise Error("Specified password without username")
192 e5e20779 Faidon Liambotis
193 b4135a1b Christos Stavrakakis
    self._auth = (username, password)
194 e5e20779 Faidon Liambotis
195 e5e20779 Faidon Liambotis
  def _SendRequest(self, method, path, query, content):
196 e5e20779 Faidon Liambotis
    """Sends an HTTP request.
197 e5e20779 Faidon Liambotis

198 e5e20779 Faidon Liambotis
    This constructs a full URL, encodes and decodes HTTP bodies, and
199 e5e20779 Faidon Liambotis
    handles invalid responses in a pythonic way.
200 e5e20779 Faidon Liambotis

201 e5e20779 Faidon Liambotis
    @type method: string
202 e5e20779 Faidon Liambotis
    @param method: HTTP method to use
203 e5e20779 Faidon Liambotis
    @type path: string
204 e5e20779 Faidon Liambotis
    @param path: HTTP URL path
205 e5e20779 Faidon Liambotis
    @type query: list of two-tuples
206 e5e20779 Faidon Liambotis
    @param query: query arguments to pass to urllib.urlencode
207 e5e20779 Faidon Liambotis
    @type content: str or None
208 e5e20779 Faidon Liambotis
    @param content: HTTP body content
209 e5e20779 Faidon Liambotis

210 e5e20779 Faidon Liambotis
    @rtype: str
211 e5e20779 Faidon Liambotis
    @return: JSON-Decoded response
212 e5e20779 Faidon Liambotis

213 e5e20779 Faidon Liambotis
    @raises CertificateError: If an invalid SSL certificate is found
214 e5e20779 Faidon Liambotis
    @raises GanetiApiError: If an invalid response is returned
215 e5e20779 Faidon Liambotis

216 e5e20779 Faidon Liambotis
    """
217 e5e20779 Faidon Liambotis
    assert path.startswith("/")
218 b4135a1b Christos Stavrakakis
    url = "%s%s" % (self._base_url, path)
219 e5e20779 Faidon Liambotis
220 b4135a1b Christos Stavrakakis
    headers = {}
221 e5e20779 Faidon Liambotis
    if content is not None:
222 e5e20779 Faidon Liambotis
      encoded_content = self._json_encoder.encode(content)
223 b4135a1b Christos Stavrakakis
      headers = {"content-type": HTTP_APP_JSON,
224 b4135a1b Christos Stavrakakis
                 "accept": HTTP_APP_JSON}
225 e5e20779 Faidon Liambotis
    else:
226 e5e20779 Faidon Liambotis
      encoded_content = ""
227 e5e20779 Faidon Liambotis
228 b4135a1b Christos Stavrakakis
    if query is not None:
229 b4135a1b Christos Stavrakakis
        query = dict(query)
230 b4135a1b Christos Stavrakakis
231 b4135a1b Christos Stavrakakis
    self._logger.debug("Sending request %s %s (query=%r) (content=%r)",
232 b4135a1b Christos Stavrakakis
                       method, url, query, encoded_content)
233 b4135a1b Christos Stavrakakis
234 b4135a1b Christos Stavrakakis
    req_method = getattr(requests, method.lower())
235 b4135a1b Christos Stavrakakis
    r = req_method(url, auth=self._auth, headers=headers, params=query,
236 b4135a1b Christos Stavrakakis
                   data=encoded_content, verify=False)
237 b4135a1b Christos Stavrakakis
238 b4135a1b Christos Stavrakakis
239 b4135a1b Christos Stavrakakis
    http_code = r.status_code
240 b4135a1b Christos Stavrakakis
    if r.content is not None:
241 b4135a1b Christos Stavrakakis
        response_content = simplejson.loads(r.content)
242 e5e20779 Faidon Liambotis
    else:
243 b4135a1b Christos Stavrakakis
        response_content = None
244 e5e20779 Faidon Liambotis
245 e5e20779 Faidon Liambotis
    if http_code != HTTP_OK:
246 e5e20779 Faidon Liambotis
      if isinstance(response_content, dict):
247 e5e20779 Faidon Liambotis
        msg = ("%s %s: %s" %
248 e5e20779 Faidon Liambotis
               (response_content["code"],
249 e5e20779 Faidon Liambotis
                response_content["message"],
250 e5e20779 Faidon Liambotis
                response_content["explain"]))
251 e5e20779 Faidon Liambotis
      else:
252 e5e20779 Faidon Liambotis
        msg = str(response_content)
253 e5e20779 Faidon Liambotis
254 e5e20779 Faidon Liambotis
      raise GanetiApiError(msg, code=http_code)
255 e5e20779 Faidon Liambotis
256 e5e20779 Faidon Liambotis
    return response_content
257 e5e20779 Faidon Liambotis
258 e5e20779 Faidon Liambotis
  def GetVersion(self):
259 e5e20779 Faidon Liambotis
    """Gets the Remote API version running on the cluster.
260 e5e20779 Faidon Liambotis

261 e5e20779 Faidon Liambotis
    @rtype: int
262 e5e20779 Faidon Liambotis
    @return: Ganeti Remote API version
263 e5e20779 Faidon Liambotis

264 e5e20779 Faidon Liambotis
    """
265 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET, "/version", None, None)
266 e5e20779 Faidon Liambotis
267 e5e20779 Faidon Liambotis
  def GetFeatures(self):
268 e5e20779 Faidon Liambotis
    """Gets the list of optional features supported by RAPI server.
269 e5e20779 Faidon Liambotis

270 e5e20779 Faidon Liambotis
    @rtype: list
271 e5e20779 Faidon Liambotis
    @return: List of optional features
272 e5e20779 Faidon Liambotis

273 e5e20779 Faidon Liambotis
    """
274 e5e20779 Faidon Liambotis
    try:
275 e5e20779 Faidon Liambotis
      return self._SendRequest(HTTP_GET, "/%s/features" % GANETI_RAPI_VERSION,
276 e5e20779 Faidon Liambotis
                               None, None)
277 e5e20779 Faidon Liambotis
    except GanetiApiError, err:
278 e5e20779 Faidon Liambotis
      # Older RAPI servers don't support this resource
279 e5e20779 Faidon Liambotis
      if err.code == HTTP_NOT_FOUND:
280 e5e20779 Faidon Liambotis
        return []
281 e5e20779 Faidon Liambotis
282 e5e20779 Faidon Liambotis
      raise
283 e5e20779 Faidon Liambotis
284 e5e20779 Faidon Liambotis
  def GetOperatingSystems(self):
285 e5e20779 Faidon Liambotis
    """Gets the Operating Systems running in the Ganeti cluster.
286 e5e20779 Faidon Liambotis

287 e5e20779 Faidon Liambotis
    @rtype: list of str
288 e5e20779 Faidon Liambotis
    @return: operating systems
289 e5e20779 Faidon Liambotis

290 e5e20779 Faidon Liambotis
    """
291 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET, "/%s/os" % GANETI_RAPI_VERSION,
292 e5e20779 Faidon Liambotis
                             None, None)
293 e5e20779 Faidon Liambotis
294 e5e20779 Faidon Liambotis
  def GetInfo(self):
295 e5e20779 Faidon Liambotis
    """Gets info about the cluster.
296 e5e20779 Faidon Liambotis

297 e5e20779 Faidon Liambotis
    @rtype: dict
298 e5e20779 Faidon Liambotis
    @return: information about the cluster
299 e5e20779 Faidon Liambotis

300 e5e20779 Faidon Liambotis
    """
301 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET, "/%s/info" % GANETI_RAPI_VERSION,
302 e5e20779 Faidon Liambotis
                             None, None)
303 e5e20779 Faidon Liambotis
304 067dda99 Vangelis Koukis
  def RedistributeConfig(self):
305 067dda99 Vangelis Koukis
    """Tells the cluster to redistribute its configuration files.
306 067dda99 Vangelis Koukis

307 a3ad611d Dimitris Aragiorgis
    @rtype: string
308 067dda99 Vangelis Koukis
    @return: job id
309 067dda99 Vangelis Koukis

310 067dda99 Vangelis Koukis
    """
311 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_PUT,
312 067dda99 Vangelis Koukis
                             "/%s/redistribute-config" % GANETI_RAPI_VERSION,
313 067dda99 Vangelis Koukis
                             None, None)
314 067dda99 Vangelis Koukis
315 067dda99 Vangelis Koukis
  def ModifyCluster(self, **kwargs):
316 067dda99 Vangelis Koukis
    """Modifies cluster parameters.
317 067dda99 Vangelis Koukis

318 067dda99 Vangelis Koukis
    More details for parameters can be found in the RAPI documentation.
319 067dda99 Vangelis Koukis

320 a3ad611d Dimitris Aragiorgis
    @rtype: string
321 067dda99 Vangelis Koukis
    @return: job id
322 067dda99 Vangelis Koukis

323 067dda99 Vangelis Koukis
    """
324 067dda99 Vangelis Koukis
    body = kwargs
325 067dda99 Vangelis Koukis
326 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_PUT,
327 067dda99 Vangelis Koukis
                             "/%s/modify" % GANETI_RAPI_VERSION, None, body)
328 067dda99 Vangelis Koukis
329 e5e20779 Faidon Liambotis
  def GetClusterTags(self):
330 e5e20779 Faidon Liambotis
    """Gets the cluster tags.
331 e5e20779 Faidon Liambotis

332 e5e20779 Faidon Liambotis
    @rtype: list of str
333 e5e20779 Faidon Liambotis
    @return: cluster tags
334 e5e20779 Faidon Liambotis

335 e5e20779 Faidon Liambotis
    """
336 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET, "/%s/tags" % GANETI_RAPI_VERSION,
337 e5e20779 Faidon Liambotis
                             None, None)
338 e5e20779 Faidon Liambotis
339 e5e20779 Faidon Liambotis
  def AddClusterTags(self, tags, dry_run=False):
340 e5e20779 Faidon Liambotis
    """Adds tags to the cluster.
341 e5e20779 Faidon Liambotis

342 e5e20779 Faidon Liambotis
    @type tags: list of str
343 e5e20779 Faidon Liambotis
    @param tags: tags to add to the cluster
344 e5e20779 Faidon Liambotis
    @type dry_run: bool
345 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
346 e5e20779 Faidon Liambotis

347 a3ad611d Dimitris Aragiorgis
    @rtype: string
348 e5e20779 Faidon Liambotis
    @return: job id
349 e5e20779 Faidon Liambotis

350 e5e20779 Faidon Liambotis
    """
351 e5e20779 Faidon Liambotis
    query = [("tag", t) for t in tags]
352 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
353 e5e20779 Faidon Liambotis
354 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT, "/%s/tags" % GANETI_RAPI_VERSION,
355 e5e20779 Faidon Liambotis
                             query, None)
356 e5e20779 Faidon Liambotis
357 e5e20779 Faidon Liambotis
  def DeleteClusterTags(self, tags, dry_run=False):
358 e5e20779 Faidon Liambotis
    """Deletes tags from the cluster.
359 e5e20779 Faidon Liambotis

360 e5e20779 Faidon Liambotis
    @type tags: list of str
361 e5e20779 Faidon Liambotis
    @param tags: tags to delete
362 e5e20779 Faidon Liambotis
    @type dry_run: bool
363 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
364 a3ad611d Dimitris Aragiorgis
    @rtype: string
365 a3ad611d Dimitris Aragiorgis
    @return: job id
366 e5e20779 Faidon Liambotis

367 e5e20779 Faidon Liambotis
    """
368 e5e20779 Faidon Liambotis
    query = [("tag", t) for t in tags]
369 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
370 e5e20779 Faidon Liambotis
371 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_DELETE, "/%s/tags" % GANETI_RAPI_VERSION,
372 e5e20779 Faidon Liambotis
                             query, None)
373 e5e20779 Faidon Liambotis
374 e5e20779 Faidon Liambotis
  def GetInstances(self, bulk=False):
375 e5e20779 Faidon Liambotis
    """Gets information about instances on the cluster.
376 e5e20779 Faidon Liambotis

377 e5e20779 Faidon Liambotis
    @type bulk: bool
378 e5e20779 Faidon Liambotis
    @param bulk: whether to return all information about all instances
379 e5e20779 Faidon Liambotis

380 e5e20779 Faidon Liambotis
    @rtype: list of dict or list of str
381 e5e20779 Faidon Liambotis
    @return: if bulk is True, info about the instances, else a list of instances
382 e5e20779 Faidon Liambotis

383 e5e20779 Faidon Liambotis
    """
384 e5e20779 Faidon Liambotis
    query = []
385 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, bulk, ("bulk", 1))
386 e5e20779 Faidon Liambotis
387 e5e20779 Faidon Liambotis
    instances = self._SendRequest(HTTP_GET,
388 e5e20779 Faidon Liambotis
                                  "/%s/instances" % GANETI_RAPI_VERSION,
389 e5e20779 Faidon Liambotis
                                  query, None)
390 e5e20779 Faidon Liambotis
    if bulk:
391 e5e20779 Faidon Liambotis
      return instances
392 e5e20779 Faidon Liambotis
    else:
393 e5e20779 Faidon Liambotis
      return [i["id"] for i in instances]
394 e5e20779 Faidon Liambotis
395 e5e20779 Faidon Liambotis
  def GetInstance(self, instance):
396 e5e20779 Faidon Liambotis
    """Gets information about an instance.
397 e5e20779 Faidon Liambotis

398 e5e20779 Faidon Liambotis
    @type instance: str
399 e5e20779 Faidon Liambotis
    @param instance: instance whose info to return
400 e5e20779 Faidon Liambotis

401 e5e20779 Faidon Liambotis
    @rtype: dict
402 e5e20779 Faidon Liambotis
    @return: info about the instance
403 e5e20779 Faidon Liambotis

404 e5e20779 Faidon Liambotis
    """
405 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
406 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s" %
407 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), None, None)
408 e5e20779 Faidon Liambotis
409 e5e20779 Faidon Liambotis
  def GetInstanceInfo(self, instance, static=None):
410 e5e20779 Faidon Liambotis
    """Gets information about an instance.
411 e5e20779 Faidon Liambotis

412 e5e20779 Faidon Liambotis
    @type instance: string
413 e5e20779 Faidon Liambotis
    @param instance: Instance name
414 e5e20779 Faidon Liambotis
    @rtype: string
415 e5e20779 Faidon Liambotis
    @return: Job ID
416 e5e20779 Faidon Liambotis

417 e5e20779 Faidon Liambotis
    """
418 e5e20779 Faidon Liambotis
    if static is not None:
419 e5e20779 Faidon Liambotis
      query = [("static", static)]
420 e5e20779 Faidon Liambotis
    else:
421 e5e20779 Faidon Liambotis
      query = None
422 e5e20779 Faidon Liambotis
423 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
424 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/info" %
425 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), query, None)
426 e5e20779 Faidon Liambotis
427 e5e20779 Faidon Liambotis
  def CreateInstance(self, mode, name, disk_template, disks, nics,
428 e5e20779 Faidon Liambotis
                     **kwargs):
429 e5e20779 Faidon Liambotis
    """Creates a new instance.
430 e5e20779 Faidon Liambotis

431 e5e20779 Faidon Liambotis
    More details for parameters can be found in the RAPI documentation.
432 e5e20779 Faidon Liambotis

433 e5e20779 Faidon Liambotis
    @type mode: string
434 e5e20779 Faidon Liambotis
    @param mode: Instance creation mode
435 e5e20779 Faidon Liambotis
    @type name: string
436 e5e20779 Faidon Liambotis
    @param name: Hostname of the instance to create
437 e5e20779 Faidon Liambotis
    @type disk_template: string
438 e5e20779 Faidon Liambotis
    @param disk_template: Disk template for instance (e.g. plain, diskless,
439 e5e20779 Faidon Liambotis
                          file, or drbd)
440 e5e20779 Faidon Liambotis
    @type disks: list of dicts
441 e5e20779 Faidon Liambotis
    @param disks: List of disk definitions
442 e5e20779 Faidon Liambotis
    @type nics: list of dicts
443 e5e20779 Faidon Liambotis
    @param nics: List of NIC definitions
444 e5e20779 Faidon Liambotis
    @type dry_run: bool
445 e5e20779 Faidon Liambotis
    @keyword dry_run: whether to perform a dry run
446 e5e20779 Faidon Liambotis

447 a3ad611d Dimitris Aragiorgis
    @rtype: string
448 e5e20779 Faidon Liambotis
    @return: job id
449 e5e20779 Faidon Liambotis

450 e5e20779 Faidon Liambotis
    """
451 e5e20779 Faidon Liambotis
    query = []
452 e5e20779 Faidon Liambotis
453 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, kwargs.get("dry_run"))
454 e5e20779 Faidon Liambotis
455 e5e20779 Faidon Liambotis
    if _INST_CREATE_REQV1 in self.GetFeatures():
456 e5e20779 Faidon Liambotis
      # All required fields for request data version 1
457 e5e20779 Faidon Liambotis
      body = {
458 e5e20779 Faidon Liambotis
        _REQ_DATA_VERSION_FIELD: 1,
459 e5e20779 Faidon Liambotis
        "mode": mode,
460 e5e20779 Faidon Liambotis
        "name": name,
461 e5e20779 Faidon Liambotis
        "disk_template": disk_template,
462 e5e20779 Faidon Liambotis
        "disks": disks,
463 e5e20779 Faidon Liambotis
        "nics": nics,
464 e5e20779 Faidon Liambotis
        }
465 e5e20779 Faidon Liambotis
466 e5e20779 Faidon Liambotis
      conflicts = set(kwargs.iterkeys()) & set(body.iterkeys())
467 e5e20779 Faidon Liambotis
      if conflicts:
468 8d5795b4 Christos Stavrakakis
        raise GanetiApiError("Required fields cannot be specified as"
469 e5e20779 Faidon Liambotis
                             " keywords: %s" % ", ".join(conflicts))
470 e5e20779 Faidon Liambotis
471 e5e20779 Faidon Liambotis
      body.update((key, value) for key, value in kwargs.iteritems()
472 e5e20779 Faidon Liambotis
                  if key != "dry_run")
473 e5e20779 Faidon Liambotis
    else:
474 a3ad611d Dimitris Aragiorgis
      raise GanetiApiError("Server does not support new-style (version 1)"
475 a3ad611d Dimitris Aragiorgis
                           " instance creation requests")
476 e5e20779 Faidon Liambotis
477 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_POST, "/%s/instances" % GANETI_RAPI_VERSION,
478 e5e20779 Faidon Liambotis
                             query, body)
479 e5e20779 Faidon Liambotis
480 74267398 Christos Stavrakakis
  def DeleteInstance(self, instance, dry_run=False, shutdown_timeout=None):
481 e5e20779 Faidon Liambotis
    """Deletes an instance.
482 e5e20779 Faidon Liambotis

483 e5e20779 Faidon Liambotis
    @type instance: str
484 e5e20779 Faidon Liambotis
    @param instance: the instance to delete
485 e5e20779 Faidon Liambotis

486 a3ad611d Dimitris Aragiorgis
    @rtype: string
487 e5e20779 Faidon Liambotis
    @return: job id
488 e5e20779 Faidon Liambotis

489 e5e20779 Faidon Liambotis
    """
490 e5e20779 Faidon Liambotis
    query = []
491 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
492 e5e20779 Faidon Liambotis
493 74267398 Christos Stavrakakis
    body = None
494 74267398 Christos Stavrakakis
    if shutdown_timeout is not None:
495 74267398 Christos Stavrakakis
        body = {"shutdown_timeout": shutdown_timeout}
496 74267398 Christos Stavrakakis
497 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_DELETE,
498 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s" %
499 74267398 Christos Stavrakakis
                              (GANETI_RAPI_VERSION, instance)), query, body)
500 e5e20779 Faidon Liambotis
501 e5e20779 Faidon Liambotis
  def ModifyInstance(self, instance, **kwargs):
502 e5e20779 Faidon Liambotis
    """Modifies an instance.
503 e5e20779 Faidon Liambotis

504 e5e20779 Faidon Liambotis
    More details for parameters can be found in the RAPI documentation.
505 e5e20779 Faidon Liambotis

506 e5e20779 Faidon Liambotis
    @type instance: string
507 e5e20779 Faidon Liambotis
    @param instance: Instance name
508 a3ad611d Dimitris Aragiorgis
    @rtype: string
509 e5e20779 Faidon Liambotis
    @return: job id
510 e5e20779 Faidon Liambotis

511 e5e20779 Faidon Liambotis
    """
512 e5e20779 Faidon Liambotis
    body = kwargs
513 e5e20779 Faidon Liambotis
514 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
515 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/modify" %
516 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), None, body)
517 e5e20779 Faidon Liambotis
518 067dda99 Vangelis Koukis
  def ActivateInstanceDisks(self, instance, ignore_size=None):
519 067dda99 Vangelis Koukis
    """Activates an instance's disks.
520 067dda99 Vangelis Koukis

521 067dda99 Vangelis Koukis
    @type instance: string
522 067dda99 Vangelis Koukis
    @param instance: Instance name
523 067dda99 Vangelis Koukis
    @type ignore_size: bool
524 067dda99 Vangelis Koukis
    @param ignore_size: Whether to ignore recorded size
525 a3ad611d Dimitris Aragiorgis
    @rtype: string
526 067dda99 Vangelis Koukis
    @return: job id
527 067dda99 Vangelis Koukis

528 067dda99 Vangelis Koukis
    """
529 067dda99 Vangelis Koukis
    query = []
530 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, ignore_size, ("ignore_size", 1))
531 067dda99 Vangelis Koukis
532 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_PUT,
533 067dda99 Vangelis Koukis
                             ("/%s/instances/%s/activate-disks" %
534 067dda99 Vangelis Koukis
                              (GANETI_RAPI_VERSION, instance)), query, None)
535 067dda99 Vangelis Koukis
536 067dda99 Vangelis Koukis
  def DeactivateInstanceDisks(self, instance):
537 067dda99 Vangelis Koukis
    """Deactivates an instance's disks.
538 067dda99 Vangelis Koukis

539 067dda99 Vangelis Koukis
    @type instance: string
540 067dda99 Vangelis Koukis
    @param instance: Instance name
541 a3ad611d Dimitris Aragiorgis
    @rtype: string
542 067dda99 Vangelis Koukis
    @return: job id
543 067dda99 Vangelis Koukis

544 067dda99 Vangelis Koukis
    """
545 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_PUT,
546 067dda99 Vangelis Koukis
                             ("/%s/instances/%s/deactivate-disks" %
547 067dda99 Vangelis Koukis
                              (GANETI_RAPI_VERSION, instance)), None, None)
548 067dda99 Vangelis Koukis
549 a3ad611d Dimitris Aragiorgis
  def RecreateInstanceDisks(self, instance, disks=None, nodes=None):
550 a3ad611d Dimitris Aragiorgis
    """Recreate an instance's disks.
551 a3ad611d Dimitris Aragiorgis

552 a3ad611d Dimitris Aragiorgis
    @type instance: string
553 a3ad611d Dimitris Aragiorgis
    @param instance: Instance name
554 a3ad611d Dimitris Aragiorgis
    @type disks: list of int
555 a3ad611d Dimitris Aragiorgis
    @param disks: List of disk indexes
556 a3ad611d Dimitris Aragiorgis
    @type nodes: list of string
557 a3ad611d Dimitris Aragiorgis
    @param nodes: New instance nodes, if relocation is desired
558 a3ad611d Dimitris Aragiorgis
    @rtype: string
559 a3ad611d Dimitris Aragiorgis
    @return: job id
560 a3ad611d Dimitris Aragiorgis

561 a3ad611d Dimitris Aragiorgis
    """
562 a3ad611d Dimitris Aragiorgis
    body = {}
563 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, disks is not None, "disks", disks)
564 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, nodes is not None, "nodes", nodes)
565 a3ad611d Dimitris Aragiorgis
566 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_POST,
567 a3ad611d Dimitris Aragiorgis
                             ("/%s/instances/%s/recreate-disks" %
568 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, instance)), None, body)
569 a3ad611d Dimitris Aragiorgis
570 067dda99 Vangelis Koukis
  def GrowInstanceDisk(self, instance, disk, amount, wait_for_sync=None):
571 067dda99 Vangelis Koukis
    """Grows a disk of an instance.
572 067dda99 Vangelis Koukis

573 067dda99 Vangelis Koukis
    More details for parameters can be found in the RAPI documentation.
574 067dda99 Vangelis Koukis

575 067dda99 Vangelis Koukis
    @type instance: string
576 067dda99 Vangelis Koukis
    @param instance: Instance name
577 067dda99 Vangelis Koukis
    @type disk: integer
578 067dda99 Vangelis Koukis
    @param disk: Disk index
579 067dda99 Vangelis Koukis
    @type amount: integer
580 067dda99 Vangelis Koukis
    @param amount: Grow disk by this amount (MiB)
581 067dda99 Vangelis Koukis
    @type wait_for_sync: bool
582 067dda99 Vangelis Koukis
    @param wait_for_sync: Wait for disk to synchronize
583 a3ad611d Dimitris Aragiorgis
    @rtype: string
584 067dda99 Vangelis Koukis
    @return: job id
585 067dda99 Vangelis Koukis

586 067dda99 Vangelis Koukis
    """
587 067dda99 Vangelis Koukis
    body = {
588 067dda99 Vangelis Koukis
      "amount": amount,
589 067dda99 Vangelis Koukis
      }
590 067dda99 Vangelis Koukis
591 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, wait_for_sync is not None, "wait_for_sync", wait_for_sync)
592 067dda99 Vangelis Koukis
593 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_POST,
594 067dda99 Vangelis Koukis
                             ("/%s/instances/%s/disk/%s/grow" %
595 067dda99 Vangelis Koukis
                              (GANETI_RAPI_VERSION, instance, disk)),
596 067dda99 Vangelis Koukis
                             None, body)
597 067dda99 Vangelis Koukis
598 e5e20779 Faidon Liambotis
  def GetInstanceTags(self, instance):
599 e5e20779 Faidon Liambotis
    """Gets tags for an instance.
600 e5e20779 Faidon Liambotis

601 e5e20779 Faidon Liambotis
    @type instance: str
602 e5e20779 Faidon Liambotis
    @param instance: instance whose tags to return
603 e5e20779 Faidon Liambotis

604 e5e20779 Faidon Liambotis
    @rtype: list of str
605 e5e20779 Faidon Liambotis
    @return: tags for the instance
606 e5e20779 Faidon Liambotis

607 e5e20779 Faidon Liambotis
    """
608 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
609 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/tags" %
610 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), None, None)
611 e5e20779 Faidon Liambotis
612 e5e20779 Faidon Liambotis
  def AddInstanceTags(self, instance, tags, dry_run=False):
613 e5e20779 Faidon Liambotis
    """Adds tags to an instance.
614 e5e20779 Faidon Liambotis

615 e5e20779 Faidon Liambotis
    @type instance: str
616 e5e20779 Faidon Liambotis
    @param instance: instance to add tags to
617 e5e20779 Faidon Liambotis
    @type tags: list of str
618 e5e20779 Faidon Liambotis
    @param tags: tags to add to the instance
619 e5e20779 Faidon Liambotis
    @type dry_run: bool
620 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
621 e5e20779 Faidon Liambotis

622 a3ad611d Dimitris Aragiorgis
    @rtype: string
623 e5e20779 Faidon Liambotis
    @return: job id
624 e5e20779 Faidon Liambotis

625 e5e20779 Faidon Liambotis
    """
626 e5e20779 Faidon Liambotis
    query = [("tag", t) for t in tags]
627 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
628 e5e20779 Faidon Liambotis
629 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
630 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/tags" %
631 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), query, None)
632 e5e20779 Faidon Liambotis
633 e5e20779 Faidon Liambotis
  def DeleteInstanceTags(self, instance, tags, dry_run=False):
634 e5e20779 Faidon Liambotis
    """Deletes tags from an instance.
635 e5e20779 Faidon Liambotis

636 e5e20779 Faidon Liambotis
    @type instance: str
637 e5e20779 Faidon Liambotis
    @param instance: instance to delete tags from
638 e5e20779 Faidon Liambotis
    @type tags: list of str
639 e5e20779 Faidon Liambotis
    @param tags: tags to delete
640 e5e20779 Faidon Liambotis
    @type dry_run: bool
641 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
642 a3ad611d Dimitris Aragiorgis
    @rtype: string
643 a3ad611d Dimitris Aragiorgis
    @return: job id
644 e5e20779 Faidon Liambotis

645 e5e20779 Faidon Liambotis
    """
646 e5e20779 Faidon Liambotis
    query = [("tag", t) for t in tags]
647 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
648 e5e20779 Faidon Liambotis
649 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_DELETE,
650 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/tags" %
651 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), query, None)
652 e5e20779 Faidon Liambotis
653 e5e20779 Faidon Liambotis
  def RebootInstance(self, instance, reboot_type=None, ignore_secondaries=None,
654 74267398 Christos Stavrakakis
                     dry_run=False, shutdown_timeout=None):
655 e5e20779 Faidon Liambotis
    """Reboots an instance.
656 e5e20779 Faidon Liambotis

657 e5e20779 Faidon Liambotis
    @type instance: str
658 e5e20779 Faidon Liambotis
    @param instance: instance to rebot
659 e5e20779 Faidon Liambotis
    @type reboot_type: str
660 e5e20779 Faidon Liambotis
    @param reboot_type: one of: hard, soft, full
661 e5e20779 Faidon Liambotis
    @type ignore_secondaries: bool
662 e5e20779 Faidon Liambotis
    @param ignore_secondaries: if True, ignores errors for the secondary node
663 e5e20779 Faidon Liambotis
        while re-assembling disks (in hard-reboot mode only)
664 e5e20779 Faidon Liambotis
    @type dry_run: bool
665 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
666 a3ad611d Dimitris Aragiorgis
    @rtype: string
667 a3ad611d Dimitris Aragiorgis
    @return: job id
668 e5e20779 Faidon Liambotis

669 e5e20779 Faidon Liambotis
    """
670 e5e20779 Faidon Liambotis
    query = []
671 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
672 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, reboot_type, ("type", reboot_type))
673 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, ignore_secondaries is not None,
674 a3ad611d Dimitris Aragiorgis
              ("ignore_secondaries", ignore_secondaries))
675 e5e20779 Faidon Liambotis
676 74267398 Christos Stavrakakis
    body = None
677 74267398 Christos Stavrakakis
    if shutdown_timeout is not None:
678 74267398 Christos Stavrakakis
        body = {"shutdown_timeout": shutdown_timeout}
679 74267398 Christos Stavrakakis
680 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_POST,
681 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/reboot" %
682 74267398 Christos Stavrakakis
                              (GANETI_RAPI_VERSION, instance)), query, body)
683 e5e20779 Faidon Liambotis
684 74267398 Christos Stavrakakis
  def ShutdownInstance(self, instance, dry_run=False, no_remember=False,
685 74267398 Christos Stavrakakis
                       timeout=None):
686 e5e20779 Faidon Liambotis
    """Shuts down an instance.
687 e5e20779 Faidon Liambotis

688 e5e20779 Faidon Liambotis
    @type instance: str
689 e5e20779 Faidon Liambotis
    @param instance: the instance to shut down
690 e5e20779 Faidon Liambotis
    @type dry_run: bool
691 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
692 a3ad611d Dimitris Aragiorgis
    @type no_remember: bool
693 a3ad611d Dimitris Aragiorgis
    @param no_remember: if true, will not record the state change
694 a3ad611d Dimitris Aragiorgis
    @rtype: string
695 a3ad611d Dimitris Aragiorgis
    @return: job id
696 e5e20779 Faidon Liambotis

697 e5e20779 Faidon Liambotis
    """
698 e5e20779 Faidon Liambotis
    query = []
699 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
700 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, no_remember, ("no-remember", 1))
701 74267398 Christos Stavrakakis
    body = None
702 74267398 Christos Stavrakakis
    if timeout is not None:
703 74267398 Christos Stavrakakis
        body = {"timeout": timeout}
704 74267398 Christos Stavrakakis
705 e5e20779 Faidon Liambotis
706 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
707 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/shutdown" %
708 74267398 Christos Stavrakakis
                              (GANETI_RAPI_VERSION, instance)), query, body)
709 e5e20779 Faidon Liambotis
710 a3ad611d Dimitris Aragiorgis
  def StartupInstance(self, instance, dry_run=False, no_remember=False):
711 e5e20779 Faidon Liambotis
    """Starts up an instance.
712 e5e20779 Faidon Liambotis

713 e5e20779 Faidon Liambotis
    @type instance: str
714 e5e20779 Faidon Liambotis
    @param instance: the instance to start up
715 e5e20779 Faidon Liambotis
    @type dry_run: bool
716 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
717 a3ad611d Dimitris Aragiorgis
    @type no_remember: bool
718 a3ad611d Dimitris Aragiorgis
    @param no_remember: if true, will not record the state change
719 a3ad611d Dimitris Aragiorgis
    @rtype: string
720 a3ad611d Dimitris Aragiorgis
    @return: job id
721 e5e20779 Faidon Liambotis

722 e5e20779 Faidon Liambotis
    """
723 e5e20779 Faidon Liambotis
    query = []
724 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
725 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, no_remember, ("no-remember", 1))
726 e5e20779 Faidon Liambotis
727 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
728 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/startup" %
729 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), query, None)
730 e5e20779 Faidon Liambotis
731 067dda99 Vangelis Koukis
  def ReinstallInstance(self, instance, os=None, no_startup=False,
732 067dda99 Vangelis Koukis
                        osparams=None):
733 e5e20779 Faidon Liambotis
    """Reinstalls an instance.
734 e5e20779 Faidon Liambotis

735 e5e20779 Faidon Liambotis
    @type instance: str
736 e5e20779 Faidon Liambotis
    @param instance: The instance to reinstall
737 e5e20779 Faidon Liambotis
    @type os: str or None
738 e5e20779 Faidon Liambotis
    @param os: The operating system to reinstall. If None, the instance's
739 e5e20779 Faidon Liambotis
        current operating system will be installed again
740 e5e20779 Faidon Liambotis
    @type no_startup: bool
741 e5e20779 Faidon Liambotis
    @param no_startup: Whether to start the instance automatically
742 a3ad611d Dimitris Aragiorgis
    @rtype: string
743 a3ad611d Dimitris Aragiorgis
    @return: job id
744 e5e20779 Faidon Liambotis

745 e5e20779 Faidon Liambotis
    """
746 067dda99 Vangelis Koukis
    if _INST_REINSTALL_REQV1 in self.GetFeatures():
747 067dda99 Vangelis Koukis
      body = {
748 067dda99 Vangelis Koukis
        "start": not no_startup,
749 067dda99 Vangelis Koukis
        }
750 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, os is not None, "os", os)
751 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, osparams is not None, "osparams", osparams)
752 067dda99 Vangelis Koukis
      return self._SendRequest(HTTP_POST,
753 067dda99 Vangelis Koukis
                               ("/%s/instances/%s/reinstall" %
754 067dda99 Vangelis Koukis
                                (GANETI_RAPI_VERSION, instance)), None, body)
755 067dda99 Vangelis Koukis
756 067dda99 Vangelis Koukis
    # Use old request format
757 067dda99 Vangelis Koukis
    if osparams:
758 067dda99 Vangelis Koukis
      raise GanetiApiError("Server does not support specifying OS parameters"
759 067dda99 Vangelis Koukis
                           " for instance reinstallation")
760 067dda99 Vangelis Koukis
761 e5e20779 Faidon Liambotis
    query = []
762 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, os, ("os", os))
763 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, no_startup, ("nostartup", 1))
764 a3ad611d Dimitris Aragiorgis
765 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_POST,
766 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/reinstall" %
767 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), query, None)
768 e5e20779 Faidon Liambotis
769 e5e20779 Faidon Liambotis
  def ReplaceInstanceDisks(self, instance, disks=None, mode=REPLACE_DISK_AUTO,
770 a3ad611d Dimitris Aragiorgis
                           remote_node=None, iallocator=None):
771 e5e20779 Faidon Liambotis
    """Replaces disks on an instance.
772 e5e20779 Faidon Liambotis

773 e5e20779 Faidon Liambotis
    @type instance: str
774 e5e20779 Faidon Liambotis
    @param instance: instance whose disks to replace
775 e5e20779 Faidon Liambotis
    @type disks: list of ints
776 e5e20779 Faidon Liambotis
    @param disks: Indexes of disks to replace
777 e5e20779 Faidon Liambotis
    @type mode: str
778 e5e20779 Faidon Liambotis
    @param mode: replacement mode to use (defaults to replace_auto)
779 e5e20779 Faidon Liambotis
    @type remote_node: str or None
780 e5e20779 Faidon Liambotis
    @param remote_node: new secondary node to use (for use with
781 e5e20779 Faidon Liambotis
        replace_new_secondary mode)
782 e5e20779 Faidon Liambotis
    @type iallocator: str or None
783 e5e20779 Faidon Liambotis
    @param iallocator: instance allocator plugin to use (for use with
784 e5e20779 Faidon Liambotis
                       replace_auto mode)
785 e5e20779 Faidon Liambotis

786 a3ad611d Dimitris Aragiorgis
    @rtype: string
787 e5e20779 Faidon Liambotis
    @return: job id
788 e5e20779 Faidon Liambotis

789 e5e20779 Faidon Liambotis
    """
790 e5e20779 Faidon Liambotis
    query = [
791 e5e20779 Faidon Liambotis
      ("mode", mode),
792 e5e20779 Faidon Liambotis
      ]
793 e5e20779 Faidon Liambotis
794 a3ad611d Dimitris Aragiorgis
    # TODO: Convert to body parameters
795 e5e20779 Faidon Liambotis
796 a3ad611d Dimitris Aragiorgis
    if disks is not None:
797 a3ad611d Dimitris Aragiorgis
      _AppendIf(query, True,
798 a3ad611d Dimitris Aragiorgis
                ("disks", ",".join(str(idx) for idx in disks)))
799 e5e20779 Faidon Liambotis
800 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, remote_node is not None, ("remote_node", remote_node))
801 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, iallocator is not None, ("iallocator", iallocator))
802 e5e20779 Faidon Liambotis
803 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_POST,
804 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/replace-disks" %
805 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), query, None)
806 e5e20779 Faidon Liambotis
807 e5e20779 Faidon Liambotis
  def PrepareExport(self, instance, mode):
808 e5e20779 Faidon Liambotis
    """Prepares an instance for an export.
809 e5e20779 Faidon Liambotis

810 e5e20779 Faidon Liambotis
    @type instance: string
811 e5e20779 Faidon Liambotis
    @param instance: Instance name
812 e5e20779 Faidon Liambotis
    @type mode: string
813 e5e20779 Faidon Liambotis
    @param mode: Export mode
814 e5e20779 Faidon Liambotis
    @rtype: string
815 e5e20779 Faidon Liambotis
    @return: Job ID
816 e5e20779 Faidon Liambotis

817 e5e20779 Faidon Liambotis
    """
818 e5e20779 Faidon Liambotis
    query = [("mode", mode)]
819 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
820 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/prepare-export" %
821 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), query, None)
822 e5e20779 Faidon Liambotis
823 e5e20779 Faidon Liambotis
  def ExportInstance(self, instance, mode, destination, shutdown=None,
824 e5e20779 Faidon Liambotis
                     remove_instance=None,
825 e5e20779 Faidon Liambotis
                     x509_key_name=None, destination_x509_ca=None):
826 e5e20779 Faidon Liambotis
    """Exports an instance.
827 e5e20779 Faidon Liambotis

828 e5e20779 Faidon Liambotis
    @type instance: string
829 e5e20779 Faidon Liambotis
    @param instance: Instance name
830 e5e20779 Faidon Liambotis
    @type mode: string
831 e5e20779 Faidon Liambotis
    @param mode: Export mode
832 e5e20779 Faidon Liambotis
    @rtype: string
833 e5e20779 Faidon Liambotis
    @return: Job ID
834 e5e20779 Faidon Liambotis

835 e5e20779 Faidon Liambotis
    """
836 e5e20779 Faidon Liambotis
    body = {
837 e5e20779 Faidon Liambotis
      "destination": destination,
838 e5e20779 Faidon Liambotis
      "mode": mode,
839 e5e20779 Faidon Liambotis
      }
840 e5e20779 Faidon Liambotis
841 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, shutdown is not None, "shutdown", shutdown)
842 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, remove_instance is not None,
843 a3ad611d Dimitris Aragiorgis
               "remove_instance", remove_instance)
844 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, x509_key_name is not None, "x509_key_name", x509_key_name)
845 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, destination_x509_ca is not None,
846 a3ad611d Dimitris Aragiorgis
               "destination_x509_ca", destination_x509_ca)
847 e5e20779 Faidon Liambotis
848 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
849 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/export" %
850 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), None, body)
851 e5e20779 Faidon Liambotis
852 e5e20779 Faidon Liambotis
  def MigrateInstance(self, instance, mode=None, cleanup=None):
853 e5e20779 Faidon Liambotis
    """Migrates an instance.
854 e5e20779 Faidon Liambotis

855 e5e20779 Faidon Liambotis
    @type instance: string
856 e5e20779 Faidon Liambotis
    @param instance: Instance name
857 e5e20779 Faidon Liambotis
    @type mode: string
858 e5e20779 Faidon Liambotis
    @param mode: Migration mode
859 e5e20779 Faidon Liambotis
    @type cleanup: bool
860 e5e20779 Faidon Liambotis
    @param cleanup: Whether to clean up a previously failed migration
861 a3ad611d Dimitris Aragiorgis
    @rtype: string
862 a3ad611d Dimitris Aragiorgis
    @return: job id
863 e5e20779 Faidon Liambotis

864 e5e20779 Faidon Liambotis
    """
865 e5e20779 Faidon Liambotis
    body = {}
866 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, mode is not None, "mode", mode)
867 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, cleanup is not None, "cleanup", cleanup)
868 e5e20779 Faidon Liambotis
869 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_PUT,
870 a3ad611d Dimitris Aragiorgis
                             ("/%s/instances/%s/migrate" %
871 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, instance)), None, body)
872 e5e20779 Faidon Liambotis
873 a3ad611d Dimitris Aragiorgis
  def FailoverInstance(self, instance, iallocator=None,
874 a3ad611d Dimitris Aragiorgis
                       ignore_consistency=None, target_node=None):
875 a3ad611d Dimitris Aragiorgis
    """Does a failover of an instance.
876 a3ad611d Dimitris Aragiorgis

877 a3ad611d Dimitris Aragiorgis
    @type instance: string
878 a3ad611d Dimitris Aragiorgis
    @param instance: Instance name
879 a3ad611d Dimitris Aragiorgis
    @type iallocator: string
880 a3ad611d Dimitris Aragiorgis
    @param iallocator: Iallocator for deciding the target node for
881 a3ad611d Dimitris Aragiorgis
      shared-storage instances
882 a3ad611d Dimitris Aragiorgis
    @type ignore_consistency: bool
883 a3ad611d Dimitris Aragiorgis
    @param ignore_consistency: Whether to ignore disk consistency
884 a3ad611d Dimitris Aragiorgis
    @type target_node: string
885 a3ad611d Dimitris Aragiorgis
    @param target_node: Target node for shared-storage instances
886 a3ad611d Dimitris Aragiorgis
    @rtype: string
887 a3ad611d Dimitris Aragiorgis
    @return: job id
888 a3ad611d Dimitris Aragiorgis

889 a3ad611d Dimitris Aragiorgis
    """
890 a3ad611d Dimitris Aragiorgis
    body = {}
891 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, iallocator is not None, "iallocator", iallocator)
892 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, ignore_consistency is not None,
893 a3ad611d Dimitris Aragiorgis
               "ignore_consistency", ignore_consistency)
894 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, target_node is not None, "target_node", target_node)
895 e5e20779 Faidon Liambotis
896 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
897 a3ad611d Dimitris Aragiorgis
                             ("/%s/instances/%s/failover" %
898 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), None, body)
899 e5e20779 Faidon Liambotis
900 e5e20779 Faidon Liambotis
  def RenameInstance(self, instance, new_name, ip_check=None, name_check=None):
901 e5e20779 Faidon Liambotis
    """Changes the name of an instance.
902 e5e20779 Faidon Liambotis

903 e5e20779 Faidon Liambotis
    @type instance: string
904 e5e20779 Faidon Liambotis
    @param instance: Instance name
905 e5e20779 Faidon Liambotis
    @type new_name: string
906 e5e20779 Faidon Liambotis
    @param new_name: New instance name
907 e5e20779 Faidon Liambotis
    @type ip_check: bool
908 e5e20779 Faidon Liambotis
    @param ip_check: Whether to ensure instance's IP address is inactive
909 e5e20779 Faidon Liambotis
    @type name_check: bool
910 e5e20779 Faidon Liambotis
    @param name_check: Whether to ensure instance's name is resolvable
911 a3ad611d Dimitris Aragiorgis
    @rtype: string
912 a3ad611d Dimitris Aragiorgis
    @return: job id
913 e5e20779 Faidon Liambotis

914 e5e20779 Faidon Liambotis
    """
915 e5e20779 Faidon Liambotis
    body = {
916 e5e20779 Faidon Liambotis
      "new_name": new_name,
917 e5e20779 Faidon Liambotis
      }
918 e5e20779 Faidon Liambotis
919 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, ip_check is not None, "ip_check", ip_check)
920 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, name_check is not None, "name_check", name_check)
921 e5e20779 Faidon Liambotis
922 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
923 e5e20779 Faidon Liambotis
                             ("/%s/instances/%s/rename" %
924 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, instance)), None, body)
925 e5e20779 Faidon Liambotis
926 067dda99 Vangelis Koukis
  def GetInstanceConsole(self, instance):
927 067dda99 Vangelis Koukis
    """Request information for connecting to instance's console.
928 067dda99 Vangelis Koukis

929 067dda99 Vangelis Koukis
    @type instance: string
930 067dda99 Vangelis Koukis
    @param instance: Instance name
931 a3ad611d Dimitris Aragiorgis
    @rtype: dict
932 a3ad611d Dimitris Aragiorgis
    @return: dictionary containing information about instance's console
933 067dda99 Vangelis Koukis

934 067dda99 Vangelis Koukis
    """
935 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_GET,
936 067dda99 Vangelis Koukis
                             ("/%s/instances/%s/console" %
937 067dda99 Vangelis Koukis
                              (GANETI_RAPI_VERSION, instance)), None, None)
938 067dda99 Vangelis Koukis
939 70a0afab Christos Stavrakakis
  def GetJobs(self, bulk=False):
940 e5e20779 Faidon Liambotis
    """Gets all jobs for the cluster.
941 e5e20779 Faidon Liambotis

942 e5e20779 Faidon Liambotis
    @rtype: list of int
943 e5e20779 Faidon Liambotis
    @return: job ids for the cluster
944 e5e20779 Faidon Liambotis

945 e5e20779 Faidon Liambotis
    """
946 70a0afab Christos Stavrakakis
    query = []
947 70a0afab Christos Stavrakakis
    _AppendIf(query, bulk, ("bulk", 1))
948 70a0afab Christos Stavrakakis
949 70a0afab Christos Stavrakakis
    jobs = self._SendRequest(HTTP_GET, "/%s/jobs" % GANETI_RAPI_VERSION,
950 70a0afab Christos Stavrakakis
                             query, None)
951 70a0afab Christos Stavrakakis
    if bulk:
952 70a0afab Christos Stavrakakis
        return jobs
953 70a0afab Christos Stavrakakis
    else:
954 70a0afab Christos Stavrakakis
        return [int(j["id"]) for j in jobs]
955 70a0afab Christos Stavrakakis
956 e5e20779 Faidon Liambotis
957 e5e20779 Faidon Liambotis
  def GetJobStatus(self, job_id):
958 e5e20779 Faidon Liambotis
    """Gets the status of a job.
959 e5e20779 Faidon Liambotis

960 a3ad611d Dimitris Aragiorgis
    @type job_id: string
961 e5e20779 Faidon Liambotis
    @param job_id: job id whose status to query
962 e5e20779 Faidon Liambotis

963 e5e20779 Faidon Liambotis
    @rtype: dict
964 e5e20779 Faidon Liambotis
    @return: job status
965 e5e20779 Faidon Liambotis

966 e5e20779 Faidon Liambotis
    """
967 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
968 e5e20779 Faidon Liambotis
                             "/%s/jobs/%s" % (GANETI_RAPI_VERSION, job_id),
969 e5e20779 Faidon Liambotis
                             None, None)
970 e5e20779 Faidon Liambotis
971 a3ad611d Dimitris Aragiorgis
  def WaitForJobCompletion(self, job_id, period=5, retries=-1):
972 a3ad611d Dimitris Aragiorgis
    """Polls cluster for job status until completion.
973 a3ad611d Dimitris Aragiorgis

974 a3ad611d Dimitris Aragiorgis
    Completion is defined as any of the following states listed in
975 a3ad611d Dimitris Aragiorgis
    L{JOB_STATUS_FINALIZED}.
976 a3ad611d Dimitris Aragiorgis

977 a3ad611d Dimitris Aragiorgis
    @type job_id: string
978 a3ad611d Dimitris Aragiorgis
    @param job_id: job id to watch
979 a3ad611d Dimitris Aragiorgis
    @type period: int
980 a3ad611d Dimitris Aragiorgis
    @param period: how often to poll for status (optional, default 5s)
981 a3ad611d Dimitris Aragiorgis
    @type retries: int
982 a3ad611d Dimitris Aragiorgis
    @param retries: how many time to poll before giving up
983 a3ad611d Dimitris Aragiorgis
                    (optional, default -1 means unlimited)
984 a3ad611d Dimitris Aragiorgis

985 a3ad611d Dimitris Aragiorgis
    @rtype: bool
986 a3ad611d Dimitris Aragiorgis
    @return: C{True} if job succeeded or C{False} if failed/status timeout
987 a3ad611d Dimitris Aragiorgis
    @deprecated: It is recommended to use L{WaitForJobChange} wherever
988 a3ad611d Dimitris Aragiorgis
      possible; L{WaitForJobChange} returns immediately after a job changed and
989 a3ad611d Dimitris Aragiorgis
      does not use polling
990 a3ad611d Dimitris Aragiorgis

991 a3ad611d Dimitris Aragiorgis
    """
992 a3ad611d Dimitris Aragiorgis
    while retries != 0:
993 a3ad611d Dimitris Aragiorgis
      job_result = self.GetJobStatus(job_id)
994 a3ad611d Dimitris Aragiorgis
995 a3ad611d Dimitris Aragiorgis
      if job_result and job_result["status"] == JOB_STATUS_SUCCESS:
996 a3ad611d Dimitris Aragiorgis
        return True
997 a3ad611d Dimitris Aragiorgis
      elif not job_result or job_result["status"] in JOB_STATUS_FINALIZED:
998 a3ad611d Dimitris Aragiorgis
        return False
999 a3ad611d Dimitris Aragiorgis
1000 a3ad611d Dimitris Aragiorgis
      if period:
1001 a3ad611d Dimitris Aragiorgis
        time.sleep(period)
1002 a3ad611d Dimitris Aragiorgis
1003 a3ad611d Dimitris Aragiorgis
      if retries > 0:
1004 a3ad611d Dimitris Aragiorgis
        retries -= 1
1005 a3ad611d Dimitris Aragiorgis
1006 a3ad611d Dimitris Aragiorgis
    return False
1007 a3ad611d Dimitris Aragiorgis
1008 e5e20779 Faidon Liambotis
  def WaitForJobChange(self, job_id, fields, prev_job_info, prev_log_serial):
1009 e5e20779 Faidon Liambotis
    """Waits for job changes.
1010 e5e20779 Faidon Liambotis

1011 a3ad611d Dimitris Aragiorgis
    @type job_id: string
1012 e5e20779 Faidon Liambotis
    @param job_id: Job ID for which to wait
1013 a3ad611d Dimitris Aragiorgis
    @return: C{None} if no changes have been detected and a dict with two keys,
1014 a3ad611d Dimitris Aragiorgis
      C{job_info} and C{log_entries} otherwise.
1015 a3ad611d Dimitris Aragiorgis
    @rtype: dict
1016 e5e20779 Faidon Liambotis

1017 e5e20779 Faidon Liambotis
    """
1018 e5e20779 Faidon Liambotis
    body = {
1019 e5e20779 Faidon Liambotis
      "fields": fields,
1020 e5e20779 Faidon Liambotis
      "previous_job_info": prev_job_info,
1021 e5e20779 Faidon Liambotis
      "previous_log_serial": prev_log_serial,
1022 e5e20779 Faidon Liambotis
      }
1023 e5e20779 Faidon Liambotis
1024 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
1025 e5e20779 Faidon Liambotis
                             "/%s/jobs/%s/wait" % (GANETI_RAPI_VERSION, job_id),
1026 e5e20779 Faidon Liambotis
                             None, body)
1027 e5e20779 Faidon Liambotis
1028 e5e20779 Faidon Liambotis
  def CancelJob(self, job_id, dry_run=False):
1029 e5e20779 Faidon Liambotis
    """Cancels a job.
1030 e5e20779 Faidon Liambotis

1031 a3ad611d Dimitris Aragiorgis
    @type job_id: string
1032 e5e20779 Faidon Liambotis
    @param job_id: id of the job to delete
1033 e5e20779 Faidon Liambotis
    @type dry_run: bool
1034 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
1035 a3ad611d Dimitris Aragiorgis
    @rtype: tuple
1036 a3ad611d Dimitris Aragiorgis
    @return: tuple containing the result, and a message (bool, string)
1037 e5e20779 Faidon Liambotis

1038 e5e20779 Faidon Liambotis
    """
1039 e5e20779 Faidon Liambotis
    query = []
1040 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1041 e5e20779 Faidon Liambotis
1042 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_DELETE,
1043 e5e20779 Faidon Liambotis
                             "/%s/jobs/%s" % (GANETI_RAPI_VERSION, job_id),
1044 e5e20779 Faidon Liambotis
                             query, None)
1045 e5e20779 Faidon Liambotis
1046 e5e20779 Faidon Liambotis
  def GetNodes(self, bulk=False):
1047 e5e20779 Faidon Liambotis
    """Gets all nodes in the cluster.
1048 e5e20779 Faidon Liambotis

1049 e5e20779 Faidon Liambotis
    @type bulk: bool
1050 e5e20779 Faidon Liambotis
    @param bulk: whether to return all information about all instances
1051 e5e20779 Faidon Liambotis

1052 e5e20779 Faidon Liambotis
    @rtype: list of dict or str
1053 e5e20779 Faidon Liambotis
    @return: if bulk is true, info about nodes in the cluster,
1054 e5e20779 Faidon Liambotis
        else list of nodes in the cluster
1055 e5e20779 Faidon Liambotis

1056 e5e20779 Faidon Liambotis
    """
1057 e5e20779 Faidon Liambotis
    query = []
1058 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, bulk, ("bulk", 1))
1059 e5e20779 Faidon Liambotis
1060 e5e20779 Faidon Liambotis
    nodes = self._SendRequest(HTTP_GET, "/%s/nodes" % GANETI_RAPI_VERSION,
1061 e5e20779 Faidon Liambotis
                              query, None)
1062 e5e20779 Faidon Liambotis
    if bulk:
1063 e5e20779 Faidon Liambotis
      return nodes
1064 e5e20779 Faidon Liambotis
    else:
1065 e5e20779 Faidon Liambotis
      return [n["id"] for n in nodes]
1066 e5e20779 Faidon Liambotis
1067 e5e20779 Faidon Liambotis
  def GetNode(self, node):
1068 e5e20779 Faidon Liambotis
    """Gets information about a node.
1069 e5e20779 Faidon Liambotis

1070 e5e20779 Faidon Liambotis
    @type node: str
1071 e5e20779 Faidon Liambotis
    @param node: node whose info to return
1072 e5e20779 Faidon Liambotis

1073 e5e20779 Faidon Liambotis
    @rtype: dict
1074 e5e20779 Faidon Liambotis
    @return: info about the node
1075 e5e20779 Faidon Liambotis

1076 e5e20779 Faidon Liambotis
    """
1077 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
1078 e5e20779 Faidon Liambotis
                             "/%s/nodes/%s" % (GANETI_RAPI_VERSION, node),
1079 e5e20779 Faidon Liambotis
                             None, None)
1080 e5e20779 Faidon Liambotis
1081 e5e20779 Faidon Liambotis
  def EvacuateNode(self, node, iallocator=None, remote_node=None,
1082 a3ad611d Dimitris Aragiorgis
                   dry_run=False, early_release=None,
1083 a3ad611d Dimitris Aragiorgis
                   mode=None, accept_old=False):
1084 e5e20779 Faidon Liambotis
    """Evacuates instances from a Ganeti node.
1085 e5e20779 Faidon Liambotis

1086 e5e20779 Faidon Liambotis
    @type node: str
1087 e5e20779 Faidon Liambotis
    @param node: node to evacuate
1088 e5e20779 Faidon Liambotis
    @type iallocator: str or None
1089 e5e20779 Faidon Liambotis
    @param iallocator: instance allocator to use
1090 e5e20779 Faidon Liambotis
    @type remote_node: str
1091 e5e20779 Faidon Liambotis
    @param remote_node: node to evaucate to
1092 e5e20779 Faidon Liambotis
    @type dry_run: bool
1093 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
1094 e5e20779 Faidon Liambotis
    @type early_release: bool
1095 e5e20779 Faidon Liambotis
    @param early_release: whether to enable parallelization
1096 a3ad611d Dimitris Aragiorgis
    @type mode: string
1097 a3ad611d Dimitris Aragiorgis
    @param mode: Node evacuation mode
1098 a3ad611d Dimitris Aragiorgis
    @type accept_old: bool
1099 a3ad611d Dimitris Aragiorgis
    @param accept_old: Whether caller is ready to accept old-style (pre-2.5)
1100 a3ad611d Dimitris Aragiorgis
        results
1101 e5e20779 Faidon Liambotis

1102 a3ad611d Dimitris Aragiorgis
    @rtype: string, or a list for pre-2.5 results
1103 a3ad611d Dimitris Aragiorgis
    @return: Job ID or, if C{accept_old} is set and server is pre-2.5,
1104 a3ad611d Dimitris Aragiorgis
      list of (job ID, instance name, new secondary node); if dry_run was
1105 a3ad611d Dimitris Aragiorgis
      specified, then the actual move jobs were not submitted and the job IDs
1106 a3ad611d Dimitris Aragiorgis
      will be C{None}
1107 e5e20779 Faidon Liambotis

1108 e5e20779 Faidon Liambotis
    @raises GanetiApiError: if an iallocator and remote_node are both
1109 e5e20779 Faidon Liambotis
        specified
1110 e5e20779 Faidon Liambotis

1111 e5e20779 Faidon Liambotis
    """
1112 e5e20779 Faidon Liambotis
    if iallocator and remote_node:
1113 e5e20779 Faidon Liambotis
      raise GanetiApiError("Only one of iallocator or remote_node can be used")
1114 e5e20779 Faidon Liambotis
1115 e5e20779 Faidon Liambotis
    query = []
1116 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1117 a3ad611d Dimitris Aragiorgis
1118 a3ad611d Dimitris Aragiorgis
    if _NODE_EVAC_RES1 in self.GetFeatures():
1119 a3ad611d Dimitris Aragiorgis
      # Server supports body parameters
1120 a3ad611d Dimitris Aragiorgis
      body = {}
1121 a3ad611d Dimitris Aragiorgis
1122 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, iallocator is not None, "iallocator", iallocator)
1123 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, remote_node is not None, "remote_node", remote_node)
1124 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, early_release is not None,
1125 a3ad611d Dimitris Aragiorgis
                 "early_release", early_release)
1126 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, mode is not None, "mode", mode)
1127 a3ad611d Dimitris Aragiorgis
    else:
1128 a3ad611d Dimitris Aragiorgis
      # Pre-2.5 request format
1129 a3ad611d Dimitris Aragiorgis
      body = None
1130 a3ad611d Dimitris Aragiorgis
1131 a3ad611d Dimitris Aragiorgis
      if not accept_old:
1132 a3ad611d Dimitris Aragiorgis
        raise GanetiApiError("Server is version 2.4 or earlier and caller does"
1133 a3ad611d Dimitris Aragiorgis
                             " not accept old-style results (parameter"
1134 a3ad611d Dimitris Aragiorgis
                             " accept_old)")
1135 a3ad611d Dimitris Aragiorgis
1136 a3ad611d Dimitris Aragiorgis
      # Pre-2.5 servers can only evacuate secondaries
1137 a3ad611d Dimitris Aragiorgis
      if mode is not None and mode != NODE_EVAC_SEC:
1138 a3ad611d Dimitris Aragiorgis
        raise GanetiApiError("Server can only evacuate secondary instances")
1139 a3ad611d Dimitris Aragiorgis
1140 a3ad611d Dimitris Aragiorgis
      _AppendIf(query, iallocator, ("iallocator", iallocator))
1141 a3ad611d Dimitris Aragiorgis
      _AppendIf(query, remote_node, ("remote_node", remote_node))
1142 a3ad611d Dimitris Aragiorgis
      _AppendIf(query, early_release, ("early_release", 1))
1143 e5e20779 Faidon Liambotis
1144 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_POST,
1145 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/evacuate" %
1146 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, node)), query, body)
1147 e5e20779 Faidon Liambotis
1148 a3ad611d Dimitris Aragiorgis
  def MigrateNode(self, node, mode=None, dry_run=False, iallocator=None,
1149 a3ad611d Dimitris Aragiorgis
                  target_node=None):
1150 e5e20779 Faidon Liambotis
    """Migrates all primary instances from a node.
1151 e5e20779 Faidon Liambotis

1152 e5e20779 Faidon Liambotis
    @type node: str
1153 e5e20779 Faidon Liambotis
    @param node: node to migrate
1154 e5e20779 Faidon Liambotis
    @type mode: string
1155 e5e20779 Faidon Liambotis
    @param mode: if passed, it will overwrite the live migration type,
1156 e5e20779 Faidon Liambotis
        otherwise the hypervisor default will be used
1157 e5e20779 Faidon Liambotis
    @type dry_run: bool
1158 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
1159 a3ad611d Dimitris Aragiorgis
    @type iallocator: string
1160 a3ad611d Dimitris Aragiorgis
    @param iallocator: instance allocator to use
1161 a3ad611d Dimitris Aragiorgis
    @type target_node: string
1162 a3ad611d Dimitris Aragiorgis
    @param target_node: Target node for shared-storage instances
1163 e5e20779 Faidon Liambotis

1164 a3ad611d Dimitris Aragiorgis
    @rtype: string
1165 e5e20779 Faidon Liambotis
    @return: job id
1166 e5e20779 Faidon Liambotis

1167 e5e20779 Faidon Liambotis
    """
1168 e5e20779 Faidon Liambotis
    query = []
1169 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1170 e5e20779 Faidon Liambotis
1171 a3ad611d Dimitris Aragiorgis
    if _NODE_MIGRATE_REQV1 in self.GetFeatures():
1172 a3ad611d Dimitris Aragiorgis
      body = {}
1173 a3ad611d Dimitris Aragiorgis
1174 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, mode is not None, "mode", mode)
1175 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, iallocator is not None, "iallocator", iallocator)
1176 a3ad611d Dimitris Aragiorgis
      _SetItemIf(body, target_node is not None, "target_node", target_node)
1177 a3ad611d Dimitris Aragiorgis
1178 a3ad611d Dimitris Aragiorgis
      assert len(query) <= 1
1179 a3ad611d Dimitris Aragiorgis
1180 a3ad611d Dimitris Aragiorgis
      return self._SendRequest(HTTP_POST,
1181 a3ad611d Dimitris Aragiorgis
                               ("/%s/nodes/%s/migrate" %
1182 a3ad611d Dimitris Aragiorgis
                                (GANETI_RAPI_VERSION, node)), query, body)
1183 a3ad611d Dimitris Aragiorgis
    else:
1184 a3ad611d Dimitris Aragiorgis
      # Use old request format
1185 a3ad611d Dimitris Aragiorgis
      if target_node is not None:
1186 a3ad611d Dimitris Aragiorgis
        raise GanetiApiError("Server does not support specifying target node"
1187 a3ad611d Dimitris Aragiorgis
                             " for node migration")
1188 a3ad611d Dimitris Aragiorgis
1189 a3ad611d Dimitris Aragiorgis
      _AppendIf(query, mode is not None, ("mode", mode))
1190 a3ad611d Dimitris Aragiorgis
1191 a3ad611d Dimitris Aragiorgis
      return self._SendRequest(HTTP_POST,
1192 a3ad611d Dimitris Aragiorgis
                               ("/%s/nodes/%s/migrate" %
1193 a3ad611d Dimitris Aragiorgis
                                (GANETI_RAPI_VERSION, node)), query, None)
1194 e5e20779 Faidon Liambotis
1195 e5e20779 Faidon Liambotis
  def GetNodeRole(self, node):
1196 e5e20779 Faidon Liambotis
    """Gets the current role for a node.
1197 e5e20779 Faidon Liambotis

1198 e5e20779 Faidon Liambotis
    @type node: str
1199 e5e20779 Faidon Liambotis
    @param node: node whose role to return
1200 e5e20779 Faidon Liambotis

1201 e5e20779 Faidon Liambotis
    @rtype: str
1202 e5e20779 Faidon Liambotis
    @return: the current role for a node
1203 e5e20779 Faidon Liambotis

1204 e5e20779 Faidon Liambotis
    """
1205 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
1206 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/role" %
1207 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, node)), None, None)
1208 e5e20779 Faidon Liambotis
1209 a3ad611d Dimitris Aragiorgis
  def SetNodeRole(self, node, role, force=False, auto_promote=None):
1210 e5e20779 Faidon Liambotis
    """Sets the role for a node.
1211 e5e20779 Faidon Liambotis

1212 e5e20779 Faidon Liambotis
    @type node: str
1213 e5e20779 Faidon Liambotis
    @param node: the node whose role to set
1214 e5e20779 Faidon Liambotis
    @type role: str
1215 e5e20779 Faidon Liambotis
    @param role: the role to set for the node
1216 e5e20779 Faidon Liambotis
    @type force: bool
1217 e5e20779 Faidon Liambotis
    @param force: whether to force the role change
1218 a3ad611d Dimitris Aragiorgis
    @type auto_promote: bool
1219 a3ad611d Dimitris Aragiorgis
    @param auto_promote: Whether node(s) should be promoted to master candidate
1220 a3ad611d Dimitris Aragiorgis
                         if necessary
1221 e5e20779 Faidon Liambotis

1222 a3ad611d Dimitris Aragiorgis
    @rtype: string
1223 e5e20779 Faidon Liambotis
    @return: job id
1224 e5e20779 Faidon Liambotis

1225 e5e20779 Faidon Liambotis
    """
1226 a3ad611d Dimitris Aragiorgis
    query = []
1227 a3ad611d Dimitris Aragiorgis
    _AppendForceIf(query, force)
1228 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, auto_promote is not None, ("auto-promote", auto_promote))
1229 e5e20779 Faidon Liambotis
1230 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
1231 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/role" %
1232 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, node)), query, role)
1233 e5e20779 Faidon Liambotis
1234 a3ad611d Dimitris Aragiorgis
  def PowercycleNode(self, node, force=False):
1235 a3ad611d Dimitris Aragiorgis
    """Powercycles a node.
1236 a3ad611d Dimitris Aragiorgis

1237 a3ad611d Dimitris Aragiorgis
    @type node: string
1238 a3ad611d Dimitris Aragiorgis
    @param node: Node name
1239 a3ad611d Dimitris Aragiorgis
    @type force: bool
1240 a3ad611d Dimitris Aragiorgis
    @param force: Whether to force the operation
1241 a3ad611d Dimitris Aragiorgis
    @rtype: string
1242 a3ad611d Dimitris Aragiorgis
    @return: job id
1243 a3ad611d Dimitris Aragiorgis

1244 a3ad611d Dimitris Aragiorgis
    """
1245 a3ad611d Dimitris Aragiorgis
    query = []
1246 a3ad611d Dimitris Aragiorgis
    _AppendForceIf(query, force)
1247 a3ad611d Dimitris Aragiorgis
1248 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_POST,
1249 a3ad611d Dimitris Aragiorgis
                             ("/%s/nodes/%s/powercycle" %
1250 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, node)), query, None)
1251 a3ad611d Dimitris Aragiorgis
1252 a3ad611d Dimitris Aragiorgis
  def ModifyNode(self, node, **kwargs):
1253 a3ad611d Dimitris Aragiorgis
    """Modifies a node.
1254 a3ad611d Dimitris Aragiorgis

1255 a3ad611d Dimitris Aragiorgis
    More details for parameters can be found in the RAPI documentation.
1256 a3ad611d Dimitris Aragiorgis

1257 a3ad611d Dimitris Aragiorgis
    @type node: string
1258 a3ad611d Dimitris Aragiorgis
    @param node: Node name
1259 a3ad611d Dimitris Aragiorgis
    @rtype: string
1260 a3ad611d Dimitris Aragiorgis
    @return: job id
1261 a3ad611d Dimitris Aragiorgis

1262 a3ad611d Dimitris Aragiorgis
    """
1263 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_POST,
1264 a3ad611d Dimitris Aragiorgis
                             ("/%s/nodes/%s/modify" %
1265 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, node)), None, kwargs)
1266 a3ad611d Dimitris Aragiorgis
1267 e5e20779 Faidon Liambotis
  def GetNodeStorageUnits(self, node, storage_type, output_fields):
1268 e5e20779 Faidon Liambotis
    """Gets the storage units for a node.
1269 e5e20779 Faidon Liambotis

1270 e5e20779 Faidon Liambotis
    @type node: str
1271 e5e20779 Faidon Liambotis
    @param node: the node whose storage units to return
1272 e5e20779 Faidon Liambotis
    @type storage_type: str
1273 e5e20779 Faidon Liambotis
    @param storage_type: storage type whose units to return
1274 e5e20779 Faidon Liambotis
    @type output_fields: str
1275 e5e20779 Faidon Liambotis
    @param output_fields: storage type fields to return
1276 e5e20779 Faidon Liambotis

1277 a3ad611d Dimitris Aragiorgis
    @rtype: string
1278 e5e20779 Faidon Liambotis
    @return: job id where results can be retrieved
1279 e5e20779 Faidon Liambotis

1280 e5e20779 Faidon Liambotis
    """
1281 e5e20779 Faidon Liambotis
    query = [
1282 e5e20779 Faidon Liambotis
      ("storage_type", storage_type),
1283 e5e20779 Faidon Liambotis
      ("output_fields", output_fields),
1284 e5e20779 Faidon Liambotis
      ]
1285 e5e20779 Faidon Liambotis
1286 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
1287 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/storage" %
1288 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, node)), query, None)
1289 e5e20779 Faidon Liambotis
1290 e5e20779 Faidon Liambotis
  def ModifyNodeStorageUnits(self, node, storage_type, name, allocatable=None):
1291 e5e20779 Faidon Liambotis
    """Modifies parameters of storage units on the node.
1292 e5e20779 Faidon Liambotis

1293 e5e20779 Faidon Liambotis
    @type node: str
1294 e5e20779 Faidon Liambotis
    @param node: node whose storage units to modify
1295 e5e20779 Faidon Liambotis
    @type storage_type: str
1296 e5e20779 Faidon Liambotis
    @param storage_type: storage type whose units to modify
1297 e5e20779 Faidon Liambotis
    @type name: str
1298 e5e20779 Faidon Liambotis
    @param name: name of the storage unit
1299 e5e20779 Faidon Liambotis
    @type allocatable: bool or None
1300 e5e20779 Faidon Liambotis
    @param allocatable: Whether to set the "allocatable" flag on the storage
1301 e5e20779 Faidon Liambotis
                        unit (None=no modification, True=set, False=unset)
1302 e5e20779 Faidon Liambotis

1303 a3ad611d Dimitris Aragiorgis
    @rtype: string
1304 e5e20779 Faidon Liambotis
    @return: job id
1305 e5e20779 Faidon Liambotis

1306 e5e20779 Faidon Liambotis
    """
1307 e5e20779 Faidon Liambotis
    query = [
1308 e5e20779 Faidon Liambotis
      ("storage_type", storage_type),
1309 e5e20779 Faidon Liambotis
      ("name", name),
1310 e5e20779 Faidon Liambotis
      ]
1311 e5e20779 Faidon Liambotis
1312 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, allocatable is not None, ("allocatable", allocatable))
1313 e5e20779 Faidon Liambotis
1314 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
1315 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/storage/modify" %
1316 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, node)), query, None)
1317 e5e20779 Faidon Liambotis
1318 e5e20779 Faidon Liambotis
  def RepairNodeStorageUnits(self, node, storage_type, name):
1319 e5e20779 Faidon Liambotis
    """Repairs a storage unit on the node.
1320 e5e20779 Faidon Liambotis

1321 e5e20779 Faidon Liambotis
    @type node: str
1322 e5e20779 Faidon Liambotis
    @param node: node whose storage units to repair
1323 e5e20779 Faidon Liambotis
    @type storage_type: str
1324 e5e20779 Faidon Liambotis
    @param storage_type: storage type to repair
1325 e5e20779 Faidon Liambotis
    @type name: str
1326 e5e20779 Faidon Liambotis
    @param name: name of the storage unit to repair
1327 e5e20779 Faidon Liambotis

1328 a3ad611d Dimitris Aragiorgis
    @rtype: string
1329 e5e20779 Faidon Liambotis
    @return: job id
1330 e5e20779 Faidon Liambotis

1331 e5e20779 Faidon Liambotis
    """
1332 e5e20779 Faidon Liambotis
    query = [
1333 e5e20779 Faidon Liambotis
      ("storage_type", storage_type),
1334 e5e20779 Faidon Liambotis
      ("name", name),
1335 e5e20779 Faidon Liambotis
      ]
1336 e5e20779 Faidon Liambotis
1337 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
1338 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/storage/repair" %
1339 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, node)), query, None)
1340 e5e20779 Faidon Liambotis
1341 e5e20779 Faidon Liambotis
  def GetNodeTags(self, node):
1342 e5e20779 Faidon Liambotis
    """Gets the tags for a node.
1343 e5e20779 Faidon Liambotis

1344 e5e20779 Faidon Liambotis
    @type node: str
1345 e5e20779 Faidon Liambotis
    @param node: node whose tags to return
1346 e5e20779 Faidon Liambotis

1347 e5e20779 Faidon Liambotis
    @rtype: list of str
1348 e5e20779 Faidon Liambotis
    @return: tags for the node
1349 e5e20779 Faidon Liambotis

1350 e5e20779 Faidon Liambotis
    """
1351 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_GET,
1352 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/tags" %
1353 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, node)), None, None)
1354 e5e20779 Faidon Liambotis
1355 e5e20779 Faidon Liambotis
  def AddNodeTags(self, node, tags, dry_run=False):
1356 e5e20779 Faidon Liambotis
    """Adds tags to a node.
1357 e5e20779 Faidon Liambotis

1358 e5e20779 Faidon Liambotis
    @type node: str
1359 e5e20779 Faidon Liambotis
    @param node: node to add tags to
1360 e5e20779 Faidon Liambotis
    @type tags: list of str
1361 e5e20779 Faidon Liambotis
    @param tags: tags to add to the node
1362 e5e20779 Faidon Liambotis
    @type dry_run: bool
1363 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
1364 e5e20779 Faidon Liambotis

1365 a3ad611d Dimitris Aragiorgis
    @rtype: string
1366 e5e20779 Faidon Liambotis
    @return: job id
1367 e5e20779 Faidon Liambotis

1368 e5e20779 Faidon Liambotis
    """
1369 e5e20779 Faidon Liambotis
    query = [("tag", t) for t in tags]
1370 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1371 e5e20779 Faidon Liambotis
1372 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_PUT,
1373 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/tags" %
1374 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, node)), query, tags)
1375 e5e20779 Faidon Liambotis
1376 e5e20779 Faidon Liambotis
  def DeleteNodeTags(self, node, tags, dry_run=False):
1377 e5e20779 Faidon Liambotis
    """Delete tags from a node.
1378 e5e20779 Faidon Liambotis

1379 e5e20779 Faidon Liambotis
    @type node: str
1380 e5e20779 Faidon Liambotis
    @param node: node to remove tags from
1381 e5e20779 Faidon Liambotis
    @type tags: list of str
1382 e5e20779 Faidon Liambotis
    @param tags: tags to remove from the node
1383 e5e20779 Faidon Liambotis
    @type dry_run: bool
1384 e5e20779 Faidon Liambotis
    @param dry_run: whether to perform a dry run
1385 e5e20779 Faidon Liambotis

1386 a3ad611d Dimitris Aragiorgis
    @rtype: string
1387 e5e20779 Faidon Liambotis
    @return: job id
1388 e5e20779 Faidon Liambotis

1389 e5e20779 Faidon Liambotis
    """
1390 e5e20779 Faidon Liambotis
    query = [("tag", t) for t in tags]
1391 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1392 e5e20779 Faidon Liambotis
1393 e5e20779 Faidon Liambotis
    return self._SendRequest(HTTP_DELETE,
1394 e5e20779 Faidon Liambotis
                             ("/%s/nodes/%s/tags" %
1395 e5e20779 Faidon Liambotis
                              (GANETI_RAPI_VERSION, node)), query, None)
1396 067dda99 Vangelis Koukis
1397 a3ad611d Dimitris Aragiorgis
  def GetNetworks(self, bulk=False):
1398 a3ad611d Dimitris Aragiorgis
    """Gets all networks in the cluster.
1399 a3ad611d Dimitris Aragiorgis

1400 a3ad611d Dimitris Aragiorgis
    @type bulk: bool
1401 a3ad611d Dimitris Aragiorgis
    @param bulk: whether to return all information about the networks
1402 a3ad611d Dimitris Aragiorgis

1403 a3ad611d Dimitris Aragiorgis
    @rtype: list of dict or str
1404 a3ad611d Dimitris Aragiorgis
    @return: if bulk is true, a list of dictionaries with info about all
1405 a3ad611d Dimitris Aragiorgis
        networks in the cluster, else a list of names of those networks
1406 a3ad611d Dimitris Aragiorgis

1407 a3ad611d Dimitris Aragiorgis
    """
1408 a3ad611d Dimitris Aragiorgis
    query = []
1409 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, bulk, ("bulk", 1))
1410 a3ad611d Dimitris Aragiorgis
1411 a3ad611d Dimitris Aragiorgis
    networks = self._SendRequest(HTTP_GET, "/%s/networks" % GANETI_RAPI_VERSION,
1412 a3ad611d Dimitris Aragiorgis
                               query, None)
1413 a3ad611d Dimitris Aragiorgis
    if bulk:
1414 a3ad611d Dimitris Aragiorgis
      return networks
1415 a3ad611d Dimitris Aragiorgis
    else:
1416 a3ad611d Dimitris Aragiorgis
      return [n["name"] for n in networks]
1417 a3ad611d Dimitris Aragiorgis
1418 a3ad611d Dimitris Aragiorgis
  def GetNetwork(self, network):
1419 a3ad611d Dimitris Aragiorgis
    """Gets information about a network.
1420 a3ad611d Dimitris Aragiorgis

1421 a3ad611d Dimitris Aragiorgis
    @type group: str
1422 a3ad611d Dimitris Aragiorgis
    @param group: name of the network whose info to return
1423 a3ad611d Dimitris Aragiorgis

1424 a3ad611d Dimitris Aragiorgis
    @rtype: dict
1425 a3ad611d Dimitris Aragiorgis
    @return: info about the network
1426 a3ad611d Dimitris Aragiorgis

1427 a3ad611d Dimitris Aragiorgis
    """
1428 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_GET,
1429 a3ad611d Dimitris Aragiorgis
                             "/%s/networks/%s" % (GANETI_RAPI_VERSION, network),
1430 a3ad611d Dimitris Aragiorgis
                             None, None)
1431 a3ad611d Dimitris Aragiorgis
1432 a3ad611d Dimitris Aragiorgis
  def CreateNetwork(self, network_name, network, gateway=None, network6=None,
1433 bc37fa88 Dimitris Aragiorgis
                    gateway6=None, mac_prefix=None,
1434 a406663f Dimitris Aragiorgis
                    add_reserved_ips=None, tags=[],
1435 a406663f Dimitris Aragiorgis
                    conflicts_check=False, dry_run=False):
1436 a3ad611d Dimitris Aragiorgis
    """Creates a new network.
1437 a3ad611d Dimitris Aragiorgis

1438 a3ad611d Dimitris Aragiorgis
    @type name: str
1439 a3ad611d Dimitris Aragiorgis
    @param name: the name of network to create
1440 a3ad611d Dimitris Aragiorgis
    @type dry_run: bool
1441 a3ad611d Dimitris Aragiorgis
    @param dry_run: whether to peform a dry run
1442 a3ad611d Dimitris Aragiorgis

1443 a3ad611d Dimitris Aragiorgis
    @rtype: string
1444 a3ad611d Dimitris Aragiorgis
    @return: job id
1445 a3ad611d Dimitris Aragiorgis

1446 a3ad611d Dimitris Aragiorgis
    """
1447 a3ad611d Dimitris Aragiorgis
    query = []
1448 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1449 a3ad611d Dimitris Aragiorgis
1450 a3ad611d Dimitris Aragiorgis
    body = {
1451 a3ad611d Dimitris Aragiorgis
      "network_name": network_name,
1452 a3ad611d Dimitris Aragiorgis
      "gateway": gateway,
1453 a3ad611d Dimitris Aragiorgis
      "network": network,
1454 a3ad611d Dimitris Aragiorgis
      "gateway6": gateway6,
1455 a3ad611d Dimitris Aragiorgis
      "network6": network6,
1456 a3ad611d Dimitris Aragiorgis
      "mac_prefix": mac_prefix,
1457 a406663f Dimitris Aragiorgis
      "add_reserved_ips": add_reserved_ips,
1458 6de25206 Dimitris Aragiorgis
      "conflicts_check": conflicts_check,
1459 a406663f Dimitris Aragiorgis
      "tags": tags,
1460 a3ad611d Dimitris Aragiorgis
      }
1461 a3ad611d Dimitris Aragiorgis
1462 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_POST, "/%s/networks" % GANETI_RAPI_VERSION,
1463 a3ad611d Dimitris Aragiorgis
                             query, body)
1464 a3ad611d Dimitris Aragiorgis
1465 6de25206 Dimitris Aragiorgis
  def ConnectNetwork(self, network_name, group_name, mode, link,
1466 a406663f Dimitris Aragiorgis
                     conflicts_check=False, depends=None, dry_run=False):
1467 a3ad611d Dimitris Aragiorgis
    """Connects a Network to a NodeGroup with the given netparams
1468 a3ad611d Dimitris Aragiorgis

1469 a3ad611d Dimitris Aragiorgis
    """
1470 a3ad611d Dimitris Aragiorgis
    body = {
1471 a3ad611d Dimitris Aragiorgis
      "group_name": group_name,
1472 a3ad611d Dimitris Aragiorgis
      "network_mode": mode,
1473 6de25206 Dimitris Aragiorgis
      "network_link": link,
1474 6de25206 Dimitris Aragiorgis
      "conflicts_check": conflicts_check,
1475 a3ad611d Dimitris Aragiorgis
      }
1476 a3ad611d Dimitris Aragiorgis
1477 a3ad611d Dimitris Aragiorgis
    if depends:
1478 99af08a4 Christos Stavrakakis
      body['depends'] = depends
1479 a3ad611d Dimitris Aragiorgis
1480 a406663f Dimitris Aragiorgis
    query = []
1481 a406663f Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1482 a3ad611d Dimitris Aragiorgis
1483 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_PUT,
1484 a3ad611d Dimitris Aragiorgis
                             ("/%s/networks/%s/connect" %
1485 a406663f Dimitris Aragiorgis
                             (GANETI_RAPI_VERSION, network_name)), query, body)
1486 a3ad611d Dimitris Aragiorgis
1487 a406663f Dimitris Aragiorgis
  def DisconnectNetwork(self, network_name, group_name,
1488 a406663f Dimitris Aragiorgis
                        depends=None, dry_run=False):
1489 a3ad611d Dimitris Aragiorgis
    """Connects a Network to a NodeGroup with the given netparams
1490 a3ad611d Dimitris Aragiorgis

1491 a3ad611d Dimitris Aragiorgis
    """
1492 a3ad611d Dimitris Aragiorgis
    body = {
1493 a3ad611d Dimitris Aragiorgis
      "group_name": group_name
1494 a3ad611d Dimitris Aragiorgis
      }
1495 a3ad611d Dimitris Aragiorgis
1496 a3ad611d Dimitris Aragiorgis
    if depends:
1497 99af08a4 Christos Stavrakakis
      body['depends'] = depends
1498 a3ad611d Dimitris Aragiorgis
1499 a406663f Dimitris Aragiorgis
    query = []
1500 a406663f Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1501 a406663f Dimitris Aragiorgis
1502 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_PUT,
1503 a3ad611d Dimitris Aragiorgis
                             ("/%s/networks/%s/disconnect" %
1504 a406663f Dimitris Aragiorgis
                             (GANETI_RAPI_VERSION, network_name)), query, body)
1505 a406663f Dimitris Aragiorgis
1506 a406663f Dimitris Aragiorgis
1507 a406663f Dimitris Aragiorgis
  def ModifyNetwork(self, network, **kwargs):
1508 a406663f Dimitris Aragiorgis
    """Modifies a network.
1509 a406663f Dimitris Aragiorgis

1510 a406663f Dimitris Aragiorgis
    More details for parameters can be found in the RAPI documentation.
1511 a3ad611d Dimitris Aragiorgis

1512 a406663f Dimitris Aragiorgis
    @type network: string
1513 a406663f Dimitris Aragiorgis
    @param network: Network name
1514 a406663f Dimitris Aragiorgis
    @rtype: string
1515 a406663f Dimitris Aragiorgis
    @return: job id
1516 a3ad611d Dimitris Aragiorgis

1517 a406663f Dimitris Aragiorgis
    """
1518 a406663f Dimitris Aragiorgis
    return self._SendRequest(HTTP_PUT,
1519 a406663f Dimitris Aragiorgis
                             ("/%s/networks/%s/modify" %
1520 a406663f Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, network)), None, kwargs)
1521 a406663f Dimitris Aragiorgis
1522 a406663f Dimitris Aragiorgis
  def DeleteNetwork(self, network, depends=None, dry_run=False):
1523 a3ad611d Dimitris Aragiorgis
    """Deletes a network.
1524 a3ad611d Dimitris Aragiorgis

1525 a3ad611d Dimitris Aragiorgis
    @type group: str
1526 a3ad611d Dimitris Aragiorgis
    @param group: the network to delete
1527 a3ad611d Dimitris Aragiorgis
    @type dry_run: bool
1528 a3ad611d Dimitris Aragiorgis
    @param dry_run: whether to peform a dry run
1529 a3ad611d Dimitris Aragiorgis

1530 a3ad611d Dimitris Aragiorgis
    @rtype: string
1531 a3ad611d Dimitris Aragiorgis
    @return: job id
1532 a3ad611d Dimitris Aragiorgis

1533 a3ad611d Dimitris Aragiorgis
    """
1534 a3ad611d Dimitris Aragiorgis
    body = {}
1535 a3ad611d Dimitris Aragiorgis
    if depends:
1536 99af08a4 Christos Stavrakakis
      body['depends'] = depends
1537 a3ad611d Dimitris Aragiorgis
1538 a406663f Dimitris Aragiorgis
    query = []
1539 a406663f Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1540 a3ad611d Dimitris Aragiorgis
1541 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_DELETE,
1542 a3ad611d Dimitris Aragiorgis
                             ("/%s/networks/%s" %
1543 a406663f Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, network)), query, body)
1544 a406663f Dimitris Aragiorgis
1545 a406663f Dimitris Aragiorgis
  def GetNetworkTags(self, network):
1546 a406663f Dimitris Aragiorgis
    """Gets tags for a network.
1547 a406663f Dimitris Aragiorgis

1548 a406663f Dimitris Aragiorgis
    @type network: string
1549 a406663f Dimitris Aragiorgis
    @param network: Node group whose tags to return
1550 a406663f Dimitris Aragiorgis

1551 a406663f Dimitris Aragiorgis
    @rtype: list of strings
1552 a406663f Dimitris Aragiorgis
    @return: tags for the network
1553 a406663f Dimitris Aragiorgis

1554 a406663f Dimitris Aragiorgis
    """
1555 a406663f Dimitris Aragiorgis
    return self._SendRequest(HTTP_GET,
1556 a406663f Dimitris Aragiorgis
                             ("/%s/networks/%s/tags" %
1557 a406663f Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, network)), None, None)
1558 a406663f Dimitris Aragiorgis
1559 a406663f Dimitris Aragiorgis
  def AddNetworkTags(self, network, tags, dry_run=False):
1560 a406663f Dimitris Aragiorgis
    """Adds tags to a network.
1561 a406663f Dimitris Aragiorgis

1562 a406663f Dimitris Aragiorgis
    @type network: str
1563 a406663f Dimitris Aragiorgis
    @param network: network to add tags to
1564 a406663f Dimitris Aragiorgis
    @type tags: list of string
1565 a406663f Dimitris Aragiorgis
    @param tags: tags to add to the network
1566 a406663f Dimitris Aragiorgis
    @type dry_run: bool
1567 a406663f Dimitris Aragiorgis
    @param dry_run: whether to perform a dry run
1568 a406663f Dimitris Aragiorgis

1569 a406663f Dimitris Aragiorgis
    @rtype: string
1570 a406663f Dimitris Aragiorgis
    @return: job id
1571 a406663f Dimitris Aragiorgis

1572 a406663f Dimitris Aragiorgis
    """
1573 a406663f Dimitris Aragiorgis
    query = [("tag", t) for t in tags]
1574 a406663f Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1575 a406663f Dimitris Aragiorgis
1576 a406663f Dimitris Aragiorgis
    return self._SendRequest(HTTP_PUT,
1577 a406663f Dimitris Aragiorgis
                             ("/%s/networks/%s/tags" %
1578 a406663f Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, network)), query, None)
1579 a406663f Dimitris Aragiorgis
1580 a406663f Dimitris Aragiorgis
  def DeleteNetworkTags(self, network, tags, dry_run=False):
1581 a406663f Dimitris Aragiorgis
    """Deletes tags from a network.
1582 a406663f Dimitris Aragiorgis

1583 a406663f Dimitris Aragiorgis
    @type network: str
1584 a406663f Dimitris Aragiorgis
    @param network: network to delete tags from
1585 a406663f Dimitris Aragiorgis
    @type tags: list of string
1586 a406663f Dimitris Aragiorgis
    @param tags: tags to delete
1587 a406663f Dimitris Aragiorgis
    @type dry_run: bool
1588 a406663f Dimitris Aragiorgis
    @param dry_run: whether to perform a dry run
1589 a406663f Dimitris Aragiorgis
    @rtype: string
1590 a406663f Dimitris Aragiorgis
    @return: job id
1591 a406663f Dimitris Aragiorgis

1592 a406663f Dimitris Aragiorgis
    """
1593 a406663f Dimitris Aragiorgis
    query = [("tag", t) for t in tags]
1594 a406663f Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1595 a406663f Dimitris Aragiorgis
1596 a406663f Dimitris Aragiorgis
    return self._SendRequest(HTTP_DELETE,
1597 a406663f Dimitris Aragiorgis
                             ("/%s/networks/%s/tags" %
1598 a406663f Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, network)), query, None)
1599 a406663f Dimitris Aragiorgis
1600 a3ad611d Dimitris Aragiorgis
1601 067dda99 Vangelis Koukis
  def GetGroups(self, bulk=False):
1602 067dda99 Vangelis Koukis
    """Gets all node groups in the cluster.
1603 067dda99 Vangelis Koukis

1604 067dda99 Vangelis Koukis
    @type bulk: bool
1605 067dda99 Vangelis Koukis
    @param bulk: whether to return all information about the groups
1606 067dda99 Vangelis Koukis

1607 067dda99 Vangelis Koukis
    @rtype: list of dict or str
1608 067dda99 Vangelis Koukis
    @return: if bulk is true, a list of dictionaries with info about all node
1609 067dda99 Vangelis Koukis
        groups in the cluster, else a list of names of those node groups
1610 067dda99 Vangelis Koukis

1611 067dda99 Vangelis Koukis
    """
1612 067dda99 Vangelis Koukis
    query = []
1613 a3ad611d Dimitris Aragiorgis
    _AppendIf(query, bulk, ("bulk", 1))
1614 067dda99 Vangelis Koukis
1615 067dda99 Vangelis Koukis
    groups = self._SendRequest(HTTP_GET, "/%s/groups" % GANETI_RAPI_VERSION,
1616 067dda99 Vangelis Koukis
                               query, None)
1617 067dda99 Vangelis Koukis
    if bulk:
1618 067dda99 Vangelis Koukis
      return groups
1619 067dda99 Vangelis Koukis
    else:
1620 067dda99 Vangelis Koukis
      return [g["name"] for g in groups]
1621 067dda99 Vangelis Koukis
1622 067dda99 Vangelis Koukis
  def GetGroup(self, group):
1623 067dda99 Vangelis Koukis
    """Gets information about a node group.
1624 067dda99 Vangelis Koukis

1625 067dda99 Vangelis Koukis
    @type group: str
1626 067dda99 Vangelis Koukis
    @param group: name of the node group whose info to return
1627 067dda99 Vangelis Koukis

1628 067dda99 Vangelis Koukis
    @rtype: dict
1629 067dda99 Vangelis Koukis
    @return: info about the node group
1630 067dda99 Vangelis Koukis

1631 067dda99 Vangelis Koukis
    """
1632 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_GET,
1633 067dda99 Vangelis Koukis
                             "/%s/groups/%s" % (GANETI_RAPI_VERSION, group),
1634 067dda99 Vangelis Koukis
                             None, None)
1635 067dda99 Vangelis Koukis
1636 067dda99 Vangelis Koukis
  def CreateGroup(self, name, alloc_policy=None, dry_run=False):
1637 067dda99 Vangelis Koukis
    """Creates a new node group.
1638 067dda99 Vangelis Koukis

1639 067dda99 Vangelis Koukis
    @type name: str
1640 067dda99 Vangelis Koukis
    @param name: the name of node group to create
1641 067dda99 Vangelis Koukis
    @type alloc_policy: str
1642 067dda99 Vangelis Koukis
    @param alloc_policy: the desired allocation policy for the group, if any
1643 067dda99 Vangelis Koukis
    @type dry_run: bool
1644 067dda99 Vangelis Koukis
    @param dry_run: whether to peform a dry run
1645 067dda99 Vangelis Koukis

1646 a3ad611d Dimitris Aragiorgis
    @rtype: string
1647 067dda99 Vangelis Koukis
    @return: job id
1648 067dda99 Vangelis Koukis

1649 067dda99 Vangelis Koukis
    """
1650 067dda99 Vangelis Koukis
    query = []
1651 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1652 067dda99 Vangelis Koukis
1653 067dda99 Vangelis Koukis
    body = {
1654 067dda99 Vangelis Koukis
      "name": name,
1655 067dda99 Vangelis Koukis
      "alloc_policy": alloc_policy
1656 067dda99 Vangelis Koukis
      }
1657 067dda99 Vangelis Koukis
1658 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_POST, "/%s/groups" % GANETI_RAPI_VERSION,
1659 067dda99 Vangelis Koukis
                             query, body)
1660 067dda99 Vangelis Koukis
1661 067dda99 Vangelis Koukis
  def ModifyGroup(self, group, **kwargs):
1662 067dda99 Vangelis Koukis
    """Modifies a node group.
1663 067dda99 Vangelis Koukis

1664 067dda99 Vangelis Koukis
    More details for parameters can be found in the RAPI documentation.
1665 067dda99 Vangelis Koukis

1666 067dda99 Vangelis Koukis
    @type group: string
1667 067dda99 Vangelis Koukis
    @param group: Node group name
1668 a3ad611d Dimitris Aragiorgis
    @rtype: string
1669 067dda99 Vangelis Koukis
    @return: job id
1670 067dda99 Vangelis Koukis

1671 067dda99 Vangelis Koukis
    """
1672 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_PUT,
1673 067dda99 Vangelis Koukis
                             ("/%s/groups/%s/modify" %
1674 067dda99 Vangelis Koukis
                              (GANETI_RAPI_VERSION, group)), None, kwargs)
1675 067dda99 Vangelis Koukis
1676 067dda99 Vangelis Koukis
  def DeleteGroup(self, group, dry_run=False):
1677 067dda99 Vangelis Koukis
    """Deletes a node group.
1678 067dda99 Vangelis Koukis

1679 067dda99 Vangelis Koukis
    @type group: str
1680 067dda99 Vangelis Koukis
    @param group: the node group to delete
1681 067dda99 Vangelis Koukis
    @type dry_run: bool
1682 067dda99 Vangelis Koukis
    @param dry_run: whether to peform a dry run
1683 067dda99 Vangelis Koukis

1684 a3ad611d Dimitris Aragiorgis
    @rtype: string
1685 067dda99 Vangelis Koukis
    @return: job id
1686 067dda99 Vangelis Koukis

1687 067dda99 Vangelis Koukis
    """
1688 067dda99 Vangelis Koukis
    query = []
1689 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1690 067dda99 Vangelis Koukis
1691 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_DELETE,
1692 067dda99 Vangelis Koukis
                             ("/%s/groups/%s" %
1693 067dda99 Vangelis Koukis
                              (GANETI_RAPI_VERSION, group)), query, None)
1694 067dda99 Vangelis Koukis
1695 067dda99 Vangelis Koukis
  def RenameGroup(self, group, new_name):
1696 067dda99 Vangelis Koukis
    """Changes the name of a node group.
1697 067dda99 Vangelis Koukis

1698 067dda99 Vangelis Koukis
    @type group: string
1699 067dda99 Vangelis Koukis
    @param group: Node group name
1700 067dda99 Vangelis Koukis
    @type new_name: string
1701 067dda99 Vangelis Koukis
    @param new_name: New node group name
1702 067dda99 Vangelis Koukis

1703 a3ad611d Dimitris Aragiorgis
    @rtype: string
1704 067dda99 Vangelis Koukis
    @return: job id
1705 067dda99 Vangelis Koukis

1706 067dda99 Vangelis Koukis
    """
1707 067dda99 Vangelis Koukis
    body = {
1708 067dda99 Vangelis Koukis
      "new_name": new_name,
1709 067dda99 Vangelis Koukis
      }
1710 067dda99 Vangelis Koukis
1711 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_PUT,
1712 067dda99 Vangelis Koukis
                             ("/%s/groups/%s/rename" %
1713 067dda99 Vangelis Koukis
                              (GANETI_RAPI_VERSION, group)), None, body)
1714 067dda99 Vangelis Koukis
1715 067dda99 Vangelis Koukis
  def AssignGroupNodes(self, group, nodes, force=False, dry_run=False):
1716 067dda99 Vangelis Koukis
    """Assigns nodes to a group.
1717 067dda99 Vangelis Koukis

1718 067dda99 Vangelis Koukis
    @type group: string
1719 067dda99 Vangelis Koukis
    @param group: Node gropu name
1720 067dda99 Vangelis Koukis
    @type nodes: list of strings
1721 067dda99 Vangelis Koukis
    @param nodes: List of nodes to assign to the group
1722 067dda99 Vangelis Koukis

1723 a3ad611d Dimitris Aragiorgis
    @rtype: string
1724 067dda99 Vangelis Koukis
    @return: job id
1725 067dda99 Vangelis Koukis

1726 067dda99 Vangelis Koukis
    """
1727 067dda99 Vangelis Koukis
    query = []
1728 a3ad611d Dimitris Aragiorgis
    _AppendForceIf(query, force)
1729 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1730 067dda99 Vangelis Koukis
1731 067dda99 Vangelis Koukis
    body = {
1732 067dda99 Vangelis Koukis
      "nodes": nodes,
1733 067dda99 Vangelis Koukis
      }
1734 067dda99 Vangelis Koukis
1735 067dda99 Vangelis Koukis
    return self._SendRequest(HTTP_PUT,
1736 067dda99 Vangelis Koukis
                             ("/%s/groups/%s/assign-nodes" %
1737 067dda99 Vangelis Koukis
                             (GANETI_RAPI_VERSION, group)), query, body)
1738 a3ad611d Dimitris Aragiorgis
1739 a3ad611d Dimitris Aragiorgis
  def GetGroupTags(self, group):
1740 a3ad611d Dimitris Aragiorgis
    """Gets tags for a node group.
1741 a3ad611d Dimitris Aragiorgis

1742 a3ad611d Dimitris Aragiorgis
    @type group: string
1743 a3ad611d Dimitris Aragiorgis
    @param group: Node group whose tags to return
1744 a3ad611d Dimitris Aragiorgis

1745 a3ad611d Dimitris Aragiorgis
    @rtype: list of strings
1746 a3ad611d Dimitris Aragiorgis
    @return: tags for the group
1747 a3ad611d Dimitris Aragiorgis

1748 a3ad611d Dimitris Aragiorgis
    """
1749 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_GET,
1750 a3ad611d Dimitris Aragiorgis
                             ("/%s/groups/%s/tags" %
1751 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, group)), None, None)
1752 a3ad611d Dimitris Aragiorgis
1753 a3ad611d Dimitris Aragiorgis
  def AddGroupTags(self, group, tags, dry_run=False):
1754 a3ad611d Dimitris Aragiorgis
    """Adds tags to a node group.
1755 a3ad611d Dimitris Aragiorgis

1756 a3ad611d Dimitris Aragiorgis
    @type group: str
1757 a3ad611d Dimitris Aragiorgis
    @param group: group to add tags to
1758 a3ad611d Dimitris Aragiorgis
    @type tags: list of string
1759 a3ad611d Dimitris Aragiorgis
    @param tags: tags to add to the group
1760 a3ad611d Dimitris Aragiorgis
    @type dry_run: bool
1761 a3ad611d Dimitris Aragiorgis
    @param dry_run: whether to perform a dry run
1762 a3ad611d Dimitris Aragiorgis

1763 a3ad611d Dimitris Aragiorgis
    @rtype: string
1764 a3ad611d Dimitris Aragiorgis
    @return: job id
1765 a3ad611d Dimitris Aragiorgis

1766 a3ad611d Dimitris Aragiorgis
    """
1767 a3ad611d Dimitris Aragiorgis
    query = [("tag", t) for t in tags]
1768 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1769 a3ad611d Dimitris Aragiorgis
1770 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_PUT,
1771 a3ad611d Dimitris Aragiorgis
                             ("/%s/groups/%s/tags" %
1772 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, group)), query, None)
1773 a3ad611d Dimitris Aragiorgis
1774 a3ad611d Dimitris Aragiorgis
  def DeleteGroupTags(self, group, tags, dry_run=False):
1775 a3ad611d Dimitris Aragiorgis
    """Deletes tags from a node group.
1776 a3ad611d Dimitris Aragiorgis

1777 a3ad611d Dimitris Aragiorgis
    @type group: str
1778 a3ad611d Dimitris Aragiorgis
    @param group: group to delete tags from
1779 a3ad611d Dimitris Aragiorgis
    @type tags: list of string
1780 a3ad611d Dimitris Aragiorgis
    @param tags: tags to delete
1781 a3ad611d Dimitris Aragiorgis
    @type dry_run: bool
1782 a3ad611d Dimitris Aragiorgis
    @param dry_run: whether to perform a dry run
1783 a3ad611d Dimitris Aragiorgis
    @rtype: string
1784 a3ad611d Dimitris Aragiorgis
    @return: job id
1785 a3ad611d Dimitris Aragiorgis

1786 a3ad611d Dimitris Aragiorgis
    """
1787 a3ad611d Dimitris Aragiorgis
    query = [("tag", t) for t in tags]
1788 a3ad611d Dimitris Aragiorgis
    _AppendDryRunIf(query, dry_run)
1789 a3ad611d Dimitris Aragiorgis
1790 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_DELETE,
1791 a3ad611d Dimitris Aragiorgis
                             ("/%s/groups/%s/tags" %
1792 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, group)), query, None)
1793 a3ad611d Dimitris Aragiorgis
1794 a3ad611d Dimitris Aragiorgis
  def Query(self, what, fields, qfilter=None):
1795 a3ad611d Dimitris Aragiorgis
    """Retrieves information about resources.
1796 a3ad611d Dimitris Aragiorgis

1797 a3ad611d Dimitris Aragiorgis
    @type what: string
1798 a3ad611d Dimitris Aragiorgis
    @param what: Resource name, one of L{constants.QR_VIA_RAPI}
1799 a3ad611d Dimitris Aragiorgis
    @type fields: list of string
1800 a3ad611d Dimitris Aragiorgis
    @param fields: Requested fields
1801 a3ad611d Dimitris Aragiorgis
    @type qfilter: None or list
1802 a3ad611d Dimitris Aragiorgis
    @param qfilter: Query filter
1803 a3ad611d Dimitris Aragiorgis

1804 a3ad611d Dimitris Aragiorgis
    @rtype: string
1805 a3ad611d Dimitris Aragiorgis
    @return: job id
1806 a3ad611d Dimitris Aragiorgis

1807 a3ad611d Dimitris Aragiorgis
    """
1808 a3ad611d Dimitris Aragiorgis
    body = {
1809 a3ad611d Dimitris Aragiorgis
      "fields": fields,
1810 a3ad611d Dimitris Aragiorgis
      }
1811 a3ad611d Dimitris Aragiorgis
1812 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, qfilter is not None, "qfilter", qfilter)
1813 a3ad611d Dimitris Aragiorgis
    # TODO: remove "filter" after 2.7
1814 a3ad611d Dimitris Aragiorgis
    _SetItemIf(body, qfilter is not None, "filter", qfilter)
1815 a3ad611d Dimitris Aragiorgis
1816 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_PUT,
1817 a3ad611d Dimitris Aragiorgis
                             ("/%s/query/%s" %
1818 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, what)), None, body)
1819 a3ad611d Dimitris Aragiorgis
1820 a3ad611d Dimitris Aragiorgis
  def QueryFields(self, what, fields=None):
1821 a3ad611d Dimitris Aragiorgis
    """Retrieves available fields for a resource.
1822 a3ad611d Dimitris Aragiorgis

1823 a3ad611d Dimitris Aragiorgis
    @type what: string
1824 a3ad611d Dimitris Aragiorgis
    @param what: Resource name, one of L{constants.QR_VIA_RAPI}
1825 a3ad611d Dimitris Aragiorgis
    @type fields: list of string
1826 a3ad611d Dimitris Aragiorgis
    @param fields: Requested fields
1827 a3ad611d Dimitris Aragiorgis

1828 a3ad611d Dimitris Aragiorgis
    @rtype: string
1829 a3ad611d Dimitris Aragiorgis
    @return: job id
1830 a3ad611d Dimitris Aragiorgis

1831 a3ad611d Dimitris Aragiorgis
    """
1832 a3ad611d Dimitris Aragiorgis
    query = []
1833 a3ad611d Dimitris Aragiorgis
1834 a3ad611d Dimitris Aragiorgis
    if fields is not None:
1835 a3ad611d Dimitris Aragiorgis
      _AppendIf(query, True, ("fields", ",".join(fields)))
1836 a3ad611d Dimitris Aragiorgis
1837 a3ad611d Dimitris Aragiorgis
    return self._SendRequest(HTTP_GET,
1838 a3ad611d Dimitris Aragiorgis
                             ("/%s/query/%s/fields" %
1839 a3ad611d Dimitris Aragiorgis
                              (GANETI_RAPI_VERSION, what)), query, None)