#520 Record the lightblue queries
Merged 4 years ago by mprahl. Opened 4 years ago by mulaieva.
mulaieva/freshmaker lightblue_data  into  master

file modified
+5
@@ -37,3 +37,8 @@ 

  

  * ``rebuilt_nvr_release_suffix`` - a suffix to add to the ``rebuilt_nvr``

    release in addition to the timestamp. This defaults to an empty string.

+ 

+ * vcrpy - use this library for recording the Lightblue queries per

+   Freshmaker event. The importing of vcrpy and the recording of Lightblue queries is performed if

+   the vcrpy configuration variables (``vcrpy_path`` and ``vcrpy_mode``) are set in

+   ``freshmaker/config.py``

file modified
+16
@@ -383,6 +383,16 @@ 

              'type': tuple,

              'default': ("Generally Available", "Tech Preview", "Beta",),

              'desc': 'Release categories',

+         },

+         'vcrpy_path': {

+             'type': str,

+             'default': '',

+             'desc': 'vcr path where lightblue queries will be recorded'

+         },

+         'vcrpy_mode': {

+             'type': str,

+             'default': 'all',

+             'desc': 'vcr mode for recording lightblue queries'

          }

      }

  
@@ -516,6 +526,12 @@ 

          fixed_permissions.update(permissions)

          self._permissions = fixed_permissions

  

+     def _setifok_vcrpy_path(self, s):

+         s = str(s)

+         if s:

+             import vcr  # noqa: F401

+         self._vcrpy_path = s

+ 

      def _get_krb_auth_ccache_file(self):

          if not self._krb_auth_ccache_file:

              return self._krb_auth_ccache_file

file modified
+18 -6
@@ -501,7 +501,7 @@ 

          return self.entity_versions.get(entity_name, '')

  

      def _make_request(self, entity, data):

-         """Make a request to query data from LightBlue

+         """Make a request to query data from LightBlue and save it if vcrpy is configured

  

          :param str entity: the entity part to construct a full URL sent to

              LightBlue. Refer to callers of ``_make_request`` to learn what
@@ -516,11 +516,23 @@ 

              of errors.

          """

          entity_url = '{}/{}'.format(self.api_root, entity)

-         response = requests.post(entity_url,

-                                  data=json.dumps(data),

-                                  verify=self.verify_ssl,

-                                  cert=(self.cert, self.private_key),

-                                  headers={'Content-Type': 'application/json'})

+         # Record the Freshmaker lightblue queries

+         request_kwargs = {

+             "data": json.dumps(data),

+             "verify": self.verify_ssl,

+             "cert": (self.cert, self.private_key),

+             "headers": {'Content-Type': 'application/json'}

+         }

+         if self.event_id and conf.vcrpy_path:

+             import vcr

+             my_vcr = vcr.VCR(

+                 cassette_library_dir=conf.vcrpy_path,

+                 record_mode=conf.vcrpy_mode,

+             )

+             with my_vcr.use_cassette(f'{self.event_id}.yml'):

+                 response = requests.post(entity_url, **request_kwargs)

+         else:

+             response = requests.post(entity_url, **request_kwargs)

  

          status_code = response.status_code

  

file modified
+7
@@ -21,6 +21,7 @@ 

  

  import flask

  import pytest

+ from unittest import mock

  

  

  @pytest.fixture(autouse=True)
@@ -34,3 +35,9 @@ 

      for attr in ('group', 'user'):

          if hasattr(flask.g, attr):

              delattr(flask.g, attr)

+ 

+ 

+ @pytest.fixture(autouse=True)

+ def mock_vcrpy():

+     with mock.patch('vcr.VCR'):

+         yield

What Freshmaker will do is highly dependent on the data in lightblue.
It gets difficult to reproduce issues when by the time we look at the
issue, the data in lightblue has already changed.
One idea to help us reproduce these issues locally is to record the
Lightblue queries per Freshmaker event (configured for only CVE rebuild
events).

rebased onto 73009cd7463bcabc84ece42dbaa58370a5a4d117

4 years ago

rebased onto 991bdf1e4a9847c42f04d68a59a4edc67a2dcddd

4 years ago

rebased onto 625d88d

4 years ago

rebased onto 2a9862bf467f13daa278335df0177e63fcb47c61

4 years ago

rebased onto a84530a88258651f36a96304169c6293bbe33306

4 years ago

rebased onto a95db79a780519c98f651647171f87960a61bf92

4 years ago

rebased onto 37e0bf988018e4be56800eaeb3233a27ce7ba29a

4 years ago

rebased onto 35078df3b45c0e669f086235e55c892e5dc4663c

4 years ago

rebased onto 5ab9123ef96987218aef90caff1e9902f0076a74

4 years ago

rebased onto 127ff56a286867515dfa292127546881c3dbc96d

4 years ago

Could you make the directory configurable?

You'd want to set this to all by default:
https://vcrpy.readthedocs.io/en/latest/usage.html#all

The reason is we want to record the HTTP requests, but we never want to replay the messages when Freshmaker is running in production.

Perhaps you can make this configurable so that when we want to debug an issue locally, we can change this value to none so that all interactions will come from the recorded cassettes:
https://vcrpy.readthedocs.io/en/latest/usage.html#none

The cassette should be named after the Freshmaker event. This allows someone who needs to debug Freshmaker locally to copy the single cassette for the specific Freshmaker event and replay it locally.

You should consider creating a pytest fixture that is automatically used which mocks vcrpy so that nothing is recorded while executing the unit tests.

The cassette should be named after the Freshmaker event. This allows someone who needs to debug Freshmaker locally to copy the single cassette for the specific Freshmaker event and replay it locally.

About this comment: do you mean that the file name you include the freshmaker event id? Mariana and I checked together and that information (the event id) is not available in that function. And it's not available also in the LightBlue base class. So we should change every method that calls the lightblue functions or that instantiate the LightBlue class to have the event info and than pass it to the _make_request method. It seems a bit too much of an effort for that info. Or do you have a smarter and easier idea in mind to get this info in there?

rebased onto d9da673

4 years ago

rebased onto c6cfca5

4 years ago

rebased onto 58fef70

4 years ago

rebased onto c2d5def

4 years ago

rebased onto bace36c

4 years ago

@gnaponie , @mprahl , can you take a look, please

Can you put a more detailed description here? Also for the mode.
Maybe mention that this is to record the lightblue requests.

Can you add a comment here explaining why we are doing this and what is this about? vcrpy is not that "famous" and some other developer might be confused by this. :)

Just to be more sure, could we check if self.event_id is defined?
you could do something like:
vcr_filename = f'event_id-{(str(self.event_id) if self.event_id else "")}-{str(int(time.time()))}.yml'
and then just:
with my_vcr.use_cassette(vcr_filename):

In my opinion, there should be no default value so that this functionality is disabled by default.

Could you please remove this extra new line?

Also the one below as well?

and save it => and save it if vcrpy is configured

I would move the vcrpy import to under this if statement so that it's only imported if it's enabled in the configuration. This allows someone that deploys Freshmaker to not have to have vcrpy installed if they don't use that functionality.

Don't use the timestamp in the filename here since we want all Lightblue requests to be recorded in a single cassette.

I'll leave this up to @gnaponie but I'd prefer if this functionality was documented as part of this PR.

In my opinion, there should be no default value so that this functionality is disabled by default.

That's a good point. @mulaieva let's do that.

Don't use the timestamp in the filename here since we want all Lightblue requests to be recorded in a single cassette.

I thought it would simply override the existing file... In that case, yeah, we can remove the timestamp. I'm still worried the self.event_id might be None (it would be a bug, but it could happen, also in case of new handlers that use Lightblue), so as a fall back maybe we could use the timestamp (only). Wdyt?

I'll leave this up to @gnaponie but I'd prefer if this functionality was documented as part of this PR.

Where would you document that? Maybe in https://docs.pagure.org/freshmaker/configuration.html ?

I'll leave this up to @gnaponie but I'd prefer if this functionality was documented as part of this PR.

Where would you document that? Maybe in https://docs.pagure.org/freshmaker/configuration.html ?

Yes, that seems like a reasonable place.

Don't use the timestamp in the filename here since we want all Lightblue requests to be recorded in a single cassette.

I thought it would simply override the existing file... In that case, yeah, we can remove the timestamp. I'm still worried the self.event_id might be None (it would be a bug, but it could happen, also in case of new handlers that use Lightblue), so as a fall back maybe we could use the timestamp (only). Wdyt?

I think event_id should be a mandatory parameter in the __init__ method or vcrpy should be disabled when it's not provided. If you go with the latter, an error or warning message should be logged.

rebased onto 2fdfc71

4 years ago

rebased onto 8a75812

4 years ago

1 new commit added

  • Add information about using vcrpy in docs
4 years ago

Since in this page we are describing the configuration variables, you should put vcrpy_path and vcrpy_mode here and write something like configuring these 2 variables you enable the feature to record Lightblue queries per Freshmaker event. Or something similar to what you wrote, but pointing out the two variables names instead.

There's a typo: lightbule :)

We should put empty value here, in order to disable the feature by default.

rebased onto 1826458

4 years ago

for the recording => for recording

Import and record are performed if configuration variables => The importing of vcrpy and the recording of Lightblue queries is performed if the vcrpy configuration variables

It'd be nice if you had a _setifok_vcrpy_path method that tried to import vcrpy if this value is truthy. This would cause Freshmaker to fail when the container is started up rather than the first Lightblue query if vcrpy is enabled but not installed.

Optional:
It'd be nice to use an f-string:

with my_vcr.use_cassette(f'{self.event_id}.yml'):

Optional:
If you put these keyword argument outside of the if branch, you can just perform:

response = requests.post(entity_url, **request_kwargs)

This will allow you to not have to repeat your self below.

rebased onto 26506b7

4 years ago

@mprahl , PTAL. Did I understand your notes right?

variables( => variables (

This is what I had in mind for the method body:

def _setifok_vcrpy_path(self, s):
    if s:
        # This will raise an exception if vcrpy is not present and cause Freshmaker to fail to start
        import vcrpy
    self._vcrpy_path = s

You could also verify that s is a string.

Optional: It'd be easier to read if it was formatted like this:

        request_kwargs = {
            "data": json.dumps(data),
            "verify": self.verify_ssl,
            "cert": (self.cert, self.private_key),
            "headers": {'Content-Type': 'application/json'}
        }

I'll leave it up to @gnaponie to enforce this though since I have no authority over style in this repo :smile:

Please remove this after addressing my comments above

Remember, we want vcrpy to be disabled if vcr_path is not set.

if self.event_id and conf.vcrpy_path:

rebased onto 7088be3

4 years ago

rebased onto ea1a5a0

4 years ago

@mprahl, I've made a change in the tox.ini because I had a flake8 error here "./freshmaker/config.py:532:13: F401 'vcr' imported but unused".

Instead of disabling the check globally, just add # noqa: F401 at the end of this line.

After addressing my one remaining comment, this looks good to me! Nice job!

rebased onto 687072c

4 years ago

Commit df5d294 fixes this pull-request

Pull-Request has been merged by mprahl

4 years ago

Pull-Request has been merged by mprahl

4 years ago
Metadata
Flags
jenkins
success (100%)
Build #1093 successful (commit: a4ef0614)
4 years ago
jenkins
success (100%)
Build #1078 successful (commit: 08276447)
4 years ago
jenkins
failure
Build #1077 failed (commit: b2f02f6b)
4 years ago
jenkins
success (100%)
Build #1074 successful (commit: d817fc28)
4 years ago
jenkins
success (100%)
Build #1067 successful (commit: 9619f6b7)
4 years ago
jenkins
success (100%)
Build #1060 successful (commit: 526ccfa1)
4 years ago
jenkins
success (100%)
Build #1059 successful (commit: 8a758129)
4 years ago
jenkins
success (100%)
Build #1057 successful (commit: 2fdfc712)
4 years ago
jenkins
success (100%)
Build #1048 successful (commit: bace36ce)
4 years ago
jenkins
failure
Build #1047 failed (commit: c2d5def6)
4 years ago
jenkins
failure
Build #1046 failed (commit: 58fef700)
4 years ago
jenkins
failure
Build #1045 failed (commit: c6cfca56)
4 years ago
jenkins
failure
Build #993 failed (commit: d9da6732)
4 years ago
jenkins
success (100%)
Build #971 successful (commit: 127ff56a)
4 years ago
jenkins
failure
Build #970 failed (commit: 5ab9123e)
4 years ago
jenkins
success (100%)
Build #969 successful (commit: 35078df3)
4 years ago
jenkins
failure
Build #968 failed (commit: 37e0bf98)
4 years ago
jenkins
failure
Build #967 failed (commit: a95db79a)
4 years ago
jenkins
failure
Build #966 failed (commit: a84530a8)
4 years ago
jenkins
failure
Build #965 failed (commit: 2a9862bf)
4 years ago
jenkins
success (100%)
Build #942 successful (commit: 625d88d7)
4 years ago
jenkins
failure
Build #941 failed (commit: 991bdf1e)
4 years ago
jenkins
failure
Build #940 failed (commit: 73009cd7)
4 years ago
jenkins
failure
Build #939 failed (commit: a78b4e82)
4 years ago