edx-enterprise-data 10.9.2__py3-none-any.whl → 10.10.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {edx_enterprise_data-10.9.2.dist-info → edx_enterprise_data-10.10.0.dist-info}/METADATA +1 -1
- {edx_enterprise_data-10.9.2.dist-info → edx_enterprise_data-10.10.0.dist-info}/RECORD +9 -8
- enterprise_data/__init__.py +1 -1
- enterprise_reporting/constants.py +7 -0
- enterprise_reporting/delivery_method.py +36 -7
- enterprise_reporting/tests/test_delivery_method.py +46 -3
- {edx_enterprise_data-10.9.2.dist-info → edx_enterprise_data-10.10.0.dist-info}/LICENSE +0 -0
- {edx_enterprise_data-10.9.2.dist-info → edx_enterprise_data-10.10.0.dist-info}/WHEEL +0 -0
- {edx_enterprise_data-10.9.2.dist-info → edx_enterprise_data-10.10.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
enterprise_data/__init__.py,sha256=
|
1
|
+
enterprise_data/__init__.py,sha256=z8VZBN4L4n3dhorf4GlhRP7qPQKCp334pTYxoE7F_As,125
|
2
2
|
enterprise_data/apps.py,sha256=aF6hZwDfI2oWj95tUTm_2ikHueQj-jLj-u0GrgzpsQI,414
|
3
3
|
enterprise_data/clients.py,sha256=pBuCQOP7NYl264ZbMtZCRPCET1pg0by8w6PVlA-icKA,4995
|
4
4
|
enterprise_data/constants.py,sha256=uCKjfpdlMYFZJsAj3n9RMw4Cmg5_6s3NuwocO-fch3s,238
|
@@ -153,7 +153,8 @@ enterprise_data_roles/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
153
153
|
enterprise_data_roles/tests/factories.py,sha256=VOm0NyOhiKkxl1MRIriRkKSpKypr9-4lG2FrsE2YfKo,1153
|
154
154
|
enterprise_data_roles/tests/test_models.py,sha256=wJv7ywk0BSbjlW_U142h0aFxZleAHyT92nIiPy_ECW4,1476
|
155
155
|
enterprise_reporting/__init__.py,sha256=yQO9ureIxFnl-1a_34H53elDwuAzXrSmhLlzqqD2SJ0,112
|
156
|
-
enterprise_reporting/
|
156
|
+
enterprise_reporting/constants.py,sha256=k3IKeKl0Rs6PnPqnnwma9SUNcmO6_6Ma4mLXV5mIrH4,208
|
157
|
+
enterprise_reporting/delivery_method.py,sha256=JpNEDT3yk4IV27OsqIq0iLv3xcTkW9B285P91YBUrsA,6109
|
157
158
|
enterprise_reporting/external_resource_link_report.py,sha256=jQ6RS0yec0IhAz4wErQ3q8Yn206R7aQbgcR2c803BLA,8066
|
158
159
|
enterprise_reporting/reporter.py,sha256=3wI46qH-CNCUC5r9-Eme1mQdMjwEsFk9myRb-ajzJkM,13807
|
159
160
|
enterprise_reporting/send_enterprise_reports.py,sha256=W9xc7hu3ZP4zmoIndITc3hdXDbd4A3QEWQN0_ZO1E1A,5270
|
@@ -167,7 +168,7 @@ enterprise_reporting/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
167
168
|
enterprise_reporting/fixtures/enterprise_customer_reporting.json,sha256=nS6E9KHW0Iqk7ZHtTyyVyrztIXxjn9OtBvMJkn7owxc,3959
|
168
169
|
enterprise_reporting/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
169
170
|
enterprise_reporting/tests/test_clients.py,sha256=h-h7xBJ6wIBKP-QqRxcJJGiQxLfTOLYByCuWfcCeCy0,8474
|
170
|
-
enterprise_reporting/tests/test_delivery_method.py,sha256=
|
171
|
+
enterprise_reporting/tests/test_delivery_method.py,sha256=AU4C6qev9ETr_hQCM1QVN1PKztyJNUGfKXI8XzeIOZ4,4555
|
171
172
|
enterprise_reporting/tests/test_enterprise_client.py,sha256=lpWm0muvA3alRjmlRAezE5901C9DU3WiySH4D5-U3qE,1058
|
172
173
|
enterprise_reporting/tests/test_external_link_report.py,sha256=zdnVOD1qtAp9c5EbIPnD9jcoLtW4iKs7gSVklgBK328,7029
|
173
174
|
enterprise_reporting/tests/test_reporter.py,sha256=PTmkGvPjGEjxiyizL88LAKnaWdvZDgOBjL4QStfOdyw,4057
|
@@ -175,8 +176,8 @@ enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=zBj7sDvRLJQbRs
|
|
175
176
|
enterprise_reporting/tests/test_utils.py,sha256=y4t6w9aKra-ftqtUeHvPwOhje-1npz7auV5o74ya8fE,9523
|
176
177
|
enterprise_reporting/tests/test_vertica_client.py,sha256=-R2yNCGUjRtoXwLMBloVFQkFYrJoo613VCr61gwI3kQ,140
|
177
178
|
enterprise_reporting/tests/utils.py,sha256=xms2LM7DV3wczXEfctOK1ddel1EE0J_YSr17UzbCDy4,1401
|
178
|
-
edx_enterprise_data-10.
|
179
|
-
edx_enterprise_data-10.
|
180
|
-
edx_enterprise_data-10.
|
181
|
-
edx_enterprise_data-10.
|
182
|
-
edx_enterprise_data-10.
|
179
|
+
edx_enterprise_data-10.10.0.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
|
180
|
+
edx_enterprise_data-10.10.0.dist-info/METADATA,sha256=BbVKWA5HCJ6IBYrXapHWyfhPWtP1t5gFieZAVoFyuUQ,1685
|
181
|
+
edx_enterprise_data-10.10.0.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
182
|
+
edx_enterprise_data-10.10.0.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
|
183
|
+
edx_enterprise_data-10.10.0.dist-info/RECORD,,
|
enterprise_data/__init__.py
CHANGED
@@ -2,15 +2,19 @@
|
|
2
2
|
Classes that handle sending reports for enterprise customers with specific delivery methods.
|
3
3
|
"""
|
4
4
|
|
5
|
-
|
6
|
-
|
7
5
|
import logging
|
8
6
|
import os
|
9
7
|
from smtplib import SMTPException
|
10
8
|
|
11
9
|
import paramiko
|
12
10
|
|
13
|
-
from enterprise_reporting.
|
11
|
+
from enterprise_reporting.constants import SFTP_OPS_GENIE_EMAIL_ALERT_EMAILS, SFTP_OPS_GENIE_EMAIL_ALERT_FROM_EMAIL
|
12
|
+
from enterprise_reporting.utils import (
|
13
|
+
compress_and_encrypt,
|
14
|
+
decrypt_string,
|
15
|
+
retry_on_exception,
|
16
|
+
send_email_with_attachment,
|
17
|
+
)
|
14
18
|
|
15
19
|
LOGGER = logging.getLogger(__name__)
|
16
20
|
|
@@ -97,6 +101,8 @@ class SFTPDeliveryMethod(DeliveryMethod):
|
|
97
101
|
"""
|
98
102
|
Class that handles sending an enterprise report file via SFTP.
|
99
103
|
"""
|
104
|
+
sender_email = SFTP_OPS_GENIE_EMAIL_ALERT_FROM_EMAIL
|
105
|
+
receiver_emails = SFTP_OPS_GENIE_EMAIL_ALERT_EMAILS
|
100
106
|
|
101
107
|
def __init__(self, reporting_config, password):
|
102
108
|
"""Initialize the SFTP Delivery Method."""
|
@@ -106,9 +112,11 @@ class SFTPDeliveryMethod(DeliveryMethod):
|
|
106
112
|
self.username = reporting_config['sftp_username']
|
107
113
|
self.file_path = reporting_config['sftp_file_path']
|
108
114
|
|
109
|
-
|
110
|
-
|
111
|
-
|
115
|
+
@retry_on_exception(max_retries=3, delay=2, backoff=2)
|
116
|
+
def send_over_sftp(self, data_reports):
|
117
|
+
"""
|
118
|
+
Send the reports via SFTP, retry on exception.
|
119
|
+
"""
|
112
120
|
LOGGER.info('Connecting via SFTP to remote host {} for {}'.format(
|
113
121
|
self.hostname,
|
114
122
|
self.enterprise_customer_name
|
@@ -129,4 +137,25 @@ class SFTPDeliveryMethod(DeliveryMethod):
|
|
129
137
|
)
|
130
138
|
sftp.close()
|
131
139
|
ssh.close()
|
132
|
-
|
140
|
+
|
141
|
+
def send(self, files):
|
142
|
+
"""Send the given files through SFTP."""
|
143
|
+
try:
|
144
|
+
data_reports = super().send(files)
|
145
|
+
self.send_over_sftp(data_reports)
|
146
|
+
except Exception: # pylint: disable=broad-except
|
147
|
+
email_subject = f'SFTP transmission failed for {self.enterprise_customer_name}'
|
148
|
+
email_body = f'Failed to send {self.data_type} report for {self.enterprise_customer_name}'
|
149
|
+
LOGGER.exception(f'SFTP transmission failed for {self.enterprise_customer_name}')
|
150
|
+
else:
|
151
|
+
LOGGER.info(f'Successfully sent report via sftp for {self.enterprise_customer_name}')
|
152
|
+
email_subject = f'SFTP transmission successful for {self.enterprise_customer_name}'
|
153
|
+
email_body = f'SFTP transmission successful for {self.enterprise_customer_name}'
|
154
|
+
|
155
|
+
send_email_with_attachment(
|
156
|
+
subject=email_subject,
|
157
|
+
body=email_body,
|
158
|
+
from_email=self.sender_email,
|
159
|
+
to_email=self.receiver_emails,
|
160
|
+
attachment_data={},
|
161
|
+
)
|
@@ -2,13 +2,12 @@
|
|
2
2
|
Test delivery methods.
|
3
3
|
"""
|
4
4
|
|
5
|
-
import sys
|
6
5
|
import unittest
|
7
6
|
|
8
7
|
import ddt
|
9
|
-
import pytest
|
10
8
|
|
11
|
-
from
|
9
|
+
from mock import patch, MagicMock
|
10
|
+
from enterprise_reporting.delivery_method import SFTPDeliveryMethod, SMTPDeliveryMethod
|
12
11
|
from enterprise_reporting.utils import encrypt_string
|
13
12
|
|
14
13
|
from .utils import create_files, verify_compressed
|
@@ -73,3 +72,47 @@ class TestDeliveryMethod(unittest.TestCase):
|
|
73
72
|
else:
|
74
73
|
assert len(delivery_files) == len(delivery_files)
|
75
74
|
assert delivery_files == [file['file'].name for file in files]
|
75
|
+
|
76
|
+
@patch('enterprise_reporting.delivery_method.send_email_with_attachment')
|
77
|
+
def test_verify_sftp_exception_handling(self, mock_send_email_with_attachment):
|
78
|
+
"""
|
79
|
+
Verify that SFTP transmission related exceptions are being handled correctly.
|
80
|
+
"""
|
81
|
+
file_data = [
|
82
|
+
{
|
83
|
+
'name': 'A History of Magic.txt',
|
84
|
+
'size': 1000
|
85
|
+
},
|
86
|
+
{
|
87
|
+
'name': 'Quidditch Through the Ages.txt',
|
88
|
+
'size': 500
|
89
|
+
},
|
90
|
+
{
|
91
|
+
'name': 'Quidditch Through the Ages.txt',
|
92
|
+
'size': 500
|
93
|
+
},
|
94
|
+
]
|
95
|
+
files, total_original_size = create_files(file_data)
|
96
|
+
sftp_delivery_method = SFTPDeliveryMethod(self.reporting_config, self.password)
|
97
|
+
|
98
|
+
# Verify failed SFTP transmission.
|
99
|
+
with patch('paramiko.SSHClient.connect', side_effect=Exception('SFTP transmission failed')):
|
100
|
+
sftp_delivery_method.send([file['file'] for file in files])
|
101
|
+
mock_send_email_with_attachment.assert_called_with(
|
102
|
+
subject='SFTP transmission failed for bleh-bleh',
|
103
|
+
body='Failed to send progress report for bleh-bleh',
|
104
|
+
from_email='enterprise-analytics@edx.org',
|
105
|
+
to_email=['enterprise-reporting-sftp@2u-internal.opsgenie.net'],
|
106
|
+
attachment_data={},
|
107
|
+
)
|
108
|
+
|
109
|
+
# Verify successful SFTP transmission.
|
110
|
+
with patch('paramiko.SSHClient', MagicMock()):
|
111
|
+
sftp_delivery_method.send([file['file'] for file in files])
|
112
|
+
mock_send_email_with_attachment.assert_called_with(
|
113
|
+
subject='SFTP transmission successful for bleh-bleh',
|
114
|
+
body='SFTP transmission successful for bleh-bleh',
|
115
|
+
from_email='enterprise-analytics@edx.org',
|
116
|
+
to_email=['enterprise-reporting-sftp@2u-internal.opsgenie.net'],
|
117
|
+
attachment_data={},
|
118
|
+
)
|
File without changes
|
File without changes
|
{edx_enterprise_data-10.9.2.dist-info → edx_enterprise_data-10.10.0.dist-info}/top_level.txt
RENAMED
File without changes
|