Repository: fedora-infra/bodhi

Issue:
bodhi allows maintainer to request testing after stable already requested
This may be related to configuration around when rawhide gating was first enabled, but there were/are 17 cases of updates where bodhi requested stable (and indeed did tag them for stable), but the maintainer then came and requested testing. This made updates that were in a state where they were stable but pending testing. When we then did the first f32 updates-testing push, these all errored.

backend:

```
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]: [2020-02-27 23:57:12,768: ERROR/ForkPoolWorker-6] ComposerThread failed. Transaction rolled back.
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]: Traceback (most recent call last):
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/koji/__init__.py", line 2631, in _callMethod
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     return self._sendCall(handler, headers, request)               
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/koji/__init__.py", line 2549, in _sendCall
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     return self._sendOneCall(handler, headers, request)                                                      
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/koji/__init__.py", line 2595, in _sendOneCall                                                                                    
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     ret = self._read_xmlrpc_response(r)
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/koji/__i
nit__.py", line 2607, in _read_xmlrpc_response
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     result = u.close()
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib64/python3.7/xmlrpc/client.py", l
ine 656, in close
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     raise Fault(**self._stack[0])
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]: xmlrpc.client.Fault: <Fault 1003: 'build icaro-2.
0-5.fc32 not in tag f32-updates-testing-pending'>

Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]: Traceback (most recent call last):
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/bodhi/server/tasks/composer.py", line 324, in run
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     self.work()
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/bodhi/server/tasks/composer.py", line 387, in work
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     self.determine_and_perform_tag_actions()
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/bodhi/server/tasks/composer.py", line 75, in wrapper
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     retval = method(self, *args, **kwargs)
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/bodhi/server/tasks/composer.py", line 547, in determine_and_perform_tag_actions
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     self._determine_tag_actions()
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/bodhi/server/tasks/composer.py", line 573, in _determine_tag_actions
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     self.eject_from_compose(update, reason)
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/bodhi/server/tasks/composer.py", line 483, in eject_from_compose
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     koji=buildsys.get_session())
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/bodhi/server/models.py", line 2969, in remove_tag
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     koji.untagBuild(tag, build.nvr, force=True)
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/koji/__init__.py", line 2135, in __call__
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     return self.__func(self.__name, args, opts)
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:   File "/usr/lib/python3.7/site-packages/koji/__init__.py", line 2650, in _callMethod
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]:     raise err
Feb 27 23:57:12 bodhi-backend01.phx2.fedoraproject.org celery-3[94211]: koji.TagError: build icaro-2.0-5.fc32 not in tag f32-updates-testing-pending
```

Full list of updates: 

   id   | stable_karma | unstable_karma | requirements | require_bugs | require_testcases |                  notes       
            |    type     | status | request |  severity   |   suggest   | locked | pushed | critpath | close_bugs |     
  date_submitted       | date_modified | date_approved | date_pushed |         alias          | release_id | user_id |   
     date_stable         | date_testing | autokarma | test_gating_status | display_name | autotime | stable_days | from_t
ag 
--------+--------------+----------------+--------------+--------------+-------------------+------------------------------
------------+-------------+--------+---------+-------------+-------------+--------+--------+----------+------------+-----
-----------------------+---------------+---------------+-------------+------------------------+------------+---------+---
-------------------------+--------------+-----------+--------------------+--------------+----------+-------------+-------
---
 163160 |            3 |             -3 |              | f            | f                 | Automatic update for abrt-2.1
3.0-1.fc32. | unspecified | stable | testing | unspecified | unspecified | f      | f      | f        | t          | 2019
-10-16 12:15:29.261695 |               |               |             | FEDORA-2019-e07c1b82f5 |         35 |    5207 | 20
19-10-16 12:18:09.294255 |              | t         | ignored            |              | t        |           0 | 
(1 row)

FEDORA-2019-4235935177

 id   | stable_karma | unstable_karma | requirements | require_bugs | require_testcases |                         notes
                          |    type     | status | request |  severity   |   suggest   | locked | pushed | critpath | clo
se_bugs |       date_submitted       | date_modified | date_approved | date_pushed |         alias          | release_id 
| user_id |        date_stable         | date_testing | autokarma | test_gating_status | display_name | autotime | stable
_days | from_tag 
--------+--------------+----------------+--------------+--------------+-------------------+------------------------------
--------------------------+-------------+--------+---------+-------------+-------------+--------+--------+----------+----
--------+----------------------------+---------------+---------------+-------------+------------------------+------------
+---------+----------------------------+--------------+-----------+--------------------+--------------+----------+-------
------+----------
 151786 |            3 |             -3 |              | f            | f                 | Automatic update for unicorn-
1.0.1-7.fc32.             | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-09-05 09:35:59.758868 |               |               |             | FEDORA-2019-49636fff66 |         35 
|     533 | 2019-09-05 09:36:20.851284 |              | t         | ignored            |              | t        |       
    0 | 
 167707 |            3 |             -3 |              | f            | f                 | Automatic update for mingw-li
bsoup-2.68.0-3.fc32.      | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-11-07 15:42:53.686931 |               |               |             | FEDORA-2019-2ec2669950 |         35 
|     638 | 2019-11-07 15:45:10.742424 |              | t         | ignored            |              | t        |       
    0 | 
 167337 |            3 |             -3 |              | f            | f                 | Automatic update for ovn-2.12
.0-5.fc32.                | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-11-06 13:00:53.3419   |               |               |             | FEDORA-2019-5afcaf165b |         35 
|    4821 | 2019-11-06 13:03:10.140105 |              | t         | ignored            |              | t        |       
    0 | 
 161782 |            3 |             -3 |              | f            | f                 | Automatic update for koji-1.1
8.1-1.fc32.               | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-10-09 14:38:13.824246 |               |               |             | FEDORA-2019-3f2a571881 |         35 
|     274 | 2019-10-09 14:39:09.954057 |              | t         | ignored            |              | t        |       
    0 | 
 160718 |            3 |             -3 |              | f            | f                 | Automatic update for osbuild-
3-1.fc32.                 | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-10-04 09:13:05.55587  |               |               |             | FEDORA-2019-ed5ff061ce |         35 
|    2749 | 2019-10-04 09:15:07.712413 |              | t         | ignored            |              | t        |       
    0 | 
 156984 |            3 |             -3 |              | f            | f                 | Automatic update for pdfarran
ger-1.3.1-2.fc32.         | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-09-26 17:49:23.01912  |               |               |             | FEDORA-2019-d0bcd616bb |         35 
|    3023 | 2019-09-26 17:51:10.100231 |              | t         | ignored            |              | t        |       
    0 | 
 156347 |            3 |             -3 |              | f            | f                 | Automatic update for icaro-2.
0-5.fc32.                 | unspecified | stable | testing | unspecified | unspecified | f      | f      | f        | t  
        | 2019-09-24 15:14:36.172781 |               |               |             | FEDORA-2019-847dd6494e |         35 
|    3081 | 2019-09-24 15:15:09.86902  |              | t         | ignored            |              | t        |       
    0 | 
 155956 |            3 |             -3 |              | f            | f                 | Automatic update for xrdp-0.9
.11-4.fc32.               | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-09-23 10:46:54.132396 |               |               |             | FEDORA-2019-fe8a9383b1 |         35 
|     198 | 2019-09-23 10:48:10.315894 |              | t         | ignored            |              | t        |       
    0 | 
 155580 |            3 |             -3 |              | f            | f                 | Automatic update for txt2tags
-2.6-1.fc32.              | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-09-21 04:18:50.228146 |               |               |             | FEDORA-2019-3d1850cf4e |         35 
|    3113 | 2019-09-21 04:21:09.660219 |              | t         | ignored            |              | t        |       
    0 | 
 154746 |            3 |             -3 |              | f            | f                 | Automatic update for virt-p2v
-1.41.0-1.fc32.           | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-09-17 16:08:06.948135 |               |               |             | FEDORA-2019-36f9e6e2a9 |         35 
|    2437 | 2019-09-17 16:09:12.362241 |              | t         | ignored            |              | t        |       
    0 | 
 152393 |            3 |             -3 |              | f            | f                 | Automatic update for thonny-3
.2.1-1.fc32.              | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-09-08 05:48:51.157895 |               |               |             | FEDORA-2019-faa6f695f4 |         35 
|    4011 | 2019-09-08 05:51:10.771225 |              | t         | ignored            |              | t        |       
    0 | 
 150685 |            3 |             -3 |              | f            | f                 | Automatic update for python-r
uamel-yaml-0.16.5-2.fc32. | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-08-30 17:55:15.85751  |               |               |             | FEDORA-2019-cb4471af03 |         35 
|    1710 | 2019-08-30 17:57:10.731742 |              | t         | ignored            |              | t        |       
    0 | 
 150377 |            3 |             -3 |              | f            | f                 | Automatic update for python-b
oolean.py-3.6-1.fc32.     | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-08-29 14:34:38.699136 |               |               |             | FEDORA-2019-a2b4b7e93f |         35 
|    4831 | 2019-08-29 14:36:07.426478 |              | t         | ignored            |              | t        |       
    0 | 
 148318 |            3 |             -3 |              | f            | f                 | Automatic update for mom-0.5.
15-1.fc32.                | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-08-20 07:10:58.860154 |               |               |             | FEDORA-2019-9c762d5ed1 |         35 
|     146 | 2019-08-20 07:12:07.161149 |              | t         | ignored            |              | t        |       
    0 | 
 147135 |            3 |             -3 |              | f            | f                 | Automatic update for python-g
ear-0.13.0-1.fc32.        | unspecified | stable | testing | unspecified | unspecified | t      | f      | f        | t  
        | 2019-08-14 08:32:48.51075  |               |               |             | FEDORA-2019-14357dc49d |         35 
|    1865 | 2019-08-14 08:33:07.411366 |              | t         | greenwave_failed   |              | t        |       
    0 | 
(15 rows)

I removed the request from all of them.


Discussion:

Resolving patch:
diff --git a/bodhi/server/services/updates.py b/bodhi/server/services/updates.py
--- a/bodhi/server/services/updates.py
+++ b/bodhi/server/services/updates.py
@@ -205,6 +205,11 @@ def set_request(request):
                            "Can't change request for an archived release")
         return
 
+    if update.status == UpdateStatus.stable and action == UpdateRequest.testing:
+        request.errors.add('body', 'request',
+                           "Pushing back to testing a stable update is not allowed")
+        return
+
     if action == UpdateRequest.stable:
         settings = request.registry.settings
         result, reason = update.check_requirements(request.db, settings)


Test patch:
diff --git a/bodhi/tests/server/services/test_updates.py b/bodhi/tests/server/services/test_updates.py
--- a/bodhi/tests/server/services/test_updates.py
+++ b/bodhi/tests/server/services/test_updates.py
@@ -985,6 +985,25 @@ def test_set_request_archived_release(self, *args):
             "Can't change request for an archived release"
         )
 
+    @mock.patch(**mock_valid_requirements)
+    def test_set_request_testing_from_stable(self, *args):
+        """Ensure that we get an error if trying to push to testing a stable update"""
+        nvr = 'bodhi-2.0-1.fc17'
+
+        up = self.db.query(Build).filter_by(nvr=nvr).one().update
+        up.locked = False
+        up.status = UpdateStatus.stable
+
+        post_data = dict(update=up.alias, request='testing',
+                         csrf_token=self.app.get('/csrf').json_body['csrf_token'])
+
+        res = self.app.post_json(f'/updates/{up.alias}/request', post_data, status=400)
+
+        assert res.json_body['status'] == 'error'
+        assert res.json_body['errors'][0]['description'] == (
+            "Pushing back to testing a stable update is not allowed"
+        )
+
     @mock.patch('bodhi.server.services.updates.log.info')
     @mock.patch.dict(config, {'test_gating.required': True})
     def test_test_gating_status_failed(self, info):
diff --git a/devel/ci/integration/tests/test_bodhi_tasks.py b/devel/ci/integration/tests/test_bodhi_tasks.py
--- a/devel/ci/integration/tests/test_bodhi_tasks.py
+++ b/devel/ci/integration/tests/test_bodhi_tasks.py
@@ -91,13 +91,16 @@ def find_update():
             with conn.cursor() as curs:
                 # First try to find an update that we can use.
                 query = base_query[:]
-                query.insert(4, "AND u.status != 'testing' AND u.request != 'testing'")
+                query.insert(
+                    4,
+                    "AND u.status NOT IN ('testing', 'stable') AND u.request != 'testing'"
+                )
                 curs.execute(" ".join(query))
                 result = curs.fetchone()
                 if result is None:
                     # Well, let's hack one into something we can use.
                     query = base_query[:]
-                    query.insert(4, "AND u.status != 'testing'")
+                    query.insert(4, "AND u.status NOT IN ('testing', 'stable')")
                     curs.execute(" ".join(query))
                     result = curs.fetchone()
                     assert result is not None