Validate commit_id sent by controller on deploy host
This commit adds a validation on software agent, to check if the commit_id sent by software controller on deploy host matches with the remote commit_id. Test Plan: PASS: run "deploy host" successfully PASS: simulate commit_id divergence, observe deploy host is blocked, remote is removed and error message is logged Story: 2010676 Task: 49904 Signed-off-by: Heitor Matsui <heitorvieira.matsui@windriver.com> Change-Id: I75176ada3a9534ac2812ecdff366d925e438a836
This commit is contained in:
parent
24016bd363
commit
60898e7ae2
|
@ -546,3 +546,37 @@ def add_ostree_remote(major_release, nodetype):
|
||||||
LOG.exception("Error adding %s ostree remote: %s" % (major_release, str(e)))
|
LOG.exception("Error adding %s ostree remote: %s" % (major_release, str(e)))
|
||||||
raise
|
raise
|
||||||
return rel_name
|
return rel_name
|
||||||
|
|
||||||
|
|
||||||
|
def delete_ostree_remote(remote):
|
||||||
|
"""
|
||||||
|
Delete an ostree remote
|
||||||
|
:param remote: remote name to be deleted
|
||||||
|
"""
|
||||||
|
cmd = ["ostree", "remote", "delete", "--if-exists", remote]
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
LOG.exception("Error deleting %s ostree remote: %s" % (remote, str(e)))
|
||||||
|
|
||||||
|
|
||||||
|
def check_commit_id(remote, commit_id):
|
||||||
|
"""
|
||||||
|
Check if commit_id matches with the commit_id from the remote ostree_repo
|
||||||
|
:param remote: ostree remote name to be checked against
|
||||||
|
:param commit_id: commit_id sent by the controller to the agent
|
||||||
|
:return: boolean indicating if commit_id matches with remote commit_id
|
||||||
|
"""
|
||||||
|
commit_id_match = False
|
||||||
|
cmd = "ostree remote summary %s | grep 'Latest Commit' -A1" % remote
|
||||||
|
try:
|
||||||
|
# output should be similar to:
|
||||||
|
# Latest Commit (<n> bytes):
|
||||||
|
# <ostree_commit_id>
|
||||||
|
output = subprocess.check_output(cmd, shell=True, text=True,
|
||||||
|
stderr=subprocess.STDOUT).strip()
|
||||||
|
remote_commit_id = output.split("\n")[1].strip()
|
||||||
|
commit_id_match = commit_id == remote_commit_id
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
LOG.exception("Error getting remote commit_id: %s: %s" % (str(e), e.stdout))
|
||||||
|
return commit_id_match
|
||||||
|
|
|
@ -340,6 +340,7 @@ class PatchMessageAgentInstallReq(messages.PatchMessage):
|
||||||
messages.PatchMessage.__init__(self, messages.PATCHMSG_AGENT_INSTALL_REQ)
|
messages.PatchMessage.__init__(self, messages.PATCHMSG_AGENT_INSTALL_REQ)
|
||||||
self.force = False
|
self.force = False
|
||||||
self.major_release = None
|
self.major_release = None
|
||||||
|
self.commit_id = None
|
||||||
|
|
||||||
def decode(self, data):
|
def decode(self, data):
|
||||||
messages.PatchMessage.decode(self, data)
|
messages.PatchMessage.decode(self, data)
|
||||||
|
@ -347,13 +348,16 @@ class PatchMessageAgentInstallReq(messages.PatchMessage):
|
||||||
self.force = data['force']
|
self.force = data['force']
|
||||||
if 'major_release' in data:
|
if 'major_release' in data:
|
||||||
self.major_release = data['major_release']
|
self.major_release = data['major_release']
|
||||||
|
if 'commit_id' in data:
|
||||||
|
self.commit_id = data['commit_id']
|
||||||
|
|
||||||
def encode(self):
|
def encode(self):
|
||||||
# Nothing to add to the HELLO_AGENT, so just call the super class
|
# Nothing to add to the HELLO_AGENT, so just call the super class
|
||||||
messages.PatchMessage.encode(self)
|
messages.PatchMessage.encode(self)
|
||||||
|
|
||||||
def handle(self, sock, addr):
|
def handle(self, sock, addr):
|
||||||
LOG.info("Handling host install request, force=%s, major_release=%s", self.force, self.major_release)
|
LOG.info("Handling host install request, force=%s, major_release=%s, commit_id=%s",
|
||||||
|
self.force, self.major_release, self.commit_id)
|
||||||
global pa
|
global pa
|
||||||
resp = PatchMessageAgentInstallResp()
|
resp = PatchMessageAgentInstallResp()
|
||||||
|
|
||||||
|
@ -371,7 +375,7 @@ class PatchMessageAgentInstallReq(messages.PatchMessage):
|
||||||
resp.reject_reason = 'Node must be locked.'
|
resp.reject_reason = 'Node must be locked.'
|
||||||
resp.send(sock, addr)
|
resp.send(sock, addr)
|
||||||
return
|
return
|
||||||
resp.status = pa.handle_install(major_release=self.major_release)
|
resp.status = pa.handle_install(major_release=self.major_release, commit_id=self.commit_id)
|
||||||
resp.send(sock, addr)
|
resp.send(sock, addr)
|
||||||
|
|
||||||
def send(self, sock): # pylint: disable=unused-argument
|
def send(self, sock): # pylint: disable=unused-argument
|
||||||
|
@ -474,10 +478,8 @@ class PatchAgent(PatchService):
|
||||||
self.latest_sysroot_commit = active_sysroot_commit
|
self.latest_sysroot_commit = active_sysroot_commit
|
||||||
self.last_repo_revision = active_sysroot_commit
|
self.last_repo_revision = active_sysroot_commit
|
||||||
|
|
||||||
|
# checks if this is a major release deployment operation
|
||||||
if major_release:
|
if major_release:
|
||||||
upgrade_feed_commit = ostree_utils.get_feed_latest_commit(major_release)
|
|
||||||
LOG.info("Major release deployment for %s with commit %s" % (major_release,
|
|
||||||
upgrade_feed_commit))
|
|
||||||
self.changes = True
|
self.changes = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -504,7 +506,8 @@ class PatchAgent(PatchService):
|
||||||
verbose_to_stdout=False,
|
verbose_to_stdout=False,
|
||||||
disallow_insvc_patch=False,
|
disallow_insvc_patch=False,
|
||||||
delete_older_deployments=False,
|
delete_older_deployments=False,
|
||||||
major_release=None):
|
major_release=None,
|
||||||
|
commit_id=None):
|
||||||
#
|
#
|
||||||
# The disallow_insvc_patch parameter is set when we're installing
|
# The disallow_insvc_patch parameter is set when we're installing
|
||||||
# the patch during init. At that time, we don't want to deal with
|
# the patch during init. At that time, we don't want to deal with
|
||||||
|
@ -558,10 +561,23 @@ class PatchAgent(PatchService):
|
||||||
remote = None
|
remote = None
|
||||||
ref = None
|
ref = None
|
||||||
if major_release:
|
if major_release:
|
||||||
|
LOG.info("Major release deployment for %s with commit %s" % (major_release, commit_id))
|
||||||
|
|
||||||
|
# add remote
|
||||||
nodetype = utils.get_platform_conf("nodetype")
|
nodetype = utils.get_platform_conf("nodetype")
|
||||||
remote = ostree_utils.add_ostree_remote(major_release, nodetype)
|
remote = ostree_utils.add_ostree_remote(major_release, nodetype)
|
||||||
ref = "%s:%s" % (remote, constants.OSTREE_REF)
|
|
||||||
LOG.info("OSTree remote added: %s" % remote)
|
LOG.info("OSTree remote added: %s" % remote)
|
||||||
|
|
||||||
|
# check if remote commit_id matches with the one sent by the controller
|
||||||
|
commit_id_match = ostree_utils.check_commit_id(remote, commit_id)
|
||||||
|
if not commit_id_match:
|
||||||
|
LOG.exception("The OSTree commit_id %s sent by the controller "
|
||||||
|
"doesn't match with the remote commit_id." % commit_id)
|
||||||
|
ostree_utils.delete_ostree_remote(remote)
|
||||||
|
LOG.info("OSTree remote deleted: %s" % remote)
|
||||||
|
return False
|
||||||
|
|
||||||
|
ref = "%s:%s" % (remote, constants.OSTREE_REF)
|
||||||
copy_target_release_pxeboot_files(major_release)
|
copy_target_release_pxeboot_files(major_release)
|
||||||
|
|
||||||
# Build up the install set
|
# Build up the install set
|
||||||
|
|
|
@ -521,12 +521,14 @@ class PatchMessageAgentInstallReq(messages.PatchMessage):
|
||||||
self.ip = None
|
self.ip = None
|
||||||
self.force = False
|
self.force = False
|
||||||
self.major_release = None
|
self.major_release = None
|
||||||
|
self.commit_id = None
|
||||||
|
|
||||||
def encode(self):
|
def encode(self):
|
||||||
global sc
|
global sc
|
||||||
messages.PatchMessage.encode(self)
|
messages.PatchMessage.encode(self)
|
||||||
self.message['force'] = self.force
|
self.message['force'] = self.force
|
||||||
self.message['major_release'] = self.major_release
|
self.message['major_release'] = self.major_release
|
||||||
|
self.message['commit_id'] = self.commit_id
|
||||||
|
|
||||||
def handle(self, sock, addr):
|
def handle(self, sock, addr):
|
||||||
LOG.error("Should not get here")
|
LOG.error("Should not get here")
|
||||||
|
@ -2735,13 +2737,15 @@ class PatchController(PatchService):
|
||||||
# Check if there is a major release deployment in progress
|
# Check if there is a major release deployment in progress
|
||||||
# and set agent request parameters accordingly
|
# and set agent request parameters accordingly
|
||||||
major_release = None
|
major_release = None
|
||||||
|
commit_id = None
|
||||||
upgrade_in_progress = self.get_software_upgrade()
|
upgrade_in_progress = self.get_software_upgrade()
|
||||||
if upgrade_in_progress:
|
if upgrade_in_progress:
|
||||||
major_release = upgrade_in_progress["to_release"]
|
major_release = upgrade_in_progress["to_release"]
|
||||||
|
commit_id = ostree_utils.get_feed_latest_commit(major_release)
|
||||||
force = False
|
force = False
|
||||||
async_req = False
|
async_req = False
|
||||||
msg = "Running major release deployment, major_release=%s, force=%s, async_req=%s" % (
|
msg = "Running major release deployment, major_release=%s, force=%s, async_req=%s, commit_id=%s" % (
|
||||||
major_release, force, async_req)
|
major_release, force, async_req, commit_id)
|
||||||
msg_info += msg + "\n"
|
msg_info += msg + "\n"
|
||||||
LOG.info(msg)
|
LOG.info(msg)
|
||||||
set_host_target_load(hostname, major_release)
|
set_host_target_load(hostname, major_release)
|
||||||
|
@ -2757,6 +2761,7 @@ class PatchController(PatchService):
|
||||||
installreq.ip = ip
|
installreq.ip = ip
|
||||||
installreq.force = force
|
installreq.force = force
|
||||||
installreq.major_release = major_release
|
installreq.major_release = major_release
|
||||||
|
installreq.commit_id = commit_id
|
||||||
installreq.encode()
|
installreq.encode()
|
||||||
self.socket_lock.acquire()
|
self.socket_lock.acquire()
|
||||||
installreq.send(self.sock_out)
|
installreq.send(self.sock_out)
|
||||||
|
|
Loading…
Reference in New Issue