diff --git a/software-client/software_client/software_client.py b/software-client/software_client/software_client.py index f99c277a..f4dae7e1 100644 --- a/software-client/software_client/software_client.py +++ b/software-client/software_client/software_client.py @@ -1011,7 +1011,7 @@ def deploy_complete_req(args): def deploy_show_req(args): - url = "http://%s/v1/software/deploy_show" % api_addr + url = "http://%s/v1/software/deploy" % api_addr headers = {} append_auth_token_if_required(headers) req = requests.get(url, headers=headers) @@ -1023,10 +1023,11 @@ def deploy_show_req(args): print("Respond code %d. Error: %s" % (req.status_code, req.reason)) return 1 - data = json.loads(req.text) + data = req.json().get("data") if not data: - print("No deploy in progress.\n") + print("No deploy in progress.") else: + data = data[0] data["reboot_required"] = "Yes" if data.get("reboot_required") else "No" data_list = [[k, v] for k, v in data.items()] transposed_data_list = list(zip(*data_list)) diff --git a/software/software/api/controllers/v1/software.py b/software/software/api/controllers/v1/software.py index 1861c8bf..929c22cd 100644 --- a/software/software/api/controllers/v1/software.py +++ b/software/software/api/controllers/v1/software.py @@ -10,6 +10,7 @@ import os from oslo_log import log from pecan import expose from pecan import request +from pecan import Response import shutil from software.exceptions import SoftwareError @@ -132,15 +133,13 @@ class SoftwareAPIController(object): return result - @expose('json') - @expose('query.xml', content_type='application/xml') - def deploy_show(self): - try: - result = sc.software_deploy_show_api() - except SoftwareError as e: - return dict(error="Error: %s" % str(e)) - - return result + @expose('json', method="GET") + def deploy(self): + from_release = request.GET.get("from_release") + to_release = request.GET.get("to_release") + result = dict(data=sc.software_deploy_show_api(from_release, to_release)) + response_data = json.dumps(result) + return Response(body=response_data, status_code=200) @expose('json') @expose('query.xml', content_type='application/xml') diff --git a/software/software/db/api.py b/software/software/db/api.py index 253d0d46..13f1397f 100644 --- a/software/software/db/api.py +++ b/software/software/db/api.py @@ -37,10 +37,17 @@ class SoftwareAPI: self.deploy_handler.create(from_release, to_release, reboot_required) self.end_update() - def get_deploy(self): + def get_deploy(self, from_release, to_release): self.begin_update() try: - return self.deploy_handler.query() + return self.deploy_handler.query(from_release, to_release) + finally: + self.end_update() + + def get_deploy_all(self): + self.begin_update() + try: + return self.deploy_handler.query_all() finally: self.end_update() diff --git a/software/software/software_controller.py b/software/software/software_controller.py index acf89cbf..522e858e 100644 --- a/software/software/software_controller.py +++ b/software/software/software_controller.py @@ -2627,9 +2627,13 @@ class PatchController(PatchService): return dict(info=msg_info, warning=msg_warning, error=msg_error) - def software_deploy_show_api(self): + def software_deploy_show_api(self, from_release=None, to_release=None): # Retrieve deploy state from db - return self.db_api_instance.get_deploy() + if from_release and to_release: + return self.db_api_instance.get_deploy(from_release, to_release) + else: + # Retrieve deploy state from db in list format + return self.db_api_instance.get_deploy_all() def software_deploy_host_api(self, host_ip, force, async_req=False): msg_info = "" @@ -2902,7 +2906,11 @@ class PatchController(PatchService): def deploy_host_list(self): query_hosts = self.query_host_cache() deploy_hosts = self.db_api_instance.get_deploy_host() - deploy = self.db_api_instance.get_deploy() + deploy = self.db_api_instance.get_deploy_all() + if not deploy: + return None + deploy = deploy[0] + # If there's a hostname missing, add it to query hosts. hostnames = [] diff --git a/software/software/software_entities.py b/software/software/software_entities.py index 62297781..18932cb7 100644 --- a/software/software/software_entities.py +++ b/software/software/software_entities.py @@ -138,7 +138,7 @@ class Deploy(ABC): """ Create a new deployment entry. - :param from_release: The source release version. + :param from_release: The current release version. :param to_release: The target release version. :param reboot_required: If is required to do host reboot. :param state: The state of the deployment. @@ -149,10 +149,11 @@ class Deploy(ABC): check_instances([state], DEPLOY_STATES) @abstractmethod - def query(self): + def query(self, from_release, to_release): """ - Get deployments based on source and target release versions. + Get deployments based on current and target release versions. """ + validate_versions([from_release, to_release]) pass @abstractmethod @@ -160,7 +161,7 @@ class Deploy(ABC): """ Update a deployment entry. - :param state: The state of the deployment. + :param new_state: The state of the deployment. """ check_instances([new_state], DEPLOY_STATES) @@ -168,7 +169,7 @@ class Deploy(ABC): @abstractmethod def delete(self): """ - Delete a deployment entry based on source and target release versions. + Delete a deployment entry based on current and target release versions. """ pass @@ -236,13 +237,13 @@ class DeployHandler(Deploy): def create(self, from_release, to_release, reboot_required, state=DEPLOY_STATES.START): """ Create a new deploy with given from and to release version - :param from_release: The source release version. + :param from_release: The current release version. :param to_release: The target release version. :param reboot_required: If is required to do host reboot. :param state: The state of the deployment. """ super().create(from_release, to_release, reboot_required, state) - deploy = self.query() + deploy = self.query(from_release, to_release) if deploy: raise DeployAlreadyExist("Error to create. Deploy already exists.") new_deploy = { @@ -253,18 +254,39 @@ class DeployHandler(Deploy): } try: - self.data["deploy"] = new_deploy + deploy_data = self.data.get("deploy", []) + if not deploy_data: + deploy_data = { + "deploy": [] + } + deploy_data["deploy"].append(new_deploy) + self.data.update(deploy_data) + else: + deploy_data.append(new_deploy) save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data) except Exception: - self.data["deploy"] = {} + self.data["deploy"][0] = {} - def query(self): + def query(self, from_release, to_release): """ Query deploy based on from and to release version - :return: A deploy dictionary + :param from_release: The current release version. + :param to_release: The target release version. + :return: A list of deploy dictionary """ - super().query() - return self.data.get("deploy", {}) + super().query(from_release, to_release) + for deploy in self.data.get("deploy", []): + if (deploy.get("from_release") == from_release + and deploy.get("to_release") == to_release): + return deploy + return [] + + def query_all(self): + """ + Query all deployments inside software.json file. + :return: A list of deploy dictionary + """ + return self.data.get("deploy", []) def update(self, new_state: DEPLOY_STATES): """ @@ -272,29 +294,29 @@ class DeployHandler(Deploy): :param new_state: The new state """ super().update(new_state) - deploy = self.query() + deploy = self.query_all() if not deploy: raise DeployDoNotExist("Error to update deploy state. No deploy in progress.") try: - self.data["deploy"]["state"] = new_state.value + self.data["deploy"][0]["state"] = new_state.value save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data) except Exception: - self.data["deploy"] = deploy + self.data["deploy"][0] = deploy def delete(self): """ Delete a deploy based on given from and to release version """ super().delete() - deploy = self.query() + deploy = self.query_all() if not deploy: raise DeployDoNotExist("Error to delete deploy state. No deploy in progress.") try: - self.data["deploy"] = {} + self.data["deploy"].clear() save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data) except Exception: - self.data["deploy"] = deploy + self.data["deploy"][0] = deploy class DeployHostHandler(DeployHosts): @@ -326,6 +348,11 @@ class DeployHostHandler(DeployHosts): save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data) def query(self, hostname): + """ + Query deploy based on hostname + :param hostname: The name of the host. + :return: A list of deploy dictionary + """ super().query(hostname) for deploy in self.data.get("deploy_host", []): if deploy.get("hostname") == hostname: