Merge "Add support for application patch dependencies"
This commit is contained in:
commit
5edab5cf8b
@ -31,6 +31,9 @@ function _swpatch()
|
|||||||
upload-dir
|
upload-dir
|
||||||
what-requires
|
what-requires
|
||||||
drop-host
|
drop-host
|
||||||
|
is-applied
|
||||||
|
report-app-dependencies
|
||||||
|
query-app-dependencies
|
||||||
"
|
"
|
||||||
if [ -f /etc/platform/.initial_config_complete ]; then
|
if [ -f /etc/platform/.initial_config_complete ]; then
|
||||||
# Post-config, so the host-install commands are accessible
|
# Post-config, so the host-install commands are accessible
|
||||||
@ -48,12 +51,18 @@ function _swpatch()
|
|||||||
# Complete the arguments to the subcommands.
|
# Complete the arguments to the subcommands.
|
||||||
#
|
#
|
||||||
case "$subcommand" in
|
case "$subcommand" in
|
||||||
apply|remove|delete|show|what-requires)
|
apply|delete|show|what-requires|is-applied)
|
||||||
# Query the list of known patches
|
# Query the list of known patches
|
||||||
local patches=$(sw-patch completion patches 2>/dev/null)
|
local patches=$(sw-patch completion patches 2>/dev/null)
|
||||||
COMPREPLY=( $(compgen -W "${patches}" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "${patches}" -- ${cur}) )
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
remove)
|
||||||
|
# Query the list of known patches
|
||||||
|
local patches=$(sw-patch completion patches 2>/dev/null)
|
||||||
|
COMPREPLY=( $(compgen -W "--skipappcheck ${patches}" -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
host-install|host-install-async|drop-host)
|
host-install|host-install-async|drop-host)
|
||||||
if [ "${prev}" = "${subcommand}" -o "${prev}" = "--force" ]; then
|
if [ "${prev}" = "${subcommand}" -o "${prev}" = "--force" ]; then
|
||||||
# Query the list of known hosts
|
# Query the list of known hosts
|
||||||
@ -109,6 +118,20 @@ function _swpatch()
|
|||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
report-app-dependencies)
|
||||||
|
if [ "${prev}" = "${subcommand}" ]; then
|
||||||
|
COMPREPLY=( $(compgen -W "--app" -- ${cur}) )
|
||||||
|
elif [ "${prev}" = "--app" ]; then
|
||||||
|
COMPREPLY=
|
||||||
|
else
|
||||||
|
local patches=$(sw-patch completion patches 2>/dev/null)
|
||||||
|
COMPREPLY=( $(compgen -W "${patches}" -- ${cur}) )
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
query-app-dependencies)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2014-2017 Wind River Systems, Inc.
|
Copyright (c) 2014-2019 Wind River Systems, Inc.
|
||||||
|
|
||||||
SPDX-License-Identifier: Apache-2.0
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
@ -258,6 +258,25 @@ class PatchAPIController(object):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def is_applied(self, *args):
|
||||||
|
return pc.is_applied(list(args))
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def report_app_dependencies(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
result = pc.report_app_dependencies(list(args), **kwargs)
|
||||||
|
except PatchError as e:
|
||||||
|
return dict(status=500, error=e.message)
|
||||||
|
|
||||||
|
pc.patch_sync()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@expose('json')
|
||||||
|
def query_app_dependencies(self):
|
||||||
|
return pc.query_app_dependencies()
|
||||||
|
|
||||||
|
|
||||||
class RootController(object):
|
class RootController(object):
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2015-2017 Wind River Systems, Inc.
|
Copyright (c) 2015-2019 Wind River Systems, Inc.
|
||||||
|
|
||||||
SPDX-License-Identifier: Apache-2.0
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
@ -20,6 +20,8 @@ PATCH_AGENT_STATE_INSTALLING = "installing"
|
|||||||
PATCH_AGENT_STATE_INSTALL_FAILED = "install-failed"
|
PATCH_AGENT_STATE_INSTALL_FAILED = "install-failed"
|
||||||
PATCH_AGENT_STATE_INSTALL_REJECTED = "install-rejected"
|
PATCH_AGENT_STATE_INSTALL_REJECTED = "install-rejected"
|
||||||
|
|
||||||
|
PATCH_STORAGE_DIR = "/opt/patching"
|
||||||
|
|
||||||
ADDRESS_VERSION_IPV4 = 4
|
ADDRESS_VERSION_IPV4 = 4
|
||||||
ADDRESS_VERSION_IPV6 = 6
|
ADDRESS_VERSION_IPV6 = 6
|
||||||
CONTROLLER_FLOATING_HOSTNAME = "controller"
|
CONTROLLER_FLOATING_HOSTNAME = "controller"
|
||||||
|
@ -45,3 +45,8 @@ class PatchValidationFailure(PatchError):
|
|||||||
class PatchMismatchFailure(PatchError):
|
class PatchMismatchFailure(PatchError):
|
||||||
"""Patch validation error."""
|
"""Patch validation error."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PatchInvalidRequest(PatchError):
|
||||||
|
"""Invalid API request."""
|
||||||
|
pass
|
||||||
|
@ -60,6 +60,13 @@ help_install_local = "Trigger patch install/remove on the local host. " + \
|
|||||||
help_drop_host = "Drop specified host from table."
|
help_drop_host = "Drop specified host from table."
|
||||||
help_query_dependencies = "List dependencies for specified patch. Use " + \
|
help_query_dependencies = "List dependencies for specified patch. Use " + \
|
||||||
constants.CLI_OPT_RECURSIVE + " for recursive query."
|
constants.CLI_OPT_RECURSIVE + " for recursive query."
|
||||||
|
help_is_applied = "Query Applied state for list of patches. " + \
|
||||||
|
"Returns True if all are Applied, False otherwise."
|
||||||
|
help_report_app_dependencies = "Report application patch dependencies, " + \
|
||||||
|
"specifying application name with --app option, plus a list of patches. " + \
|
||||||
|
"Reported dependencies can be dropped by specifying app with no patch list."
|
||||||
|
help_query_app_dependencies = "Display set of reported application patch " + \
|
||||||
|
"dependencies."
|
||||||
help_commit = "Commit patches to free disk space. WARNING: This action " + \
|
help_commit = "Commit patches to free disk space. WARNING: This action " + \
|
||||||
"is irreversible!"
|
"is irreversible!"
|
||||||
help_region_name = "Send the request to a specified region"
|
help_region_name = "Send the request to a specified region"
|
||||||
@ -132,6 +139,15 @@ def print_help():
|
|||||||
print(textwrap.fill(" {0:<15} ".format("query-dependencies:") + help_query_dependencies,
|
print(textwrap.fill(" {0:<15} ".format("query-dependencies:") + help_query_dependencies,
|
||||||
width=TERM_WIDTH, subsequent_indent=' ' * 20))
|
width=TERM_WIDTH, subsequent_indent=' ' * 20))
|
||||||
print("")
|
print("")
|
||||||
|
print(textwrap.fill(" {0:<15} ".format("is-applied:") + help_is_applied,
|
||||||
|
width=TERM_WIDTH, subsequent_indent=' ' * 20))
|
||||||
|
print("")
|
||||||
|
print(textwrap.fill(" {0:<15} ".format("report-app-dependencies:") + help_report_app_dependencies,
|
||||||
|
width=TERM_WIDTH, subsequent_indent=' ' * 20))
|
||||||
|
print("")
|
||||||
|
print(textwrap.fill(" {0:<15} ".format("query-app-dependencies:") + help_query_app_dependencies,
|
||||||
|
width=TERM_WIDTH, subsequent_indent=' ' * 20))
|
||||||
|
print("")
|
||||||
print(textwrap.fill(" {0:<15} ".format("commit:") + help_commit,
|
print(textwrap.fill(" {0:<15} ".format("commit:") + help_commit,
|
||||||
width=TERM_WIDTH, subsequent_indent=' ' * 20))
|
width=TERM_WIDTH, subsequent_indent=' ' * 20))
|
||||||
print("")
|
print("")
|
||||||
@ -433,14 +449,14 @@ def patch_apply_req(debug, args):
|
|||||||
|
|
||||||
|
|
||||||
def patch_remove_req(debug, args):
|
def patch_remove_req(debug, args):
|
||||||
extra_opts = ""
|
|
||||||
|
|
||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
print_help()
|
print_help()
|
||||||
|
|
||||||
# Ignore interrupts during this function
|
# Ignore interrupts during this function
|
||||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
|
||||||
|
extra_opts = []
|
||||||
|
|
||||||
# The removeunremovable option is hidden and should not be added to help
|
# The removeunremovable option is hidden and should not be added to help
|
||||||
# text or customer documentation. It is for emergency use only - under
|
# text or customer documentation. It is for emergency use only - under
|
||||||
# supervision of the design team.
|
# supervision of the design team.
|
||||||
@ -450,12 +466,25 @@ def patch_remove_req(debug, args):
|
|||||||
# Get rid of the --removeunremovable
|
# Get rid of the --removeunremovable
|
||||||
args.pop(idx)
|
args.pop(idx)
|
||||||
|
|
||||||
# Format the extra opts
|
# Append the extra opts
|
||||||
extra_opts = "?removeunremovable=yes"
|
extra_opts.append('removeunremovable=yes')
|
||||||
|
|
||||||
|
if "--skipappcheck" in args:
|
||||||
|
idx = args.index("--skipappcheck")
|
||||||
|
|
||||||
|
# Get rid of the --skipappcheck
|
||||||
|
args.pop(idx)
|
||||||
|
|
||||||
|
# Append the extra opts
|
||||||
|
extra_opts.append("skipappcheck=yes")
|
||||||
|
|
||||||
|
if len(extra_opts) == 0:
|
||||||
|
extra_opts_str = ''
|
||||||
|
else:
|
||||||
|
extra_opts_str = '?%s' % '&'.join(extra_opts)
|
||||||
|
|
||||||
patches = "/".join(args)
|
patches = "/".join(args)
|
||||||
|
url = "http://%s/patch/remove/%s%s" % (api_addr, patches, extra_opts_str)
|
||||||
url = "http://%s/patch/remove/%s%s" % (api_addr, patches, extra_opts)
|
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
append_auth_token_if_required(headers)
|
append_auth_token_if_required(headers)
|
||||||
@ -1097,6 +1126,103 @@ def patch_del_release(debug, args):
|
|||||||
return check_rc(req)
|
return check_rc(req)
|
||||||
|
|
||||||
|
|
||||||
|
def patch_is_applied_req(args):
|
||||||
|
if len(args) == 0:
|
||||||
|
print_help()
|
||||||
|
|
||||||
|
patches = "/".join(args)
|
||||||
|
url = "http://%s/patch/is_applied/%s" % (api_addr, patches)
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
append_auth_token_if_required(headers)
|
||||||
|
req = requests.post(url, headers=headers)
|
||||||
|
|
||||||
|
rc = 1
|
||||||
|
|
||||||
|
if req.status_code == 200:
|
||||||
|
result = json.loads(req.text)
|
||||||
|
print(result)
|
||||||
|
if result is True:
|
||||||
|
rc = 0
|
||||||
|
elif req.status_code == 500:
|
||||||
|
print("An internal error has occurred. Please check /var/log/patching.log for details")
|
||||||
|
|
||||||
|
return rc
|
||||||
|
|
||||||
|
|
||||||
|
def patch_report_app_dependencies_req(debug, args):
|
||||||
|
if len(args) < 2:
|
||||||
|
print_help()
|
||||||
|
|
||||||
|
extra_opts = []
|
||||||
|
|
||||||
|
if "--app" in args:
|
||||||
|
idx = args.index("--app")
|
||||||
|
|
||||||
|
# Get rid of the --app and get the app name
|
||||||
|
args.pop(idx)
|
||||||
|
app = args.pop(idx)
|
||||||
|
|
||||||
|
# Append the extra opts
|
||||||
|
extra_opts.append("app=%s" % app)
|
||||||
|
else:
|
||||||
|
print("Application name must be specified with --app argument.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
extra_opts_str = '?%s' % '&'.join(extra_opts)
|
||||||
|
|
||||||
|
patches = "/".join(args)
|
||||||
|
url = "http://%s/patch/report_app_dependencies/%s%s" % (api_addr, patches, extra_opts_str)
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
append_auth_token_if_required(headers)
|
||||||
|
req = requests.post(url, headers=headers)
|
||||||
|
|
||||||
|
if req.status_code == 200:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def patch_query_app_dependencies_req():
|
||||||
|
url = "http://%s/patch/query_app_dependencies" % api_addr
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
append_auth_token_if_required(headers)
|
||||||
|
req = requests.post(url, headers=headers)
|
||||||
|
|
||||||
|
if req.status_code == 200:
|
||||||
|
data = json.loads(req.text)
|
||||||
|
if len(data) == 0:
|
||||||
|
print("There are no application dependencies.")
|
||||||
|
else:
|
||||||
|
hdr_app = "Application"
|
||||||
|
hdr_list = "Required Patches"
|
||||||
|
width_app = len(hdr_app)
|
||||||
|
width_list = len(hdr_list)
|
||||||
|
|
||||||
|
for app, patch_list in data.items():
|
||||||
|
width_app = max(width_app, len(app))
|
||||||
|
width_list = max(width_list, len(', '.join(patch_list)))
|
||||||
|
|
||||||
|
print("{0:<{width_app}} {1:<{width_list}}".format(
|
||||||
|
hdr_app, hdr_list,
|
||||||
|
width_app=width_app, width_list=width_list))
|
||||||
|
|
||||||
|
print("{0} {1}".format(
|
||||||
|
'=' * width_app, '=' * width_list))
|
||||||
|
|
||||||
|
for app, patch_list in sorted(data.items()):
|
||||||
|
print("{0:<{width_app}} {1:<{width_list}}".format(
|
||||||
|
app, ', '.join(patch_list),
|
||||||
|
width_app=width_app, width_list=width_list))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print("An internal error has occurred. Please check /var/log/patching.log for details")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def completion_opts(args):
|
def completion_opts(args):
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
return 1
|
return 1
|
||||||
@ -1306,6 +1432,12 @@ def main():
|
|||||||
rc = patch_init_release(debug, sys.argv[2:])
|
rc = patch_init_release(debug, sys.argv[2:])
|
||||||
elif action == "del-release":
|
elif action == "del-release":
|
||||||
rc = patch_del_release(debug, sys.argv[2:])
|
rc = patch_del_release(debug, sys.argv[2:])
|
||||||
|
elif action == "is-applied":
|
||||||
|
rc = patch_is_applied_req(sys.argv[2:])
|
||||||
|
elif action == "report-app-dependencies":
|
||||||
|
rc = patch_report_app_dependencies_req(debug, sys.argv[2:])
|
||||||
|
elif action == "query-app-dependencies":
|
||||||
|
rc = patch_query_app_dependencies_req()
|
||||||
elif action == "completion":
|
elif action == "completion":
|
||||||
rc = completion_opts(sys.argv[2:])
|
rc = completion_opts(sys.argv[2:])
|
||||||
else:
|
else:
|
||||||
|
@ -5,6 +5,7 @@ SPDX-License-Identifier: Apache-2.0
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import shutil
|
import shutil
|
||||||
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import socket
|
import socket
|
||||||
@ -36,6 +37,7 @@ from cgcs_patch.exceptions import MetadataFail
|
|||||||
from cgcs_patch.exceptions import RpmFail
|
from cgcs_patch.exceptions import RpmFail
|
||||||
from cgcs_patch.exceptions import PatchError
|
from cgcs_patch.exceptions import PatchError
|
||||||
from cgcs_patch.exceptions import PatchFail
|
from cgcs_patch.exceptions import PatchFail
|
||||||
|
from cgcs_patch.exceptions import PatchInvalidRequest
|
||||||
from cgcs_patch.exceptions import PatchValidationFailure
|
from cgcs_patch.exceptions import PatchValidationFailure
|
||||||
from cgcs_patch.exceptions import PatchMismatchFailure
|
from cgcs_patch.exceptions import PatchMismatchFailure
|
||||||
from cgcs_patch.patch_functions import LOG
|
from cgcs_patch.patch_functions import LOG
|
||||||
@ -58,7 +60,9 @@ CONF = oslo_cfg.CONF
|
|||||||
pidfile_path = "/var/run/patch_controller.pid"
|
pidfile_path = "/var/run/patch_controller.pid"
|
||||||
|
|
||||||
pc = None
|
pc = None
|
||||||
state_file = "/opt/patching/.controller.state"
|
state_file = "%s/.controller.state" % constants.PATCH_STORAGE_DIR
|
||||||
|
app_dependency_basename = "app_dependencies.json"
|
||||||
|
app_dependency_filename = "%s/%s" % (constants.PATCH_STORAGE_DIR, app_dependency_basename)
|
||||||
|
|
||||||
insvc_patch_restart_controller = "/run/patching/.restart.patch-controller"
|
insvc_patch_restart_controller = "/run/patching/.restart.patch-controller"
|
||||||
|
|
||||||
@ -581,6 +585,15 @@ class PatchController(PatchService):
|
|||||||
|
|
||||||
self.allow_insvc_patching = True
|
self.allow_insvc_patching = True
|
||||||
|
|
||||||
|
if os.path.exists(app_dependency_filename):
|
||||||
|
try:
|
||||||
|
with open(app_dependency_filename, 'r') as f:
|
||||||
|
self.app_dependencies = json.loads(f.read())
|
||||||
|
except Exception:
|
||||||
|
LOG.exception("Failed to read app dependencies: %s" % app_dependency_filename)
|
||||||
|
else:
|
||||||
|
self.app_dependencies = {}
|
||||||
|
|
||||||
if os.path.isfile(state_file):
|
if os.path.isfile(state_file):
|
||||||
self.read_state_file()
|
self.read_state_file()
|
||||||
else:
|
else:
|
||||||
@ -669,6 +682,16 @@ class PatchController(PatchService):
|
|||||||
self.patch_data.load_all()
|
self.patch_data.load_all()
|
||||||
self.check_patch_states()
|
self.check_patch_states()
|
||||||
self.hosts_lock.release()
|
self.hosts_lock.release()
|
||||||
|
|
||||||
|
if os.path.exists(app_dependency_filename):
|
||||||
|
try:
|
||||||
|
with open(app_dependency_filename, 'r') as f:
|
||||||
|
self.app_dependencies = json.loads(f.read())
|
||||||
|
except Exception:
|
||||||
|
LOG.exception("Failed to read app dependencies: %s" % app_dependency_filename)
|
||||||
|
else:
|
||||||
|
self.app_dependencies = {}
|
||||||
|
|
||||||
self.patch_data_lock.release()
|
self.patch_data_lock.release()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@ -1221,6 +1244,24 @@ 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)
|
||||||
|
|
||||||
|
if kwargs.get("skipappcheck") != "yes":
|
||||||
|
# Check application dependencies before removing
|
||||||
|
required_patches = {}
|
||||||
|
for patch_id in patch_list:
|
||||||
|
for appname, iter_patch_list in self.app_dependencies.items():
|
||||||
|
if patch_id in iter_patch_list:
|
||||||
|
if patch_id not in required_patches:
|
||||||
|
required_patches[patch_id] = []
|
||||||
|
required_patches[patch_id].append(appname)
|
||||||
|
|
||||||
|
if len(required_patches) > 0:
|
||||||
|
for req_patch, app_list in required_patches.items():
|
||||||
|
msg = "%s is required by application(s): %s" % (req_patch, ", ".join(sorted(app_list)))
|
||||||
|
msg_error += msg + "\n"
|
||||||
|
LOG.info(msg)
|
||||||
|
|
||||||
|
return dict(info=msg_info, warning=msg_warning, error=msg_error)
|
||||||
|
|
||||||
for patch_id in patch_list:
|
for patch_id in patch_list:
|
||||||
msg = "Removing patch: %s" % patch_id
|
msg = "Removing patch: %s" % patch_id
|
||||||
LOG.info(msg)
|
LOG.info(msg)
|
||||||
@ -2103,6 +2144,71 @@ 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 is_applied(self, patch_ids):
|
||||||
|
all_applied = True
|
||||||
|
|
||||||
|
self.patch_data_lock.acquire()
|
||||||
|
|
||||||
|
for patch_id in patch_ids:
|
||||||
|
if patch_id not in self.patch_data.metadata:
|
||||||
|
all_applied = False
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.patch_data.metadata[patch_id]["patchstate"] != constants.APPLIED:
|
||||||
|
all_applied = False
|
||||||
|
break
|
||||||
|
|
||||||
|
self.patch_data_lock.release()
|
||||||
|
|
||||||
|
return all_applied
|
||||||
|
|
||||||
|
def report_app_dependencies(self, patch_ids, **kwargs):
|
||||||
|
"""
|
||||||
|
Handle report of application dependencies
|
||||||
|
"""
|
||||||
|
if "app" not in kwargs:
|
||||||
|
raise PatchInvalidRequest
|
||||||
|
|
||||||
|
appname = kwargs.get("app")
|
||||||
|
|
||||||
|
LOG.info("Handling app dependencies report: app=%s, patch_ids=%s" %
|
||||||
|
(appname, ','.join(patch_ids)))
|
||||||
|
|
||||||
|
self.patch_data_lock.acquire()
|
||||||
|
|
||||||
|
if len(patch_ids) == 0:
|
||||||
|
if appname in self.app_dependencies:
|
||||||
|
del self.app_dependencies[appname]
|
||||||
|
else:
|
||||||
|
self.app_dependencies[appname] = patch_ids
|
||||||
|
|
||||||
|
try:
|
||||||
|
tmpfile, tmpfname = tempfile.mkstemp(
|
||||||
|
prefix=app_dependency_basename,
|
||||||
|
dir=constants.PATCH_STORAGE_DIR)
|
||||||
|
|
||||||
|
os.write(tmpfile, json.dumps(self.app_dependencies))
|
||||||
|
os.close(tmpfile)
|
||||||
|
|
||||||
|
os.rename(tmpfname, app_dependency_filename)
|
||||||
|
except Exception:
|
||||||
|
LOG.exception("Failed in report_app_dependencies")
|
||||||
|
raise PatchFail("Internal failure")
|
||||||
|
finally:
|
||||||
|
self.patch_data_lock.release()
|
||||||
|
|
||||||
|
def query_app_dependencies(self):
|
||||||
|
"""
|
||||||
|
Query application dependencies
|
||||||
|
"""
|
||||||
|
self.patch_data_lock.acquire()
|
||||||
|
|
||||||
|
data = self.app_dependencies
|
||||||
|
|
||||||
|
self.patch_data_lock.release()
|
||||||
|
|
||||||
|
return dict(data)
|
||||||
|
|
||||||
|
|
||||||
# The wsgiref.simple_server module has an error handler that catches
|
# The wsgiref.simple_server module has an error handler that catches
|
||||||
# and prints any exceptions that occur during the API handling to stderr.
|
# and prints any exceptions that occur during the API handling to stderr.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
"""
|
"""
|
||||||
Copyright (c) 2014-2018 Wind River Systems, Inc.
|
Copyright (c) 2014-2019 Wind River Systems, Inc.
|
||||||
|
|
||||||
SPDX-License-Identifier: Apache-2.0
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ except Exception:
|
|||||||
SW_VERSION = "unknown"
|
SW_VERSION = "unknown"
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
patch_dir = "/opt/patching"
|
patch_dir = constants.PATCH_STORAGE_DIR
|
||||||
avail_dir = "%s/metadata/available" % patch_dir
|
avail_dir = "%s/metadata/available" % patch_dir
|
||||||
applied_dir = "%s/metadata/applied" % patch_dir
|
applied_dir = "%s/metadata/applied" % patch_dir
|
||||||
committed_dir = "%s/metadata/committed" % patch_dir
|
committed_dir = "%s/metadata/committed" % patch_dir
|
||||||
|
Loading…
x
Reference in New Issue
Block a user