)]}'
{"openstack/block_storage/v3/_proxy.py":[{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"baeeea5bfc2be5e0f4e1df0415ad6eac5751e81f","unresolved":true,"context_lines":[{"line_number":487,"context_line":"        backup \u003d self._get_resource(_backup.Backup, backup)"},{"line_number":488,"context_line":"        return backup.restore(self, volume_id\u003dvolume_id, name\u003dname)"},{"line_number":489,"context_line":""},{"line_number":490,"context_line":"    def get_limits(self, requires_id\u003dFalse):"},{"line_number":491,"context_line":"        \"\"\"Retrieves limits"},{"line_number":492,"context_line":""},{"line_number":493,"context_line":"        :returns: A Limit object, including both"}],"source_content_type":"text/x-python","patch_set":1,"id":"e3f676cf_9f547107","line":490,"range":{"start_line":490,"start_character":25,"end_line":490,"end_character":43},"updated":"2021-03-15 17:47:33.000000000","message":"What happens if a user provides \u0027True\u0027 to this? Is this really something we want to expose, rather than setting for the user (i.e. just passing \u0027requires_id\u003dTrue\u0027 to the \u0027_get\u0027 call below)","commit_id":"e0b693e92fd29e9ba658e4715215d8cb912314c2"},{"author":{"_account_id":33032,"name":"Dylan Zapzalka","email":"dylanjameszapzalka@hotmail.com","username":"dylanzapzalka"},"change_message_id":"b24251fc345739360f32590bb2f24d18159e49f2","unresolved":false,"context_lines":[{"line_number":487,"context_line":"        backup \u003d self._get_resource(_backup.Backup, backup)"},{"line_number":488,"context_line":"        return backup.restore(self, volume_id\u003dvolume_id, name\u003dname)"},{"line_number":489,"context_line":""},{"line_number":490,"context_line":"    def get_limits(self, requires_id\u003dFalse):"},{"line_number":491,"context_line":"        \"\"\"Retrieves limits"},{"line_number":492,"context_line":""},{"line_number":493,"context_line":"        :returns: A Limit object, including both"}],"source_content_type":"text/x-python","patch_set":1,"id":"38540d15_2ee53e68","line":490,"range":{"start_line":490,"start_character":25,"end_line":490,"end_character":43},"in_reply_to":"e3f676cf_9f547107","updated":"2021-03-16 01:35:50.000000000","message":"I agree, the user shouldn\u0027t have access to that parameter as if it were anything other than False, the method would not work.","commit_id":"e0b693e92fd29e9ba658e4715215d8cb912314c2"},{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"ebeb5bf682322f82ae79732ad925d10315094ced","unresolved":true,"context_lines":[{"line_number":495,"context_line":"            :class:`~openstack.block_storage.v3.limits.RateLimit`"},{"line_number":496,"context_line":"        :rtype: :class:`~openstack.block_storage.v3.limits.Limit`"},{"line_number":497,"context_line":"        \"\"\""},{"line_number":498,"context_line":"        return self._get(_limits.Limit, requires_id\u003dFalse)"},{"line_number":499,"context_line":""},{"line_number":500,"context_line":"    def availability_zones(self):"},{"line_number":501,"context_line":"        \"\"\"Return a generator of availability zones"}],"source_content_type":"text/x-python","patch_set":2,"id":"8e239c30_7ff5df87","line":498,"updated":"2021-03-23 12:26:22.000000000","message":"This is almost right. It looks like the rate limiting part of this API is really meant for API v2. To get this working, you need to modify your \u0027api-paste.ini\u0027 file (\u0027/etc/cinder/api-paste.ini\u0027 on a DevStack deployment) to enable it for Cinder, changing the following:\n\n  [composite:openstack_volume_api_v2]\n  use \u003d call:cinder.api.middleware.auth:pipeline_factory\n  noauth \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler noauth apiv2\n  keystone \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2\n  keystone_nolimit \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2\n\n  [composite:openstack_volume_api_v3]\n  use \u003d call:cinder.api.middleware.auth:pipeline_factory\n  noauth \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler noauth apiv3\n  keystone \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv3\n  keystone_nolimit \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv3\n\nto:\n\n  [composite:openstack_volume_api_v2]\n  use \u003d call:cinder.api.middleware.auth:pipeline_factory\n  noauth \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler noauth ratelimit apiv2\n  keystone \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext ratelimit apiv2\n  keystone_nolimit \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext ratelimit apiv2\n\n  [composite:openstack_volume_api_v3]\n  use \u003d call:cinder.api.middleware.auth:pipeline_factory\n  noauth \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler noauth ratelimit apiv3\n  keystone \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext ratelimit apiv3\n  keystone_nolimit \u003d cors http_proxy_to_wsgi request_id faultwrap sizelimit osprofiler authtoken keystonecontext ratelimit apiv3\n\n  [filter:ratelimit]\n  paste.filter_factory \u003d cinder.api.v2.limits:RateLimitingMiddleware.factory\n\ni.e. add a new filter and enable that for the v2 and v3 pipelines. This basically isn\u0027t documented and I had to use Compute service docs [1] to figure out this Block Storage service configuration 😞 However, with that done, I get the following:\n\n  $ cinder absolute-limits\n  +--------------------------+-------+\n  | Name                     | Value |\n  +--------------------------+-------+\n  | maxTotalBackupGigabytes  | 1000  |\n  | maxTotalBackups          | 10    |\n  | maxTotalSnapshots        | 10    |\n  | maxTotalVolumeGigabytes  | 1000  |\n  | maxTotalVolumes          | 10    |\n  | totalBackupGigabytesUsed | 0     |\n  | totalBackupsUsed         | 0     |\n  | totalGigabytesUsed       | 0     |\n  | totalSnapshotsUsed       | 0     |\n  | totalVolumesUsed         | 0     |\n  +--------------------------+-------+\n\n  $ OS_VOLUME_API_VERSION\u003d2 cinder rate-limits\n  WARNING:cinderclient.api_versions:Version 2 is deprecated, use alternative version 3 instead.\n  +--------+-----------------+-------+--------+--------+---------------------+\n  | Verb   | URI             | Value | Remain | Unit   | Next_Available      |\n  +--------+-----------------+-------+--------+--------+---------------------+\n  | DELETE | *               | 100   | 100    | MINUTE | 2021-03-23T12:02:39 |\n  | GET    | *changes-since* | 3     | 3      | MINUTE | 2021-03-23T12:02:39 |\n  | POST   | *               | 10    | 10     | MINUTE | 2021-03-23T12:02:39 |\n  | POST   | */servers       | 50    | 50     | DAY    | 2021-03-23T12:02:39 |\n  | PUT    | *               | 10    | 10     | MINUTE | 2021-03-23T12:02:39 |\n  +--------+-----------------+-------+--------+--------+---------------------+\n\nUsing \u0027OS_VOLUME_API_VERSION\u003d3 cinder rate-limits\u0027 returns the same information assuming the pipeline configuration is correct. However, that isn\u0027t the case here. With this change and using the default OS_VOLUME_API_VERSION, we see:\n\n  $ python\n  \u003e\u003e\u003e import openstack\n  \u003e\u003e\u003e openstack.enable_logging(debug\u003dFalse)\n  \u003e\u003e\u003e conn \u003d openstack.connect()\n  \u003e\u003e\u003e import pprint\n  \u003e\u003e\u003e pprint.pprint(conn.block_storage.get_limits().to_dict())\n  {\u0027absolute\u0027: {\u0027id\u0027: None,\n                \u0027location\u0027: None,\n                \u0027max_total_backup_gigabytes\u0027: 1000,\n                \u0027max_total_backups\u0027: 10,\n                \u0027max_total_snapshots\u0027: 10,\n                \u0027max_total_volume_gigabytes\u0027: 1000,\n                \u0027max_total_volumes\u0027: 10,\n                \u0027name\u0027: None,\n                \u0027total_backup_gigabytes_used\u0027: 0,\n                \u0027total_backups_used\u0027: 0,\n                \u0027total_gigabytes_used\u0027: 0,\n                \u0027total_snapshots_used\u0027: 0,\n                \u0027total_volumes_used\u0027: 0},\n   \u0027id\u0027: None,\n   \u0027location\u0027: {\u0027cloud\u0027: \u0027envvars\u0027,\n                \u0027project\u0027: {\u0027domain_id\u0027: \u0027default\u0027,\n                            \u0027domain_name\u0027: None,\n                            \u0027id\u0027: \u0027742ec5fd9b97453ba33643d8306e8a7b\u0027,\n                            \u0027name\u0027: \u0027demo\u0027},\n                \u0027region_name\u0027: \u0027RegionOne\u0027,\n                \u0027zone\u0027: None},\n   \u0027name\u0027: None,\n   \u0027rate\u0027: [{\u0027id\u0027: None,\n             \u0027limits\u0027: [{\u0027id\u0027: None,\n                         \u0027location\u0027: None,\n                         \u0027name\u0027: None,\n                         \u0027next_available\u0027: \u00272021-03-23T12:15:07\u0027,\n                         \u0027remaining\u0027: 10,\n                         \u0027unit\u0027: \u0027MINUTE\u0027,\n                         \u0027value\u0027: 10,\n                         \u0027verb\u0027: \u0027POST\u0027},\n                        {\u0027id\u0027: None,\n                         \u0027location\u0027: None,\n                         \u0027name\u0027: None,\n                         \u0027next_available\u0027: \u00272021-03-23T12:15:07\u0027,\n                         \u0027remaining\u0027: 10,\n                         \u0027unit\u0027: \u0027MINUTE\u0027,\n                         \u0027value\u0027: 10,\n                         \u0027verb\u0027: \u0027PUT\u0027},\n                        {\u0027id\u0027: None,\n                         \u0027location\u0027: None,\n                         \u0027name\u0027: None,\n                         \u0027next_available\u0027: \u00272021-03-23T12:15:07\u0027,\n                         \u0027remaining\u0027: 100,\n                         \u0027unit\u0027: \u0027MINUTE\u0027,\n                         \u0027value\u0027: 100,\n                         \u0027verb\u0027: \u0027DELETE\u0027}],\n             \u0027location\u0027: None,\n             \u0027name\u0027: None,\n             \u0027regex\u0027: \u0027.*\u0027,\n             \u0027uri\u0027: \u0027*\u0027},\n            {\u0027id\u0027: None,\n             \u0027limits\u0027: [{\u0027id\u0027: None,\n                         \u0027location\u0027: None,\n                         \u0027name\u0027: None,\n                         \u0027next_available\u0027: \u00272021-03-23T12:15:07\u0027,\n                         \u0027remaining\u0027: 50,\n                         \u0027unit\u0027: \u0027DAY\u0027,\n                         \u0027value\u0027: 50,\n                         \u0027verb\u0027: \u0027POST\u0027}],\n             \u0027location\u0027: None,\n             \u0027name\u0027: None,\n             \u0027regex\u0027: \u0027^/servers\u0027,\n             \u0027uri\u0027: \u0027*/servers\u0027},\n            {\u0027id\u0027: None,\n             \u0027limits\u0027: [{\u0027id\u0027: None,\n                         \u0027location\u0027: None,\n                         \u0027name\u0027: None,\n                         \u0027next_available\u0027: \u00272021-03-23T12:15:07\u0027,\n                         \u0027remaining\u0027: 3,\n                         \u0027unit\u0027: \u0027MINUTE\u0027,\n                         \u0027value\u0027: 3,\n                         \u0027verb\u0027: \u0027GET\u0027}],\n             \u0027location\u0027: None,\n             \u0027name\u0027: None,\n             \u0027regex\u0027: \u0027.*changes-since.*\u0027,\n             \u0027uri\u0027: \u0027*changes-since*\u0027}]}\n\nHowever, requesting it with v2 fails:\n\n  $ python\n  \u003e\u003e\u003e import openstack\n  \u003e\u003e\u003e openstack.enable_logging(debug\u003dFalse)\n  \u003e\u003e\u003e conn \u003d openstack.connect()\n  \u003e\u003e\u003e import pprint\n  \u003e\u003e\u003e conn.block_storage.get_limits()\n  Traceback (most recent call last):\n    File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\n  AttributeError: \u0027Proxy\u0027 object has no attribute \u0027get_limits\u0027\n\nThat\u0027s because you haven\u0027t added this to \u0027openstack/block_storage/v2/_proxy.py\u0027 also. We should probably do this.\n\n(NOTE: I\u0027m using the \u0027pprint\u0027 lib and \u0027to_dict\u0027 so we\u0027ve something readable here)\n\n[1] https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/8/html/configuration_reference_guide/configuring-compute-api","commit_id":"9a91047da6e6ca120b72a16e936aea9acc4c03eb"}],"openstack/block_storage/v3/limits.py":[{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"ebeb5bf682322f82ae79732ad925d10315094ced","unresolved":true,"context_lines":[{"line_number":42,"context_line":""},{"line_number":43,"context_line":"class RateLimit(resource.Resource):"},{"line_number":44,"context_line":"    #: Properties"},{"line_number":45,"context_line":"    #: Rate limits next availabe time."},{"line_number":46,"context_line":"    next_available \u003d resource.Body(\"next-available\")"},{"line_number":47,"context_line":"    #: Integer for rate limits remaining."},{"line_number":48,"context_line":"    remaining \u003d resource.Body(\"remaining\", type\u003dint)"}],"source_content_type":"text/x-python","patch_set":2,"id":"6661d40b_8b89ad53","line":45,"range":{"start_line":45,"start_character":24,"end_line":45,"end_character":32},"updated":"2021-03-23 12:26:22.000000000","message":"nit: available","commit_id":"9a91047da6e6ca120b72a16e936aea9acc4c03eb"}],"openstack/tests/unit/block_storage/v3/test_proxy.py":[{"author":{"_account_id":15334,"name":"Stephen Finucane","display_name":"stephenfin","email":"stephenfin@redhat.com","username":"sfinucan"},"change_message_id":"baeeea5bfc2be5e0f4e1df0415ad6eac5751e81f","unresolved":true,"context_lines":[{"line_number":220,"context_line":"            expected_kwargs\u003d{\u0027volume_id\u0027: \u0027vol_id\u0027, \u0027name\u0027: \u0027name\u0027}"},{"line_number":221,"context_line":"        )"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":"    def test_limits_get(self, ignore_value\u003dTrue):"},{"line_number":224,"context_line":"        self.verify_get("},{"line_number":225,"context_line":"            self.proxy.get_limits, limits.Limit, ignore_value\u003dignore_value,"},{"line_number":226,"context_line":"            expected_kwargs\u003d{\u0027requires_id\u0027: False})"}],"source_content_type":"text/x-python","patch_set":1,"id":"6ce81912_358e5b47","line":223,"range":{"start_line":223,"start_character":28,"end_line":223,"end_character":47},"updated":"2021-03-15 17:47:33.000000000","message":"Same question. In general too, you shouldn\u0027t pass arguments to test since people shouldn\u0027t be calling them separately. The only exception would be helper functions, i.e.\n\n  def _test_foo(self, use_bar):\n      # lots of common stuff here\n      if use_bar:\n          # bar-specific stuff\n      # lots more common stuff here\n\n  def test_foo_with_bar(self):\n      self._test_foo(use_bar\u003dTrue)\n\n  def test_foo_without_bar(self):\n      self._test_foo(use_bar\u003dFalse)\n\nIf that makes sense?","commit_id":"e0b693e92fd29e9ba658e4715215d8cb912314c2"},{"author":{"_account_id":33032,"name":"Dylan Zapzalka","email":"dylanjameszapzalka@hotmail.com","username":"dylanzapzalka"},"change_message_id":"b24251fc345739360f32590bb2f24d18159e49f2","unresolved":false,"context_lines":[{"line_number":220,"context_line":"            expected_kwargs\u003d{\u0027volume_id\u0027: \u0027vol_id\u0027, \u0027name\u0027: \u0027name\u0027}"},{"line_number":221,"context_line":"        )"},{"line_number":222,"context_line":""},{"line_number":223,"context_line":"    def test_limits_get(self, ignore_value\u003dTrue):"},{"line_number":224,"context_line":"        self.verify_get("},{"line_number":225,"context_line":"            self.proxy.get_limits, limits.Limit, ignore_value\u003dignore_value,"},{"line_number":226,"context_line":"            expected_kwargs\u003d{\u0027requires_id\u0027: False})"}],"source_content_type":"text/x-python","patch_set":1,"id":"834f22d0_01f7f441","line":223,"range":{"start_line":223,"start_character":28,"end_line":223,"end_character":47},"in_reply_to":"6ce81912_358e5b47","updated":"2021-03-16 01:35:50.000000000","message":"I agree, that makes sense.","commit_id":"e0b693e92fd29e9ba658e4715215d8cb912314c2"}]}
