Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
f5c9c73
M2: close the socket after dereferencing the Connection instance
chaen Jun 11, 2020
d72ae88
CI: disable coverage in pytest (because Test_PoolCE is too sensitive …
chaen Jun 12, 2020
e32252b
RMS/DMS: cancel FTS operations if the matching RMS request does not e…
chaen Jun 15, 2020
62d7195
gitignore: ignore env file for vscode
chaen Jun 15, 2020
21ee399
REMOVE READLONLY VARIABLES
chaen Jun 16, 2020
1900ac8
SMS: drop tables in the correct order
chaen Jun 16, 2020
8c09485
tests: fix dropDBs bad escape
chaen Jun 16, 2020
4814400
Print error if LFN list is missing
sfayer Jun 16, 2020
f0ab1d0
fix hospital handling
phicharp Jun 17, 2020
a7c1fda
dirac-admin-add-host: adding host to ComponentMonitoring
andresailer Jun 8, 2020
52f597d
CSAPI: fix and expand parameter docstrings
andresailer Jun 11, 2020
6c669c1
Config: add documentation for type of gConfig
andresailer Jun 11, 2020
97dd214
dirac-admin-add-host: Fix typo in log message
andresailer Jun 22, 2020
e4207d1
pytest without coverage
atsareg Jun 24, 2020
6b995e9
no --no-cov fir general pytest
atsareg Jun 24, 2020
c08871d
once again
atsareg Jun 25, 2020
ebc8639
test adapted for --no-cov pytest running
atsareg Jun 25, 2020
b996650
hopefully the final --no-cov
atsareg Jun 25, 2020
e8d903f
typo fixed
atsareg Jun 25, 2020
dc3f581
autopep8
atsareg Jun 25, 2020
4a727cc
Merge pull request #4655 from atsareg/pytest-no-cov
Jun 25, 2020
105bcfb
ComponentInstaller: allow underscores in installed components
andresailer Jun 25, 2020
2661d6b
dirac-transformation-clean: fix use of position arguments
andresailer Jun 25, 2020
b3bd16c
Transformation scripts: allow command line flags (e.g., -ddd)
andresailer Jun 25, 2020
c0d15d1
Merge pull request #4646 from sfayer/fix_missing_lfnlist
Jun 28, 2020
6385e74
Resolve error under DIRACOS environment
atsareg Jun 28, 2020
4a28881
v6r22p31 notes and tags
atsareg Jun 28, 2020
7207751
Merge pull request #4642 from chaen/v7r0_FIX_m2again
Jun 28, 2020
160be33
Merge pull request #4644 from chaen/rel-v7r0_FIX_rmsNoExist
Jun 28, 2020
5f221fa
Merge pull request #4647 from phicharp/200617-FixHpital-PhC
Jun 28, 2020
cba0493
Merge pull request #4652 from andresailer/v7r0_addHost
Jun 28, 2020
027019e
Merge pull request #4656 from andresailer/v7r0_minor
Jun 28, 2020
412f0e9
v7r0p28 notes and tags
atsareg Jun 28, 2020
6f5d2c1
Resolved conflicts with rel-v6r22
atsareg Jun 28, 2020
4465c68
Resolved conflicts with rel-v7r0
atsareg Jun 28, 2020
1e5b3ef
pep8
atsareg Jun 28, 2020
dd7a56e
Merge pull request #4660 from atsareg/rel-v7r1-merge-resolved
Jun 29, 2020
103cbb4
Merge pull request #4645 from chaen/rel-v7r1_NOREADONLY
Jun 29, 2020
ff771ea
py2 to 3
fstagni Jun 10, 2020
596f1e4
changed dir
fstagni Jun 11, 2020
79100eb
added more selectable fields for methods using gJobDB.getDistinctJobA…
fstagni Jun 11, 2020
938fa73
TransformationCleaningAgent will (re)clean very old transformations t…
fstagni Jun 11, 2020
8f2db06
sanitize DNs
fstagni Jun 12, 2020
b371142
no need for casting to list
fstagni Jun 12, 2020
f9af4b8
moved clean of very old transformations to the finalize
fstagni Jun 12, 2020
423ef41
added explanation
fstagni Jun 25, 2020
c6d239e
implement suggestions on spacing in lists
fstagni Jun 25, 2020
41fc0d6
sanitize DNs
fstagni Jun 12, 2020
816e5d6
minor/py3 fixes
fstagni Jun 15, 2020
9de4feb
inheriting from Client
fstagni Jun 15, 2020
846b851
some py2 to 3 fixes
fstagni Jun 15, 2020
d5175ac
fix sh
fstagni Jun 15, 2020
92e6791
.keys -> list()
fstagni Jun 29, 2020
2079340
use super for Clients
fstagni Jun 29, 2020
bffb798
Merge pull request #4641 from fstagni/v7r0-fixes60
Jun 29, 2020
18d38eb
Merge pull request #4643 from fstagni/v7r1-fixes
Jun 29, 2020
da6eb9c
v7r1p6 notes and tags
atsareg Jun 29, 2020
47d40e2
Resolved conflicts with rel-v7r1
atsareg Jun 29, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/basic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ jobs:
fail-fast: False
matrix:
command:
- pytest
- DIRAC_USE_M2CRYPTO=Yes DIRAC_M2CRYPTO_SPLIT_HANDSHAKE=Yes pytest
- pytest --no-cov
- DIRAC_USE_M2CRYPTO=Yes DIRAC_M2CRYPTO_SPLIT_HANDSHAKE=Yes pytest --no-cov
# Security tests are flakey due to reference counting bugs in pyGSI/src/crypto/asn1.c
- pytest Core/Security/test || (echo "Retrying..."; pytest Core/Security/test) || (echo "Retrying again..."; pytest Core/Security/test)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repeated running was added for failures due to the pyGSI library, so it should probably stay with the repetition, but adding --no-cov?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is targetting integration the repeated runs can be removed as pyGSI was removed in #4481

- DIRAC_USE_M2CRYPTO=Yes DIRAC_M2CRYPTO_SPLIT_HANDSHAKE=Yes pytest Core/Security/test || (echo "Retrying..."; DIRAC_USE_M2CRYPTO=No pytest Core/Security/test) || (echo "Retrying again..."; DIRAC_USE_M2CRYPTO=No pytest Core/Security/test)
- pytest --no-cov Core/Security/test
- DIRAC_USE_M2CRYPTO=Yes DIRAC_M2CRYPTO_SPLIT_HANDSHAKE=Yes pytest --no-cov Core/Security/test
- tests/checkDocs.sh
# TODO This should cover more than just tests/CI
# Excluded codes related to sourcing files
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ tests/CI/SERVERCONFIG

# VSCode
.vscode
.env

# docs
# this is auto generated
Expand Down
49 changes: 27 additions & 22 deletions ConfigurationSystem/Client/CSAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def listHosts(self):
def describeUsers(self, users=None):
""" describe users by nickname

:param list users: list of users' nickanames
:param list users: list of users' nicknames
:return: a S_OK(description) of the users in input
"""
if users is None:
Expand Down Expand Up @@ -329,14 +329,14 @@ def addUser(self, username, properties):
"""
Add a user to the cs

:param str username: group name
:param dict properties: dictionary describing user properties:
:param str username: username
:param dict properties: dictionary describing user properties:

- DN
- groups
- <extra params>
- DN
- groups
- <extra params>

:return: True/False
:return: True/False
"""
if not self.__initialized['OK']:
return self.__initialized
Expand Down Expand Up @@ -368,14 +368,15 @@ def modifyUser(self, username, properties, createIfNonExistant=False):
"""
Modify a user

:param str username: group name
:param dict properties: dictionary describing user properties:
:param str username: group name
:param dict properties: dictionary describing user properties:

- DN
- Groups
- <extra params>

:return: S_OK, Value = True/False
:param bool createIfNonExistant: if true, registers the users if it did not exist
:return: S_OK, Value = True/False
"""
if not self.__initialized['OK']:
return self.__initialized
Expand Down Expand Up @@ -430,14 +431,14 @@ def addGroup(self, groupname, properties):
"""
Add a group to the cs

:param str groupname: group name
:param dict properties: dictionary describing group properties:
:param str groupname: group name
:param dict properties: dictionary describing group properties:

- Users
- Properties
- <extra params>

:return: True/False
:return: S_OK, Value = True/False
"""
if not self.__initialized['OK']:
return self.__initialized
Expand All @@ -455,14 +456,15 @@ def modifyGroup(self, groupname, properties, createIfNonExistant=False):
"""
Modify a group

:param str groupname: group name
:param dict properties: dictionary describing group properties:
:param str groupname: group name
:param dict properties: dictionary describing group properties:

- Users
- Properties
- <extra params>

:return: True/False
:param bool createIfNonExistant: if true, creates the group if it did not exist
:return: S_OK, Value = True/False
"""
if not self.__initialized['OK']:
return self.__initialized
Expand Down Expand Up @@ -490,14 +492,15 @@ def modifyGroup(self, groupname, properties, createIfNonExistant=False):
def addHost(self, hostname, properties):
"""
Add a host to the cs
:param str hostname: hostname name
:param dict properties: dictionary describing host properties:

:param str hostname: host name
:param dict properties: dictionary describing host properties:

- DN
- Properties
- <extra params>

:return: True/False
:return: S_OK, Value = True/False
"""
if not self.__initialized['OK']:
return self.__initialized
Expand Down Expand Up @@ -617,14 +620,16 @@ def getOpsSection():
def modifyHost(self, hostname, properties, createIfNonExistant=False):
"""
Modify a host
:param str hostname: hostname name
:param dict properties: dictionary describing host properties:

:param str hostname: hostname name
:param dict properties: dictionary describing host properties:

- DN
- Properties
- <extra params>

:return: True/False
:param bool createIfNonExistant: if true, creates the host if it did not exist
:return: S_OK, Value = True/False
"""
if not self.__initialized['OK']:
return self.__initialized
Expand Down
5 changes: 5 additions & 0 deletions ConfigurationSystem/Client/Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@

from DIRAC.ConfigurationSystem.private.ConfigurationClient import ConfigurationClient

#: Global gConfig object of type :class:`~DIRAC.ConfigurationSystem.private.ConfigurationClient.ConfigurationClient`
gConfig = ConfigurationClient()


def getConfig():
"""
:returns: gConfig
:rtype: ~DIRAC.ConfigurationSystem.private.ConfigurationClient.ConfigurationClient
"""
return gConfig
4 changes: 4 additions & 0 deletions ConfigurationSystem/Client/Helpers/Registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def getUsernameForDN(dn, usersList=None):

:return: S_OK(str)/S_ERROR()
"""
dn = dn.strip()
if not usersList:
result = gConfig.getSections("%s/Users" % gBaseRegistrySection)
if not result['OK']:
Expand Down Expand Up @@ -63,6 +64,7 @@ def getGroupsForDN(dn):

:return: S_OK(list)/S_ERROR() -- contain list of groups
"""
dn = dn.strip()
result = getUsernameForDN(dn)
if not result['OK']:
return result
Expand Down Expand Up @@ -128,6 +130,7 @@ def getHostnameForDN(dn):

:return: S_OK()/S_ERROR()
"""
dn = dn.strip()
result = gConfig.getSections("%s/Hosts" % gBaseRegistrySection)
if not result['OK']:
return result
Expand All @@ -153,6 +156,7 @@ def findDefaultGroupForDN(dn):

:return: S_OK()/S_ERROR()
"""
dn = dn.strip()
result = getUsernameForDN(dn)
if not result['OK']:
return result
Expand Down
84 changes: 75 additions & 9 deletions Core/DISET/private/Transports/M2SSLTransport.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ def __init__(self, *args, **kwargs):
as for other transports. If ctx is specified (as an instance of
SSL.Context) then use that rather than creating a new context.
"""
# The thread init of M2Crypto is not really thread safe.
# So we put it a second time
M2Threading.init()
self.remoteAddress = None
self.peerCredentials = {}
self.__timeout = 1
Expand Down Expand Up @@ -98,9 +101,7 @@ def initAsClient(self):
error = "%s:%s" % (e, repr(e))

if self.oSocket is not None:
self.oSocket.close()
self.oSocket.socket.close()
self.oSocket = None
self.close()

return S_ERROR(error)

Expand All @@ -125,20 +126,85 @@ def initAsServer(self):
return S_OK()

def close(self):
# pylint: disable=line-too-long
""" Close this socket. """

if self.oSocket:
# TL;DR:
# Do NOT touch that method
#
# Surprisingly (to me at least), M2Crypto does not close
# the socket when calling SSL.Connection.close
# It only does it when the garbage collector kicks in
# We have to manually close it here, otherwise the connections
# will hang forever
# the underlying socket when calling SSL.Connection.close
# It only does it when the garbage collector kicks in (see ~M2Crypto.SSL.Connection.Connection.__del__)
# If the socket is not closed, the connection may hang forever.
#
# Thus, we are setting self.oSocket to None to allow the GC to do the work, but since we are not sure
# that it will run, we anyway force the connection to be closed
#
# However, we should close the underlying socket only after SSL was shutdown properly.
# This is because OpenSSL `ssl3_shutdown` (see callstack below) may still read some data
# (see https://github.com/openssl/openssl/blob/master/ssl/s3_lib.c#L4509)::
#
#
# 1 0x00007fffe9d48fc0 in sock_read () from /lib/libcrypto.so.1.0.0
# 2 0x00007fffe9d46e83 in BIO_read () from /lib/libcrypto.so.1.0.0
# 3 0x00007fffe9eab9dd in ssl3_read_n () from /lib/libssl.so.1.0.0
# 4 0x00007fffe9ead216 in ssl3_read_bytes () from /lib/libssl.so.1.0.0
# 5 0x00007fffe9ea999c in ssl3_shutdown () from /lib/libssl.so.1.0.0
# 6 0x00007fffe9ed4f93 in ssl_free () from /lib/libssl.so.1.0.0
# 7 0x00007fffe9d46d5b in BIO_free () from /lib/libcrypto.so.1.0.0
# 8 0x00007fffe9f30a96 in bio_free (bio=0x5555556f3200) at SWIG/_m2crypto_wrap.c:5008
# 9 0x00007fffe9f30b1e in _wrap_bio_free (self=<optimized out>, args=<optimized out>) at SWIG/_m2crypto_wrap.c
#
# We unfortunately have no way to force that order, and there is a risk of deadlock
# when running in a multi threaded environment like the agents::
#
# Thread A opens socket, gets FD = 111
# Thread A works on it
# Thread A closes FD 111 (underlying socket.close())
# Thread B opens socket, gets FD = 111
# Thread A calls read on FD=111 from ssl3_shutdown
#
# This is illustrated on the strace below::
#
# 26461 14:25:15.266692 write(111<TCPv6:[[<srcAddressV6>]:42688->[<dstAddressV6>]:9140]>,
# "blabla", 37 <unfinished ...>
# 26464 14:25:15.266857 <... connect resumed>) = 0 <0.000195>
# 26464 14:25:15.267023 getsockname(120<UDP:[<srcAddress>:44252->188.185.84.86:9140]>, <unfinished ...>
# 26461 14:25:15.267176 <... write resumed>) = 37 <0.000453>
# 26464 14:25:15.267425 <... getsockname resumed>{sa_family=AF_INET, sin_port=htons(44252),
# sin_addr=inet_addr("<srcAddress>")}, [28->16]) = 0 <0.000292>
# 26461 14:25:15.267466 close(111<TCPv6:[[<srcAddressV6>]:42688->[<dstAddressV6>]:9140]> <unfinished ...>
# 26464 14:25:15.267637 close(120<UDP:[<srcAddress>:44252->188.185.84.86:9140]> <unfinished ...>
# 26464 14:25:15.267738 <... close resumed>) = 0 <0.000086>
# 26461 14:25:15.267768 <... close resumed>) = 0 <0.000285>
# 26464 14:25:15.267827 socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP <unfinished ...>
# 26461 14:25:15.267888 futex(0x21f8620, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
# 26464 14:25:15.267976 <... socket resumed>) = 111<UDPv6:[1207802822]> <0.000138>
# 26461 14:25:15.268092 <... futex resumed>) = 1 <0.000196>
# 26464 14:25:15.268195 connect(111<UDPv6:[1207802822]>,
# {sa_family=AF_INET6, sin6_port=htons(9140),
# inet_pton(AF_INET6, "<dstAddressV6>", &sin6_addr),
# sin6_flowinfo=htonl(0), sin6_scope_id=0
# }, 28 <unfinished ...>
# 26461 14:25:15.268294 read(111<UDPv6:[[<srcAddressV6>]:42480->[<dstAddressV6>]:9140]>, <unfinished ...>
# 26464 14:25:15.268503 <... connect resumed>) = 0 <0.000217>
# 26464 14:25:15.268673 getsockname(111<UDPv6:[[<srcAddressV6>]:42480->[<dstAddressV6>]:9140]>, <unfinished ...>
# 26464 14:25:15.268862 <... getsockname resumed>{sa_family=AF_INET6, sin6_port=htons(42480),
# inet_pton(AF_INET6, "<srcAddressV6>", &sin6_addr), sin6_flowinfo=htonl(0), sin6_scope_id=
# 0}, [28]) = 0 <0.000168>
# 26464 14:25:15.269048
# close(111<UDPv6:[[<srcAddressV6>]:42480->[<dstAddressV6>]:9140]>
# <unfinished ...>

self.oSocket.close()
self.oSocket.socket.close()
# del self.oSocket
underlyingSocket = self.oSocket.socket
self.oSocket = None
underlyingSocket.close()
return S_OK()

def renewServerContext(self):
# pylint: disable=line-too-long
""" Renews the server context.
This reloads the certificates and re-initialises the SSL context.

Expand Down
38 changes: 25 additions & 13 deletions DataManagementSystem/Agent/FTS3Agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,24 +369,36 @@ def _treatOperation(self, operation):
continueOperationProcessing = True

# Check the status of the associated RMS Request.
# If it is canceled then we will not create new FTS3Jobs, and mark
# If it is canceled or does not exist anymore then we will not create new FTS3Jobs, and mark
# this as FTS3Operation canceled.

if operation.rmsReqID:
res = ReqClient().getRequestStatus(operation.rmsReqID)
if not res['OK']:
log.error("Could not get request status", res)
return operation, res
rmsReqStatus = res['Value']

if rmsReqStatus == 'Canceled':
log.info(
"The RMS Request is canceled, canceling the FTS3Operation",
"rmsReqID: %s, FTS3OperationID: %s" %
(operation.rmsReqID,
operation.operationID))
operation.status = 'Canceled'
continueOperationProcessing = False
# If the Request does not exist anymore
if cmpError(res, errno.ENOENT):
log.info(
"The RMS Request does not exist anymore, canceling the FTS3Operation",
"rmsReqID: %s, FTS3OperationID: %s" %
(operation.rmsReqID,
operation.operationID))
operation.status = 'Canceled'
continueOperationProcessing = False
else:
log.error("Could not get request status", res)
return operation, res

else:
rmsReqStatus = res['Value']

if rmsReqStatus == 'Canceled':
log.info(
"The RMS Request is canceled, canceling the FTS3Operation",
"rmsReqID: %s, FTS3OperationID: %s" %
(operation.rmsReqID,
operation.operationID))
operation.status = 'Canceled'
continueOperationProcessing = False

if continueOperationProcessing:
res = operation.prepareNewJobs(
Expand Down
2 changes: 1 addition & 1 deletion DataManagementSystem/Client/FTS3Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class FTS3Client(Client):
def __init__(self, url=None, **kwargs):
""" Constructor function.
"""
Client.__init__(self, **kwargs)
super(FTS3Client, self).__init__(**kwargs)
self.setServer('DataManagement/FTS3Manager')
if url:
self.setServer(url)
Expand Down
2 changes: 1 addition & 1 deletion DataManagementSystem/Client/S3GatewayClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class S3GatewayClient(Client):
def __init__(self, url=None, **kwargs):
""" Constructor function.
"""
Client.__init__(self, **kwargs)
super(S3GatewayClient, self).__init__(**kwargs)
self.setServer('DataManagement/S3Gateway')
if url:
self.setServer(url)
Expand Down
Loading