X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/527fbde865ca95ae107edd0f6dcec7d54e29fef0..7fa310f6d84e06934a7d2bc55c9a1e2b84ce613a:/lib/rapi/rlib2.py diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py index 94511a2..66b0ece 100644 --- a/lib/rapi/rlib2.py +++ b/lib/rapi/rlib2.py @@ -86,13 +86,15 @@ _NR_OFFLINE = "offline" _NR_REGULAR = "regular" _NR_MAP = { - "M": _NR_MASTER, - "C": _NR_MASTER_CANDIATE, - "D": _NR_DRAINED, - "O": _NR_OFFLINE, - "R": _NR_REGULAR, + constants.NR_MASTER: _NR_MASTER, + constants.NR_MCANDIDATE: _NR_MASTER_CANDIATE, + constants.NR_DRAINED: _NR_DRAINED, + constants.NR_OFFLINE: _NR_OFFLINE, + constants.NR_REGULAR: _NR_REGULAR, } +assert frozenset(_NR_MAP.keys()) == constants.NR_ALL + # Request data version field _REQ_DATA_VERSION = "__version__" @@ -429,7 +431,7 @@ class R_2_nodes_name_evacuate(baserlib.R_Generic): result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn) jobs = [] - for iname, node in result: + for iname, node in result[0]: if dry_run: jid = None else: @@ -749,67 +751,6 @@ class R_2_instances(baserlib.R_Generic): return baserlib.BuildUriList(instanceslist, "/2/instances/%s", uri_fields=("id", "uri")) - def _ParseVersion0CreateRequest(self): - """Parses an instance creation request version 0. - - Request data version 0 is deprecated and should not be used anymore. - - @rtype: L{opcodes.OpInstanceCreate} - @return: Instance creation opcode - - """ - # Do not modify anymore, request data version 0 is deprecated - beparams = baserlib.MakeParamsDict(self.request_body, - constants.BES_PARAMETERS) - hvparams = baserlib.MakeParamsDict(self.request_body, - constants.HVS_PARAMETERS) - fn = self.getBodyParameter - - # disk processing - disk_data = fn('disks') - if not isinstance(disk_data, list): - raise http.HttpBadRequest("The 'disks' parameter should be a list") - disks = [] - for idx, d in enumerate(disk_data): - if not isinstance(d, int): - raise http.HttpBadRequest("Disk %d specification wrong: should" - " be an integer" % idx) - disks.append({"size": d}) - - # nic processing (one nic only) - nics = [{"mac": fn("mac", constants.VALUE_AUTO)}] - if fn("ip", None) is not None: - nics[0]["ip"] = fn("ip") - if fn("mode", None) is not None: - nics[0]["mode"] = fn("mode") - if fn("link", None) is not None: - nics[0]["link"] = fn("link") - if fn("bridge", None) is not None: - nics[0]["bridge"] = fn("bridge") - - # Do not modify anymore, request data version 0 is deprecated - return opcodes.OpInstanceCreate( - mode=constants.INSTANCE_CREATE, - instance_name=fn('name'), - disks=disks, - disk_template=fn('disk_template'), - os_type=fn('os'), - pnode=fn('pnode', None), - snode=fn('snode', None), - iallocator=fn('iallocator', None), - nics=nics, - start=fn('start', True), - ip_check=fn('ip_check', True), - name_check=fn('name_check', True), - wait_for_sync=True, - hypervisor=fn('hypervisor', None), - hvparams=hvparams, - beparams=beparams, - file_storage_dir=fn('file_storage_dir', None), - file_driver=fn('file_driver', constants.FD_LOOP), - dry_run=bool(self.dryRun()), - ) - def POST(self): """Create an instance. @@ -823,10 +764,13 @@ class R_2_instances(baserlib.R_Generic): data_version = self.getBodyParameter(_REQ_DATA_VERSION, 0) if data_version == 0: - op = self._ParseVersion0CreateRequest() + raise http.HttpBadRequest("Instance creation request version 0 is no" + " longer supported") elif data_version == 1: - op = _ParseInstanceCreateRequestVersion1(self.request_body, - self.dryRun()) + data = self.request_body.copy() + # Remove "__version__" + data.pop(_REQ_DATA_VERSION, None) + op = _ParseInstanceCreateRequestVersion1(data, self.dryRun()) else: raise http.HttpBadRequest("Unsupported request data version %s" % data_version) @@ -925,6 +869,19 @@ class R_2_instances_name_startup(baserlib.R_Generic): return baserlib.SubmitJob([op]) +def _ParseShutdownInstanceRequest(name, data, dry_run): + """Parses a request for an instance shutdown. + + @rtype: L{opcodes.OpInstanceShutdown} + @return: Instance shutdown opcode + + """ + return baserlib.FillOpcode(opcodes.OpInstanceShutdown, data, { + "instance_name": name, + "dry_run": dry_run, + }) + + class R_2_instances_name_shutdown(baserlib.R_Generic): """/2/instances/[instance_name]/shutdown resource. @@ -934,10 +891,13 @@ class R_2_instances_name_shutdown(baserlib.R_Generic): def PUT(self): """Shutdown an instance. + @return: a job id + """ - instance_name = self.items[0] - op = opcodes.OpInstanceShutdown(instance_name=instance_name, - dry_run=bool(self.dryRun())) + baserlib.CheckType(self.request_body, dict, "Body contents") + + op = _ParseShutdownInstanceRequest(self.items[0], self.request_body, + bool(self.dryRun())) return baserlib.SubmitJob([op]) @@ -949,7 +909,7 @@ def _ParseInstanceReinstallRequest(name, data): if not isinstance(data, dict): raise http.HttpBadRequest("Invalid body contents, not a dictionary") - ostype = baserlib.CheckParameter(data, "os") + ostype = baserlib.CheckParameter(data, "os", default=None) start = baserlib.CheckParameter(data, "start", exptype=bool, default=True) osparams = baserlib.CheckParameter(data, "osparams", default=None) @@ -985,14 +945,14 @@ class R_2_instances_name_reinstall(baserlib.R_Generic): raise http.HttpBadRequest("Can't combine query and body parameters") body = self.request_body - else: - if not self.queryargs: - raise http.HttpBadRequest("Missing query parameters") + elif self.queryargs: # Legacy interface, do not modify/extend body = { "os": self._checkStringVariable("os"), "start": not self._checkIntVariable("nostartup"), } + else: + body = {} ops = _ParseInstanceReinstallRequest(self.items[0], body) @@ -1233,6 +1193,105 @@ class R_2_instances_name_disk_grow(baserlib.R_Generic): return baserlib.SubmitJob([op]) +class R_2_instances_name_console(baserlib.R_Generic): + """/2/instances/[instance_name]/console resource. + + """ + GET_ACCESS = [rapi.RAPI_ACCESS_WRITE] + + def GET(self): + """Request information for connecting to instance's console. + + @return: Serialized instance console description, see + L{objects.InstanceConsole} + + """ + client = baserlib.GetClient() + + ((console, ), ) = client.QueryInstances([self.items[0]], ["console"], False) + + if console is None: + raise http.HttpServiceUnavailable("Instance console unavailable") + + assert isinstance(console, dict) + return console + + +def _GetQueryFields(args): + """ + + """ + try: + fields = args["fields"] + except KeyError: + raise http.HttpBadRequest("Missing 'fields' query argument") + + return _SplitQueryFields(fields[0]) + + +def _SplitQueryFields(fields): + """ + + """ + return [i.strip() for i in fields.split(",")] + + +class R_2_query(baserlib.R_Generic): + """/2/query/[resource] resource. + + """ + # Results might contain sensitive information + GET_ACCESS = [rapi.RAPI_ACCESS_WRITE] + + def _Query(self, fields, filter_): + return baserlib.GetClient().Query(self.items[0], fields, filter_).ToDict() + + def GET(self): + """Returns resource information. + + @return: Query result, see L{objects.QueryResponse} + + """ + return self._Query(_GetQueryFields(self.queryargs), None) + + def PUT(self): + """Submits job querying for resources. + + @return: Query result, see L{objects.QueryResponse} + + """ + body = self.request_body + + baserlib.CheckType(body, dict, "Body contents") + + try: + fields = body["fields"] + except KeyError: + fields = _GetQueryFields(self.queryargs) + + return self._Query(fields, self.request_body.get("filter", None)) + + +class R_2_query_fields(baserlib.R_Generic): + """/2/query/[resource]/fields resource. + + """ + def GET(self): + """Retrieves list of available fields for a resource. + + @return: List of serialized L{objects.QueryFieldDefinition} + + """ + try: + raw_fields = self.queryargs["fields"] + except KeyError: + fields = None + else: + fields = _SplitQueryFields(raw_fields[0]) + + return baserlib.GetClient().QueryFields(self.items[0], fields).ToDict() + + class _R_Tags(baserlib.R_Generic): """ Quasiclass for tagging resources