+ # Validate response
+ if (not isinstance(data, dict) or
+ KEY_SUCCESS not in data or
+ KEY_RESULT not in data):
+ raise DecodingError("Invalid response from server: %s" % str(data))
+
+ result = data[KEY_RESULT]
+
+ if not data[KEY_SUCCESS]:
+ # TODO: decide on a standard exception
+ if (isinstance(result, (tuple, list)) and len(result) == 2 and
+ isinstance(result[1], (tuple, list))):
+ # custom ganeti errors
+ err_class = errors.GetErrorClass(result[0])
+ if err_class is not None:
+ raise err_class, tuple(result[1])
+
+ raise RequestError(result)
+
+ return result
+
+ def SetQueueDrainFlag(self, drain_flag):
+ return self.CallMethod(REQ_QUEUE_SET_DRAIN_FLAG, drain_flag)
+
+ def SubmitJob(self, ops):
+ ops_state = map(lambda op: op.__getstate__(), ops)
+ return self.CallMethod(REQ_SUBMIT_JOB, ops_state)
+
+ def CancelJob(self, job_id):
+ return self.CallMethod(REQ_CANCEL_JOB, job_id)
+
+ def ArchiveJob(self, job_id):
+ return self.CallMethod(REQ_ARCHIVE_JOB, job_id)
+
+ def AutoArchiveJobs(self, age):
+ timeout = (DEF_RWTO - 1) / 2
+ return self.CallMethod(REQ_AUTOARCHIVE_JOBS, (age, timeout))
+
+ def WaitForJobChange(self, job_id, fields, prev_job_info, prev_log_serial):
+ timeout = (DEF_RWTO - 1) / 2
+ while True:
+ result = self.CallMethod(REQ_WAIT_FOR_JOB_CHANGE,
+ (job_id, fields, prev_job_info,
+ prev_log_serial, timeout))
+ if result != constants.JOB_NOTCHANGED:
+ break
+ return result
+
+ def QueryJobs(self, job_ids, fields):
+ return self.CallMethod(REQ_QUERY_JOBS, (job_ids, fields))
+
+ def QueryInstances(self, names, fields):
+ return self.CallMethod(REQ_QUERY_INSTANCES, (names, fields))
+
+ def QueryNodes(self, names, fields):
+ return self.CallMethod(REQ_QUERY_NODES, (names, fields))
+
+ def QueryExports(self, nodes):
+ return self.CallMethod(REQ_QUERY_EXPORTS, nodes)
+
+ def QueryConfigValues(self, fields):
+ return self.CallMethod(REQ_QUERY_CONFIG_VALUES, fields)
+