Skip to content

Commit b6491cd

Browse files
committed
Fix bug introduced by e1393a2 commit
1 parent 62f7d14 commit b6491cd

2 files changed

Lines changed: 203 additions & 90 deletions

File tree

iib/workers/tasks/opm_operations.py

Lines changed: 112 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
import os
44
import random
5+
import re
56
import shutil
67
import socket
78
import subprocess
@@ -78,7 +79,7 @@ def lock_acquire(self):
7879
# test if port is free
7980
s.bind(("localhost", self.port))
8081
# create file-lock
81-
f = os.open(self.filename, os.O_CREAT | os.O_EXCL | os.O_RDWR)
82+
f = os.open(self.filename, os.O_CREAT | os.O_EXCL)
8283
self.locked = True
8384
log.debug("Port %s used as %s was locked.", self.port, self.purpose)
8485
except FileExistsError:
@@ -92,7 +93,7 @@ def lock_acquire(self):
9293
finally:
9394
s.close()
9495
if f:
95-
f.close()
96+
os.close(f)
9697

9798
def unlock(self):
9899
"""Delete file representing port lock."""
@@ -143,7 +144,7 @@ def port_file_locks_generator(
143144
raise IIBError(err_msg)
144145

145146

146-
def get_opm_port_stacks() -> Tuple[List[List[int]], List[str]]:
147+
def get_opm_port_stacks(port_purposes: List[str]) -> Tuple[List[List[int]], List[str]]:
147148
"""
148149
Get stack with port numbers and list of their intended purposes.
149150
@@ -160,18 +161,20 @@ def get_opm_port_stacks() -> Tuple[List[List[int]], List[str]]:
160161
Example:
161162
ports, purposes = get_opm_port_stacks()
162163
ports contains: [[50051, 50151], [50052, 50152]]
163-
purposes content: ['opm_port', 'pprof_port']
164+
purposes content: ['opm_port', 'opm_pprof_port']
164165
165166
In this example, ports 50051 and 50052 are port intended to use as 'opm_port' and ports 50151
166-
and 50152 as 'pprof_port'.
167+
and 50152 as 'opm_pprof_port'.
168+
169+
:param list(str) port_purposes: list with port intended purposes
167170
:return: tuple with port stacks and their purposes
168171
:rtype: tuple(list(list(int)), list(str))
169172
"""
170173
conf = get_worker_config()
171-
port_purposes = list(conf.iib_opm_port_ranges)
172174

173-
if Version(Opm.opm_version) < Version(conf.iib_opm_pprof_lock_required_min_version):
174-
port_purposes.remove('pprof_port')
175+
opm_version = Opm.get_opm_version_number()
176+
if Version(opm_version) < Version(conf.iib_opm_pprof_lock_required_min_version):
177+
port_purposes.remove('opm_pprof_port')
175178

176179
# get port_ranges we need for the give opm_version
177180
port_ranges = [range(*conf.iib_opm_port_ranges[port_purpose]) for port_purpose in port_purposes]
@@ -184,60 +187,78 @@ def get_opm_port_stacks() -> Tuple[List[List[int]], List[str]]:
184187
return ports_list, port_purposes
185188

186189

187-
def create_port_filelocks(func: Callable) -> Callable:
190+
def create_port_filelocks(port_purposes: List[str]) -> Callable:
188191
"""
189192
Create a file-lock on random port from the configured range.
190193
191-
:param function func: the function to be decorated
192-
:rtype: function
193-
:return: the decorated function
194+
:param List[str] port_purposes: the list of port purposes to be locked
195+
:rtype: Callable
196+
:return: the decorator function
194197
"""
195198

196-
@wraps(func)
197-
def inner(*args, **kwargs):
199+
def decorator(func: Callable) -> Callable:
200+
"""
201+
Create a file-lock on random port from the configured range.
198202
199-
port_stacks, port_purposes = get_opm_port_stacks()
200-
# Attempt to acquire the lock for each port in the range (shuffled order)
201-
lock_success = False
203+
:param function func: the function to be decorated
204+
:rtype: function
205+
:return: the decorated function
206+
"""
202207

203-
# Initialize the generator
204-
gen = port_file_locks_generator(port_stacks=port_stacks, port_purposes=port_purposes)
208+
@wraps(func)
209+
def inner(*args, **kwargs):
205210

206-
# Use the function to retrieve values from the generator
207-
while not lock_success:
208-
new_locks = next(gen)
209-
currently_active_locks = []
211+
# If we do not have any ports to lock
212+
if len(port_purposes) == 0:
213+
return func(*args, **kwargs)
210214

211-
try:
212-
# Atomically acquire the locks for the given ports
213-
for new_lock in new_locks:
214-
new_lock.lock_acquire()
215-
currently_active_locks.append(new_lock)
216-
217-
port_args = {
218-
port_purpose: currently_active_locks[port_position].port
219-
for port_position, port_purpose in enumerate(port_purposes)
220-
}
221-
222-
result = func(*args, **port_args, **kwargs)
223-
lock_success = True
224-
225-
# Exception raised during execution of func()
226-
except AddressAlreadyInUse:
227-
lock_success = False
228-
for active_lock in currently_active_locks:
229-
active_lock.unlock()
230-
231-
finally:
232-
# Exit loop after successful lock acquisition
233-
if lock_success:
215+
port_stacks, port_purposes_updated = get_opm_port_stacks(port_purposes)
216+
# Attempt to acquire the lock for each port in the range (shuffled order)
217+
lock_success = False
218+
219+
# Initialize the generator
220+
gen = port_file_locks_generator(
221+
port_stacks=port_stacks,
222+
port_purposes=port_purposes_updated,
223+
)
224+
225+
# Use the function to retrieve values from the generator
226+
while not lock_success:
227+
new_locks = next(gen)
228+
currently_active_locks = []
229+
230+
try:
231+
# Atomically acquire the locks for the given ports
232+
for new_lock in new_locks:
233+
new_lock.lock_acquire()
234+
currently_active_locks.append(new_lock)
235+
236+
port_args = {
237+
port_purpose: currently_active_locks[port_position].port
238+
for port_position, port_purpose in enumerate(port_purposes_updated)
239+
}
240+
241+
result = func(*args, **port_args, **kwargs)
242+
lock_success = True
243+
244+
# Exception raised during execution of func()
245+
except AddressAlreadyInUse:
246+
lock_success = False
234247
for active_lock in currently_active_locks:
235248
active_lock.unlock()
236-
break
237249

238-
return result
250+
finally:
251+
# Exit loop after successful lock acquisition
252+
if lock_success:
253+
for active_lock in currently_active_locks:
254+
active_lock.unlock()
255+
break
256+
257+
return result
239258

240-
return inner
259+
return inner
260+
261+
return decorator
241262

242263

243264
def opm_serve_from_index(base_dir: str, from_index: str) -> Tuple[int, subprocess.Popen]:
@@ -263,11 +284,11 @@ def opm_serve_from_index(base_dir: str, from_index: str) -> Tuple[int, subproces
263284
return opm_serve(catalog_dir=catalog_dir)
264285

265286

266-
@create_port_filelocks
287+
@create_port_filelocks(port_purposes=["opm_port", "opm_pprof_port"])
267288
def opm_serve(
268289
opm_port: int,
269290
catalog_dir: str,
270-
pprof_port: Optional[int] = None,
291+
opm_pprof_port: Optional[int] = None,
271292
) -> Tuple[int, subprocess.Popen]:
272293
"""
273294
Locally start OPM service, which can be communicated with using gRPC queries.
@@ -276,7 +297,7 @@ def opm_serve(
276297
binding conflicts. Resolution of port conflicts is handled in this function as well.
277298
278299
:param int opm_port: OPM port number obtained from create_port_filelock decorator
279-
:param int pprof_port: Pprof opm port number obtained from create_port_filelock decorator
300+
:param int opm_pprof_port: Pprof opm port number obtained from create_port_filelock decorator
280301
:param str catalog_dir: path to file-based catalog directory that should be served.
281302
:return: tuple containing port number of the running service and the running Popen object.
282303
:rtype: (int, Popen)
@@ -288,14 +309,14 @@ def opm_serve(
288309
'serve',
289310
catalog_dir,
290311
'-p',
291-
opm_port,
312+
str(opm_port),
292313
'-t',
293314
'/dev/null',
294315
]
295316

296-
if pprof_port:
317+
if opm_pprof_port:
297318
# by default opm uses the 127.0.0.1:6060
298-
cmd.extend(["--pprof-addr", f"127.0.0.1:{pprof_port}"])
319+
cmd.extend(["--pprof-addr", f"127.0.0.1:{str(opm_pprof_port)}"])
299320

300321
cwd = os.path.abspath(os.path.join(catalog_dir, os.path.pardir))
301322
result = (
@@ -305,11 +326,11 @@ def opm_serve(
305326
return result
306327

307328

308-
@create_port_filelocks
329+
@create_port_filelocks(port_purposes=["opm_port", "opm_pprof_port"])
309330
def opm_registry_serve(
310331
opm_port: int,
311332
db_path: str,
312-
pprof_port: Optional[int] = None,
333+
opm_pprof_port: Optional[int] = None,
313334
) -> Tuple[int, subprocess.Popen]:
314335
"""
315336
Locally start OPM registry service, which can be communicated with using gRPC queries.
@@ -318,7 +339,7 @@ def opm_registry_serve(
318339
binding conflicts. Resolution of port conflicts is handled in this function as well.
319340
320341
:param int opm_port: OPM port number obtained from create_port_filelock decorator
321-
:param int pprof_port: Pprof opm port number obtained from create_port_filelock decorator
342+
:param int opm_pprof_port: Pprof opm port number obtained from create_port_filelock decorator
322343
:param str db_path: path to index database containing the registry data.
323344
:return: tuple containing port number of the running service and the running Popen object.
324345
:rtype: (int, Popen)
@@ -330,15 +351,15 @@ def opm_registry_serve(
330351
'registry',
331352
'serve',
332353
'-p',
333-
opm_port,
354+
str(opm_port),
334355
'-d',
335356
db_path,
336357
'-t',
337358
'/dev/null',
338359
]
339-
if pprof_port:
360+
if opm_pprof_port:
340361
# by default opm uses the 127.0.0.1:6060
341-
cmd.extend(["--pprof-addr", f"127.0.0.1:{pprof_port}"])
362+
cmd.extend(["--pprof-addr", f"127.0.0.1:{str(opm_pprof_port)}"])
342363

343364
cwd = os.path.dirname(db_path)
344365
result = (
@@ -695,7 +716,13 @@ def insert_cache_into_dockerfile(dockerfile_path: str) -> None:
695716
verify_cache_insertion_edit_dockerfile(f.readlines())
696717

697718

698-
def generate_cache_locally(base_dir: str, fbc_dir: str, local_cache_path: str) -> None:
719+
@create_port_filelocks(port_purposes=["opm_pprof_port"])
720+
def generate_cache_locally(
721+
base_dir: str,
722+
fbc_dir: str,
723+
local_cache_path: str,
724+
opm_pprof_port: Optional[int] = None,
725+
) -> None:
699726
"""
700727
Generate the cache for the index image locally before building it.
701728
@@ -719,6 +746,10 @@ def generate_cache_locally(base_dir: str, fbc_dir: str, local_cache_path: str) -
719746
'/dev/null',
720747
]
721748

749+
if opm_pprof_port:
750+
# by default opm uses the 127.0.0.1:6060
751+
cmd.extend(["--pprof-addr", f"127.0.0.1:{str(opm_pprof_port)}"])
752+
722753
log.info('Generating cache for the file-based catalog')
723754
if os.path.exists(local_cache_path):
724755
shutil.rmtree(local_cache_path)
@@ -1369,3 +1400,22 @@ def set_opm_version(cls, from_index: Optional[str] = None):
13691400
if index_version in opm_versions_config:
13701401
Opm.opm_version = opm_versions_config.get(index_version)
13711402
log.info("OPM version set to %s", Opm.opm_version)
1403+
1404+
@classmethod
1405+
def get_opm_version_number(cls):
1406+
"""
1407+
Get the opm version number to be used for the entire IIB operation.
1408+
1409+
:return: currently set-up Opm version number
1410+
:rtype: str
1411+
"""
1412+
log.info("Determining the OPM version number")
1413+
1414+
from iib.workers.tasks.utils import run_cmd
1415+
1416+
opm_version_output = run_cmd([Opm.opm_version, 'version'])
1417+
match = re.search(r'OpmVersion:"v([\d.]+)"', opm_version_output)
1418+
if match:
1419+
return match.group(1)
1420+
else:
1421+
raise IIBError("Opm version not found in the output of \"OPM version\" command")

0 commit comments

Comments
 (0)