diff --git a/software/software/ostree_utils.py b/software/software/ostree_utils.py index c5e713e1..cd1a5842 100644 --- a/software/software/ostree_utils.py +++ b/software/software/ostree_utils.py @@ -546,3 +546,37 @@ def add_ostree_remote(major_release, nodetype): LOG.exception("Error adding %s ostree remote: %s" % (major_release, str(e))) raise 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 ( bytes): + # + 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 diff --git a/software/software/software_agent.py b/software/software/software_agent.py index 46549a4e..19322381 100644 --- a/software/software/software_agent.py +++ b/software/software/software_agent.py @@ -340,6 +340,7 @@ class PatchMessageAgentInstallReq(messages.PatchMessage): messages.PatchMessage.__init__(self, messages.PATCHMSG_AGENT_INSTALL_REQ) self.force = False self.major_release = None + self.commit_id = None def decode(self, data): messages.PatchMessage.decode(self, data) @@ -347,13 +348,16 @@ class PatchMessageAgentInstallReq(messages.PatchMessage): self.force = data['force'] if 'major_release' in data: self.major_release = data['major_release'] + if 'commit_id' in data: + self.commit_id = data['commit_id'] def encode(self): # Nothing to add to the HELLO_AGENT, so just call the super class messages.PatchMessage.encode(self) 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 resp = PatchMessageAgentInstallResp() @@ -371,7 +375,7 @@ class PatchMessageAgentInstallReq(messages.PatchMessage): resp.reject_reason = 'Node must be locked.' resp.send(sock, addr) 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) def send(self, sock): # pylint: disable=unused-argument @@ -474,10 +478,8 @@ class PatchAgent(PatchService): self.latest_sysroot_commit = active_sysroot_commit self.last_repo_revision = active_sysroot_commit + # checks if this is a major release deployment operation 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 return True @@ -504,7 +506,8 @@ class PatchAgent(PatchService): verbose_to_stdout=False, disallow_insvc_patch=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 patch during init. At that time, we don't want to deal with @@ -558,10 +561,23 @@ class PatchAgent(PatchService): remote = None ref = None 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") remote = ostree_utils.add_ostree_remote(major_release, nodetype) - ref = "%s:%s" % (remote, constants.OSTREE_REF) 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) # Build up the install set diff --git a/software/software/software_controller.py b/software/software/software_controller.py index 66975fbf..006ad43b 100644 --- a/software/software/software_controller.py +++ b/software/software/software_controller.py @@ -521,12 +521,14 @@ class PatchMessageAgentInstallReq(messages.PatchMessage): self.ip = None self.force = False self.major_release = None + self.commit_id = None def encode(self): global sc messages.PatchMessage.encode(self) self.message['force'] = self.force self.message['major_release'] = self.major_release + self.message['commit_id'] = self.commit_id def handle(self, sock, addr): LOG.error("Should not get here") @@ -2735,13 +2737,15 @@ class PatchController(PatchService): # Check if there is a major release deployment in progress # and set agent request parameters accordingly major_release = None + commit_id = None upgrade_in_progress = self.get_software_upgrade() if upgrade_in_progress: major_release = upgrade_in_progress["to_release"] + commit_id = ostree_utils.get_feed_latest_commit(major_release) force = False async_req = False - msg = "Running major release deployment, major_release=%s, force=%s, async_req=%s" % ( - major_release, force, async_req) + msg = "Running major release deployment, major_release=%s, force=%s, async_req=%s, commit_id=%s" % ( + major_release, force, async_req, commit_id) msg_info += msg + "\n" LOG.info(msg) set_host_target_load(hostname, major_release) @@ -2757,6 +2761,7 @@ class PatchController(PatchService): installreq.ip = ip installreq.force = force installreq.major_release = major_release + installreq.commit_id = commit_id installreq.encode() self.socket_lock.acquire() installreq.send(self.sock_out)