Deploy show implement

This commit add some changes to deploy show endpoint, the name was
changed to just deploy with GET verb and also changes the deploy to
be saved as a list of dict to attend the API requirements. Now the
api accepts from_release and to_release as optional params, in case
it is provided the endpoint will return a dict otherwise will return
a list of dict.

Test Plan:
PASS: Create deploy
PASS: Update deploy
PASS: Software deploy start
PASS: Software deploy show

Story: 2010676
Task: 49645

Change-Id: I68d243c05da88c7eecf2d866c7202c3c7be51a2b
Signed-off-by: Luis Eduardo Bonatti <LuizEduardo.Bonatti@windriver.com>
This commit is contained in:
Luis Eduardo Bonatti 2024-02-22 16:55:32 -03:00
parent 88e95d5c1f
commit 98cd083cff
5 changed files with 78 additions and 36 deletions

View File

@ -1011,7 +1011,7 @@ def deploy_complete_req(args):
def deploy_show_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 = {} headers = {}
append_auth_token_if_required(headers) append_auth_token_if_required(headers)
req = requests.get(url, headers=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)) print("Respond code %d. Error: %s" % (req.status_code, req.reason))
return 1 return 1
data = json.loads(req.text) data = req.json().get("data")
if not data: if not data:
print("No deploy in progress.\n") print("No deploy in progress.")
else: else:
data = data[0]
data["reboot_required"] = "Yes" if data.get("reboot_required") else "No" data["reboot_required"] = "Yes" if data.get("reboot_required") else "No"
data_list = [[k, v] for k, v in data.items()] data_list = [[k, v] for k, v in data.items()]
transposed_data_list = list(zip(*data_list)) transposed_data_list = list(zip(*data_list))

View File

@ -10,6 +10,7 @@ import os
from oslo_log import log from oslo_log import log
from pecan import expose from pecan import expose
from pecan import request from pecan import request
from pecan import Response
import shutil import shutil
from software.exceptions import SoftwareError from software.exceptions import SoftwareError
@ -132,15 +133,13 @@ class SoftwareAPIController(object):
return result return result
@expose('json') @expose('json', method="GET")
@expose('query.xml', content_type='application/xml') def deploy(self):
def deploy_show(self): from_release = request.GET.get("from_release")
try: to_release = request.GET.get("to_release")
result = sc.software_deploy_show_api() result = dict(data=sc.software_deploy_show_api(from_release, to_release))
except SoftwareError as e: response_data = json.dumps(result)
return dict(error="Error: %s" % str(e)) return Response(body=response_data, status_code=200)
return result
@expose('json') @expose('json')
@expose('query.xml', content_type='application/xml') @expose('query.xml', content_type='application/xml')

View File

@ -37,10 +37,17 @@ class SoftwareAPI:
self.deploy_handler.create(from_release, to_release, reboot_required) self.deploy_handler.create(from_release, to_release, reboot_required)
self.end_update() self.end_update()
def get_deploy(self): def get_deploy(self, from_release, to_release):
self.begin_update() self.begin_update()
try: 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: finally:
self.end_update() self.end_update()

View File

@ -2627,9 +2627,13 @@ class PatchController(PatchService):
return dict(info=msg_info, warning=msg_warning, error=msg_error) 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 # 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): def software_deploy_host_api(self, host_ip, force, async_req=False):
msg_info = "" msg_info = ""
@ -2902,7 +2906,11 @@ class PatchController(PatchService):
def deploy_host_list(self): def deploy_host_list(self):
query_hosts = self.query_host_cache() query_hosts = self.query_host_cache()
deploy_hosts = self.db_api_instance.get_deploy_host() 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. # If there's a hostname missing, add it to query hosts.
hostnames = [] hostnames = []

View File

@ -138,7 +138,7 @@ class Deploy(ABC):
""" """
Create a new deployment entry. 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 to_release: The target release version.
:param reboot_required: If is required to do host reboot. :param reboot_required: If is required to do host reboot.
:param state: The state of the deployment. :param state: The state of the deployment.
@ -149,10 +149,11 @@ class Deploy(ABC):
check_instances([state], DEPLOY_STATES) check_instances([state], DEPLOY_STATES)
@abstractmethod @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 pass
@abstractmethod @abstractmethod
@ -160,7 +161,7 @@ class Deploy(ABC):
""" """
Update a deployment entry. 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) check_instances([new_state], DEPLOY_STATES)
@ -168,7 +169,7 @@ class Deploy(ABC):
@abstractmethod @abstractmethod
def delete(self): 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 pass
@ -236,13 +237,13 @@ class DeployHandler(Deploy):
def create(self, from_release, to_release, reboot_required, state=DEPLOY_STATES.START): def create(self, from_release, to_release, reboot_required, state=DEPLOY_STATES.START):
""" """
Create a new deploy with given from and to release version 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 to_release: The target release version.
:param reboot_required: If is required to do host reboot. :param reboot_required: If is required to do host reboot.
:param state: The state of the deployment. :param state: The state of the deployment.
""" """
super().create(from_release, to_release, reboot_required, state) super().create(from_release, to_release, reboot_required, state)
deploy = self.query() deploy = self.query(from_release, to_release)
if deploy: if deploy:
raise DeployAlreadyExist("Error to create. Deploy already exists.") raise DeployAlreadyExist("Error to create. Deploy already exists.")
new_deploy = { new_deploy = {
@ -253,18 +254,39 @@ class DeployHandler(Deploy):
} }
try: 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) save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data)
except Exception: 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 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() super().query(from_release, to_release)
return self.data.get("deploy", {}) 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): def update(self, new_state: DEPLOY_STATES):
""" """
@ -272,29 +294,29 @@ class DeployHandler(Deploy):
:param new_state: The new state :param new_state: The new state
""" """
super().update(new_state) super().update(new_state)
deploy = self.query() deploy = self.query_all()
if not deploy: if not deploy:
raise DeployDoNotExist("Error to update deploy state. No deploy in progress.") raise DeployDoNotExist("Error to update deploy state. No deploy in progress.")
try: 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) save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data)
except Exception: except Exception:
self.data["deploy"] = deploy self.data["deploy"][0] = deploy
def delete(self): def delete(self):
""" """
Delete a deploy based on given from and to release version Delete a deploy based on given from and to release version
""" """
super().delete() super().delete()
deploy = self.query() deploy = self.query_all()
if not deploy: if not deploy:
raise DeployDoNotExist("Error to delete deploy state. No deploy in progress.") raise DeployDoNotExist("Error to delete deploy state. No deploy in progress.")
try: try:
self.data["deploy"] = {} self.data["deploy"].clear()
save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data) save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data)
except Exception: except Exception:
self.data["deploy"] = deploy self.data["deploy"][0] = deploy
class DeployHostHandler(DeployHosts): class DeployHostHandler(DeployHosts):
@ -326,6 +348,11 @@ class DeployHostHandler(DeployHosts):
save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data) save_to_json_file(constants.SOFTWARE_JSON_FILE, self.data)
def query(self, hostname): 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) super().query(hostname)
for deploy in self.data.get("deploy_host", []): for deploy in self.data.get("deploy_host", []):
if deploy.get("hostname") == hostname: if deploy.get("hostname") == hostname: