Repository: softlayer/softlayer-python

Issue:
xmlrpc y2038 problem
(originally filed in the openSUSE Bugzilla](https://bugzilla.suse.com/show_bug.cgi?id=1203311)):

While working on reproducible builds for openSUSE, I found that our python-softlayer package failed tests in 2038 with

```
 self = <xmlrpc.client.Marshaller object at 0x7fa5770e91f0>, value = 2167459529
 write = <built-in method append of list object at 0x7fa577194740>
 
     def dump_long(self, value, write):
         if value > MAXINT or value < MININT:
 >           raise OverflowError("int exceeds XML-RPC limits")
 E           OverflowError: int exceeds XML-RPC limits
 
 /usr/lib64/python3.8/xmlrpc/client.py:539: OverflowError
 =========================== short test summary info ============================
 FAILED tests/CLI/modules/cdn_tests.py::CdnTests::test_detail_account - Overfl...
 FAILED tests/managers/cdn_tests.py::CDNTests::test_detail_usage_metric - Over...
 =========== 2 failed, 1831 passed, 6 skipped, 5 deselected in 38.01s ===========
```

To Reproduce:
```
osc co openSUSE:Factory/python-softlayer && cd $_
osc build --noservice --trust-all-projects --vm-type=kvm \
  --alternative-project=home:bmwiedemann:reproducible \
  --build-opt=--vm-custom-opt="-rtc base=2038-01-20T00:00:00" \
  openSUSE_Tumbleweed x86_64
```

(basically run with the machine hardware clock set to post-2038)

**Expected behavior**
Test suite should pass.


**Version**
6.1.2 from tarball.

Discussion:

Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e322a5b4..5d0d1277 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -48,5 +48,5 @@ jobs:
       with:
         user: __token__
         password: ${{ secrets.CGALLO_PYPI }}
-        repository_url: https://pypi.org/legacy/
+        repository_url: https://upload.pypi.org/legacy/
 
diff --git a/SoftLayer/CLI/cdn/detail.py b/SoftLayer/CLI/cdn/detail.py
index a9bdce60..973b1acc 100644
--- a/SoftLayer/CLI/cdn/detail.py
+++ b/SoftLayer/CLI/cdn/detail.py
@@ -41,6 +41,6 @@ def cli(env, unique_id, history):
     table.add_row(['status', cdn_mapping['status']])
     table.add_row(['total_bandwidth', total_bandwidth])
     table.add_row(['total_hits', total_hits])
-    table.add_row(['hit_radio', hit_ratio])
+    table.add_row(['hit_ratio', hit_ratio])
 
     env.fout(table)
diff --git a/SoftLayer/CLI/virt/credentials.py b/SoftLayer/CLI/virt/credentials.py
index f64444ec..86c6909d 100644
--- a/SoftLayer/CLI/virt/credentials.py
+++ b/SoftLayer/CLI/virt/credentials.py
@@ -19,10 +19,7 @@ def cli(env, identifier):
     vs_id = helpers.resolve_id(vsi.resolve_ids, identifier, 'VS')
     instance = vsi.get_instance(vs_id)
 
-    table = formatting.Table(['username', 'password', 'Software', 'Version'])
-
+    table = formatting.Table(['username', 'password'])
     for item in instance['operatingSystem']['passwords']:
-        table.add_row([item['username'], item['password'],
-                       instance['operatingSystem']['softwareLicense']['softwareDescription']['referenceCode'],
-                       instance['operatingSystem']['softwareLicense']['softwareDescription']['version']])
+        table.add_row([item['username'], item['password']])
     env.fout(table)
diff --git a/SoftLayer/fixtures/SoftLayer_Network_CdnMarketplace_Configuration_Mapping.py b/SoftLayer/fixtures/SoftLayer_Network_CdnMarketplace_Configuration_Mapping.py
index dc3ca178..e080c40e 100644
--- a/SoftLayer/fixtures/SoftLayer_Network_CdnMarketplace_Configuration_Mapping.py
+++ b/SoftLayer/fixtures/SoftLayer_Network_CdnMarketplace_Configuration_Mapping.py
@@ -11,7 +11,7 @@
         "path": "/",
         "protocol": "HTTP",
         "status": "CNAME_CONFIGURATION",
-        "uniqueId": "9934111111111",
+        "uniqueId": "11223344",
         "vendorName": "akamai"
     }
 ]
@@ -28,7 +28,7 @@
         "path": "/",
         "protocol": "HTTP",
         "status": "CNAME_CONFIGURATION",
-        "uniqueId": "9934111111111",
+        "uniqueId": "11223344",
         "vendorName": "akamai"
     }
 ]
@@ -41,7 +41,7 @@
         "performanceConfiguration": "Large file optimization",
         "protocol": "HTTP",
         "respectHeaders": True,
-        "uniqueId": "424406419091111",
+        "uniqueId": "11223344",
         "vendorName": "akamai",
         "header": "www.test.com",
         "httpPort": 83,
diff --git a/SoftLayer/fixtures/SoftLayer_Network_CdnMarketplace_Metrics.py b/SoftLayer/fixtures/SoftLayer_Network_CdnMarketplace_Metrics.py
index 6b6aab5b..2e4bc333 100644
--- a/SoftLayer/fixtures/SoftLayer_Network_CdnMarketplace_Metrics.py
+++ b/SoftLayer/fixtures/SoftLayer_Network_CdnMarketplace_Metrics.py
@@ -6,9 +6,9 @@
             "HitRatio"
         ],
         "totals": [
-            "0.0",
-            "0",
-            "0.0"
+            1.0,
+            3,
+            2.0
         ],
         "type": "TOTALS"
     }
diff --git a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
index aab22b5e..762b923a 100644
--- a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
+++ b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py
@@ -75,7 +75,7 @@
         'passwords': [{'username': 'user', 'password': 'pass'}],
         'softwareLicense': {
             'softwareDescription': {'version': '12.04-64 Minimal for VSI',
-                                    'name': 'Ubuntu', 'referenceCode': 'UBUNTU_8_64', }}
+                                    'name': 'Ubuntu'}}
     },
     'softwareComponents': [{
         'passwords': [{'username': 'user', 'password': 'pass'}],


Test patch:
diff --git a/tests/CLI/modules/cdn_tests.py b/tests/CLI/modules/cdn_tests.py
index c0a96fee..a7dfa340 100644
--- a/tests/CLI/modules/cdn_tests.py
+++ b/tests/CLI/modules/cdn_tests.py
@@ -4,7 +4,9 @@
 
     :license: MIT, see LICENSE for more details.
 """
+import datetime
 import json
+from unittest import mock as mock
 
 from SoftLayer.CLI import exceptions
 from SoftLayer import testing
@@ -21,27 +23,22 @@ def test_list_accounts(self):
                            'domain': 'test.example.com',
                            'origin': '1.1.1.1',
                            'status': 'CNAME_CONFIGURATION',
-                           'unique_id': '9934111111111',
+                           'unique_id': '11223344',
                            'vendor': 'akamai'}]
                          )
 
-    def test_detail_account(self):
+    @mock.patch('SoftLayer.utils.days_to_datetime')
+    def test_detail_account(self, mock_now):
+        mock_now.return_value = datetime.datetime(2020, 1, 1)
         result = self.run_command(['cdn', 'detail', '--history=30', '1245'])
 
         self.assert_no_fail(result)
-        self.assertEqual(json.loads(result.output),
-                         {'hit_radio': '0.0 %',
-                          'hostname': 'test.example.com',
-                          'origin': '1.1.1.1',
-                          'origin_type': 'HOST_SERVER',
-                          'path': '/',
-                          'protocol': 'HTTP',
-                          'provider': 'akamai',
-                          'status': 'CNAME_CONFIGURATION',
-                          'total_bandwidth': '0.0 GB',
-                          'total_hits': '0',
-                          'unique_id': '9934111111111'}
-                         )
+        api_results = json.loads(result.output)
+        self.assertEqual(api_results['hit_ratio'], '2.0 %')
+        self.assertEqual(api_results['total_bandwidth'], '1.0 GB')
+        self.assertEqual(api_results['total_hits'], 3)
+        self.assertEqual(api_results['hostname'], 'test.example.com')
+        self.assertEqual(api_results['protocol'], 'HTTP')
 
     def test_purge_content(self):
         result = self.run_command(['cdn', 'purge', '1234',
@@ -122,7 +119,7 @@ def test_edit_cache(self):
         self.assertEqual('include: test', header_result['Cache key optimization'])
 
     def test_edit_cache_by_uniqueId(self):
-        result = self.run_command(['cdn', 'edit', '9934111111111', '--cache', 'include-specified', '--cache', 'test'])
+        result = self.run_command(['cdn', 'edit', '11223344', '--cache', 'include-specified', '--cache', 'test'])
         self.assert_no_fail(result)
         header_result = json.loads(result.output)
         self.assertEqual('include: test', header_result['Cache key optimization'])
diff --git a/tests/CLI/modules/vs/vs_tests.py b/tests/CLI/modules/vs/vs_tests.py
index a4f80c38..46a0b994 100644
--- a/tests/CLI/modules/vs/vs_tests.py
+++ b/tests/CLI/modules/vs/vs_tests.py
@@ -904,10 +904,10 @@ def test_list_vsi(self):
     def test_credentail(self):
         result = self.run_command(['vs', 'credentials', '100'])
         self.assert_no_fail(result)
-        # self.assertEqual(json.loads(result.output), [{
-        #     "username": "user",
-        #     "password": "pass"
-        # }])
+        self.assertEqual(json.loads(result.output), [{
+            "username": "user",
+            "password": "pass"
+        }])
 
     @mock.patch('SoftLayer.CLI.formatting.confirm')
     def test_authorize_storage_vs_no_confirm(self, confirm_mock):
diff --git a/tests/managers/cdn_tests.py b/tests/managers/cdn_tests.py
index 7e56f81a..b0e641c6 100644
--- a/tests/managers/cdn_tests.py
+++ b/tests/managers/cdn_tests.py
@@ -4,6 +4,8 @@
 
     :license: MIT, see LICENSE for more details.
 """
+import datetime
+from unittest import mock as mock
 
 from SoftLayer import fixtures
 from SoftLayer.managers import cdn
@@ -28,7 +30,9 @@ def test_detail_cdn(self):
                                 'listDomainMappingByUniqueId',
                                 args=args)
 
-    def test_detail_usage_metric(self):
+    @mock.patch('SoftLayer.utils.days_to_datetime')
+    def test_detail_usage_metric(self, mock_now):
+        mock_now.return_value = datetime.datetime(2020, 1, 1)
         self.cdn_client.get_usage_metrics(12345, history=30, frequency="aggregate")
 
         args = (12345,
@@ -39,6 +43,15 @@ def test_detail_usage_metric(self):
                                 'getMappingUsageMetrics',
                                 args=args)
 
+    # Does this still work in 2038 ? https://github.com/softlayer/softlayer-python/issues/1764 for context
+    @mock.patch('SoftLayer.utils.days_to_datetime')
+    def test_detail_usage_metric_future(self, mock_now):
+        mock_now.return_value = datetime.datetime(2040, 1, 1)
+        self.assertRaises(
+            OverflowError,
+            self.cdn_client.get_usage_metrics, 12345, history=30, frequency="aggregate"
+        )
+
     def test_get_origins(self):
         self.cdn_client.get_origins("12345")
         self.assert_called_with('SoftLayer_Network_CdnMarketplace_Configuration_Mapping_Path',
@@ -105,7 +118,7 @@ def test_purge_content(self):
                                 args=args)
 
     def test_cdn_edit(self):
-        identifier = '9934111111111'
+        identifier = '11223344'
         header = 'www.test.com'
         result = self.cdn_client.edit(identifier, header=header)
 
@@ -116,7 +129,7 @@ def test_cdn_edit(self):
             'SoftLayer_Network_CdnMarketplace_Configuration_Mapping',
             'updateDomainMapping',
             args=({
-                'uniqueId': '9934111111111',
+                'uniqueId': '11223344',
                 'originType': 'HOST_SERVER',
                 'protocol': 'HTTP',
                 'path': '/',