diff --git a/src/utils/resources.py b/src/utils/resources.py index 0d3f584da..5ce76cabe 100644 --- a/src/utils/resources.py +++ b/src/utils/resources.py @@ -1216,17 +1216,24 @@ class PortsResource(AppResource): if properties[port]["default"] is None: properties[port]["default"] = random.randint(10000, 60000) + # This is to prevent using twice the same port during provisionning. + self.ports_used_by_self: list[int] = [] + super().__init__({"ports": properties}, *args, **kwargs) def _port_is_used(self, port): # FIXME : this could be less brutal than two os.system... - cmd1 = ( + used_by_process = os.system( "ss --numeric --listening --tcp --udp | awk '{print$5}' | grep --quiet --extended-regexp ':%s$'" % port - ) + ) == 0 # This second command is mean to cover (most) case where an app is using a port yet ain't currently using it for some reason (typically service ain't up) - cmd2 = f"grep --quiet --extended-regexp \"port: '?{port}'?\" /etc/yunohost/apps/*/settings.yml" - return os.system(cmd1) == 0 or os.system(cmd2) == 0 + used_by_app = os.system( + f"grep --quiet --extended-regexp \"port: '?{port}'?\" /etc/yunohost/apps/*/settings.yml" + ) == 0 + used_by_self_provisioning = port in self.ports_used_by_self + + return used_by_process or used_by_app or used_by_self_provisioning def provision_or_update(self, context: Dict = {}): from yunohost.firewall import firewall_allow, firewall_disallow @@ -1256,6 +1263,7 @@ class PortsResource(AppResource): while self._port_is_used(port_value): port_value += 1 + self.ports_used_by_self.append(port_value) self.set_setting(setting_name, port_value) if infos["exposed"]: