Skip to content

Commit

Permalink
Reject conflicting entries in run::bind
Browse files Browse the repository at this point in the history
If there is more than one permuation of source and/or options in a 'bind'
entry, reject the configuration.

Change-Id: I4cd23b842470fe6abc4fbda64fdf23d1b2ea153c
  • Loading branch information
matthoosier-garmin authored and JoshuaWatt committed Jul 26, 2024
1 parent c617275 commit e03a3a5
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
52 changes: 52 additions & 0 deletions ci/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,58 @@ def test_malformed_bind_dest(self):
s = self.assertPyrexContainerShellCommand("true", capture=True, returncode=1)
self.assertIn("Error: too many colons in run.bind entry '%s'." % b, s)

def test_duplicate_bind(self):
temp_dir = tempfile.mkdtemp("-pyrex")
self.addCleanup(shutil.rmtree, temp_dir)

conf = self.get_config()
conf["run"]["bind"] += " %s" % (temp_dir)
conf["run"]["bind"] += " %s" % (temp_dir)
conf.write_conf()

self.assertPyrexContainerShellCommand(
"test -e {dir}".format(dir=temp_dir), returncode=0
)

def test_equivalent_bind(self):
temp_dir = tempfile.mkdtemp("-pyrex")
self.addCleanup(shutil.rmtree, temp_dir)

conf = self.get_config()
conf["run"]["bind"] += " %s" % (temp_dir)
conf["run"]["bind"] += " %s:%s" % (temp_dir, temp_dir)
conf.write_conf()

self.assertPyrexContainerShellCommand(
"test -e {dir}".format(dir=temp_dir), returncode=0
)

def test_conflicting_bind_sources(self):
temp_dir1 = tempfile.mkdtemp("-pyrex")
self.addCleanup(shutil.rmtree, temp_dir1)

temp_dir2 = tempfile.mkdtemp("-pyrex")
self.addCleanup(shutil.rmtree, temp_dir2)

conf = self.get_config()
conf["run"]["bind"] += " %s:/dst" % (temp_dir1)
conf["run"]["bind"] += " %s:/dst" % (temp_dir2)
conf.write_conf()

s = self.assertPyrexContainerShellCommand("true", capture=True, returncode=1)
self.assertIn("Error: more than one bind for same destination path", s)

def test_conflicting_bind_options(self):
conf = self.get_config()
conf["run"]["bind"] += " /foo,optional"
conf["run"]["bind"] += " /foo"
conf.write_conf()

s = self.assertPyrexContainerShellCommand(
"test -e /foo", capture=True, returncode=1
)
self.assertIn("Error: more than one bind for same destination path", s)

def test_bad_confversion(self):
# Verify that a bad config is an error
conf = self.get_config()
Expand Down
32 changes: 31 additions & 1 deletion pyrex.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,17 @@ def parse_bind_options(bind):
return src, dst, options


def prettyprint_bind(src, dst, options):
options_keys = list(vars(options).keys())
options_keys.sort()
options_str = ""
for k in options_keys:
if getattr(options, k):
options_str = options_str + ",{option}".format(option=k)

return "{src}:{dst}{options}".format(src=src, dst=dst, options=options_str)


def prep_container(
config,
build_config,
Expand Down Expand Up @@ -547,13 +558,32 @@ def prep_container(
+ os.environ.get("PYREX_CONFIG_BIND", "").split()
+ extra_bind
)
for b in set(binds):

binds_by_dst = {}
prettyprinted_binds_by_dst = {}

for b in binds:
try:
src, dst, options = parse_bind_options(b)
except ParsingError as e:
print("Error: %s" % e)
return []

if dst in binds_by_dst:
# Allow identical entries
if prettyprint_bind(src, dst, options) == prettyprinted_binds_by_dst[dst]:
continue
else:
print(
"Error: more than one bind for same destination path {dst}: '{bind1}' and '{bind2}'".format(
dst=dst, bind1=binds_by_dst[dst], bind2=b
)
)
return []
else:
binds_by_dst[dst] = b
prettyprinted_binds_by_dst[dst] = prettyprint_bind(src, dst, options)

if not os.path.exists(src):
if options.optional:
continue
Expand Down

0 comments on commit e03a3a5

Please sign in to comment.