diff --git a/IM/InfrastructureManager.py b/IM/InfrastructureManager.py index 265351a01..5103df6a1 100644 --- a/IM/InfrastructureManager.py +++ b/IM/InfrastructureManager.py @@ -990,6 +990,9 @@ def GetInfrastructureState(inf_id, auth): else: state = VirtualMachine.UNKNOWN + if sel_inf.deleting: + state = VirtualMachine.DELETING + InfrastructureManager.logger.info("Inf ID: " + str(inf_id) + " is in state: " + state) return {'state': state, 'vm_states': vm_states} diff --git a/IM/VirtualMachine.py b/IM/VirtualMachine.py index ed168f444..afd5b9623 100644 --- a/IM/VirtualMachine.py +++ b/IM/VirtualMachine.py @@ -43,6 +43,7 @@ class VirtualMachine(LoggerMixin): FAILED = "failed" CONFIGURED = "configured" UNCONFIGURED = "unconfigured" + DELETING = "deleting" WAIT_TO_PID = "WAIT" @@ -92,6 +93,8 @@ def __init__(self, inf, cloud_id, cloud, info, requested_radl, cloud_connector=N """Flag to specify that this VM is creation process""" self.error_msg = None """Message with the cause of the the error in the VM (if known) """ + self.deleting = False + """Flag to specify that this VM is deletion process""" def serialize(self): with self._lock: @@ -155,16 +158,20 @@ def delete(self, delete_list, auth, exceptions): last = self.is_last_in_cloud(delete_list, remain_vms) success = False try: + self.deleting = True VirtualMachine.logger.info("Inf ID: " + self.inf.id + ": Finalizing the VM id: " + str(self.id)) self.kill_check_ctxt_process() (success, msg) = self.getCloudConnector().finalize(self, last, auth) - if success: - self.destroy = True - # force the update of the information - self.last_update = 0 except Exception as e: msg = str(e) + finally: + self.deleting = False + + if success: + self.destroy = True + # force the update of the information + self.last_update = 0 if not success: VirtualMachine.logger.info("Inf ID: " + self.inf.id + ": The VM cannot be finalized: %s" % msg) @@ -500,6 +507,10 @@ def update_status(self, auth, force=False): if self.state == VirtualMachine.FAILED and self.id is None: return False + if self.deleting: + self.state = VirtualMachine.DELETING + return True + now = int(time.time()) state = self.state updated = False diff --git a/doc/source/REST.rst b/doc/source/REST.rst index e97eb836c..5befefef4 100644 --- a/doc/source/REST.rst +++ b/doc/source/REST.rst @@ -161,8 +161,8 @@ GET ``http://imserver.com/infrastructures//`` (the virtual infrastructure will not be modified). :``state``: a JSON object with two elements: - :``state``: a string with the aggregated state of the infrastructure. - :``vm_states``: a dict indexed with the VM ID and the value the VM state. + :``state``: a string with the aggregated state of the infrastructure (see list of valid states in :ref:`IM-States`). + :``vm_states``: a dict indexed with the VM ID and the value the VM state (see list of valid states in :ref:`IM-States`). The result is JSON format has the following format:: diff --git a/doc/source/xmlrpc.rst b/doc/source/xmlrpc.rst index b2023b238..27dc5bb47 100644 --- a/doc/source/xmlrpc.rst +++ b/doc/source/xmlrpc.rst @@ -12,6 +12,43 @@ Every credential is represented as a struct datatype, whose keys and values are described in :ref:`auth-file`. Then the parameter is an array of these structs. +.. _IM-States: + +IM valid States +---------------- + +List of valid VM and infrastructure states: + + The ``state`` can be + + * ``pending``, launched, but still in initialization stage; + * ``running``, created successfully and running, but still in the configuration stage; + * ``configured``, running and contextualized; + * ``unconfigured``, running but not correctly contextualized; + * ``stopped``, stopped or suspended; + * ``off``, shutdown or removed from the infrastructure; + * ``failed``, an error happened during the launching; or + * ``unknown``, unable to obtain the status. + * ``deleting``, in the deletion process. + + The next figure shows a state diagram of virtual machine status. This figure is illustrative + as if may differ in case of Cloud Providers. + + .. digraph:: stategraph + + layout=dot; + node [shape=circle, fontsize=10, fixedsize=true, height=.9, weight=.9]; + "pending" -> "running" -> "configured" -> "off" ; + "pending" -> "failed"; + "running" -> "unconfigured"; + "configured" -> "stopped"; + "configured" -> "running"; + "stopped" -> "pending"; + "configured" -> "deleting"; + +Methods +------- + This is the list of method names: ``GetInfrastructureList`` @@ -64,17 +101,6 @@ This is the list of method names: Return the aggregated state associated to the infrastructure with ID ``infId``. - - The ``state`` can be - - * ``pending``, At least one VM is still in initialization stage; - * ``running``, All the VMs are created successfully and running, but at least one of them are still in the configuration stage; - * ``configured``, All the VMs are running and contextualized; - * ``unconfigured``, All the VMs are running but at least one of them are not correctly contextualized; - * ``stopped``, All the VMs are stopped or suspended; - * ``off``, All the VMs are shutdown or removed from the infrastructure; - * ``failed``, There are at least one VM in status ``failed``. - * ``unknown``, There are at least one VM in status ``unknown``. ``GetInfrastructureRADL`` :parameter 0: ``infId``: integer @@ -96,31 +122,6 @@ This is the list of method names: Return a string with information about the virtual machine with ID ``vmId`` in the infrastructure with ID ``infId``. The returned string is in RADL format. - - The ``state`` can be - - * ``pending``, launched, but still in initialization stage; - * ``running``, created successfully and running, but still in the configuration stage; - * ``configured``, running and contextualized; - * ``unconfigured``, running but not correctly contextualized; - * ``stopped``, stopped or suspended; - * ``off``, shutdown or removed from the infrastructure; - * ``failed``, an error happened during the launching; or - * ``unknown``, unable to obtain the status. - - The next figure shows a state diagram of virtual machine status. This figure is illustrative - as if may differ in case of Cloud Providers. - - .. digraph:: stategraph - - layout=dot; - node [shape=circle, fontsize=10, fixedsize=true, height=.9, weight=.9]; - "pending" -> "running" -> "configured" -> "off" ; - "pending" -> "failed"; - "running" -> "unconfigured"; - "configured" -> "stopped"; - "configured" -> "running"; - "stopped" -> "pending"; ``GetVMProperty`` :parameter 0: ``infId``: integer diff --git a/doc/swagger_api.yaml b/doc/swagger_api.yaml index 7c3cdeebf..47603cc21 100644 --- a/doc/swagger_api.yaml +++ b/doc/swagger_api.yaml @@ -356,13 +356,87 @@ paths: 404: description: Not Found - /infrastructures/{InfId}/{Property}: + /infrastructures/{InfId}/state: get: tags: - infrastructures - summary: Get a infrastructure property. - description: Return a property associated to the infrastructure with ID InfId. - operationId: GetInfrastructureProperty + summary: Get infrastructure state. + description: Return a the state of the infrastructure with ID InfId. + operationId: GetInfrastructureState + produces: + - application/json + parameters: + - name: Authorization + in: header + description: |- + The Authentication header must provide the content of the [Authorization File](https://imdocs.readthedocs.io/en/latest/client.html#auth-file), but putting all the elements in one line using “\n” as separator. + required: true + type: string + - name: InfId + in: path + description: The ID of the specific infrastructure. + required: true + type: string + responses: + 200: + description: successful operation + schema: + $ref: '#/definitions/InfrastructureState' + 400: + description: Invalid status value + 401: + description: Unauthorized + 403: + description: Forbidden + 404: + description: Not Found + + /infrastructures/{InfId}/outputs: + get: + tags: + - infrastructures + summary: Get the infrastructure outputs. + description: In case of TOSCA documents it will return a JSON object with the outputs of the TOSCA document. + operationId: GetInfrastructureOutpus + produces: + - application/json + parameters: + - name: Authorization + in: header + description: |- + The Authentication header must provide the content of the [Authorization File](https://imdocs.readthedocs.io/en/latest/client.html#auth-file), but putting all the elements in one line using “\n” as separator. + required: true + type: string + - name: InfId + in: path + description: The ID of the specific infrastructure. + required: true + type: string + responses: + 200: + description: successful operation + examples: + application/json: | + { + "output_name1": "output_value1", + "output_name2": "output_value2", + } + 400: + description: Invalid status value + 401: + description: Unauthorized + 403: + description: Forbidden + 404: + description: Not Found + + /infrastructures/{InfId}/contmsg: + get: + tags: + - infrastructures + summary: Get a infrastructure contextualization message. + description: Return a string with the contextualization message. In case of headeronly flag is set to ‘yes’, ‘true’ or ‘1’ only the initial part of the infrastructure contextualization log will be returned (without any VM contextualization log). + operationId: GetInfrastructureContmsg produces: - text/plain - application/json @@ -380,7 +454,7 @@ paths: type: string - name: headeronly in: query - description: Only used with `contmsg` property. In case of headeronly flag is set to `yes`, `true` or `1` only the initial part of the infrastructure contextualization log will be returned (without any VM contextualization log). + description: In case of headeronly flag is set to `yes`, `true` or `1` only the initial part of the infrastructure contextualization log will be returned (without any VM contextualization log). default: false required: false type: string @@ -391,35 +465,151 @@ paths: - false - 0 - 1 - - name: Property + responses: + 200: + description: successful operation + examples: + text/plain: | + 2019-12-11 11:08:14.574891: Select master VM + 2019-12-11 11:08:14.576685: Wait master VM to boot + 2019-12-11 11:08:14.577905: Wait master VM to have the SSH active. + application/json: | + { + "contmsg": " 2019-12-11 11:08:14.574891: Select master VM\n 2019-12-11 11:08:14.576685: Wait master VM to boot\n 2019-12-11 11:08:14.577905: Wait master VM to have the SSH active." + } + 400: + description: Invalid status value + 401: + description: Unauthorized + 403: + description: Forbidden + 404: + description: Not Found + + /infrastructures/{InfId}/data: + get: + tags: + - infrastructures + summary: Export an infrastructure. + description: Return the serialization of the infrastructure with ID InfId. This function is useful to transfer the control of an infrastructure to other IM server (See PUT /infrastructures). In case of delete flag is set to ‘yes’, ‘true’ or ‘1’ the data not only will be exported but also the infrastructure will be set deleted (the virtual infrastructure will not be modified). + operationId: GetInfrastructureData + produces: + - application/json + parameters: + - name: Authorization + in: header + description: |- + The Authentication header must provide the content of the [Authorization File](https://imdocs.readthedocs.io/en/latest/client.html#auth-file), but putting all the elements in one line using “\n” as separator. + required: true + type: string + - name: InfId in: path - description: | - The specific infrastructure property: - * `outputs`: in case of TOSCA documents it will return a JSON object with the outputs of the TOSCA document. - * `contmsg`: a string with the contextualization message. In case of headeronly flag is set to ‘yes’, ‘true’ or ‘1’ only the initial part of the infrastructure contextualization log will be returned (without any VM contextualization log). - * `radl`: a string with the original specified RADL of the infrastructure. - * `tosca`: a string with the TOSCA representation of the infrastructure. - * `data`: a string with the JSOMN serialized data of the infrastructure. In case of delete flag is set to ‘yes’, ‘true’ or ‘1’ the data not only will be exported but also the infrastructure will be set deleted (the virtual infrastructure will not be modified). - * `state`: a JSON object with two elements: - * `state`: a string with the aggregated state of the infrastructure. - * `vm_states`: a dict indexed with the VM ID and the value the VM state. + description: The ID of the specific infrastructure. required: true type: string + - name: delete + in: query + description: In case of delete flag is set to ‘yes’, ‘true’ or ‘1’ the data not only will be exported but also the infrastructure will be set deleted (the virtual infrastructure will not be modified). + default: false + required: false + type: string enum: - - outputs - - contmsg - - radl - - tosca - - data - - state + - yes + - no + - true + - false + - 0 + - 1 responses: 200: description: successful operation examples: - text/plain: property_value application/json: | { - "property_name": "property_value" + "vm_list": [], + ... + } + 400: + description: Invalid status value + 401: + description: Unauthorized + 403: + description: Forbidden + 404: + description: Not Found + + /infrastructures/{InfId}/radl: + get: + tags: + - infrastructures + summary: Get the infrastructure RADL used to create it. + description: Return a string with the original specified RADL of the infrastructure with ID InfId. + operationId: GetInfrastructureRADL + produces: + - text/plain + - application/json + parameters: + - name: Authorization + in: header + description: |- + The Authentication header must provide the content of the [Authorization File](https://imdocs.readthedocs.io/en/latest/client.html#auth-file), but putting all the elements in one line using “\n” as separator. + required: true + type: string + - name: InfId + in: path + description: The ID of the specific infrastructure. + required: true + type: string + responses: + 200: + description: successful operation + examples: + text/plain: | + network net (outbound = 'yes') + system node ( + ... + ) + application/json: | + { + "radl": "network net (outbound = 'yes')\nsystem node ( ... )" + } + 400: + description: Invalid status value + 401: + description: Unauthorized + 403: + description: Forbidden + 404: + description: Not Found + + /infrastructures/{InfId}/tosca: + get: + tags: + - infrastructures + summary: Get the TOSCA representation of the infrastructure. + description: Return a string with the TOSCA representation of the infrastructure with ID InfId. + operationId: GetInfrastructureTOSCA + produces: + - application/json + parameters: + - name: Authorization + in: header + description: |- + The Authentication header must provide the content of the [Authorization File](https://imdocs.readthedocs.io/en/latest/client.html#auth-file), but putting all the elements in one line using “\n” as separator. + required: true + type: string + - name: InfId + in: path + description: The ID of the specific infrastructure. + required: true + type: string + responses: + 200: + description: successful operation + examples: + application/json: | + { + "tosca": "tosca_definitions_version: tosca_simple_yaml_1_0\ndescription: Some TOSCA template\n..." } 400: description: Invalid status value @@ -701,7 +891,54 @@ paths: description: Forbidden 404: description: Not Found - + + /infrastructures/{InfId}/vms/{VMId}/contmsg: + get: + tags: + - infrastructures + summary: Get a VM contextualization message. + description: Return a string with the contextualization message associated to the virtual machine with ID VMId in the infrastructure with with ID infId + operationId: GetVMContMsg + produces: + - text/plain + - application/json + parameters: + - name: Authorization + in: header + description: |- + The Authentication header must provide the content of the [Authorization File](https://imdocs.readthedocs.io/en/latest/client.html#auth-file), but putting all the elements in one line using “\n” as separator. + required: true + type: string + - name: InfId + in: path + description: The ID of the specific infrastructure. + required: true + type: string + - name: VMId + in: path + description: The ID of the specific VM. + required: true + type: string + responses: + 200: + description: successful operation + examples: + text/plain: | + Launch task: basic + ... + application/json: | + { + "contmsg": "Launch task: basic\n..." + } + 400: + description: Invalid status value + 401: + description: Unauthorized + 403: + description: Forbidden + 404: + description: Not Found + /infrastructures/{InfId}/vms/{VMId}/{Property}: get: tags: @@ -731,10 +968,7 @@ paths: type: string - name: Property in: path - description: | - The specific infrastructure property: - * `radl property`: any VM RADL property. - * `contmsg`: a string with the contextualization message. + description: The specific VM RADL property to get. required: true type: string responses: @@ -933,6 +1167,38 @@ paths: 404: description: Not Found +definitions: + + State: + type: string + enum: + - pending + - running + - configured + - unconfigured + - stopped + - off + - failed + - unknown + - deleting + title: State + example: running + + InfrastructureState: + type: object + properties: + state: + $ref: '#/definitions/State' + vm_states: + type: array + items: + $ref: '#/definitions/State' + example: + - running + - running + title: InfrastructureState + + externalDocs: description: Find out more about IM url: http://www.grycap.upv.es/im diff --git a/test/unit/test_im_logic.py b/test/unit/test_im_logic.py index 6bfb99e07..e5ee36edb 100755 --- a/test/unit/test_im_logic.py +++ b/test/unit/test_im_logic.py @@ -731,6 +731,7 @@ def test_get_inf_state(self, get_inf_ids): inf.id = "1" inf.auth = auth0 inf.deleted = False + inf.deleting = False inf.has_expired.return_value = False vm1 = MagicMock() vm1.im_id = 0 @@ -1297,6 +1298,8 @@ def test_inf_delete_async(self): inf.destroy_vms = Mock(side_effect=self.sleep_5) IM.DestroyInfrastructure(infId, auth0, False, True) self.assertEqual(inf.deleted, False) + state = IM.GetInfrastructureState(infId, auth0) + self.assertEqual(state["state"], VirtualMachine.DELETING) time.sleep(10) self.assertEqual(inf.deleted, True)