Skip to content

Commit 4d98c99

Browse files
authored
Merge pull request DIRACGrid#8050 from fstagni/cherry-pick-2-9af438937-integration
[sweep:integration] dirac-apptainer-exec: creating the correct environment inside the container
2 parents 204757e + dbd11ff commit 4d98c99

File tree

9 files changed

+71
-75
lines changed

9 files changed

+71
-75
lines changed

src/DIRAC/Core/LCG/GOCDBClient.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,11 @@ def getHostnameDowntime(self, hostname, startDate=None, ongoing=False):
210210
if ongoing:
211211
params += "&ongoing_only=yes"
212212

213-
caPath = getCAsLocation()
214-
215213
try:
216214
response = requests.get(
217-
"https://goc.egi.eu/gocdbpi/public/?method=get_downtime&topentity=" + params, verify=caPath, timeout=20
215+
"https://goc.egi.eu/gocdbpi/public/?method=get_downtime&topentity=" + params,
216+
verify=getCAsLocation(),
217+
timeout=20,
218218
)
219219
response.raise_for_status()
220220
except requests.exceptions.RequestException as e:
@@ -269,8 +269,7 @@ def _downTimeCurlDownload(self, entity=None, startDate=None):
269269
gocdb_ep = gocdb_ep + "&topentity=" + entity
270270
gocdb_ep = gocdb_ep + when + gocdbpi_startDate + "&scope="
271271

272-
caPath = getCAsLocation()
273-
dtPage = requests.get(gocdb_ep, verify=caPath, timeout=20)
272+
dtPage = requests.get(gocdb_ep, verify=getCAsLocation(), timeout=20)
274273

275274
dt = dtPage.text
276275

@@ -294,8 +293,7 @@ def _getServiceEndpointCurlDownload(self, granularity, entity):
294293
# GOCDB-PI query
295294
gocdb_ep = "https://goc.egi.eu/gocdbpi/public/?method=get_service_endpoint&" + granularity + "=" + entity
296295

297-
caPath = getCAsLocation()
298-
service_endpoint_page = requests.get(gocdb_ep, verify=caPath, timeout=20)
296+
service_endpoint_page = requests.get(gocdb_ep, verify=getCAsLocation(), timeout=20)
299297

300298
return service_endpoint_page.text
301299

src/DIRAC/Core/Security/IAMService.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33

44
import requests
55

6-
from DIRAC import gConfig, gLogger, S_OK, S_ERROR
7-
from DIRAC.Core.Utilities import DErrno
8-
from DIRAC.Core.Security.Locations import getProxyLocation, getCAsLocation
9-
from DIRAC.Core.Utilities.Decorators import deprecated
10-
from DIRAC.ConfigurationSystem.Client.Helpers.Registry import getVOOption
6+
from DIRAC import S_OK, gConfig, gLogger
117
from DIRAC.ConfigurationSystem.Client.Helpers.CSGlobals import getVO
128

139

src/DIRAC/Core/Security/Locations.py

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
""" Collection of utilities for locating certs, proxy, CAs
22
"""
33
import os
4+
45
import DIRAC
56
from DIRAC import gConfig
67

@@ -24,12 +25,6 @@ def getProxyLocation():
2425
if os.path.isfile(f"/tmp/{proxyName}"):
2526
return f"/tmp/{proxyName}"
2627

27-
# No gridproxy found
28-
return False
29-
30-
31-
# Retrieve CA's location
32-
3328

3429
def getCAsLocation():
3530
"""Retrieve the CA's files location"""
@@ -63,22 +58,36 @@ def getCAsLocationNoConfig():
6358
casPath = "/etc/grid-security/certificates"
6459
if os.path.isdir(casPath):
6560
return casPath
66-
# No CA's location found
67-
return False
68-
69-
70-
# Retrieve CA's location
71-
72-
73-
def getCAsDefaultLocation():
74-
"""Retrievethe CAs Location inside DIRAC etc directory"""
7561
# rootPath./etc/grid-security/certificates
7662
casPath = f"{DIRAC.rootPath}/etc/grid-security/certificates"
77-
return casPath
63+
if os.path.isdir(casPath):
64+
return casPath
7865

7966

80-
# TODO: Static depending on files specified on CS
81-
# Retrieve certificate
67+
def getVOMSLocation():
68+
"""Retrieve the CA's files location"""
69+
# Grid-Security
70+
retVal = gConfig.getOption(f"{g_SecurityConfPath}/Grid-Security")
71+
if retVal["OK"]:
72+
vomsPath = f"{retVal['Value']}/vomsdir"
73+
if os.path.isdir(vomsPath):
74+
return vomsPath
75+
# Look up the X509_VOMS_DIR environment variable
76+
if "X509_VOMS_DIR" in os.environ:
77+
vomsPath = os.environ["X509_VOMS_DIR"]
78+
return vomsPath
79+
# rootPath./etc/grid-security/vomsdir
80+
vomsPath = f"{DIRAC.rootPath}/etc/grid-security/vomsdir"
81+
if os.path.isdir(vomsPath):
82+
return vomsPath
83+
# /etc/grid-security/vomsdir
84+
vomsPath = "/etc/grid-security/vomsdir"
85+
if os.path.isdir(vomsPath):
86+
return vomsPath
87+
# rootPath./etc/grid-security/vomsdir
88+
vomsPath = f"{DIRAC.rootPath}/etc/grid-security/vomsdir"
89+
if os.path.isdir(vomsPath):
90+
return vomsPath
8291

8392

8493
def getHostCertificateAndKeyLocation(specificLocation=None):

src/DIRAC/Core/Security/VOMSService.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ def getUsers(self):
6464
if not self.urls:
6565
return S_ERROR(DErrno.ENOAUTH, "No VOMS server defined")
6666

67-
userProxy = getProxyLocation()
68-
caPath = getCAsLocation()
6967
rawUserList = []
7068
result = None
7169
for url in self.urls:
@@ -79,8 +77,8 @@ def getUsers(self):
7977
result = requests.get(
8078
url,
8179
headers={"X-VOMS-CSRF-GUARD": "y"},
82-
cert=userProxy,
83-
verify=caPath,
80+
cert=getProxyLocation(),
81+
verify=getCAsLocation(),
8482
params={"startIndex": str(startIndex), "pageSize": "100"},
8583
)
8684
except requests.ConnectionError as exc:

src/DIRAC/Core/scripts/dirac_apptainer_exec.py

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,29 @@
22
"""
33

44
import os
5-
import shutil
65
import sys
76

87
import DIRAC
98
from DIRAC import S_ERROR, gConfig, gLogger
109
from DIRAC.Core.Base.Script import Script
10+
from DIRAC.Core.Security.Locations import getCAsLocation, getProxyLocation, getVOMSLocation
1111
from DIRAC.Core.Utilities.Subprocess import systemCall
1212

1313
CONTAINER_WRAPPER = """#!/bin/bash
1414
15-
echo "Starting inner container wrapper scripts (no install) at `date`."
1615
export DIRAC=%(dirac_env_var)s
1716
export DIRACOS=%(diracos_env_var)s
18-
# In any case we need to find a bashrc, and a cfg
17+
export X509_USER_PROXY=/etc/proxy
18+
export X509_CERT_DIR=/etc/grid-security/certificates
19+
export X509_VOMS_DIR=/etc/grid-security/vomsdir
20+
export DIRACSYSCONFIG=%(etc_dir)s/dirac.cfg
1921
source %(rc_script)s
2022
%(command)s
21-
echo "Finishing inner container wrapper scripts at `date`."
2223
"""
2324

2425
CONTAINER_DEFROOT = "" # Should add something like "/cvmfs/dirac.egi.eu/container/apptainer/alma9/x86_64"
2526

2627

27-
def getEnv():
28-
"""Gets the environment for use within the container.
29-
We blank almost everything to prevent contamination from the host system.
30-
"""
31-
32-
payloadEnv = {k: v for k, v in os.environ.items()}
33-
payloadEnv["TMP"] = "/tmp"
34-
payloadEnv["TMPDIR"] = "/tmp"
35-
payloadEnv["X509_USER_PROXY"] = os.path.join("tmp", "proxy")
36-
payloadEnv["DIRACSYSCONFIG"] = os.path.join("tmp", "dirac.cfg")
37-
38-
return payloadEnv
39-
40-
4128
@Script()
4229
def main():
4330
Script.registerArgument(" command: Command to execute inside the container")
@@ -50,41 +37,45 @@ def main():
5037
if switch[0].lower() == "i" or switch[0].lower() == "image":
5138
user_image = switch[1]
5239

40+
etc_dir = os.path.join(DIRAC.rootPath, "etc")
41+
5342
wrapSubs = {
5443
"dirac_env_var": os.environ.get("DIRAC", os.getcwd()),
5544
"diracos_env_var": os.environ.get("DIRACOS", os.getcwd()),
45+
"etc_dir": etc_dir,
5646
}
5747
wrapSubs["rc_script"] = os.path.join(os.path.realpath(sys.base_prefix), "diracosrc")
5848
wrapSubs["command"] = command
59-
shutil.copyfile("dirac.cfg", os.path.join("tmp", "dirac.cfg"))
6049

61-
wrapLoc = os.path.join("tmp", "dirac_container.sh")
62-
rawfd = os.open(wrapLoc, os.O_WRONLY | os.O_CREAT, 0o700)
50+
rawfd = os.open("dirac_container.sh", os.O_WRONLY | os.O_CREAT, 0o700)
6351
fd = os.fdopen(rawfd, "w")
6452
fd.write(CONTAINER_WRAPPER % wrapSubs)
6553
fd.close()
6654

67-
innerCmd = os.path.join("tmp", "dirac_container.sh")
6855
cmd = ["apptainer", "exec"]
6956
cmd.extend(["--contain"]) # use minimal /dev and empty other directories (e.g. /tmp and $HOME)
7057
cmd.extend(["--ipc"]) # run container in a new IPC namespace
71-
cmd.extend(["--workdir", "/tmp"]) # working directory to be used for /tmp, /var/tmp and $HOME
72-
cmd.extend(["--home", "/tmp"]) # Avoid using small tmpfs for default $HOME and use scratch /tmp instead
73-
cmd.extend(["--bind", "{0}:{0}:ro".format(os.path.join(os.path.realpath(sys.base_prefix)))])
58+
cmd.extend(["--bind", f"{os.getcwd()}:/mnt"]) # bind current directory for dirac_container.sh
59+
cmd.extend(["--bind", f"{getProxyLocation()}:/etc/proxy"]) # bind proxy file
60+
cmd.extend(["--bind", f"{getCAsLocation()}:/etc/grid-security/certificates"]) # X509_CERT_DIR
61+
cmd.extend(["--bind", f"{getVOMSLocation()}:/etc/grid-security/vomsdir"]) # X509_VOMS_DIR
62+
cmd.extend(["--bind", "{0}:{0}:ro".format(etc_dir)]) # etc dir for dirac.cfg
63+
cmd.extend(["--bind", "{0}:{0}:ro".format(os.path.join(os.path.realpath(sys.base_prefix)))]) # code dir
7464

7565
rootImage = user_image or gConfig.getValue("/Resources/Computing/Singularity/ContainerRoot") or CONTAINER_DEFROOT
7666

7767
if os.path.isdir(rootImage) or os.path.isfile(rootImage):
78-
cmd.extend([rootImage, innerCmd])
68+
cmd.extend([rootImage, "/mnt/dirac_container.sh"])
7969
else:
8070
# if we are here is because there's no image, or it is not accessible (e.g. not on CVMFS)
8171
gLogger.error("Apptainer image to exec not found: ", rootImage)
8272
return S_ERROR("Failed to find Apptainer image to exec")
8373

84-
gLogger.debug(f"Execute Apptainer command: {cmd}")
85-
result = systemCall(0, cmd, env=getEnv())
74+
gLogger.debug(f"Execute Apptainer command: {' '.join(cmd)}")
75+
result = systemCall(0, cmd)
8676
if not result["OK"]:
8777
DIRAC.exit(1)
78+
gLogger.notice(result["Value"][1])
8879

8980

9081
if __name__ == "__main__":

src/DIRAC/FrameworkSystem/Client/BundleDeliveryClient.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,9 @@ def syncCAs(self):
143143
if "X509_CERT_DIR" in os.environ:
144144
X509_CERT_DIR = os.environ["X509_CERT_DIR"]
145145
del os.environ["X509_CERT_DIR"]
146-
casLocation = Locations.getCAsLocation()
147-
if not casLocation:
148-
casLocation = Locations.getCAsDefaultLocation()
149-
result = self.syncDir("CAs", casLocation)
150146
if X509_CERT_DIR:
151147
os.environ["X509_CERT_DIR"] = X509_CERT_DIR
152-
return result
148+
return self.syncDir("CAs", Locations.getCAsLocation())
153149

154150
def syncCRLs(self):
155151
"""Synchronize CRLs
@@ -160,10 +156,9 @@ def syncCRLs(self):
160156
if "X509_CERT_DIR" in os.environ:
161157
X509_CERT_DIR = os.environ["X509_CERT_DIR"]
162158
del os.environ["X509_CERT_DIR"]
163-
result = self.syncDir("CRLs", Locations.getCAsLocation())
164159
if X509_CERT_DIR:
165160
os.environ["X509_CERT_DIR"] = X509_CERT_DIR
166-
return result
161+
return self.syncDir("CRLs", Locations.getCAsLocation())
167162

168163
def getCAs(self):
169164
"""This method can be used to create the CAs. If the file can not be created,

src/DIRAC/Resources/Storage/OccupancyPlugins/WLCGAccountingHTTPJson.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ def _downloadJsonFile(self, occupancyLFN, filePath):
4141
"""
4242
try:
4343
with open(filePath, "w") as fd:
44-
caPath = getCAsLocation()
45-
userProxy = getProxyLocation()
46-
res = requests.get(occupancyLFN, cert=userProxy, verify=caPath, timeout=30)
44+
res = requests.get(occupancyLFN, cert=getProxyLocation(), verify=getCAsLocation(), timeout=30)
4745
res.raise_for_status()
4846
fd.write(res.text)
4947
except Exception as e:

src/DIRAC/Resources/Storage/StorageElement.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,13 @@ def __call__(self, name, protocolSections=None, vo=None, hideExceptions=False):
6565
# Because the gfal2 context caches the proxy location,
6666
# we also use the proxy location as a key.
6767
# In practice, there should almost always be one, except for the REA
68-
# If we see its memory consumtpion exploding, this might be a place to look
69-
proxyLoc = getProxyLocation()
68+
# If we see its memory consumption exploding, this might be a place to look
7069

7170
# ensure protocolSections is hashable! (tuple)
7271
if isinstance(protocolSections, list):
7372
protocolSections = tuple(protocolSections)
7473

75-
argTuple = (tId, name, protocolSections, vo, proxyLoc)
74+
argTuple = (tId, name, protocolSections, vo, getProxyLocation())
7675
seObj = self.seCache.get(argTuple)
7776

7877
if not seObj:

tests/System/client_core.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,15 @@ if ! dirac-configuration-dump-local-cache; then
8181
exit 1
8282
fi
8383
echo " "
84+
85+
echo " "
86+
echo "====== dirac-apptainer-exec dirac-platform"
87+
if ! dirac-apptainer-exec dirac-platform; then
88+
exit 1
89+
fi
90+
91+
echo " "
92+
echo "====== dirac-apptainer-exec dirac-proxy-info --help"
93+
if ! dirac-apptainer-exec dirac-proxy-info --help; then
94+
exit 1
95+
fi

0 commit comments

Comments
 (0)