)]}'
{"nova/compute/api.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"dfdc29a9b954e7aa001aa5edca5fa447ef5b409e","unresolved":false,"context_lines":[{"line_number":5164,"context_line":"        this function is written to support both."},{"line_number":5165,"context_line":"        \"\"\""},{"line_number":5166,"context_line":""},{"line_number":5167,"context_line":"        count \u003d objects.Quotas.count_as_dict(context,"},{"line_number":5168,"context_line":"                                             \u0027security_group_rules\u0027, id)"},{"line_number":5169,"context_line":"        count_value \u003d count[\u0027project\u0027][\u0027security_group_rules\u0027]"},{"line_number":5170,"context_line":"        try:"},{"line_number":5171,"context_line":"            projected \u003d count_value + len(vals)"},{"line_number":5172,"context_line":"            objects.Quotas.limit_check(context, security_group_rules\u003dprojected)"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_67263518","line":5169,"range":{"start_line":5167,"start_character":8,"end_line":5169,"end_character":62},"updated":"2017-05-22 15:57:26.000000000","message":"So this is the oddball when compared to server_group_members and key_pairs, because those are filtered on user_id, and here the id is the security group ID, which is the parent resource of the secgroup rules. So we\u0027re using security_group_rule_count_by_group but it\u0027s not clear to me that we\u0027re actually filtering by project, since I don\u0027t think model_query in this case in the DB API is going to filter by project_id. It\u0027s certainly not filtering by user_id. So I guess we just pick project here since that\u0027s our default? Now the parent security group does have a user_id and project_id field, so I guess we\u0027re implicitly tied to a specific project. It\u0027s weird though because security groups are a reservable resource and counted by project id and userid in _security_group_count_by_project_and_user.\n\nSo in the case of counting for security groups, they can be on a per-user basis, but in the case of security group rules, they are a per-project basis, is that right?\n\nAnyway, this all looks to be backward compatible, even if what we\u0027re being compatible with is really confusing to me.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7c05c3974b139be82401b56dda57416486178031","unresolved":false,"context_lines":[{"line_number":5164,"context_line":"        this function is written to support both."},{"line_number":5165,"context_line":"        \"\"\""},{"line_number":5166,"context_line":""},{"line_number":5167,"context_line":"        count \u003d objects.Quotas.count_as_dict(context,"},{"line_number":5168,"context_line":"                                             \u0027security_group_rules\u0027, id)"},{"line_number":5169,"context_line":"        count_value \u003d count[\u0027project\u0027][\u0027security_group_rules\u0027]"},{"line_number":5170,"context_line":"        try:"},{"line_number":5171,"context_line":"            projected \u003d count_value + len(vals)"},{"line_number":5172,"context_line":"            objects.Quotas.limit_check(context, security_group_rules\u003dprojected)"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_2a992478","line":5169,"range":{"start_line":5167,"start_character":8,"end_line":5169,"end_character":62},"in_reply_to":"ff0f0b1f_67263518","updated":"2017-05-22 16:54:10.000000000","message":"Short answer is, you\u0027re right, this is an oddball and scoped \u0027project\u0027 as the \"most correct\" way to get it consistent with the other counts formats [1]. And yes, implicitly tied to a specific project.\n\nLong answer: reservable resources count across a project and a user so that those counts can be checked against the project limit and user limit, respectively. The other Countable resources don\u0027t work that way. They only check against the user limit if there is one, else the project limit.\n\nSecurity groups can be counted across a project and/or across a user. Security group rules are counted across a security group. And since security groups are per-project, I thought to make the rules per-project too, for the sake of the dict format anyway.\n\n+1, what we\u0027re staying compatible with is confusing. And most of the confusion comes from the project + user scoping, IMHO. That\u0027s why I\u0027m for not supporting user_id when we go to do unified limits. It makes things really hard to code and understand with checking against both a project limit and user limit in certain cases. User_id was added later to the existing quota system and we suspect it was done as a way to get a rudimentary one-level hierarchical quota. So if we can support a real hierarchy, I don\u0027t think we\u0027ll need user_id based limits anymore.\n\n[1] https://review.openstack.org/#/c/446239/7/nova/quota.py@1889","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4dfe22af0f0be3573f05bd1af9c6191bf94d7393","unresolved":false,"context_lines":[{"line_number":1064,"context_line":"                        count_value \u003d count[\u0027user\u0027][\u0027server_group_members\u0027]"},{"line_number":1065,"context_line":"                        try:"},{"line_number":1066,"context_line":"                            objects.Quotas.limit_check("},{"line_number":1067,"context_line":"                                context, server_group_members\u003dcount_value + 1)"},{"line_number":1068,"context_line":"                        except exception.OverQuota:"},{"line_number":1069,"context_line":"                            msg \u003d _(\"Quota exceeded, too many servers in \""},{"line_number":1070,"context_line":"                                    \"group\")"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_77563e2c","line":1067,"updated":"2017-05-30 15:58:57.000000000","message":"Not necessary to fix this in this patch, but the above is incorrect. It should be count_value + min_count, not count_value + 1...","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"aceb38298fa935db70cc2d15a5733a0124f8e8bd","unresolved":false,"context_lines":[{"line_number":1064,"context_line":"                        count_value \u003d count[\u0027user\u0027][\u0027server_group_members\u0027]"},{"line_number":1065,"context_line":"                        try:"},{"line_number":1066,"context_line":"                            objects.Quotas.limit_check("},{"line_number":1067,"context_line":"                                context, server_group_members\u003dcount_value + 1)"},{"line_number":1068,"context_line":"                        except exception.OverQuota:"},{"line_number":1069,"context_line":"                            msg \u003d _(\"Quota exceeded, too many servers in \""},{"line_number":1070,"context_line":"                                    \"group\")"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_9280c08d","line":1067,"in_reply_to":"df140735_77563e2c","updated":"2017-05-30 16:28:10.000000000","message":"We\u0027re in a loop here, so to use min_count would mean pulling this out of the loop. That does make more sense though so we\u0027re not racing with another request building a server group with the same user_id.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"}],"nova/exception.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"7a29e334d656eaa34d57a83368127e70bb2558dc","unresolved":false,"context_lines":[{"line_number":984,"context_line":""},{"line_number":985,"context_line":""},{"line_number":986,"context_line":"class InvalidQuotaKeyMismatch(Invalid):"},{"line_number":987,"context_line":"    msg_fmt \u003d _(\"Quota values: %(user_values)s and project values \""},{"line_number":988,"context_line":"                \"%(proj_values)s keys do not match.\")"},{"line_number":989,"context_line":""},{"line_number":990,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_6552ade0","line":987,"range":{"start_line":987,"start_character":31,"end_line":987,"end_character":46},"updated":"2017-05-22 16:58:32.000000000","message":"This should be \"user values %(user_values)s and project values\" for context. -1 here.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":984,"context_line":""},{"line_number":985,"context_line":""},{"line_number":986,"context_line":"class InvalidQuotaKeyMismatch(Invalid):"},{"line_number":987,"context_line":"    msg_fmt \u003d _(\"Quota values: %(user_values)s and project values \""},{"line_number":988,"context_line":"                \"%(proj_values)s keys do not match.\")"},{"line_number":989,"context_line":""},{"line_number":990,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_b8234b56","line":987,"range":{"start_line":987,"start_character":31,"end_line":987,"end_character":46},"in_reply_to":"ff0f0b1f_6552ade0","updated":"2017-05-22 19:01:59.000000000","message":"Ack.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"7e38266f61ad7e22cb239f4245653d94d24914ef","unresolved":false,"context_lines":[{"line_number":984,"context_line":""},{"line_number":985,"context_line":""},{"line_number":986,"context_line":"class InvalidQuotaKeyMismatch(Invalid):"},{"line_number":987,"context_line":"    msg_fmt \u003d _(\"Quota project values: %(project_values)s and user values \""},{"line_number":988,"context_line":"                \"%(user_values)s keys do not match.\")"},{"line_number":989,"context_line":""},{"line_number":990,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_e9df5a63","line":987,"range":{"start_line":987,"start_character":37,"end_line":987,"end_character":38},"updated":"2017-05-25 02:18:07.000000000","message":"Or remove this colon. I think colons are weird in the middle of a sentence, personally.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b33cdb8e90b042b213bae475de1ff4dd8ba3cc76","unresolved":false,"context_lines":[{"line_number":984,"context_line":""},{"line_number":985,"context_line":""},{"line_number":986,"context_line":"class InvalidQuotaKeyMismatch(Invalid):"},{"line_number":987,"context_line":"    msg_fmt \u003d _(\"Quota project values: %(project_values)s and user values \""},{"line_number":988,"context_line":"                \"%(user_values)s keys do not match.\")"},{"line_number":989,"context_line":""},{"line_number":990,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_3815a240","line":987,"range":{"start_line":987,"start_character":73,"end_line":987,"end_character":74},"updated":"2017-05-25 00:10:39.000000000","message":"Should have put a colon here.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"5a34915b6d97de1aed13f544ddccf17bcd2625e2","unresolved":false,"context_lines":[{"line_number":984,"context_line":""},{"line_number":985,"context_line":""},{"line_number":986,"context_line":"class InvalidQuotaKeyMismatch(Invalid):"},{"line_number":987,"context_line":"    msg_fmt \u003d _(\"Quota project values: %(project_values)s and user values \""},{"line_number":988,"context_line":"                \"%(user_values)s keys do not match.\")"},{"line_number":989,"context_line":""},{"line_number":990,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_8e4b2b5e","line":987,"range":{"start_line":987,"start_character":37,"end_line":987,"end_character":38},"in_reply_to":"ff0f0b1f_e9df5a63","updated":"2017-05-25 17:01:17.000000000","message":"Okay, that works too.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"}],"nova/objects/quotas.py":[{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"b1316d52977a37f963b33ab1afb1faa3ee06c5d4","unresolved":false,"context_lines":[{"line_number":302,"context_line":"        self.obj_reset_changes()"},{"line_number":303,"context_line":""},{"line_number":304,"context_line":"    @base.remotable_classmethod"},{"line_number":305,"context_line":"    def limit_check(cls, context, proj_values\u003dNone, project_id\u003dNone,"},{"line_number":306,"context_line":"                    user_id\u003dNone, **values):"},{"line_number":307,"context_line":"        \"\"\"Check quota limits.\"\"\""},{"line_number":308,"context_line":"        return quota.QUOTAS.limit_check("}],"source_content_type":"text/x-python","patch_set":1,"id":"1a1ced50_7c99396e","line":305,"updated":"2017-03-17 14:49:09.000000000","message":"I assume we have to leave this alone in this new split?","commit_id":"5cd9167048fc108c4c37dbe240909b19ae13064b"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"b1316d52977a37f963b33ab1afb1faa3ee06c5d4","unresolved":false,"context_lines":[{"line_number":324,"context_line":"        provided deltas."},{"line_number":325,"context_line":""},{"line_number":326,"context_line":"        :param context: The request context, for access checks"},{"line_number":327,"context_line":"        :param resource: The resource to count. Must be one of: \u0027instances\u0027,"},{"line_number":328,"context_line":"                         \u0027cores\u0027, \u0027ram\u0027, \u0027security_groups\u0027, \u0027server_groups\u0027,"},{"line_number":329,"context_line":"                         \u0027fixed_ips\u0027, \u0027floating_ips\u0027, \u0027networks\u0027"},{"line_number":330,"context_line":"        :param deltas: A dictionary {resource: delta} to check against"}],"source_content_type":"text/x-python","patch_set":1,"id":"1a1ced50_fc9fe95c","line":327,"updated":"2017-03-17 14:49:09.000000000","message":"Worth creating a resource enum thing just to use here?","commit_id":"5cd9167048fc108c4c37dbe240909b19ae13064b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":12,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"#    under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"from collections import defaultdict"},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"from nova import db"},{"line_number":18,"context_line":"from nova import exception"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_9f12bc08","line":15,"updated":"2017-04-26 18:45:22.000000000","message":"meh, should just be importing modules, not objects...","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":12,"context_line":"#    License for the specific language governing permissions and limitations"},{"line_number":13,"context_line":"#    under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"from collections import defaultdict"},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"from nova import db"},{"line_number":18,"context_line":"from nova import exception"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_5fc79446","line":15,"in_reply_to":"5ff73747_9f12bc08","updated":"2017-04-26 19:32:21.000000000","message":"Okay, will change it.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":161,"context_line":"                                 different project"},{"line_number":162,"context_line":"        :param check_user_id: The user_id for scoping the limit check, e.g."},{"line_number":163,"context_line":"                              admin acting upon a resource owned by a different"},{"line_number":164,"context_line":"                              user"},{"line_number":165,"context_line":"        :raises: exception.OverQuota if the limit check exceeds the quota"},{"line_number":166,"context_line":"                 limits"},{"line_number":167,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_7ff930c6","line":164,"updated":"2017-04-26 18:45:22.000000000","message":"For this and check_project_id, instead of saying \"e.g. admin acting...\" it might be clearer to say \"We don\u0027t use the context to find resource ownership information because an admin may be acting on someone else\u0027s resources.\"","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":161,"context_line":"                                 different project"},{"line_number":162,"context_line":"        :param check_user_id: The user_id for scoping the limit check, e.g."},{"line_number":163,"context_line":"                              admin acting upon a resource owned by a different"},{"line_number":164,"context_line":"                              user"},{"line_number":165,"context_line":"        :raises: exception.OverQuota if the limit check exceeds the quota"},{"line_number":166,"context_line":"                 limits"},{"line_number":167,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_7ffa5075","line":164,"in_reply_to":"5ff73747_7ff930c6","updated":"2017-04-26 19:32:21.000000000","message":"Okay, I\u0027ll reword this. It\u0027s optional for if you want to scope it to a project_id/user_id different than what\u0027s in the context. I tried giving an example to explain it but maybe that just adds confusion.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        if check_user_id is not None:"},{"line_number":183,"context_line":"            check_kwargs[\u0027user_id\u0027] \u003d check_user_id"},{"line_number":184,"context_line":"        try:"},{"line_number":185,"context_line":"            cls.limit_check_project_and_user(context, **check_kwargs)"},{"line_number":186,"context_line":"        except exception.OverQuota as exc:"},{"line_number":187,"context_line":"            if isinstance(count, dict):"},{"line_number":188,"context_line":"                exc.kwargs[\u0027usages\u0027] \u003d count[\u0027user\u0027]"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_5ff434cf","line":185,"updated":"2017-04-26 18:45:22.000000000","message":"There is an inherent race condition that exists between line 172 and here. The usage count grabbed on line 172 could be entirely different by the time we get here, but meh, that isn\u0027t a new issue to this code and hopefully will get fixed when we use the placement API (and generations on the consumer) to handle consistency checks.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        if check_user_id is not None:"},{"line_number":183,"context_line":"            check_kwargs[\u0027user_id\u0027] \u003d check_user_id"},{"line_number":184,"context_line":"        try:"},{"line_number":185,"context_line":"            cls.limit_check_project_and_user(context, **check_kwargs)"},{"line_number":186,"context_line":"        except exception.OverQuota as exc:"},{"line_number":187,"context_line":"            if isinstance(count, dict):"},{"line_number":188,"context_line":"                exc.kwargs[\u0027usages\u0027] \u003d count[\u0027user\u0027]"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_5f3af433","line":185,"in_reply_to":"5ff73747_5ff434cf","updated":"2017-04-26 19:32:21.000000000","message":"Yes, you are correct and it\u0027s latent and the hope is that we can use this area of the code to add atomicity later. Currently the plan for using placement is only for counting cores and ram. Counting other things like keypairs, server groups, server group members, are not represented in placement.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"062a5dc3a47984e526f4581221a0b4f7bc977032","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        check_user_id \u003d count_kwargs.pop(\u0027check_user_id\u0027, None)"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"        resource_object \u003d quota.QUOTAS._resources.get(resource)"},{"line_number":185,"context_line":"        if isinstance(resource_object, quota.MultiCountableResource):"},{"line_number":186,"context_line":"            count \u003d cls.counts(context, resource, *count_args, **count_kwargs)"},{"line_number":187,"context_line":"        else:"},{"line_number":188,"context_line":"            count \u003d cls.count(context, resource, *count_args, **count_kwargs)"},{"line_number":189,"context_line":"        check_kwargs \u003d collections.defaultdict(dict)"},{"line_number":190,"context_line":"        for k, v in deltas.items():"},{"line_number":191,"context_line":"            if isinstance(count, dict):"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_237d1c6e","line":188,"range":{"start_line":185,"start_character":8,"end_line":188,"end_character":77},"updated":"2017-05-03 17:59:01.000000000","message":"It seems odd we don\u0027t have the same function name here I guess, but I guess this makes sense.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7e642a3599607c3a185b527308e020b6048eeae6","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        check_user_id \u003d count_kwargs.pop(\u0027check_user_id\u0027, None)"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"        resource_object \u003d quota.QUOTAS._resources.get(resource)"},{"line_number":185,"context_line":"        if isinstance(resource_object, quota.MultiCountableResource):"},{"line_number":186,"context_line":"            count \u003d cls.counts(context, resource, *count_args, **count_kwargs)"},{"line_number":187,"context_line":"        else:"},{"line_number":188,"context_line":"            count \u003d cls.count(context, resource, *count_args, **count_kwargs)"},{"line_number":189,"context_line":"        check_kwargs \u003d collections.defaultdict(dict)"},{"line_number":190,"context_line":"        for k, v in deltas.items():"},{"line_number":191,"context_line":"            if isinstance(count, dict):"}],"source_content_type":"text/x-python","patch_set":5,"id":"3f044301_a9e92881","line":188,"range":{"start_line":185,"start_character":8,"end_line":188,"end_character":77},"in_reply_to":"3f044301_8221aca2","updated":"2017-05-04 14:23:29.000000000","message":"No, count() always returns an integer and counts() returns a dict containing multiple counts. CountableResource has count() and MultiCountableResource has counts().\n\nIn an earlier PS, I had everything as CountableResource and count() even though sometimes I returned an integer and sometimes returned a dict.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"ac7f88b2cf2c3ab7d1aaabd543c90e699d7b7b6b","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        check_user_id \u003d count_kwargs.pop(\u0027check_user_id\u0027, None)"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"        resource_object \u003d quota.QUOTAS._resources.get(resource)"},{"line_number":185,"context_line":"        if isinstance(resource_object, quota.MultiCountableResource):"},{"line_number":186,"context_line":"            count \u003d cls.counts(context, resource, *count_args, **count_kwargs)"},{"line_number":187,"context_line":"        else:"},{"line_number":188,"context_line":"            count \u003d cls.count(context, resource, *count_args, **count_kwargs)"},{"line_number":189,"context_line":"        check_kwargs \u003d collections.defaultdict(dict)"},{"line_number":190,"context_line":"        for k, v in deltas.items():"},{"line_number":191,"context_line":"            if isinstance(count, dict):"}],"source_content_type":"text/x-python","patch_set":5,"id":"3f044301_b6bfbca8","line":188,"range":{"start_line":185,"start_character":8,"end_line":188,"end_character":77},"in_reply_to":"3f044301_a9e92881","updated":"2017-05-11 12:24:36.000000000","message":"I totally missed line 191... makes way more sense now. I guess we could do counts_dict or count as the variable name, but this works now.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"7e5ff6c1caf43a12203ddeb37cec23ea103159a6","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        check_user_id \u003d count_kwargs.pop(\u0027check_user_id\u0027, None)"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"        resource_object \u003d quota.QUOTAS._resources.get(resource)"},{"line_number":185,"context_line":"        if isinstance(resource_object, quota.MultiCountableResource):"},{"line_number":186,"context_line":"            count \u003d cls.counts(context, resource, *count_args, **count_kwargs)"},{"line_number":187,"context_line":"        else:"},{"line_number":188,"context_line":"            count \u003d cls.count(context, resource, *count_args, **count_kwargs)"},{"line_number":189,"context_line":"        check_kwargs \u003d collections.defaultdict(dict)"},{"line_number":190,"context_line":"        for k, v in deltas.items():"},{"line_number":191,"context_line":"            if isinstance(count, dict):"}],"source_content_type":"text/x-python","patch_set":5,"id":"3f044301_8221aca2","line":188,"range":{"start_line":185,"start_character":8,"end_line":188,"end_character":77},"in_reply_to":"5ff73747_1e0ef7e4","updated":"2017-05-04 13:54:55.000000000","message":"I guess if the structure could contain multiple counts for both, its probably OK it being the same method name?  I am torn.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"416a1f2d7b4e344ea7b94269a10fdfb08d69e28e","unresolved":false,"context_lines":[{"line_number":182,"context_line":"        check_user_id \u003d count_kwargs.pop(\u0027check_user_id\u0027, None)"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"        resource_object \u003d quota.QUOTAS._resources.get(resource)"},{"line_number":185,"context_line":"        if isinstance(resource_object, quota.MultiCountableResource):"},{"line_number":186,"context_line":"            count \u003d cls.counts(context, resource, *count_args, **count_kwargs)"},{"line_number":187,"context_line":"        else:"},{"line_number":188,"context_line":"            count \u003d cls.count(context, resource, *count_args, **count_kwargs)"},{"line_number":189,"context_line":"        check_kwargs \u003d collections.defaultdict(dict)"},{"line_number":190,"context_line":"        for k, v in deltas.items():"},{"line_number":191,"context_line":"            if isinstance(count, dict):"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_1e0ef7e4","line":188,"range":{"start_line":185,"start_character":8,"end_line":188,"end_character":77},"in_reply_to":"5ff73747_237d1c6e","updated":"2017-05-03 18:24:14.000000000","message":"I did in the earlier PS have both of them being just \"count()\" but I changed things to add MultiCountableResource and \"counts()\" for cases where multiple counts would be returned. Trying to make this minimally confusing and I\u0027m open to other ideas if you have any.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"7a29e334d656eaa34d57a83368127e70bb2558dc","unresolved":false,"context_lines":[{"line_number":127,"context_line":"            context, project_id\u003dproject_id, user_id\u003duser_id, **values)"},{"line_number":128,"context_line":""},{"line_number":129,"context_line":"    @base.remotable_classmethod"},{"line_number":130,"context_line":"    def limit_check_project_and_user(cls, context, proj_values\u003dNone,"},{"line_number":131,"context_line":"                                     user_values\u003dNone, project_id\u003dNone,"},{"line_number":132,"context_line":"                                     user_id\u003dNone):"},{"line_number":133,"context_line":"        \"\"\"Check values against quota limits.\"\"\""},{"line_number":134,"context_line":"        return quota.QUOTAS.limit_check_project_and_user(context,"},{"line_number":135,"context_line":"            proj_values\u003dproj_values, user_values\u003duser_values,"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_4572094b","line":132,"range":{"start_line":130,"start_character":42,"end_line":132,"end_character":49},"updated":"2017-05-22 16:58:32.000000000","message":"Descriptions on these in the docstring would be nice, since proj_values and user_values are dicts. Also, project_values would be a nicer name IMO.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":127,"context_line":"            context, project_id\u003dproject_id, user_id\u003duser_id, **values)"},{"line_number":128,"context_line":""},{"line_number":129,"context_line":"    @base.remotable_classmethod"},{"line_number":130,"context_line":"    def limit_check_project_and_user(cls, context, proj_values\u003dNone,"},{"line_number":131,"context_line":"                                     user_values\u003dNone, project_id\u003dNone,"},{"line_number":132,"context_line":"                                     user_id\u003dNone):"},{"line_number":133,"context_line":"        \"\"\"Check values against quota limits.\"\"\""},{"line_number":134,"context_line":"        return quota.QUOTAS.limit_check_project_and_user(context,"},{"line_number":135,"context_line":"            proj_values\u003dproj_values, user_values\u003duser_values,"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_18da374b","line":132,"range":{"start_line":130,"start_character":42,"end_line":132,"end_character":49},"in_reply_to":"ff0f0b1f_4572094b","updated":"2017-05-22 19:01:59.000000000","message":"Yeah, those are documented in nova/quota.py and I didn\u0027t duplicate them here.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"7a29e334d656eaa34d57a83368127e70bb2558dc","unresolved":false,"context_lines":[{"line_number":153,"context_line":"                     **count_kwargs):"},{"line_number":154,"context_line":"        \"\"\"Check usage deltas against quota limits."},{"line_number":155,"context_line":""},{"line_number":156,"context_line":"        This does a Quotas.count followed by a"},{"line_number":157,"context_line":"        Quotas.limit_check_project_and_user using the provided deltas."},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"        :param context: The request context, for access checks"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_2530359f","line":156,"range":{"start_line":156,"start_character":27,"end_line":156,"end_character":32},"updated":"2017-05-22 16:58:32.000000000","message":"count_as_dict","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":153,"context_line":"                     **count_kwargs):"},{"line_number":154,"context_line":"        \"\"\"Check usage deltas against quota limits."},{"line_number":155,"context_line":""},{"line_number":156,"context_line":"        This does a Quotas.count followed by a"},{"line_number":157,"context_line":"        Quotas.limit_check_project_and_user using the provided deltas."},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"        :param context: The request context, for access checks"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_98e5270c","line":156,"range":{"start_line":156,"start_character":27,"end_line":156,"end_character":32},"in_reply_to":"ff0f0b1f_2530359f","updated":"2017-05-22 19:01:59.000000000","message":"Thanks.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"7a29e334d656eaa34d57a83368127e70bb2558dc","unresolved":false,"context_lines":[{"line_number":157,"context_line":"        Quotas.limit_check_project_and_user using the provided deltas."},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"        :param context: The request context, for access checks"},{"line_number":160,"context_line":"        :param resource: The resource to count. Must be one of: \u0027instances\u0027,"},{"line_number":161,"context_line":"                         \u0027cores\u0027, \u0027ram\u0027, \u0027security_groups\u0027, \u0027server_groups\u0027,"},{"line_number":162,"context_line":"                         \u0027fixed_ips\u0027, \u0027floating_ips\u0027, \u0027networks\u0027"},{"line_number":163,"context_line":"        :param deltas: A dictionary {resource: delta} to check against"},{"line_number":164,"context_line":"                       the quota limits"},{"line_number":165,"context_line":"        :param count_args: Optional positional arguments to pass to"},{"line_number":166,"context_line":"                           count_as_dict()"},{"line_number":167,"context_line":"        :param count_kwargs: Optional keyword arguments to pass to"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_c585f9d0","line":164,"range":{"start_line":160,"start_character":8,"end_line":164,"end_character":39},"updated":"2017-05-22 16:58:32.000000000","message":"This is odd. So deltas is always just a single-key dict? It would have to be, because resource is passed to count_as_dict and then the dict returned from that just has that resource and it\u0027s count value. We\u0027re iterating over deltas though and assuming that\u0027s what is in deltas for keys is also in the count dict from count_as_dict, and if someone screwed up here we\u0027re going to get a KeyError. Couldn\u0027t we replace the deltas dict with just a \u0027delta\u0027 value which is our int to check against for the resource?\n\nIf we really want deltas to be a dict with multiple resource keys, then I think we need to get rid of resource as a parameter and handle building the count dict via count_as_dict by iterating over the keys in the deltas dict.\n\n-1 here.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":157,"context_line":"        Quotas.limit_check_project_and_user using the provided deltas."},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"        :param context: The request context, for access checks"},{"line_number":160,"context_line":"        :param resource: The resource to count. Must be one of: \u0027instances\u0027,"},{"line_number":161,"context_line":"                         \u0027cores\u0027, \u0027ram\u0027, \u0027security_groups\u0027, \u0027server_groups\u0027,"},{"line_number":162,"context_line":"                         \u0027fixed_ips\u0027, \u0027floating_ips\u0027, \u0027networks\u0027"},{"line_number":163,"context_line":"        :param deltas: A dictionary {resource: delta} to check against"},{"line_number":164,"context_line":"                       the quota limits"},{"line_number":165,"context_line":"        :param count_args: Optional positional arguments to pass to"},{"line_number":166,"context_line":"                           count_as_dict()"},{"line_number":167,"context_line":"        :param count_kwargs: Optional keyword arguments to pass to"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_00bf5fb0","line":164,"range":{"start_line":160,"start_character":8,"end_line":164,"end_character":39},"in_reply_to":"ff0f0b1f_c585f9d0","updated":"2017-05-22 19:01:59.000000000","message":"Good point -- I can\u0027t remember why I did it this way. Will change.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":181,"context_line":"            # the defaultdict."},{"line_number":182,"context_line":"            if (resource in check_kwargs.get(\u0027project_values\u0027, {}) or"},{"line_number":183,"context_line":"                    resource in check_kwargs.get(\u0027user_values\u0027, {})):"},{"line_number":184,"context_line":"                continue"},{"line_number":185,"context_line":"            count \u003d cls.count_as_dict(context, resource, *count_args,"},{"line_number":186,"context_line":"                                      **count_kwargs)"},{"line_number":187,"context_line":"            for res in count.get(\u0027project\u0027, {}):"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_89932501","line":184,"range":{"start_line":184,"start_character":16,"end_line":184,"end_character":24},"updated":"2017-05-25 17:59:06.000000000","message":"We don\u0027t have a test that hits this case.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"50207133ed03a9a1cb5d2ffae5b82b207b290db0","unresolved":false,"context_lines":[{"line_number":181,"context_line":"            # the defaultdict."},{"line_number":182,"context_line":"            if (resource in check_kwargs.get(\u0027project_values\u0027, {}) or"},{"line_number":183,"context_line":"                    resource in check_kwargs.get(\u0027user_values\u0027, {})):"},{"line_number":184,"context_line":"                continue"},{"line_number":185,"context_line":"            count \u003d cls.count_as_dict(context, resource, *count_args,"},{"line_number":186,"context_line":"                                      **count_kwargs)"},{"line_number":187,"context_line":"            for res in count.get(\u0027project\u0027, {}):"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_844f8791","line":184,"range":{"start_line":184,"start_character":16,"end_line":184,"end_character":24},"in_reply_to":"ff0f0b1f_89932501","updated":"2017-05-25 20:21:14.000000000","message":"Done","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4dfe22af0f0be3573f05bd1af9c6191bf94d7393","unresolved":false,"context_lines":[{"line_number":203,"context_line":"            # Report usage in the exception when going over quota"},{"line_number":204,"context_line":"            key \u003d \u0027user\u0027 if \u0027user\u0027 in count else \u0027project\u0027"},{"line_number":205,"context_line":"            exc.kwargs[\u0027usages\u0027] \u003d count[key]"},{"line_number":206,"context_line":"            raise exc"},{"line_number":207,"context_line":""},{"line_number":208,"context_line":"    @base.remotable_classmethod"},{"line_number":209,"context_line":"    def create_limit(cls, context, project_id, resource, limit, user_id\u003dNone):"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_3751e637","line":206,"updated":"2017-05-30 15:58:57.000000000","message":"OK, yes, the above is eminently more explainable/readable than the original patch :)","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"}],"nova/quota.py":[{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"b1316d52977a37f963b33ab1afb1faa3ee06c5d4","unresolved":false,"context_lines":[{"line_number":133,"context_line":"                usage \u003d usages.get(resource.name, {})"},{"line_number":134,"context_line":"                modified_quotas[resource.name].update("},{"line_number":135,"context_line":"                    in_use\u003dusage.get(\u0027in_use\u0027, 0),"},{"line_number":136,"context_line":"                    reserved\u003dusage.get(\u0027reserved\u0027, 0),"},{"line_number":137,"context_line":"                    )"},{"line_number":138,"context_line":"            # Initialize remains quotas."},{"line_number":139,"context_line":"            if remains:"}],"source_content_type":"text/x-python","patch_set":1,"id":"1a1ced50_7c0f79e1","side":"PARENT","line":136,"updated":"2017-03-17 14:49:09.000000000","message":"hmm, seems like its too soon to do this if we split things up?","commit_id":"ca9736b5b6c7d12bd2b210a7b7e25a34707f2d4b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":125,"context_line":""},{"line_number":126,"context_line":"            # Include usages if desired.  This is optional because one"},{"line_number":127,"context_line":"            # internal consumer of this interface wants to access the"},{"line_number":128,"context_line":"            # usages directly from inside a transaction."},{"line_number":129,"context_line":"            if usages:"},{"line_number":130,"context_line":"                usage \u003d usages.get(resource.name, {})"},{"line_number":131,"context_line":"                modified_quotas[resource.name].update("}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_3f03a8ba","side":"PARENT","line":128,"updated":"2017-04-26 18:45:22.000000000","message":"You removed this comment. Does that mean that usages is no longer optional here? If so, we can remove line 130 and de-indent lines 131-134","commit_id":"3e7709d778e600160ac32e38de34c0b236d1605d"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":125,"context_line":""},{"line_number":126,"context_line":"            # Include usages if desired.  This is optional because one"},{"line_number":127,"context_line":"            # internal consumer of this interface wants to access the"},{"line_number":128,"context_line":"            # usages directly from inside a transaction."},{"line_number":129,"context_line":"            if usages:"},{"line_number":130,"context_line":"                usage \u003d usages.get(resource.name, {})"},{"line_number":131,"context_line":"                modified_quotas[resource.name].update("}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_9a49aa8c","side":"PARENT","line":128,"in_reply_to":"5ff73747_3f03a8ba","updated":"2017-04-26 19:32:21.000000000","message":"They are still optional but I thought the part about \"one internal consumer wants to access usages inside a transaction\" wasn\u0027t helpful and I\u0027m not sure it\u0027s accurate that the quota_usages table query goes into the same transaction as the quota limits query anyway.","commit_id":"3e7709d778e600160ac32e38de34c0b236d1605d"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":161,"context_line":"                # (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027), they are counted at the same"},{"line_number":162,"context_line":"                # time for efficiency. So a count of any one of them contains"},{"line_number":163,"context_line":"                # counts for the others we need to skip if we already counted"},{"line_number":164,"context_line":"                # one of them."},{"line_number":165,"context_line":"                continue"},{"line_number":166,"context_line":"            if resource.name in (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027):"},{"line_number":167,"context_line":"                counts \u003d resource.count(context, project_id, user_id\u003duser_id)"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_1ffeacad","line":164,"updated":"2017-04-26 18:45:22.000000000","message":"Wait, what? Why would a CountableResource for VCPU contain counts for RAM?","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":161,"context_line":"                # (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027), they are counted at the same"},{"line_number":162,"context_line":"                # time for efficiency. So a count of any one of them contains"},{"line_number":163,"context_line":"                # counts for the others we need to skip if we already counted"},{"line_number":164,"context_line":"                # one of them."},{"line_number":165,"context_line":"                continue"},{"line_number":166,"context_line":"            if resource.name in (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027):"},{"line_number":167,"context_line":"                counts \u003d resource.count(context, project_id, user_id\u003duser_id)"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_3f08482a","line":164,"in_reply_to":"5ff73747_1ffeacad","updated":"2017-04-26 19:32:21.000000000","message":"I guess my comment here wasn\u0027t good. The reason is because to count VCPU, we have to pull all of the instances. We pull all instances matching project, iterate through and add up instance.vcpus, instance.memory_mb, and an instance count. That\u0027s how we get 3 counts at the same time. So \u0027instances\u0027, \u0027cores\u0027, and \u0027ram\u0027 are each a Countable resource with the same count function. \n\nI considered merging the 3 resources into one CountableResource like \u0027instances_cores_ram\u0027 but I thought that might be more confusing and might also break the ability to limit check on a more granular resources like only \u0027cores\u0027 or only \u0027instances\u0027.\n\nIdeally, we would want a way to have each resource \u0027cores\u0027, \u0027ram\u0027, and \u0027instances\u0027 have a different count function that returns a count across the project and the count across the user, without re-querying the database for each.\n\nIf you have a suggestion on a better way to do this, let me know.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":164,"context_line":"                # one of them."},{"line_number":165,"context_line":"                continue"},{"line_number":166,"context_line":"            if resource.name in (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027):"},{"line_number":167,"context_line":"                counts \u003d resource.count(context, project_id, user_id\u003duser_id)"},{"line_number":168,"context_line":"                # If we got a count for \u0027instances\u0027, \u0027cores\u0027, or \u0027ram\u0027, then we"},{"line_number":169,"context_line":"                # have counts for the other two resources, so parse them at"},{"line_number":170,"context_line":"                # the same time and skip the duplicates so we don\u0027t recount."}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_ff2e6041","line":167,"updated":"2017-04-26 18:45:22.000000000","message":"This doesn\u0027t make sense. CountableResource.count is a functor that returns an integer, not a dict. See line 1357.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":164,"context_line":"                # one of them."},{"line_number":165,"context_line":"                continue"},{"line_number":166,"context_line":"            if resource.name in (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027):"},{"line_number":167,"context_line":"                counts \u003d resource.count(context, project_id, user_id\u003duser_id)"},{"line_number":168,"context_line":"                # If we got a count for \u0027instances\u0027, \u0027cores\u0027, or \u0027ram\u0027, then we"},{"line_number":169,"context_line":"                # have counts for the other two resources, so parse them at"},{"line_number":170,"context_line":"                # the same time and skip the duplicates so we don\u0027t recount."}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_9af64af9","line":167,"in_reply_to":"5ff73747_ff2e6041","updated":"2017-04-26 19:32:21.000000000","message":"Yes, I changed this in several cases where we need count to return 1) a count across the project 2) a count across the user, without re-counting or re-querying the database each time. The project-wide count has to be checked against the project quota, the user-wide count has to be checked against the user quota. I\u0027m open to suggestions.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":181,"context_line":"                # The other per user resources are special cases whose"},{"line_number":182,"context_line":"                # usages aren\u0027t considered when validating quota limit"},{"line_number":183,"context_line":"                # creates or updates."},{"line_number":184,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":185,"context_line":"        return usages"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"    def get_user_quotas(self, context, resources, project_id, user_id,"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_df3164a4","line":184,"updated":"2017-04-26 18:45:22.000000000","message":"I honestly don\u0027t think you could *try* to make a more confusing data structure for modeling counts of resources than whatever the CountableResource is above. :(","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":181,"context_line":"                # The other per user resources are special cases whose"},{"line_number":182,"context_line":"                # usages aren\u0027t considered when validating quota limit"},{"line_number":183,"context_line":"                # creates or updates."},{"line_number":184,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":185,"context_line":"        return usages"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"    def get_user_quotas(self, context, resources, project_id, user_id,"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_fa378eaf","line":184,"in_reply_to":"5ff73747_df3164a4","updated":"2017-04-26 19:32:21.000000000","message":"Sorry, was trying to make this fit within the infra we have for CountableResource. I\u0027m open to suggestions.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":227,"context_line":"            user_usages \u003d self._get_usages(context, resources, project_id,"},{"line_number":228,"context_line":"                                           user_id\u003duser_id)"},{"line_number":229,"context_line":"            # TODO(melwitt): This is for compat with ReservableResources and"},{"line_number":230,"context_line":"            # should be removed when there are no more ReservableResources."},{"line_number":231,"context_line":"            from_usages_table \u003d db.quota_usage_get_all_by_project_and_user("},{"line_number":232,"context_line":"                    context, project_id, user_id)"},{"line_number":233,"context_line":"            for resource, usage in from_usages_table.items():"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_bf28d833","line":230,"updated":"2017-04-26 18:45:22.000000000","message":"I\u0027m a little unclear what this has to do with reservable resources? Would you mind elaborating on why this is compat code for that?","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":227,"context_line":"            user_usages \u003d self._get_usages(context, resources, project_id,"},{"line_number":228,"context_line":"                                           user_id\u003duser_id)"},{"line_number":229,"context_line":"            # TODO(melwitt): This is for compat with ReservableResources and"},{"line_number":230,"context_line":"            # should be removed when there are no more ReservableResources."},{"line_number":231,"context_line":"            from_usages_table \u003d db.quota_usage_get_all_by_project_and_user("},{"line_number":232,"context_line":"                    context, project_id, user_id)"},{"line_number":233,"context_line":"            for resource, usage in from_usages_table.items():"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_1a691a8a","line":230,"in_reply_to":"5ff73747_bf28d833","updated":"2017-04-26 19:32:21.000000000","message":"ReservableResources usage comes from the quota_usages table, so we need to pull usages from the quota_usages table too while any ReservableResources still exist. (The megapatch was split up into several pieces, so the conversion isn\u0027t happening all at once anymore. With each step, we change a ReservableResource to a CountableResource until finally we won\u0027t have any ReservableResources in the end.\n\nI\u0027ll add more to this comment.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":511,"context_line":"    def limit_check_project_and_user(self, context, resources,"},{"line_number":512,"context_line":"                                     proj_values\u003dNone, user_values\u003dNone,"},{"line_number":513,"context_line":"                                     project_id\u003dNone, user_id\u003dNone):"},{"line_number":514,"context_line":"        \"\"\"Check values against quota limits."},{"line_number":515,"context_line":""},{"line_number":516,"context_line":"        For limits--this method checks that a set of"},{"line_number":517,"context_line":"        proposed values are permitted by the limit restriction."}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_9f2bdc2e","line":514,"updated":"2017-04-26 18:45:22.000000000","message":"\"values\" contain usage?","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":511,"context_line":"    def limit_check_project_and_user(self, context, resources,"},{"line_number":512,"context_line":"                                     proj_values\u003dNone, user_values\u003dNone,"},{"line_number":513,"context_line":"                                     project_id\u003dNone, user_id\u003dNone):"},{"line_number":514,"context_line":"        \"\"\"Check values against quota limits."},{"line_number":515,"context_line":""},{"line_number":516,"context_line":"        For limits--this method checks that a set of"},{"line_number":517,"context_line":"        proposed values are permitted by the limit restriction."}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_7aa37e9f","line":514,"in_reply_to":"5ff73747_9f2bdc2e","updated":"2017-04-26 19:32:21.000000000","message":"They are usage + desired delta. The way limit_check() works is it takes the current usage count + desired delta and checks it against quota limits.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":530,"context_line":"        :param proj_values: Dict containing the resource values to check"},{"line_number":531,"context_line":"                            against project quota"},{"line_number":532,"context_line":"        :param user_values: Dict containing the resource values to check"},{"line_number":533,"context_line":"                            against user quota"},{"line_number":534,"context_line":"        :param project_id: The project_id for scoping the limit check, e.g."},{"line_number":535,"context_line":"                           admin acting upon a resource owned by a different"},{"line_number":536,"context_line":"                           project"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_7f225054","line":533,"updated":"2017-04-26 18:45:22.000000000","message":"Might be good to show an example of what these dicts look like, really. \"Resource values\" is fairly vague.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":530,"context_line":"        :param proj_values: Dict containing the resource values to check"},{"line_number":531,"context_line":"                            against project quota"},{"line_number":532,"context_line":"        :param user_values: Dict containing the resource values to check"},{"line_number":533,"context_line":"                            against user quota"},{"line_number":534,"context_line":"        :param project_id: The project_id for scoping the limit check, e.g."},{"line_number":535,"context_line":"                           admin acting upon a resource owned by a different"},{"line_number":536,"context_line":"                           project"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_3ac6164a","line":533,"in_reply_to":"5ff73747_7f225054","updated":"2017-04-26 19:32:21.000000000","message":"Good idea. It\u0027s the same way they are represented in the already existing limit_check() except as a **values.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":536,"context_line":"                           project"},{"line_number":537,"context_line":"        :param user_id: The user_id for scoping the limit check, e.g."},{"line_number":538,"context_line":"                        admin acting upon a resource owned by a different"},{"line_number":539,"context_line":"                        user"},{"line_number":540,"context_line":"        \"\"\""},{"line_number":541,"context_line":"        if proj_values is None:"},{"line_number":542,"context_line":"            proj_values \u003d {}"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_5f1d540d","line":539,"updated":"2017-04-26 18:45:22.000000000","message":"See comment above about rephrasing the whole \"e.g. admin acting...\" thing.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":536,"context_line":"                           project"},{"line_number":537,"context_line":"        :param user_id: The user_id for scoping the limit check, e.g."},{"line_number":538,"context_line":"                        admin acting upon a resource owned by a different"},{"line_number":539,"context_line":"                        user"},{"line_number":540,"context_line":"        \"\"\""},{"line_number":541,"context_line":"        if proj_values is None:"},{"line_number":542,"context_line":"            proj_values \u003d {}"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_1ac11a2f","line":539,"in_reply_to":"5ff73747_5f1d540d","updated":"2017-04-26 19:32:21.000000000","message":"Ack.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":588,"context_line":"        quotas \u003d self._get_quotas(context, resources, values.keys(),"},{"line_number":589,"context_line":"                                  has_sync\u003dFalse, project_id\u003dproject_id,"},{"line_number":590,"context_line":"                                  project_quotas\u003dproject_quotas)"},{"line_number":591,"context_line":"        # per user quotas, user quota"},{"line_number":592,"context_line":"        user_quotas \u003d self._get_quotas(context, resources, values.keys(),"},{"line_number":593,"context_line":"                                       has_sync\u003dFalse, project_id\u003dproject_id,"},{"line_number":594,"context_line":"                                       user_id\u003duser_id,"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_3f1cc810","line":591,"updated":"2017-04-26 18:45:22.000000000","message":"s/, user quota//","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":588,"context_line":"        quotas \u003d self._get_quotas(context, resources, values.keys(),"},{"line_number":589,"context_line":"                                  has_sync\u003dFalse, project_id\u003dproject_id,"},{"line_number":590,"context_line":"                                  project_quotas\u003dproject_quotas)"},{"line_number":591,"context_line":"        # per user quotas, user quota"},{"line_number":592,"context_line":"        user_quotas \u003d self._get_quotas(context, resources, values.keys(),"},{"line_number":593,"context_line":"                                       has_sync\u003dFalse, project_id\u003dproject_id,"},{"line_number":594,"context_line":"                                       user_id\u003duser_id,"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_da2e12f9","line":591,"in_reply_to":"5ff73747_3f1cc810","updated":"2017-04-26 19:32:21.000000000","message":"I know this is confusing but there are two types of quota limits: project quotas that have no user concept (fixed_ips, floating_ips, networks) and user quotas (everything else) and user quotas can be per project and per user. I\u0027ll add more to the comments.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"062a5dc3a47984e526f4581221a0b4f7bc977032","unresolved":false,"context_lines":[{"line_number":158,"context_line":"        # limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":159,"context_line":"        # resource usages in the os-used-limits API. This function is not used"},{"line_number":160,"context_line":"        # for checking resource usage against quota limits."},{"line_number":161,"context_line":"        key \u003d \u0027user\u0027 if user_id else \u0027project\u0027"},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if resource.name in usages:"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_d809c731","line":161,"updated":"2017-05-03 17:59:01.000000000","message":"If we check the user quota, doesn\u0027t that actually mean we need to check both the project and the user quota?\n\nSeems like we throw some of the things away here in ln186?\n\nI mean we just call into this twice I guess, but it seems a bit wasteful.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"7e5ff6c1caf43a12203ddeb37cec23ea103159a6","unresolved":false,"context_lines":[{"line_number":158,"context_line":"        # limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":159,"context_line":"        # resource usages in the os-used-limits API. This function is not used"},{"line_number":160,"context_line":"        # for checking resource usage against quota limits."},{"line_number":161,"context_line":"        key \u003d \u0027user\u0027 if user_id else \u0027project\u0027"},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if resource.name in usages:"}],"source_content_type":"text/x-python","patch_set":5,"id":"3f044301_eec61617","line":161,"in_reply_to":"5ff73747_692d4345","updated":"2017-05-04 13:54:55.000000000","message":"Ah, OK. Thats not so bad.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4a8239981b985ea0cff483bdc9ca08fa9317a212","unresolved":false,"context_lines":[{"line_number":158,"context_line":"        # limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":159,"context_line":"        # resource usages in the os-used-limits API. This function is not used"},{"line_number":160,"context_line":"        # for checking resource usage against quota limits."},{"line_number":161,"context_line":"        key \u003d \u0027user\u0027 if user_id else \u0027project\u0027"},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if resource.name in usages:"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_692d4345","line":161,"in_reply_to":"5ff73747_a91b4b71","updated":"2017-05-03 18:44:49.000000000","message":"The only time it\u0027s called twice is by get_settable_quotas and that\u0027s used when displaying/creating/updating quota limits. So in that case it\u0027s wasteful.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"1cfc22b7ee59ea20ee04837777c7ea1e44ccef6e","unresolved":false,"context_lines":[{"line_number":158,"context_line":"        # limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":159,"context_line":"        # resource usages in the os-used-limits API. This function is not used"},{"line_number":160,"context_line":"        # for checking resource usage against quota limits."},{"line_number":161,"context_line":"        key \u003d \u0027user\u0027 if user_id else \u0027project\u0027"},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if resource.name in usages:"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_a91b4b71","line":161,"in_reply_to":"5ff73747_be902350","updated":"2017-05-03 18:33:32.000000000","message":"Sorry, I just realized what you meant, that get_project_quotas and get_user_quotas both call in here and that\u0027s wasteful. I\u0027ll think about it more.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"416a1f2d7b4e344ea7b94269a10fdfb08d69e28e","unresolved":false,"context_lines":[{"line_number":158,"context_line":"        # limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":159,"context_line":"        # resource usages in the os-used-limits API. This function is not used"},{"line_number":160,"context_line":"        # for checking resource usage against quota limits."},{"line_number":161,"context_line":"        key \u003d \u0027user\u0027 if user_id else \u0027project\u0027"},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if resource.name in usages:"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_be902350","line":161,"in_reply_to":"5ff73747_d809c731","updated":"2017-05-03 18:24:14.000000000","message":"This function isn\u0027t for checking against quota limits at all (as explained in comment at L157). This is for validating quota limit changes and showing used limits.\n\nIf you look in _get_quotas() which is called by the limit_check_project_and_user, it passes usages\u003dFalse to get_project_quotas and get_user_quotas, so _get_usages() should not be called for a limit check.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"062a5dc3a47984e526f4581221a0b4f7bc977032","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                                 \u0027security_group_rules\u0027):"},{"line_number":173,"context_line":"                # These per user resources are special cases whose usages"},{"line_number":174,"context_line":"                # aren not considered when validating limit create/update or"},{"line_number":175,"context_line":"                # displaying used limits. They are always zero."},{"line_number":176,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":177,"context_line":"            elif isinstance(resource, MultiCountableResource):"},{"line_number":178,"context_line":"                # NOTE(melwitt): This assumes a specific signature for"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_23a4fc07","line":175,"updated":"2017-05-03 17:59:01.000000000","message":"Its odd that includes key_pairs, I guess its because the limit is set on a project, but the count should always be done on the user. That might need sorting out later on in this series I guess...","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"416a1f2d7b4e344ea7b94269a10fdfb08d69e28e","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                                 \u0027security_group_rules\u0027):"},{"line_number":173,"context_line":"                # These per user resources are special cases whose usages"},{"line_number":174,"context_line":"                # aren not considered when validating limit create/update or"},{"line_number":175,"context_line":"                # displaying used limits. They are always zero."},{"line_number":176,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":177,"context_line":"            elif isinstance(resource, MultiCountableResource):"},{"line_number":178,"context_line":"                # NOTE(melwitt): This assumes a specific signature for"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_bee26300","line":175,"in_reply_to":"5ff73747_23a4fc07","updated":"2017-05-03 18:24:14.000000000","message":"Yeah, I\u0027m not sure what the reason is from a historical standpoint, but it\u0027s not as straightforward as just including them because each of these have special counting functions with different signatures. So we\u0027d need a conditional for each and in some cases, we\u0027ll need to query some objects (like all InstanceGroups) to count the members in each group. Unless we change the server group members counting strategy.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"7e5ff6c1caf43a12203ddeb37cec23ea103159a6","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                                 \u0027security_group_rules\u0027):"},{"line_number":173,"context_line":"                # These per user resources are special cases whose usages"},{"line_number":174,"context_line":"                # aren not considered when validating limit create/update or"},{"line_number":175,"context_line":"                # displaying used limits. They are always zero."},{"line_number":176,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":177,"context_line":"            elif isinstance(resource, MultiCountableResource):"},{"line_number":178,"context_line":"                # NOTE(melwitt): This assumes a specific signature for"}],"source_content_type":"text/x-python","patch_set":5,"id":"3f044301_aee92e81","line":175,"in_reply_to":"5ff73747_bee26300","updated":"2017-05-04 13:54:55.000000000","message":"Yeah, the count is hard for each of those, because of all the extra info needed, like server_group_uuid, etc. Probably best to scope that out for now.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"062a5dc3a47984e526f4581221a0b4f7bc977032","unresolved":false,"context_lines":[{"line_number":621,"context_line":"            # must pass both the quota for the project and the quota for the"},{"line_number":622,"context_line":"            # user."},{"line_number":623,"context_line":"            # Combine per user project quotas and user_quotas for use in the"},{"line_number":624,"context_line":"            # checks, taking the minimum limit between the two."},{"line_number":625,"context_line":"            merged_quotas \u003d copy.deepcopy(quotas)"},{"line_number":626,"context_line":"            for k, v in user_quotas.items():"},{"line_number":627,"context_line":"                if k in merged_quotas:"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_5efebf05","line":624,"updated":"2017-05-03 17:59:01.000000000","message":"This one is messing with my head, maybe worth an extra example in here? not sure.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"416a1f2d7b4e344ea7b94269a10fdfb08d69e28e","unresolved":false,"context_lines":[{"line_number":621,"context_line":"            # must pass both the quota for the project and the quota for the"},{"line_number":622,"context_line":"            # user."},{"line_number":623,"context_line":"            # Combine per user project quotas and user_quotas for use in the"},{"line_number":624,"context_line":"            # checks, taking the minimum limit between the two."},{"line_number":625,"context_line":"            merged_quotas \u003d copy.deepcopy(quotas)"},{"line_number":626,"context_line":"            for k, v in user_quotas.items():"},{"line_number":627,"context_line":"                if k in merged_quotas:"}],"source_content_type":"text/x-python","patch_set":5,"id":"5ff73747_9eab2774","line":624,"in_reply_to":"5ff73747_5efebf05","updated":"2017-05-03 18:24:14.000000000","message":"Okay, will add an example. The main idea is if the usage is counted across a user only, it still has to pass the project limit and the user limit.","commit_id":"28ed1e3b38ac830fd8a16b964c1d0ecdf02eb96a"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":665,"context_line":"                                      project_id\u003dproject_id, user_id\u003duser_id)"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"    def destroy_all_by_project_and_user(self, context, project_id, user_id):"},{"line_number":668,"context_line":"        \"\"\"Destroy all quotas, usages, and reservations associated with a"},{"line_number":669,"context_line":"        project and user."},{"line_number":670,"context_line":""},{"line_number":671,"context_line":"        :param context: The request context, for access checks."},{"line_number":672,"context_line":"        :param project_id: The ID of the project being deleted."}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_b648fd86","side":"PARENT","line":669,"range":{"start_line":668,"start_character":8,"end_line":669,"end_character":25},"updated":"2017-05-22 18:35:32.000000000","message":"Updating this seems premature, but I guess you\u0027re just making it more generic so it\u0027s probably fine.","commit_id":"5df773c93badd620c2eb29ff384d582089c0b312"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":665,"context_line":"                                      project_id\u003dproject_id, user_id\u003duser_id)"},{"line_number":666,"context_line":""},{"line_number":667,"context_line":"    def destroy_all_by_project_and_user(self, context, project_id, user_id):"},{"line_number":668,"context_line":"        \"\"\"Destroy all quotas, usages, and reservations associated with a"},{"line_number":669,"context_line":"        project and user."},{"line_number":670,"context_line":""},{"line_number":671,"context_line":"        :param context: The request context, for access checks."},{"line_number":672,"context_line":"        :param project_id: The ID of the project being deleted."}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_fee40be2","side":"PARENT","line":669,"range":{"start_line":668,"start_character":8,"end_line":669,"end_character":25},"in_reply_to":"ff0f0b1f_b648fd86","updated":"2017-05-22 19:51:33.000000000","message":"Yeah, so this is a holdover from when the table migration was first in the series and the meaning of destroy_all_by_project_and_user had changed. I had to move the migration to support having old stuff still work during each patch in the series (patch for counting used to be one monolithic one that followed the table migrations).","commit_id":"5df773c93badd620c2eb29ff384d582089c0b312"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":60,"context_line":""},{"line_number":61,"context_line":"    def get_defaults(self, context, resources):"},{"line_number":62,"context_line":"        \"\"\"Given a list of resources, retrieve the default quotas."},{"line_number":63,"context_line":"        Use the class quotas named `_DEFAULT_QUOTA_NAME` as default quotas,"},{"line_number":64,"context_line":"        if it exists."},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"        :param context: The request context, for access checks."}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_05f77161","line":63,"range":{"start_line":63,"start_character":36,"end_line":63,"end_character":55},"updated":"2017-05-22 18:35:32.000000000","message":"Unrelated, but this is some fun referencing to private variables down in the DB API code.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":60,"context_line":""},{"line_number":61,"context_line":"    def get_defaults(self, context, resources):"},{"line_number":62,"context_line":"        \"\"\"Given a list of resources, retrieve the default quotas."},{"line_number":63,"context_line":"        Use the class quotas named `_DEFAULT_QUOTA_NAME` as default quotas,"},{"line_number":64,"context_line":"        if it exists."},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"        :param context: The request context, for access checks."}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_18c3575f","line":63,"range":{"start_line":63,"start_character":36,"end_line":63,"end_character":55},"in_reply_to":"ff0f0b1f_05f77161","updated":"2017-05-22 19:01:59.000000000","message":"Yeah. :(","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":136,"context_line":"                    in_use\u003dusage.get(\u0027in_use\u0027, 0),"},{"line_number":137,"context_line":"                    reserved\u003dusage.get(\u0027reserved\u0027, 0))"},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"            # Initialize remains quotas with the default limits."},{"line_number":140,"context_line":"            if remains:"},{"line_number":141,"context_line":"                modified_quotas[resource.name].update(remains\u003dlimit)"},{"line_number":142,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_4529e998","line":139,"range":{"start_line":139,"start_character":40,"end_line":139,"end_character":63},"updated":"2017-05-22 18:35:32.000000000","message":"This isn\u0027t necessarily the default limit if the limit was overridden for this resource on this project/user, right?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":136,"context_line":"                    in_use\u003dusage.get(\u0027in_use\u0027, 0),"},{"line_number":137,"context_line":"                    reserved\u003dusage.get(\u0027reserved\u0027, 0))"},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"            # Initialize remains quotas with the default limits."},{"line_number":140,"context_line":"            if remains:"},{"line_number":141,"context_line":"                modified_quotas[resource.name].update(remains\u003dlimit)"},{"line_number":142,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_78e253a2","line":139,"range":{"start_line":139,"start_character":40,"end_line":139,"end_character":63},"in_reply_to":"ff0f0b1f_4529e998","updated":"2017-05-22 19:01:59.000000000","message":"On L119, it pulls the default limits, so I think overrides of the default quota class still count as defaults, right?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"fdd829a53fc78060ba235a6ced8751c886af1f63","unresolved":false,"context_lines":[{"line_number":136,"context_line":"                    in_use\u003dusage.get(\u0027in_use\u0027, 0),"},{"line_number":137,"context_line":"                    reserved\u003dusage.get(\u0027reserved\u0027, 0))"},{"line_number":138,"context_line":""},{"line_number":139,"context_line":"            # Initialize remains quotas with the default limits."},{"line_number":140,"context_line":"            if remains:"},{"line_number":141,"context_line":"                modified_quotas[resource.name].update(remains\u003dlimit)"},{"line_number":142,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_bb2905e7","line":139,"range":{"start_line":139,"start_character":40,"end_line":139,"end_character":63},"in_reply_to":"ff0f0b1f_78e253a2","updated":"2017-05-22 19:22:59.000000000","message":"Oh maybe yeah, I\u0027m probably just tripped up on semantics here. Ignore.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":141,"context_line":"                modified_quotas[resource.name].update(remains\u003dlimit)"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        if remains:"},{"line_number":144,"context_line":"            # Get all user quotas and for a project and subtract their limits"},{"line_number":145,"context_line":"            # from the class limits to get the remains. For example, if the"},{"line_number":146,"context_line":"            # class/default is 20 and there are two users each with quota of 5,"},{"line_number":147,"context_line":"            # then there is quota of 10 left to give out."}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_a50fa535","line":144,"range":{"start_line":144,"start_character":14,"end_line":144,"end_character":51},"updated":"2017-05-22 18:35:32.000000000","message":"This is confusing me. Do you mean user and project quotas? But quota_get_all is filtering on project.\n\nOr did you mean, get all user quotas for a project?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":141,"context_line":"                modified_quotas[resource.name].update(remains\u003dlimit)"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        if remains:"},{"line_number":144,"context_line":"            # Get all user quotas and for a project and subtract their limits"},{"line_number":145,"context_line":"            # from the class limits to get the remains. For example, if the"},{"line_number":146,"context_line":"            # class/default is 20 and there are two users each with quota of 5,"},{"line_number":147,"context_line":"            # then there is quota of 10 left to give out."}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_987527ce","line":144,"range":{"start_line":144,"start_character":14,"end_line":144,"end_character":51},"in_reply_to":"ff0f0b1f_a50fa535","updated":"2017-05-22 19:01:59.000000000","message":"Argh, sorry yes it should be \"get all user quotas for a project.\" When the code says \"project quotas\" it means the \"quotas\" table which is only for fixed_ips, floating_ips, and networks limits. The \"user quotas\" are the \"project_user_quotas\" table which is for all other resources  (and has a user_id column).","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":155,"context_line":""},{"line_number":156,"context_line":"    def _get_usages(self, context, resources, project_id, user_id\u003dNone,"},{"line_number":157,"context_line":"                    usages\u003dNone):"},{"line_number":158,"context_line":"        # This function is called to get resource usages for validating quota"},{"line_number":159,"context_line":"        # limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":160,"context_line":"        # resource usages in the os-used-limits API. This function is not used"},{"line_number":161,"context_line":"        # for checking resource usage against quota limits."},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if not isinstance(resource, CountableResource):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_408c377e","line":161,"range":{"start_line":158,"start_character":8,"end_line":161,"end_character":59},"updated":"2017-05-22 18:35:32.000000000","message":"nit: turning this into a docstring with param definitions would be nice, i.e. I don\u0027t really know what \u0027resources\u0027 is without looking at what is using this method. I guess it\u0027s really self._resources from the QuotaEngine.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":155,"context_line":""},{"line_number":156,"context_line":"    def _get_usages(self, context, resources, project_id, user_id\u003dNone,"},{"line_number":157,"context_line":"                    usages\u003dNone):"},{"line_number":158,"context_line":"        # This function is called to get resource usages for validating quota"},{"line_number":159,"context_line":"        # limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":160,"context_line":"        # resource usages in the os-used-limits API. This function is not used"},{"line_number":161,"context_line":"        # for checking resource usage against quota limits."},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if not isinstance(resource, CountableResource):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_18535741","line":161,"range":{"start_line":158,"start_character":8,"end_line":161,"end_character":59},"in_reply_to":"ff0f0b1f_408c377e","updated":"2017-05-22 19:01:59.000000000","message":"Ack.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":161,"context_line":"        # for checking resource usage against quota limits."},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if not isinstance(resource, CountableResource):"},{"line_number":165,"context_line":"                continue"},{"line_number":166,"context_line":"            if resource.name in usages:"},{"line_number":167,"context_line":"                # This is needed because for any of the resources:"},{"line_number":168,"context_line":"                # (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027), they are counted at the same"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_e0da2b49","line":165,"range":{"start_line":164,"start_character":12,"end_line":165,"end_character":24},"updated":"2017-05-22 18:35:32.000000000","message":"Can you leave a comment here? I think this is because in the new world, ReservableResources are going to become CountableResources (which I read from the spec) but that\u0027s not clear to me here.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":161,"context_line":"        # for checking resource usage against quota limits."},{"line_number":162,"context_line":"        usages \u003d {}"},{"line_number":163,"context_line":"        for resource in resources.values():"},{"line_number":164,"context_line":"            if not isinstance(resource, CountableResource):"},{"line_number":165,"context_line":"                continue"},{"line_number":166,"context_line":"            if resource.name in usages:"},{"line_number":167,"context_line":"                # This is needed because for any of the resources:"},{"line_number":168,"context_line":"                # (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027), they are counted at the same"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_d8483f88","line":165,"range":{"start_line":164,"start_character":12,"end_line":165,"end_character":24},"in_reply_to":"ff0f0b1f_e0da2b49","updated":"2017-05-22 19:01:59.000000000","message":"Yes, that is why. Will add.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":168,"context_line":"                # (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027), they are counted at the same"},{"line_number":169,"context_line":"                # time for efficiency (query the instances table once instead"},{"line_number":170,"context_line":"                # of multiple times). So, a count of any one of them contains"},{"line_number":171,"context_line":"                # counts for the others and we can re-counting those."},{"line_number":172,"context_line":"                continue"},{"line_number":173,"context_line":"            if resource.name in (\u0027key_pairs\u0027, \u0027server_group_members\u0027,"},{"line_number":174,"context_line":"                                 \u0027security_group_rules\u0027):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_60aa9b71","line":171,"range":{"start_line":171,"start_character":47,"end_line":171,"end_character":62},"updated":"2017-05-22 18:35:32.000000000","message":"can avoid?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":168,"context_line":"                # (\u0027instances\u0027, \u0027cores\u0027, \u0027ram\u0027), they are counted at the same"},{"line_number":169,"context_line":"                # time for efficiency (query the instances table once instead"},{"line_number":170,"context_line":"                # of multiple times). So, a count of any one of them contains"},{"line_number":171,"context_line":"                # counts for the others and we can re-counting those."},{"line_number":172,"context_line":"                continue"},{"line_number":173,"context_line":"            if resource.name in (\u0027key_pairs\u0027, \u0027server_group_members\u0027,"},{"line_number":174,"context_line":"                                 \u0027security_group_rules\u0027):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_7857f327","line":171,"range":{"start_line":171,"start_character":47,"end_line":171,"end_character":62},"in_reply_to":"ff0f0b1f_60aa9b71","updated":"2017-05-22 19:01:59.000000000","message":"Yes, will fix.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                continue"},{"line_number":173,"context_line":"            if resource.name in (\u0027key_pairs\u0027, \u0027server_group_members\u0027,"},{"line_number":174,"context_line":"                                 \u0027security_group_rules\u0027):"},{"line_number":175,"context_line":"                # These per user resources are special cases whose usages"},{"line_number":176,"context_line":"                # are not considered when validating limit create/update or"},{"line_number":177,"context_line":"                # displaying used limits. They are always zero."},{"line_number":178,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_60c3bb39","line":175,"range":{"start_line":175,"start_character":28,"end_line":175,"end_character":32},"updated":"2017-05-22 18:35:32.000000000","message":"security_group_rules isn\u0027t really per-user, but maybe that doesn\u0027t matter here?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                continue"},{"line_number":173,"context_line":"            if resource.name in (\u0027key_pairs\u0027, \u0027server_group_members\u0027,"},{"line_number":174,"context_line":"                                 \u0027security_group_rules\u0027):"},{"line_number":175,"context_line":"                # These per user resources are special cases whose usages"},{"line_number":176,"context_line":"                # are not considered when validating limit create/update or"},{"line_number":177,"context_line":"                # displaying used limits. They are always zero."},{"line_number":178,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_381cdb76","line":175,"range":{"start_line":175,"start_character":28,"end_line":175,"end_character":32},"in_reply_to":"ff0f0b1f_60c3bb39","updated":"2017-05-22 19:01:59.000000000","message":"Yeah, I wrote this comment ages ago and security_group_rules doesn\u0027t really fit in anywhere. I can clarify in the comment. These are the oddball resources. I\u0027m pretty sure the limit for security_group_rules can be set per user_id, so maybe it\u0027s more appropriate to think of as per user.\n\nThe way the tables work is, \"if resource in (\u0027fixed_ips\u0027, \u0027floating_ips\u0027, \u0027networks\u0027) then use quotas table else use project_user_quotas table.\" And any limit in the project_user_quotas table can be scoped to a user.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":177,"context_line":"                # displaying used limits. They are always zero."},{"line_number":178,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":179,"context_line":"            else:"},{"line_number":180,"context_line":"                if resource.name in (\u0027networks\u0027, \u0027fixed_ips\u0027, \u0027floating_ips\u0027):"},{"line_number":181,"context_line":"                    count \u003d resource.count_as_dict(context, project_id)"},{"line_number":182,"context_line":"                else:"},{"line_number":183,"context_line":"                    # NOTE(melwitt): This assumes a specific signature for"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_00ce3f2d","line":180,"range":{"start_line":180,"start_character":36,"end_line":180,"end_character":77},"updated":"2017-05-22 18:35:32.000000000","message":"Can we take this directly from the PER_PROJECT_QUOTAS list in the DB API so we\u0027re consistent?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":177,"context_line":"                # displaying used limits. They are always zero."},{"line_number":178,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":179,"context_line":"            else:"},{"line_number":180,"context_line":"                if resource.name in (\u0027networks\u0027, \u0027fixed_ips\u0027, \u0027floating_ips\u0027):"},{"line_number":181,"context_line":"                    count \u003d resource.count_as_dict(context, project_id)"},{"line_number":182,"context_line":"                else:"},{"line_number":183,"context_line":"                    # NOTE(melwitt): This assumes a specific signature for"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_3bd4d547","line":180,"range":{"start_line":180,"start_character":36,"end_line":180,"end_character":77},"in_reply_to":"ff0f0b1f_00ce3f2d","updated":"2017-05-22 19:01:59.000000000","message":"Yeah, probably the right thing. There is actually a public function in nova/db/api.py called quota_get_per_project_resources that I should use instead of the private variable.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"fdd829a53fc78060ba235a6ced8751c886af1f63","unresolved":false,"context_lines":[{"line_number":177,"context_line":"                # displaying used limits. They are always zero."},{"line_number":178,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":179,"context_line":"            else:"},{"line_number":180,"context_line":"                if resource.name in (\u0027networks\u0027, \u0027fixed_ips\u0027, \u0027floating_ips\u0027):"},{"line_number":181,"context_line":"                    count \u003d resource.count_as_dict(context, project_id)"},{"line_number":182,"context_line":"                else:"},{"line_number":183,"context_line":"                    # NOTE(melwitt): This assumes a specific signature for"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_9bb0818c","line":180,"range":{"start_line":180,"start_character":36,"end_line":180,"end_character":77},"in_reply_to":"ff0f0b1f_3bd4d547","updated":"2017-05-22 19:22:59.000000000","message":"Thanks ccarmack.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":190,"context_line":"                # Example count_as_dict() return value:"},{"line_number":191,"context_line":"                #   {\u0027project\u0027: {\u0027instances\u0027: 5},"},{"line_number":192,"context_line":"                #    \u0027user\u0027: {\u0027instances\u0027: 2}}"},{"line_number":193,"context_line":"                key \u003d \u0027user\u0027 if user_id and \u0027user\u0027 in count else \u0027project\u0027"},{"line_number":194,"context_line":"                counted_resources \u003d count[key].keys()"},{"line_number":195,"context_line":"                for res in counted_resources:"},{"line_number":196,"context_line":"                    count_value \u003d count[key][res]"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_40f8b747","line":193,"updated":"2017-05-22 18:35:32.000000000","message":"nit: you could just define the key in the if/else conditionals above where you\u0027re calling count_as_dict.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b9334f70f65a6a9febd1b53ffce04b67c80d9bf3","unresolved":false,"context_lines":[{"line_number":190,"context_line":"                # Example count_as_dict() return value:"},{"line_number":191,"context_line":"                #   {\u0027project\u0027: {\u0027instances\u0027: 5},"},{"line_number":192,"context_line":"                #    \u0027user\u0027: {\u0027instances\u0027: 2}}"},{"line_number":193,"context_line":"                key \u003d \u0027user\u0027 if user_id and \u0027user\u0027 in count else \u0027project\u0027"},{"line_number":194,"context_line":"                counted_resources \u003d count[key].keys()"},{"line_number":195,"context_line":"                for res in counted_resources:"},{"line_number":196,"context_line":"                    count_value \u003d count[key][res]"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_fbc9bdab","line":193,"in_reply_to":"ff0f0b1f_40f8b747","updated":"2017-05-22 19:01:59.000000000","message":"Thanks.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":246,"context_line":"            # long as we still have ReservableResources."},{"line_number":247,"context_line":"            from_usages_table \u003d db.quota_usage_get_all_by_project_and_user("},{"line_number":248,"context_line":"                    context, project_id, user_id)"},{"line_number":249,"context_line":"            for resource, usage in from_usages_table.items():"},{"line_number":250,"context_line":"                if resource in user_usages:"},{"line_number":251,"context_line":"                    continue"},{"line_number":252,"context_line":"                user_usages[resource] \u003d usage"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_60573b28","line":249,"range":{"start_line":249,"start_character":12,"end_line":249,"end_character":61},"updated":"2017-05-22 18:35:32.000000000","message":"from_usages_table can also contain a project_id key and user_id key, which would end up going in your user_usages dict. Is that OK? I suppose it must be because before this change we were just passing it through to _process_quotas.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":246,"context_line":"            # long as we still have ReservableResources."},{"line_number":247,"context_line":"            from_usages_table \u003d db.quota_usage_get_all_by_project_and_user("},{"line_number":248,"context_line":"                    context, project_id, user_id)"},{"line_number":249,"context_line":"            for resource, usage in from_usages_table.items():"},{"line_number":250,"context_line":"                if resource in user_usages:"},{"line_number":251,"context_line":"                    continue"},{"line_number":252,"context_line":"                user_usages[resource] \u003d usage"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_7e335bf7","line":249,"range":{"start_line":249,"start_character":12,"end_line":249,"end_character":61},"in_reply_to":"ff0f0b1f_60573b28","updated":"2017-05-22 19:51:33.000000000","message":"Hm, good point. It\u0027s true the result before this change is the dict contains \u0027project_id\u0027 and \u0027user_id\u0027 but my code is assuming all the keys are resources (via the variable name), which they aren\u0027t. So maybe this part is best generalized to \"for k, v in items()\" or something.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":286,"context_line":"            # TODO(melwitt): This is for compat with ReservableResources and"},{"line_number":287,"context_line":"            # should be removed when all of the ReservableResources have been"},{"line_number":288,"context_line":"            # removed. ReservableResource usage comes from the quota_usages"},{"line_number":289,"context_line":"            # table in the database, so we need to query usages from there as"},{"line_number":290,"context_line":"            # long as we still have ReservableResources."},{"line_number":291,"context_line":"            from_usages_table \u003d db.quota_usage_get_all_by_project(context,"},{"line_number":292,"context_line":"                                                                  project_id)"},{"line_number":293,"context_line":"            for resource, usage in from_usages_table.items():"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_db1f1c59","line":290,"range":{"start_line":289,"start_character":75,"end_line":290,"end_character":56},"updated":"2017-05-22 18:35:32.000000000","message":"I\u0027m not sure what the data migration story is to get us to the point that the quota_usages table will be empty so we can remove this code. Maybe that will be revealed to me in later changes. I just wonder because until then we\u0027re doing double the work. Plus, this old style won\u0027t really work with multiple cells since the context isn\u0027t targeted to a specific cell and we don\u0027t have quotas in the API DB yet (we have the tables, but no data I think).","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":286,"context_line":"            # TODO(melwitt): This is for compat with ReservableResources and"},{"line_number":287,"context_line":"            # should be removed when all of the ReservableResources have been"},{"line_number":288,"context_line":"            # removed. ReservableResource usage comes from the quota_usages"},{"line_number":289,"context_line":"            # table in the database, so we need to query usages from there as"},{"line_number":290,"context_line":"            # long as we still have ReservableResources."},{"line_number":291,"context_line":"            from_usages_table \u003d db.quota_usage_get_all_by_project(context,"},{"line_number":292,"context_line":"                                                                  project_id)"},{"line_number":293,"context_line":"            for resource, usage in from_usages_table.items():"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_3e9de3bb","line":290,"range":{"start_line":289,"start_character":75,"end_line":290,"end_character":56},"in_reply_to":"ff0f0b1f_db1f1c59","updated":"2017-05-22 19:51:33.000000000","message":"It won\u0027t be empty, it\u0027s just data that will lay around unused (after the last change in the series merges). If we count resources, we don\u0027t need to read usages records because they are just syncs of counts.\n\nAnd yes, multi-cell won\u0027t work until the last change in this series merges.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":460,"context_line":""},{"line_number":461,"context_line":"        return {k: v[\u0027limit\u0027] for k, v in quotas.items()}"},{"line_number":462,"context_line":""},{"line_number":463,"context_line":"    def limit_check(self, context, resources, values, project_id\u003dNone,"},{"line_number":464,"context_line":"                    user_id\u003dNone):"},{"line_number":465,"context_line":"        \"\"\"Check simple quota limits."},{"line_number":466,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_d67b7178","line":463,"updated":"2017-05-22 18:35:32.000000000","message":"Like count(), do we want a TODO to eventually remove limit_check also?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"65b04272be217bea60ad7b86c18a0d3900e35364","unresolved":false,"context_lines":[{"line_number":460,"context_line":""},{"line_number":461,"context_line":"        return {k: v[\u0027limit\u0027] for k, v in quotas.items()}"},{"line_number":462,"context_line":""},{"line_number":463,"context_line":"    def limit_check(self, context, resources, values, project_id\u003dNone,"},{"line_number":464,"context_line":"                    user_id\u003dNone):"},{"line_number":465,"context_line":"        \"\"\"Check simple quota limits."},{"line_number":466,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_0c531541","line":463,"in_reply_to":"ff0f0b1f_a13f92b2","updated":"2017-05-22 21:34:52.000000000","message":"Yeah, that\u0027s right. Adding a comment to this too.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"deb5cf54d98266489d2abe7d8cd0383dd3030ad2","unresolved":false,"context_lines":[{"line_number":460,"context_line":""},{"line_number":461,"context_line":"        return {k: v[\u0027limit\u0027] for k, v in quotas.items()}"},{"line_number":462,"context_line":""},{"line_number":463,"context_line":"    def limit_check(self, context, resources, values, project_id\u003dNone,"},{"line_number":464,"context_line":"                    user_id\u003dNone):"},{"line_number":465,"context_line":"        \"\"\"Check simple quota limits."},{"line_number":466,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_a13f92b2","line":463,"in_reply_to":"ff0f0b1f_bec7b396","updated":"2017-05-22 20:05:35.000000000","message":"Oh I thought limit_check_project_and_user was going to replace limit_check because the former is basically 90% the same as the latter.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":460,"context_line":""},{"line_number":461,"context_line":"        return {k: v[\u0027limit\u0027] for k, v in quotas.items()}"},{"line_number":462,"context_line":""},{"line_number":463,"context_line":"    def limit_check(self, context, resources, values, project_id\u003dNone,"},{"line_number":464,"context_line":"                    user_id\u003dNone):"},{"line_number":465,"context_line":"        \"\"\"Check simple quota limits."},{"line_number":466,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_bec7b396","line":463,"in_reply_to":"ff0f0b1f_d67b7178","updated":"2017-05-22 19:51:33.000000000","message":"Yeah. The only thing that would be made slightly more complicated are AbsoluteResources (metadata_items, injected_file_path_bytes, injected_file_content_bytes, injected_files) to call limit_check_project_and_user() instead.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":578,"context_line":"        # Ensure there are the same keys in both proj_values and user_values"},{"line_number":579,"context_line":"        if all([proj_values, user_values]):"},{"line_number":580,"context_line":"            if set(user_values.keys()) !\u003d set(proj_values.keys()):"},{"line_number":581,"context_line":"                raise exception.InvalidQuotaKeyMismatch("},{"line_number":582,"context_line":"                        user_values\u003dsorted(user_values),"},{"line_number":583,"context_line":"                        proj_values\u003dsorted(proj_values))"},{"line_number":584,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_5648815a","line":581,"range":{"start_line":581,"start_character":32,"end_line":581,"end_character":55},"updated":"2017-05-22 18:35:32.000000000","message":"Is anything calling this method from the API yet? I don\u0027t think so, but when we do, we\u0027ll need to be sure to handle this so it doesn\u0027t leak a 500 out of the API.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":578,"context_line":"        # Ensure there are the same keys in both proj_values and user_values"},{"line_number":579,"context_line":"        if all([proj_values, user_values]):"},{"line_number":580,"context_line":"            if set(user_values.keys()) !\u003d set(proj_values.keys()):"},{"line_number":581,"context_line":"                raise exception.InvalidQuotaKeyMismatch("},{"line_number":582,"context_line":"                        user_values\u003dsorted(user_values),"},{"line_number":583,"context_line":"                        proj_values\u003dsorted(proj_values))"},{"line_number":584,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_9e72af7a","line":581,"range":{"start_line":581,"start_character":32,"end_line":581,"end_character":55},"in_reply_to":"ff0f0b1f_5648815a","updated":"2017-05-22 19:51:33.000000000","message":"Nothing yet, but good point, thanks.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":607,"context_line":"        # per user quotas, project quota limits (for quotas that have"},{"line_number":608,"context_line":"        # user-scoping, limits for the project)"},{"line_number":609,"context_line":"        quotas \u003d self._get_quotas(context, resources, values.keys(),"},{"line_number":610,"context_line":"                                  has_sync\u003dFalse, project_id\u003dproject_id,"},{"line_number":611,"context_line":"                                  project_quotas\u003dproject_quotas)"},{"line_number":612,"context_line":"        # per user quotas, user quota limits (for quotas that have"},{"line_number":613,"context_line":"        # user-scoping, the limits for the user)"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_b66fddfa","line":610,"range":{"start_line":610,"start_character":34,"end_line":610,"end_character":48},"updated":"2017-05-22 18:35:32.000000000","message":"It seems like this might eventually be a problem, because ReservableResources have a _sync function and we want to do away with those. Although I think limit_check* methods are only called for AbsoluteResources and I guess count_as_dict will be used for everything else?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":607,"context_line":"        # per user quotas, project quota limits (for quotas that have"},{"line_number":608,"context_line":"        # user-scoping, limits for the project)"},{"line_number":609,"context_line":"        quotas \u003d self._get_quotas(context, resources, values.keys(),"},{"line_number":610,"context_line":"                                  has_sync\u003dFalse, project_id\u003dproject_id,"},{"line_number":611,"context_line":"                                  project_quotas\u003dproject_quotas)"},{"line_number":612,"context_line":"        # per user quotas, user quota limits (for quotas that have"},{"line_number":613,"context_line":"        # user-scoping, the limits for the user)"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_deb827e6","line":610,"range":{"start_line":610,"start_character":34,"end_line":610,"end_character":48},"in_reply_to":"ff0f0b1f_b66fddfa","updated":"2017-05-22 19:51:33.000000000","message":"limit_check* are called for AbsoluteResources and CountableResources. All CountableResources will use count_as_dict() and fall back on count() in order to handle the possibility of old code calling new code and expecting count(). I don\u0027t think that\u0027s actually possible because I think only nova-api ever calls count(), but Dan said I can\u0027t cheat and break the remotable API for upgrades.\n\nIn the last parts of the series, the has_sync kwarg is removed once no more ReservableResources exist.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"deb5cf54d98266489d2abe7d8cd0383dd3030ad2","unresolved":false,"context_lines":[{"line_number":607,"context_line":"        # per user quotas, project quota limits (for quotas that have"},{"line_number":608,"context_line":"        # user-scoping, limits for the project)"},{"line_number":609,"context_line":"        quotas \u003d self._get_quotas(context, resources, values.keys(),"},{"line_number":610,"context_line":"                                  has_sync\u003dFalse, project_id\u003dproject_id,"},{"line_number":611,"context_line":"                                  project_quotas\u003dproject_quotas)"},{"line_number":612,"context_line":"        # per user quotas, user quota limits (for quotas that have"},{"line_number":613,"context_line":"        # user-scoping, the limits for the user)"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_c16ba6b4","line":610,"range":{"start_line":610,"start_character":34,"end_line":610,"end_character":48},"in_reply_to":"ff0f0b1f_deb827e6","updated":"2017-05-22 20:05:35.000000000","message":"\u003e I don\u0027t think that\u0027s actually possible because I think only nova-api ever calls count(), but Dan said I can\u0027t cheat and break the remotable API for upgrades.\n\nI think I asked about this later below...","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":1067,"context_line":"        :param context: The request context, for access checks."},{"line_number":1068,"context_line":"        :param resource: The name of the resource, as a string."},{"line_number":1069,"context_line":"        \"\"\""},{"line_number":1070,"context_line":"        pass"},{"line_number":1071,"context_line":""},{"line_number":1072,"context_line":"    def limit_check(self, context, resources, values, project_id\u003dNone,"},{"line_number":1073,"context_line":"                    user_id\u003dNone):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_9b6be4b5","line":1070,"updated":"2017-05-22 18:35:32.000000000","message":"This is going to result in a KeyError in the API, so we need to handle something here. I\u0027m thinking in the server_group_members case:\n\nhttps://review.openstack.org/#/c/446239/7/nova/compute/api.py@1064\n\nI don\u0027t really know how that works today with the NoopQuotaDriver and count() method if it returns None because None + 1 is going to be a TypeError. Maybe that\u0027s just a latent bug.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":1067,"context_line":"        :param context: The request context, for access checks."},{"line_number":1068,"context_line":"        :param resource: The name of the resource, as a string."},{"line_number":1069,"context_line":"        \"\"\""},{"line_number":1070,"context_line":"        pass"},{"line_number":1071,"context_line":""},{"line_number":1072,"context_line":"    def limit_check(self, context, resources, values, project_id\u003dNone,"},{"line_number":1073,"context_line":"                    user_id\u003dNone):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_be29f3e6","line":1070,"in_reply_to":"ff0f0b1f_9b6be4b5","updated":"2017-05-22 19:51:33.000000000","message":"I messed up here. count() isn\u0027t even a quota driver method, it\u0027s only on the QuotaEngine and doesn\u0027t pass through to a driver at all. So adding these does nothing.\n\nI was trying to account for the case where someone is using the NoopQuotaDriver to avoid counting resources for no reason, but I think that can\u0027t be avoided. At least not like this.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"9cb4a5d598e0b7234e15374262869b3f62009dcf","unresolved":false,"context_lines":[{"line_number":1068,"context_line":"        :param resource: The name of the resource, as a string."},{"line_number":1069,"context_line":"        \"\"\""},{"line_number":1070,"context_line":"        pass"},{"line_number":1071,"context_line":""},{"line_number":1072,"context_line":"    def limit_check(self, context, resources, values, project_id\u003dNone,"},{"line_number":1073,"context_line":"                    user_id\u003dNone):"},{"line_number":1074,"context_line":"        \"\"\"Check simple quota limits."}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_51a9b321","line":1071,"updated":"2017-05-22 15:18:59.000000000","message":"I added these to the NoopQuotaDriver, thinking that otherwise it would count wastefully even though limits aren\u0027t being checked. But, it\u0027s supposed to be possible for someone to get a count independent of limit checking, so maybe this shouldn\u0027t be added?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":1403,"context_line":""},{"line_number":1404,"context_line":"        The counting function will be passed the context, along with"},{"line_number":1405,"context_line":"        the extra positional and keyword arguments that are passed to"},{"line_number":1406,"context_line":"        Quota.count_as_dict().  It should return an dict specifying the"},{"line_number":1407,"context_line":"        count scoped to a project and/or a user."},{"line_number":1408,"context_line":""},{"line_number":1409,"context_line":"        Example count of instances, cores, or ram returned as a rollup"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_7848135b","line":1406,"range":{"start_line":1406,"start_character":49,"end_line":1406,"end_character":51},"updated":"2017-05-22 18:35:32.000000000","message":"a dict","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":1403,"context_line":""},{"line_number":1404,"context_line":"        The counting function will be passed the context, along with"},{"line_number":1405,"context_line":"        the extra positional and keyword arguments that are passed to"},{"line_number":1406,"context_line":"        Quota.count_as_dict().  It should return an dict specifying the"},{"line_number":1407,"context_line":"        count scoped to a project and/or a user."},{"line_number":1408,"context_line":""},{"line_number":1409,"context_line":"        Example count of instances, cores, or ram returned as a rollup"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_5e1c17c0","line":1406,"range":{"start_line":1406,"start_character":49,"end_line":1406,"end_character":51},"in_reply_to":"ff0f0b1f_7848135b","updated":"2017-05-22 19:51:33.000000000","message":"Ack.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":1427,"context_line":"            {\u0027user\u0027: {\u0027key_pairs\u0027: 5}}"},{"line_number":1428,"context_line":""},{"line_number":1429,"context_line":"        Note that this counting is not performed in a transaction-safe"},{"line_number":1430,"context_line":"        manner.  This resource class is a temporary measure to provide"},{"line_number":1431,"context_line":"        required functionality, until a better approach to solving"},{"line_number":1432,"context_line":"        this problem can be evolved."},{"line_number":1433,"context_line":""},{"line_number":1434,"context_line":"        :param name: The name of the resource, i.e., \"instances\"."},{"line_number":1435,"context_line":"        :param count_as_dict: A callable which returns the count of the"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_f8a2e3fb","line":1432,"range":{"start_line":1430,"start_character":17,"end_line":1432,"end_character":36},"updated":"2017-05-22 18:35:32.000000000","message":"8 years later....we\u0027re still doing this.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":1446,"context_line":"        super(CountableResource, self).__init__(name, flag\u003dflag)"},{"line_number":1447,"context_line":"        self.count_as_dict \u003d count_as_dict"},{"line_number":1448,"context_line":"        # NOTE(melwitt): This can be removed once no old code can call count()."},{"line_number":1449,"context_line":"        if count_as_int is not None:"},{"line_number":1450,"context_line":"            self.count \u003d count_as_int"},{"line_number":1451,"context_line":""},{"line_number":1452,"context_line":""},{"line_number":1453,"context_line":"class QuotaEngine(object):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_18d9177e","line":1450,"range":{"start_line":1449,"start_character":8,"end_line":1450,"end_character":37},"updated":"2017-05-22 18:35:32.000000000","message":"Does anything using self.count anymore?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":1446,"context_line":"        super(CountableResource, self).__init__(name, flag\u003dflag)"},{"line_number":1447,"context_line":"        self.count_as_dict \u003d count_as_dict"},{"line_number":1448,"context_line":"        # NOTE(melwitt): This can be removed once no old code can call count()."},{"line_number":1449,"context_line":"        if count_as_int is not None:"},{"line_number":1450,"context_line":"            self.count \u003d count_as_int"},{"line_number":1451,"context_line":""},{"line_number":1452,"context_line":""},{"line_number":1453,"context_line":"class QuotaEngine(object):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_5e71b70b","line":1450,"range":{"start_line":1449,"start_character":8,"end_line":1450,"end_character":37},"in_reply_to":"ff0f0b1f_18d9177e","updated":"2017-05-22 19:51:33.000000000","message":"Nothing current, this is a fallback for upgrades. nova-compute doesn\u0027t ever call count(), but conceptually old computes are supposed to be able to call count() in the new code, so I put this here for that.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"65b04272be217bea60ad7b86c18a0d3900e35364","unresolved":false,"context_lines":[{"line_number":1446,"context_line":"        super(CountableResource, self).__init__(name, flag\u003dflag)"},{"line_number":1447,"context_line":"        self.count_as_dict \u003d count_as_dict"},{"line_number":1448,"context_line":"        # NOTE(melwitt): This can be removed once no old code can call count()."},{"line_number":1449,"context_line":"        if count_as_int is not None:"},{"line_number":1450,"context_line":"            self.count \u003d count_as_int"},{"line_number":1451,"context_line":""},{"line_number":1452,"context_line":""},{"line_number":1453,"context_line":"class QuotaEngine(object):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_8c23a5bd","line":1450,"range":{"start_line":1449,"start_character":8,"end_line":1450,"end_character":37},"in_reply_to":"ff0f0b1f_21e4a2e0","updated":"2017-05-22 21:34:52.000000000","message":"Yup, that will work.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"34a2c02612d5fc9f240f97d01cf9ea95548cb27a","unresolved":false,"context_lines":[{"line_number":1446,"context_line":"        super(CountableResource, self).__init__(name, flag\u003dflag)"},{"line_number":1447,"context_line":"        self.count_as_dict \u003d count_as_dict"},{"line_number":1448,"context_line":"        # NOTE(melwitt): This can be removed once no old code can call count()."},{"line_number":1449,"context_line":"        if count_as_int is not None:"},{"line_number":1450,"context_line":"            self.count \u003d count_as_int"},{"line_number":1451,"context_line":""},{"line_number":1452,"context_line":""},{"line_number":1453,"context_line":"class QuotaEngine(object):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_21e4a2e0","line":1450,"range":{"start_line":1449,"start_character":8,"end_line":1450,"end_character":37},"in_reply_to":"ff0f0b1f_41eb1612","updated":"2017-05-22 20:18:12.000000000","message":"Couldn\u0027t we avoid doing this by having nova.objects.Quotas.count call count_as_dict in the quota engine and then pull the proper thing out of the dict response and return the int so we don\u0027t mess up the remotable method contract? We don\u0027t know if we\u0027d get things back in the \u0027user\u0027 or \u0027project\u0027 key in the dict, but we could prioritize and pick one, i.e. key \u003d \u0027user\u0027 if user in count else \u0027project\u0027","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"deb5cf54d98266489d2abe7d8cd0383dd3030ad2","unresolved":false,"context_lines":[{"line_number":1446,"context_line":"        super(CountableResource, self).__init__(name, flag\u003dflag)"},{"line_number":1447,"context_line":"        self.count_as_dict \u003d count_as_dict"},{"line_number":1448,"context_line":"        # NOTE(melwitt): This can be removed once no old code can call count()."},{"line_number":1449,"context_line":"        if count_as_int is not None:"},{"line_number":1450,"context_line":"            self.count \u003d count_as_int"},{"line_number":1451,"context_line":""},{"line_number":1452,"context_line":""},{"line_number":1453,"context_line":"class QuotaEngine(object):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_41eb1612","line":1450,"range":{"start_line":1449,"start_character":8,"end_line":1450,"end_character":37},"in_reply_to":"ff0f0b1f_5e71b70b","updated":"2017-05-22 20:05:35.000000000","message":"But old computes are going to be calling count in the old code, right? Old binaries don\u0027t magically start talking to new code, and it\u0027s not like this is a separate service or something. So I don\u0027t get that.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":1470,"context_line":"        self.__driver \u003d self._driver_cls"},{"line_number":1471,"context_line":"        return self.__driver"},{"line_number":1472,"context_line":""},{"line_number":1473,"context_line":"    def __contains__(self, resource):"},{"line_number":1474,"context_line":"        return resource in self._resources"},{"line_number":1475,"context_line":""},{"line_number":1476,"context_line":"    def __getitem__(self, key):"},{"line_number":1477,"context_line":"        if key in self._resources:"},{"line_number":1478,"context_line":"            return self._resources[key]"},{"line_number":1479,"context_line":""},{"line_number":1480,"context_line":"    def register_resource(self, resource):"},{"line_number":1481,"context_line":"        \"\"\"Register a resource.\"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_fb9b0015","line":1478,"range":{"start_line":1473,"start_character":0,"end_line":1478,"end_character":39},"updated":"2017-05-22 18:35:32.000000000","message":"I don\u0027t think these are used anymore since you changed _valid_method_call_check_resource.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":1470,"context_line":"        self.__driver \u003d self._driver_cls"},{"line_number":1471,"context_line":"        return self.__driver"},{"line_number":1472,"context_line":""},{"line_number":1473,"context_line":"    def __contains__(self, resource):"},{"line_number":1474,"context_line":"        return resource in self._resources"},{"line_number":1475,"context_line":""},{"line_number":1476,"context_line":"    def __getitem__(self, key):"},{"line_number":1477,"context_line":"        if key in self._resources:"},{"line_number":1478,"context_line":"            return self._resources[key]"},{"line_number":1479,"context_line":""},{"line_number":1480,"context_line":"    def register_resource(self, resource):"},{"line_number":1481,"context_line":"        \"\"\"Register a resource.\"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_1e69ff1f","line":1478,"range":{"start_line":1473,"start_character":0,"end_line":1478,"end_character":39},"in_reply_to":"ff0f0b1f_fb9b0015","updated":"2017-05-22 19:51:33.000000000","message":"Okay, I\u0027ll check that.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":1619,"context_line":""},{"line_number":1620,"context_line":"        :param context: The request context, for access checks."},{"line_number":1621,"context_line":"        :param resource: The name of the resource, as a string."},{"line_number":1622,"context_line":"        \"\"\""},{"line_number":1623,"context_line":""},{"line_number":1624,"context_line":"        # Get the resource"},{"line_number":1625,"context_line":"        res \u003d self._resources.get(resource)"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_a029d3e6","line":1622,"updated":"2017-05-22 18:35:32.000000000","message":"nit: add a :return: entry to the docstring and define what is in the returned dict, at least the keys and value structure.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":1619,"context_line":""},{"line_number":1620,"context_line":"        :param context: The request context, for access checks."},{"line_number":1621,"context_line":"        :param resource: The name of the resource, as a string."},{"line_number":1622,"context_line":"        \"\"\""},{"line_number":1623,"context_line":""},{"line_number":1624,"context_line":"        # Get the resource"},{"line_number":1625,"context_line":"        res \u003d self._resources.get(resource)"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_fe59ab8d","line":1622,"in_reply_to":"ff0f0b1f_a029d3e6","updated":"2017-05-22 19:51:33.000000000","message":"Will do.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e84bb6ba3806f0b5c45359dffe470cfb39ffca5","unresolved":false,"context_lines":[{"line_number":1911,"context_line":"    CountableResource(\u0027security_group_rules\u0027,"},{"line_number":1912,"context_line":"                      _security_group_rule_count_by_group,"},{"line_number":1913,"context_line":"                      \u0027security_group_rules\u0027,"},{"line_number":1914,"context_line":"                      db.security_group_rule_count_by_group),"},{"line_number":1915,"context_line":"    CountableResource(\u0027key_pairs\u0027, _keypair_get_count_by_user,"},{"line_number":1916,"context_line":"                      \u0027key_pairs\u0027, _keypair_get_count_by_user_as_int),"},{"line_number":1917,"context_line":"    ReservableResource(\u0027server_groups\u0027, \u0027_sync_server_groups\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_58e1cf29","line":1914,"range":{"start_line":1914,"start_character":25,"end_line":1914,"end_character":59},"updated":"2017-05-22 18:35:32.000000000","message":"Do we really need these for security_group_rules, key_pairs and server_group_members since you\u0027ve already changed the API to call count_as_dict now?","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"8467d3d990c083f9f6c8edfab3b2b06982d78ef7","unresolved":false,"context_lines":[{"line_number":1911,"context_line":"    CountableResource(\u0027security_group_rules\u0027,"},{"line_number":1912,"context_line":"                      _security_group_rule_count_by_group,"},{"line_number":1913,"context_line":"                      \u0027security_group_rules\u0027,"},{"line_number":1914,"context_line":"                      db.security_group_rule_count_by_group),"},{"line_number":1915,"context_line":"    CountableResource(\u0027key_pairs\u0027, _keypair_get_count_by_user,"},{"line_number":1916,"context_line":"                      \u0027key_pairs\u0027, _keypair_get_count_by_user_as_int),"},{"line_number":1917,"context_line":"    ReservableResource(\u0027server_groups\u0027, \u0027_sync_server_groups\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_5e4ad7ab","line":1914,"range":{"start_line":1914,"start_character":25,"end_line":1914,"end_character":59},"in_reply_to":"ff0f0b1f_58e1cf29","updated":"2017-05-22 19:51:33.000000000","message":"Conceptually for upgrades even though I think no old code could call new code via the Quotas.count() remotable method.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"deb5cf54d98266489d2abe7d8cd0383dd3030ad2","unresolved":false,"context_lines":[{"line_number":1911,"context_line":"    CountableResource(\u0027security_group_rules\u0027,"},{"line_number":1912,"context_line":"                      _security_group_rule_count_by_group,"},{"line_number":1913,"context_line":"                      \u0027security_group_rules\u0027,"},{"line_number":1914,"context_line":"                      db.security_group_rule_count_by_group),"},{"line_number":1915,"context_line":"    CountableResource(\u0027key_pairs\u0027, _keypair_get_count_by_user,"},{"line_number":1916,"context_line":"                      \u0027key_pairs\u0027, _keypair_get_count_by_user_as_int),"},{"line_number":1917,"context_line":"    ReservableResource(\u0027server_groups\u0027, \u0027_sync_server_groups\u0027,"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_a1db127a","line":1914,"range":{"start_line":1914,"start_character":25,"end_line":1914,"end_character":59},"in_reply_to":"ff0f0b1f_5e4ad7ab","updated":"2017-05-22 20:05:35.000000000","message":"Yeah, see above - is this really what Dan was thinking, because if so, I don\u0027t get it.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"9f3af6c8cb3de8f10f53401874e5ce9e1e25728a","unresolved":false,"context_lines":[{"line_number":1242,"context_line":"        pass"},{"line_number":1243,"context_line":""},{"line_number":1244,"context_line":"    def destroy_all_by_project_and_user(self, context, project_id, user_id):"},{"line_number":1245,"context_line":"        \"\"\"Destroy all quotas associated with a project and user."},{"line_number":1246,"context_line":""},{"line_number":1247,"context_line":"        :param context: The request context, for access checks."},{"line_number":1248,"context_line":"        :param project_id: The ID of the project being deleted."}],"source_content_type":"text/x-python","patch_set":8,"id":"ff0f0b1f_d681e3c4","line":1245,"updated":"2017-05-24 17:24:39.000000000","message":"Missed reverting this back.","commit_id":"ea28d3a00cb9be4399b58041a450458a2e1dfb3c"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"9f3af6c8cb3de8f10f53401874e5ce9e1e25728a","unresolved":false,"context_lines":[{"line_number":1251,"context_line":"        pass"},{"line_number":1252,"context_line":""},{"line_number":1253,"context_line":"    def destroy_all_by_project(self, context, project_id):"},{"line_number":1254,"context_line":"        \"\"\"Destroy all quotas associated with a project."},{"line_number":1255,"context_line":""},{"line_number":1256,"context_line":"        :param context: The request context, for access checks."},{"line_number":1257,"context_line":"        :param project_id: The ID of the project being deleted."}],"source_content_type":"text/x-python","patch_set":8,"id":"ff0f0b1f_167cfbe9","line":1254,"updated":"2017-05-24 17:24:39.000000000","message":"Missed reverting this back.","commit_id":"ea28d3a00cb9be4399b58041a450458a2e1dfb3c"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"9f3af6c8cb3de8f10f53401874e5ce9e1e25728a","unresolved":false,"context_lines":[{"line_number":1381,"context_line":""},{"line_number":1382,"context_line":""},{"line_number":1383,"context_line":"class AbsoluteResource(BaseResource):"},{"line_number":1384,"context_line":"    \"\"\"Describe a resource that does not correspond to database objects.\"\"\""},{"line_number":1385,"context_line":"    valid_method \u003d \u0027check\u0027"},{"line_number":1386,"context_line":""},{"line_number":1387,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"ff0f0b1f_361b7fca","line":1384,"updated":"2017-05-24 17:24:39.000000000","message":"Missed reverting this back.","commit_id":"ea28d3a00cb9be4399b58041a450458a2e1dfb3c"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"33ed308d0502753e4514bfa9980e88e8b6fbb378","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                   \u0027user_id\u0027: \u0027user-uuid\u0027,"},{"line_number":173,"context_line":"                   \u0027instances\u0027: {\u0027in_use\u0027: 5, \u0027reserved\u0027: 1},"},{"line_number":174,"context_line":"                   \u0027fixed_ips\u0027: {\u0027in_use\u0027: 5, \u0027reserved\u0027: 1}}"},{"line_number":175,"context_line":"                  The \u0027reserved\u0027 value can only be non-zero for"},{"line_number":176,"context_line":"                  ReservableResources."},{"line_number":177,"context_line":"        \"\"\""},{"line_number":178,"context_line":"        usages \u003d {}"},{"line_number":179,"context_line":"        for resource in resources.values():"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_896b3eef","line":176,"range":{"start_line":175,"start_character":18,"end_line":176,"end_character":38},"updated":"2017-05-25 02:55:46.000000000","message":"We skip non-CountableResources in this method though, so should we note this here?","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"5a34915b6d97de1aed13f544ddccf17bcd2625e2","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                   \u0027user_id\u0027: \u0027user-uuid\u0027,"},{"line_number":173,"context_line":"                   \u0027instances\u0027: {\u0027in_use\u0027: 5, \u0027reserved\u0027: 1},"},{"line_number":174,"context_line":"                   \u0027fixed_ips\u0027: {\u0027in_use\u0027: 5, \u0027reserved\u0027: 1}}"},{"line_number":175,"context_line":"                  The \u0027reserved\u0027 value can only be non-zero for"},{"line_number":176,"context_line":"                  ReservableResources."},{"line_number":177,"context_line":"        \"\"\""},{"line_number":178,"context_line":"        usages \u003d {}"},{"line_number":179,"context_line":"        for resource in resources.values():"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_4e6e33ca","line":176,"range":{"start_line":175,"start_character":18,"end_line":176,"end_character":38},"in_reply_to":"ff0f0b1f_896b3eef","updated":"2017-05-25 17:01:17.000000000","message":"Hm, good point. This shouldn\u0027t be in here. The \u0027reserved\u0027 can only come from the DB query \"quota_usage_get_all*\"","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":269,"context_line":"                    context, project_id, user_id)"},{"line_number":270,"context_line":"            for k, v in from_usages_table.items():"},{"line_number":271,"context_line":"                if k in user_usages:"},{"line_number":272,"context_line":"                    continue"},{"line_number":273,"context_line":"                user_usages[k] \u003d v"},{"line_number":274,"context_line":"        return self._process_quotas(context, resources, project_id,"},{"line_number":275,"context_line":"                                    user_quotas, quota_class,"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_69c1f1e4","line":272,"range":{"start_line":272,"start_character":20,"end_line":272,"end_character":28},"updated":"2017-05-25 17:59:06.000000000","message":"This isn\u0027t a test for this, not sure how easy that is though.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":313,"context_line":"                                                                  project_id)"},{"line_number":314,"context_line":"            for k, v in from_usages_table.items():"},{"line_number":315,"context_line":"                if k in project_usages:"},{"line_number":316,"context_line":"                    continue"},{"line_number":317,"context_line":"                project_usages[k] \u003d v"},{"line_number":318,"context_line":"        return self._process_quotas(context, resources, project_id,"},{"line_number":319,"context_line":"                                    project_quotas, quota_class,"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_e9ace136","line":316,"range":{"start_line":316,"start_character":20,"end_line":316,"end_character":28},"updated":"2017-05-25 17:59:06.000000000","message":"same","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":603,"context_line":"                # TODO(melwitt): We need to handle this in the REST API once"},{"line_number":604,"context_line":"                # limit_check_project_and_user starts being used so we don\u0027t"},{"line_number":605,"context_line":"                # leak 500 codes out of the API."},{"line_number":606,"context_line":"                raise exception.InvalidQuotaKeyMismatch("},{"line_number":607,"context_line":"                        user_values\u003dsorted(user_values),"},{"line_number":608,"context_line":"                        project_values\u003dsorted(project_values))"},{"line_number":609,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_c97ebdae","line":606,"range":{"start_line":606,"start_character":32,"end_line":606,"end_character":55},"updated":"2017-05-25 17:59:06.000000000","message":"Don\u0027t see a test for this case.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"33ed308d0502753e4514bfa9980e88e8b6fbb378","unresolved":false,"context_lines":[{"line_number":1578,"context_line":"                                                project_id,"},{"line_number":1579,"context_line":"                                                user_id\u003duser_id)"},{"line_number":1580,"context_line":""},{"line_number":1581,"context_line":"    # TODO(melwitt): This can be removed once no old code can call count()."},{"line_number":1582,"context_line":"    def count(self, context, resource, *args, **kwargs):"},{"line_number":1583,"context_line":"        \"\"\"Count a resource."},{"line_number":1584,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_c91c9679","line":1581,"updated":"2017-05-25 02:55:46.000000000","message":"I actually thought we could kill this in the quota engine now, and leave the facade in the remotable count() method in the quotas object, but have the count() method in the quotas object call count_as_dict to return the old style int value?","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"5a34915b6d97de1aed13f544ddccf17bcd2625e2","unresolved":false,"context_lines":[{"line_number":1578,"context_line":"                                                project_id,"},{"line_number":1579,"context_line":"                                                user_id\u003duser_id)"},{"line_number":1580,"context_line":""},{"line_number":1581,"context_line":"    # TODO(melwitt): This can be removed once no old code can call count()."},{"line_number":1582,"context_line":"    def count(self, context, resource, *args, **kwargs):"},{"line_number":1583,"context_line":"        \"\"\"Count a resource."},{"line_number":1584,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_4e7cf371","line":1581,"in_reply_to":"ff0f0b1f_c91c9679","updated":"2017-05-25 17:01:17.000000000","message":"Ah, okay. I didn\u0027t think of that. Will try it.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":1621,"context_line":"        # Get the resource"},{"line_number":1622,"context_line":"        res \u003d self._resources.get(resource)"},{"line_number":1623,"context_line":"        if not res or not hasattr(res, \u0027count_as_dict\u0027):"},{"line_number":1624,"context_line":"            raise exception.QuotaResourceUnknown(unknown\u003d[resource])"},{"line_number":1625,"context_line":""},{"line_number":1626,"context_line":"        return res.count_as_dict(context, *args, **kwargs)"},{"line_number":1627,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_c957dd26","line":1624,"range":{"start_line":1624,"start_character":28,"end_line":1624,"end_character":48},"updated":"2017-05-25 17:59:06.000000000","message":"There is no test for this.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"c13921da540032f341d571fd0639d57036ea3651","unresolved":false,"context_lines":[{"line_number":606,"context_line":"        # need to be checked against both quotas, merge them into one dict,"},{"line_number":607,"context_line":"        # and remove them from project_values and user_values."},{"line_number":608,"context_line":"        keys_to_merge \u003d set(project_values).symmetric_difference(user_values)"},{"line_number":609,"context_line":"        values \u003d {}"},{"line_number":610,"context_line":"        for key in keys_to_merge:"},{"line_number":611,"context_line":"            values[key] \u003d project_values.get(key) or user_values.get(key)"},{"line_number":612,"context_line":"            project_values.pop(key, None)"}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_4de9997e","line":609,"range":{"start_line":609,"start_character":8,"end_line":609,"end_character":14},"updated":"2017-05-28 01:23:37.000000000","message":"Maybe name this \"merged_values\"","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"c13921da540032f341d571fd0639d57036ea3651","unresolved":false,"context_lines":[{"line_number":608,"context_line":"        keys_to_merge \u003d set(project_values).symmetric_difference(user_values)"},{"line_number":609,"context_line":"        values \u003d {}"},{"line_number":610,"context_line":"        for key in keys_to_merge:"},{"line_number":611,"context_line":"            values[key] \u003d project_values.get(key) or user_values.get(key)"},{"line_number":612,"context_line":"            project_values.pop(key, None)"},{"line_number":613,"context_line":"            user_values.pop(key, None)"},{"line_number":614,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_0d03a144","line":611,"updated":"2017-05-28 01:23:37.000000000","message":"Maybe add a comment here that says the key will be either in project_values or user_values","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b8e58219bc903b2b23741f6de05c19e3638d499e","unresolved":false,"context_lines":[{"line_number":663,"context_line":"                                          quotas\u003dmerged_quotas, usages\u003d{},"},{"line_number":664,"context_line":"                                          headroom\u003dheadroom)"},{"line_number":665,"context_line":""},{"line_number":666,"context_line":"        # This is for resources that are counted across a project and"},{"line_number":667,"context_line":"        # across a user. The project_values must pass the quota for the"},{"line_number":668,"context_line":"        # project and the user_values must pass the quota for the user."},{"line_number":669,"context_line":"        over_user_quota \u003d False"}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_3c6fbdc6","line":666,"range":{"start_line":666,"start_character":22,"end_line":666,"end_character":31},"updated":"2017-05-27 14:14:22.000000000","message":"Would be nice to have an example, e.g. security_group_rules?","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7861577ff19cfa5f2ff1e387bbf0b854a547b294","unresolved":false,"context_lines":[{"line_number":663,"context_line":"                                          quotas\u003dmerged_quotas, usages\u003d{},"},{"line_number":664,"context_line":"                                          headroom\u003dheadroom)"},{"line_number":665,"context_line":""},{"line_number":666,"context_line":"        # This is for resources that are counted across a project and"},{"line_number":667,"context_line":"        # across a user. The project_values must pass the quota for the"},{"line_number":668,"context_line":"        # project and the user_values must pass the quota for the user."},{"line_number":669,"context_line":"        over_user_quota \u003d False"}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_2d39c540","line":666,"range":{"start_line":666,"start_character":22,"end_line":666,"end_character":31},"in_reply_to":"df140735_3c6fbdc6","updated":"2017-05-28 00:53:06.000000000","message":"Ack. Will add.","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b8e58219bc903b2b23741f6de05c19e3638d499e","unresolved":false,"context_lines":[{"line_number":669,"context_line":"        over_user_quota \u003d False"},{"line_number":670,"context_line":"        overs \u003d []"},{"line_number":671,"context_line":"        for key in user_values.keys():"},{"line_number":672,"context_line":"            if quotas[key] \u003e\u003d 0 and quotas[key] \u003c project_values[key]:"},{"line_number":673,"context_line":"                overs.append(key)"},{"line_number":674,"context_line":"            elif (user_quotas[key] \u003e\u003d 0 and"},{"line_number":675,"context_line":"                  user_quotas[key] \u003c user_values[key]):"}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_bc62add7","line":672,"range":{"start_line":672,"start_character":50,"end_line":672,"end_character":69},"updated":"2017-05-27 14:14:22.000000000","message":"Isn\u0027t project_values optional and therefore we could get a KeyError here?","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7861577ff19cfa5f2ff1e387bbf0b854a547b294","unresolved":false,"context_lines":[{"line_number":669,"context_line":"        over_user_quota \u003d False"},{"line_number":670,"context_line":"        overs \u003d []"},{"line_number":671,"context_line":"        for key in user_values.keys():"},{"line_number":672,"context_line":"            if quotas[key] \u003e\u003d 0 and quotas[key] \u003c project_values[key]:"},{"line_number":673,"context_line":"                overs.append(key)"},{"line_number":674,"context_line":"            elif (user_quotas[key] \u003e\u003d 0 and"},{"line_number":675,"context_line":"                  user_quotas[key] \u003c user_values[key]):"}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_ed3aad32","line":672,"range":{"start_line":672,"start_character":50,"end_line":672,"end_character":69},"in_reply_to":"df140735_bc62add7","updated":"2017-05-28 00:53:06.000000000","message":"project_values and user_values are both optional and set to empty dicts if they are None on L579.\n\nI think what\u0027s here is safe because after we remove keys from project_values and user_values that they don\u0027t have in common at L608 - L613, we\u0027re left with project_values and user_values containing the same keys or being empty. Let me know if there\u0027s something more I\u0027m missing.","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"008d3757e895fd7355b2483318c787e2a6a1cc81","unresolved":false,"context_lines":[{"line_number":669,"context_line":"        over_user_quota \u003d False"},{"line_number":670,"context_line":"        overs \u003d []"},{"line_number":671,"context_line":"        for key in user_values.keys():"},{"line_number":672,"context_line":"            if quotas[key] \u003e\u003d 0 and quotas[key] \u003c project_values[key]:"},{"line_number":673,"context_line":"                overs.append(key)"},{"line_number":674,"context_line":"            elif (user_quotas[key] \u003e\u003d 0 and"},{"line_number":675,"context_line":"                  user_quotas[key] \u003c user_values[key]):"}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_1e4ded71","line":672,"range":{"start_line":672,"start_character":50,"end_line":672,"end_character":69},"in_reply_to":"df140735_ed3aad32","updated":"2017-05-30 01:19:24.000000000","message":"OK yeah, it\u0027s a big method so easy to lose context on what\u0027s going on. The symmetric difference in the project and user values sets will remove anything not common to both, so when iterating over user_values keys here, we expect those keys to also be in project_values.","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4dfe22af0f0be3573f05bd1af9c6191bf94d7393","unresolved":false,"context_lines":[{"line_number":160,"context_line":"        This function is called to get resource usages for validating quota"},{"line_number":161,"context_line":"        limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":162,"context_line":"        resource usages in the os-used-limits API. This function is not used"},{"line_number":163,"context_line":"        for checking resource usage against quota limits."},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"        :param context: The request context for access checks"},{"line_number":166,"context_line":"        :param resources: The dict of Resources for which to get usages"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_1746e27d","line":163,"updated":"2017-05-30 15:58:57.000000000","message":"No? If it isn\u0027t, which function *is* used when checking resource usage against quota limits? Might be worth noting that here in this comment.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"aceb38298fa935db70cc2d15a5733a0124f8e8bd","unresolved":false,"context_lines":[{"line_number":160,"context_line":"        This function is called to get resource usages for validating quota"},{"line_number":161,"context_line":"        limit creates or updates in the os-quota-sets API and for displaying"},{"line_number":162,"context_line":"        resource usages in the os-used-limits API. This function is not used"},{"line_number":163,"context_line":"        for checking resource usage against quota limits."},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"        :param context: The request context for access checks"},{"line_number":166,"context_line":"        :param resources: The dict of Resources for which to get usages"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_32369405","line":163,"in_reply_to":"df140735_1746e27d","updated":"2017-05-30 16:28:10.000000000","message":"That would be limit_check_project_and_user.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4dfe22af0f0be3573f05bd1af9c6191bf94d7393","unresolved":false,"context_lines":[{"line_number":169,"context_line":"        :returns: A dict containing resources and their usage information,"},{"line_number":170,"context_line":"                  for example:"},{"line_number":171,"context_line":"                  {\u0027project_id\u0027: \u0027project-uuid\u0027,"},{"line_number":172,"context_line":"                   \u0027user_id\u0027: \u0027user-uuid\u0027,"},{"line_number":173,"context_line":"                   \u0027instances\u0027: {\u0027in_use\u0027: 5},"},{"line_number":174,"context_line":"                   \u0027fixed_ips\u0027: {\u0027in_use\u0027: 5}}"},{"line_number":175,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_f74a4e7e","line":172,"updated":"2017-05-30 15:58:57.000000000","message":"I don\u0027t see where the project_id and user_id keys are being added to the returned dict?","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"43072bd62e287356e13aebaba65810516fda0b3e","unresolved":false,"context_lines":[{"line_number":169,"context_line":"        :returns: A dict containing resources and their usage information,"},{"line_number":170,"context_line":"                  for example:"},{"line_number":171,"context_line":"                  {\u0027project_id\u0027: \u0027project-uuid\u0027,"},{"line_number":172,"context_line":"                   \u0027user_id\u0027: \u0027user-uuid\u0027,"},{"line_number":173,"context_line":"                   \u0027instances\u0027: {\u0027in_use\u0027: 5},"},{"line_number":174,"context_line":"                   \u0027fixed_ips\u0027: {\u0027in_use\u0027: 5}}"},{"line_number":175,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_cf5faa3f","line":172,"in_reply_to":"df140735_f74a4e7e","updated":"2017-05-30 18:33:08.000000000","message":"Ah, you\u0027re right. This was a holdover from when I was trying to do something like call the backward compat quota_usages_get_all* functions here. I\u0027ll fix the docstring in a follow up patch.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4dfe22af0f0be3573f05bd1af9c6191bf94d7393","unresolved":false,"context_lines":[{"line_number":193,"context_line":"                # These per user resources are special cases whose usages"},{"line_number":194,"context_line":"                # are not considered when validating limit create/update or"},{"line_number":195,"context_line":"                # displaying used limits. They are always zero."},{"line_number":196,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":197,"context_line":"            else:"},{"line_number":198,"context_line":"                if resource.name in db.quota_get_per_project_resources():"},{"line_number":199,"context_line":"                    count \u003d resource.count_as_dict(context, project_id)"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_d75f4a3f","line":196,"updated":"2017-05-30 15:58:57.000000000","message":"le sigh. :)","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4dfe22af0f0be3573f05bd1af9c6191bf94d7393","unresolved":false,"context_lines":[{"line_number":195,"context_line":"                # displaying used limits. They are always zero."},{"line_number":196,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":197,"context_line":"            else:"},{"line_number":198,"context_line":"                if resource.name in db.quota_get_per_project_resources():"},{"line_number":199,"context_line":"                    count \u003d resource.count_as_dict(context, project_id)"},{"line_number":200,"context_line":"                    key \u003d \u0027project\u0027"},{"line_number":201,"context_line":"                else:"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_b75cd64b","line":198,"updated":"2017-05-30 15:58:57.000000000","message":"I believe we should be calling db.quota_get_per_project_resources() only *once*, not one time for each resource in the resources dict. Can you put this call on line 176 and simply refer to the result of the db.quota_get_per_project_resources() call inside the for loop?","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"aceb38298fa935db70cc2d15a5733a0124f8e8bd","unresolved":false,"context_lines":[{"line_number":195,"context_line":"                # displaying used limits. They are always zero."},{"line_number":196,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":197,"context_line":"            else:"},{"line_number":198,"context_line":"                if resource.name in db.quota_get_per_project_resources():"},{"line_number":199,"context_line":"                    count \u003d resource.count_as_dict(context, project_id)"},{"line_number":200,"context_line":"                    key \u003d \u0027project\u0027"},{"line_number":201,"context_line":"                else:"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_d20d183f","line":198,"in_reply_to":"df140735_b75cd64b","updated":"2017-05-30 16:28:10.000000000","message":"That\u0027s what L184 is for I believe.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"43072bd62e287356e13aebaba65810516fda0b3e","unresolved":false,"context_lines":[{"line_number":195,"context_line":"                # displaying used limits. They are always zero."},{"line_number":196,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":197,"context_line":"            else:"},{"line_number":198,"context_line":"                if resource.name in db.quota_get_per_project_resources():"},{"line_number":199,"context_line":"                    count \u003d resource.count_as_dict(context, project_id)"},{"line_number":200,"context_line":"                    key \u003d \u0027project\u0027"},{"line_number":201,"context_line":"                else:"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_8f6d329a","line":198,"in_reply_to":"df140735_b75cd64b","updated":"2017-05-30 18:33:08.000000000","message":"db.quota_get_per_project_resources() is just a pass through to the list of resources that are project-scoped-only. That is, it returns [\u0027fixed_ips\u0027, \u0027floating_ips\u0027, \u0027networks\u0027] which is the PER_PROJECT_QUOTAS constant in nova/db/sqlalchemy/api.py. So this is just checking \"is this resource one of fixed_ips, floating_ips or networks?\" Like in L191.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8fd3bb99e7de9fb18ca7acf5473b3e2502bcd3bd","unresolved":false,"context_lines":[{"line_number":195,"context_line":"                # displaying used limits. They are always zero."},{"line_number":196,"context_line":"                usages[resource.name] \u003d {\u0027in_use\u0027: 0}"},{"line_number":197,"context_line":"            else:"},{"line_number":198,"context_line":"                if resource.name in db.quota_get_per_project_resources():"},{"line_number":199,"context_line":"                    count \u003d resource.count_as_dict(context, project_id)"},{"line_number":200,"context_line":"                    key \u003d \u0027project\u0027"},{"line_number":201,"context_line":"                else:"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_f8f7dbf4","line":198,"in_reply_to":"df140735_d20d183f","updated":"2017-05-30 17:06:51.000000000","message":"Oh... yeah, sorry that was confusing. :(","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4dfe22af0f0be3573f05bd1af9c6191bf94d7393","unresolved":false,"context_lines":[{"line_number":382,"context_line":"                # corresponding nova-manage command. The idea is when someone"},{"line_number":383,"context_line":"                # attempts to update a quota, the value chosen must be at least"},{"line_number":384,"context_line":"                # as much as the current usage and less than or equal to the"},{"line_number":385,"context_line":"                # project limit less the sum of existing per user limits."},{"line_number":386,"context_line":"                minimum \u003d value[\u0027in_use\u0027] + value[\u0027reserved\u0027]"},{"line_number":387,"context_line":"                settable_quotas[key] \u003d {\u0027minimum\u0027: minimum, \u0027maximum\u0027: maximum}"},{"line_number":388,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_9759d25b","line":385,"updated":"2017-05-30 15:58:57.000000000","message":"Just making a note... this is the area that we would like to eventually just rip out of Nova. There really should be no usage-checking involved when updating limit amounts.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"43072bd62e287356e13aebaba65810516fda0b3e","unresolved":false,"context_lines":[{"line_number":382,"context_line":"                # corresponding nova-manage command. The idea is when someone"},{"line_number":383,"context_line":"                # attempts to update a quota, the value chosen must be at least"},{"line_number":384,"context_line":"                # as much as the current usage and less than or equal to the"},{"line_number":385,"context_line":"                # project limit less the sum of existing per user limits."},{"line_number":386,"context_line":"                minimum \u003d value[\u0027in_use\u0027] + value[\u0027reserved\u0027]"},{"line_number":387,"context_line":"                settable_quotas[key] \u003d {\u0027minimum\u0027: minimum, \u0027maximum\u0027: maximum}"},{"line_number":388,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_022219a5","line":385,"in_reply_to":"df140735_9759d25b","updated":"2017-05-30 18:33:08.000000000","message":"Yeah, with unified limits in Keystone, we wouldn\u0027t be doing any validation of limit updates. I think sdague has a todo to sanity-check with operators whether anyone found any value in the limit update validation. We know that some operators like CERN already disable the validation in the present quota system.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"950fc2fbb513907566bdf641f3ddcca5c7da7bdc","unresolved":false,"context_lines":[{"line_number":642,"context_line":"                                       project_quotas\u003dproject_quotas)"},{"line_number":643,"context_line":""},{"line_number":644,"context_line":"        if merged_values:"},{"line_number":645,"context_line":"            # This is for resources that are not counted across a project and"},{"line_number":646,"context_line":"            # must pass both the quota for the project and the quota for the"},{"line_number":647,"context_line":"            # user."},{"line_number":648,"context_line":"            # Combine per user project quotas and user_quotas for use in the"},{"line_number":649,"context_line":"            # checks, taking the minimum limit between the two."},{"line_number":650,"context_line":"            merged_quotas \u003d copy.deepcopy(quotas)"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_fe7a3986","line":647,"range":{"start_line":645,"start_character":14,"end_line":647,"end_character":19},"updated":"2017-05-30 01:23:23.000000000","message":"nit: example here would be nice also, but only if you need to respin.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"950fc2fbb513907566bdf641f3ddcca5c7da7bdc","unresolved":false,"context_lines":[{"line_number":673,"context_line":"        over_user_quota \u003d False"},{"line_number":674,"context_line":"        overs \u003d []"},{"line_number":675,"context_line":"        for key in user_values.keys():"},{"line_number":676,"context_line":"            # project_values and user_values should contain the same keys or"},{"line_number":677,"context_line":"            # be empty after the keys in the symmetric_difference were removed"},{"line_number":678,"context_line":"            # from both dicts."},{"line_number":679,"context_line":"            if quotas[key] \u003e\u003d 0 and quotas[key] \u003c project_values[key]:"},{"line_number":680,"context_line":"                overs.append(key)"},{"line_number":681,"context_line":"            elif (user_quotas[key] \u003e\u003d 0 and"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_de6f75c3","line":678,"range":{"start_line":676,"start_character":12,"end_line":678,"end_character":30},"updated":"2017-05-30 01:23:23.000000000","message":"Thanks for adding this comment per my confusion in PS10.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"}],"nova/tests/unit/api/openstack/compute/test_serversV21.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":3218,"context_line":"        def fake_instance_destroy(context, uuid, constraint):"},{"line_number":3219,"context_line":"            return fakes.stub_instance(1)"},{"line_number":3220,"context_line":""},{"line_number":3221,"context_line":"        self.stubs.Set(fakes.QUOTAS, \u0027count\u0027, fake_count)"},{"line_number":3222,"context_line":"        self.stubs.Set(fakes.QUOTAS, \u0027limit_check\u0027, fake_limit_check)"},{"line_number":3223,"context_line":"        self.stub_out(\u0027nova.db.instance_destroy\u0027, fake_instance_destroy)"},{"line_number":3224,"context_line":"        self.body[\u0027os:scheduler_hints\u0027] \u003d {\u0027group\u0027: fake_group.uuid}"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_a94f0933","line":3221,"range":{"start_line":3221,"start_character":38,"end_line":3221,"end_character":43},"updated":"2017-05-25 17:59:06.000000000","message":"Shouldn\u0027t this be count_as_dict? Because count doesn\u0027t really behave the way you\u0027re stubbing it out.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"50207133ed03a9a1cb5d2ffae5b82b207b290db0","unresolved":false,"context_lines":[{"line_number":3218,"context_line":"        def fake_instance_destroy(context, uuid, constraint):"},{"line_number":3219,"context_line":"            return fakes.stub_instance(1)"},{"line_number":3220,"context_line":""},{"line_number":3221,"context_line":"        self.stubs.Set(fakes.QUOTAS, \u0027count\u0027, fake_count)"},{"line_number":3222,"context_line":"        self.stubs.Set(fakes.QUOTAS, \u0027limit_check\u0027, fake_limit_check)"},{"line_number":3223,"context_line":"        self.stub_out(\u0027nova.db.instance_destroy\u0027, fake_instance_destroy)"},{"line_number":3224,"context_line":"        self.body[\u0027os:scheduler_hints\u0027] \u003d {\u0027group\u0027: fake_group.uuid}"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_843427fd","line":3221,"range":{"start_line":3221,"start_character":38,"end_line":3221,"end_character":43},"in_reply_to":"ff0f0b1f_a94f0933","updated":"2017-05-25 20:21:14.000000000","message":"Done","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"}],"nova/tests/unit/objects/test_quotas.py":[{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"9306500ed541516a00884ba8f40bee2ee3a696a1","unresolved":false,"context_lines":[{"line_number":387,"context_line":"                          user_id\u003duser_id, check_project_id\u003dproject_id,"},{"line_number":388,"context_line":"                          check_user_id\u003duser_id)"},{"line_number":389,"context_line":"        mock_count.assert_called_once_with(self.context, \u0027instances\u0027,"},{"line_number":390,"context_line":"                                           project_id, user_id\u003duser_id)"},{"line_number":391,"context_line":""},{"line_number":392,"context_line":""},{"line_number":393,"context_line":"class TestQuotasObject(_TestQuotasObject, test_objects._LocalTest):"}],"source_content_type":"text/x-python","patch_set":1,"id":"1a1ced50_d034d1df","line":390,"updated":"2017-03-17 14:49:50.000000000","message":"Do we not want to test each of the types of resource here, instance ones, and the other types?","commit_id":"5cd9167048fc108c4c37dbe240909b19ae13064b"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":163,"context_line":"            return {\u0027user\u0027: {resource: 2}}"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"        mock_count.side_effect \u003d fake_count"},{"line_number":166,"context_line":"        deltas \u003d {\u0027key_pairs\u0027: 1, \u0027server_group_members\u0027: 1}"},{"line_number":167,"context_line":"        project_id \u003d \u0027fake-other-project\u0027"},{"line_number":168,"context_line":"        user_id \u003d \u0027fake-other-user\u0027"},{"line_number":169,"context_line":"        quotas_obj.Quotas.check_deltas(self.context, deltas,"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_c96b5d83","line":166,"range":{"start_line":166,"start_character":34,"end_line":166,"end_character":60},"updated":"2017-05-25 17:59:06.000000000","message":"Can we have a wrinkle where we are decrementing usage, so -1 or something?","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"50207133ed03a9a1cb5d2ffae5b82b207b290db0","unresolved":false,"context_lines":[{"line_number":163,"context_line":"            return {\u0027user\u0027: {resource: 2}}"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"        mock_count.side_effect \u003d fake_count"},{"line_number":166,"context_line":"        deltas \u003d {\u0027key_pairs\u0027: 1, \u0027server_group_members\u0027: 1}"},{"line_number":167,"context_line":"        project_id \u003d \u0027fake-other-project\u0027"},{"line_number":168,"context_line":"        user_id \u003d \u0027fake-other-user\u0027"},{"line_number":169,"context_line":"        quotas_obj.Quotas.check_deltas(self.context, deltas,"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_f70dd735","line":166,"range":{"start_line":166,"start_character":34,"end_line":166,"end_character":60},"in_reply_to":"ff0f0b1f_c96b5d83","updated":"2017-05-25 20:21:14.000000000","message":"Negative deltas aren\u0027t a thing anymore because we\u0027re counting resources and there\u0027s no \"usage record\" to update to decrement. That is, no quota operations happen when you delete a resource (like delete an instance, key pair, etc), the object is deleted from the database and then no longer counted.\n\nI can\u0027t think of a use case for providing a negative delta, so I guess that should be an error condition and we should have an exception for that.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"f2eb0675874d2b96d3318a8998de685b0d16c738","unresolved":false,"context_lines":[{"line_number":163,"context_line":"            return {\u0027user\u0027: {resource: 2}}"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"        mock_count.side_effect \u003d fake_count"},{"line_number":166,"context_line":"        deltas \u003d {\u0027key_pairs\u0027: 1, \u0027server_group_members\u0027: 1}"},{"line_number":167,"context_line":"        project_id \u003d \u0027fake-other-project\u0027"},{"line_number":168,"context_line":"        user_id \u003d \u0027fake-other-user\u0027"},{"line_number":169,"context_line":"        quotas_obj.Quotas.check_deltas(self.context, deltas,"}],"source_content_type":"text/x-python","patch_set":9,"id":"df140735_5c51510e","line":166,"range":{"start_line":166,"start_character":34,"end_line":166,"end_character":60},"in_reply_to":"ff0f0b1f_f70dd735","updated":"2017-05-27 14:01:35.000000000","message":"Ah nice, didn\u0027t think about that, but that makes things simpler.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"96473caf2f29c20a026fe439034968b5f6a866f8","unresolved":false,"context_lines":[{"line_number":163,"context_line":"            return {\u0027user\u0027: {resource: 2}}"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"        mock_count.side_effect \u003d fake_count"},{"line_number":166,"context_line":"        deltas \u003d {\u0027key_pairs\u0027: 1, \u0027server_group_members\u0027: 1}"},{"line_number":167,"context_line":"        project_id \u003d \u0027fake-other-project\u0027"},{"line_number":168,"context_line":"        user_id \u003d \u0027fake-other-user\u0027"},{"line_number":169,"context_line":"        quotas_obj.Quotas.check_deltas(self.context, deltas,"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_97121bb4","line":166,"range":{"start_line":166,"start_character":34,"end_line":166,"end_character":60},"in_reply_to":"ff0f0b1f_f70dd735","updated":"2017-05-25 20:43:32.000000000","message":"Meh, I\u0027ll just add a test for the negative delta even though I can\u0027t think of why anyone would want to do it.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":191,"context_line":"        mock_count.side_effect \u003d fake_count"},{"line_number":192,"context_line":"        deltas \u003d {\u0027key_pairs\u0027: 0, \u0027server_group_members\u0027: 0}"},{"line_number":193,"context_line":"        project_id \u003d \u0027fake-other-project\u0027"},{"line_number":194,"context_line":"        user_id \u003d \u0027fake-other-user\u0027"},{"line_number":195,"context_line":"        self.assertRaises(exception.OverQuota, quotas_obj.Quotas.check_deltas,"},{"line_number":196,"context_line":"                          self.context, deltas,"},{"line_number":197,"context_line":"                          check_project_id\u003dproject_id,"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_09203549","line":194,"updated":"2017-05-25 17:59:06.000000000","message":"Maybe good to have a test where user_id isn\u0027t passed in, as it\u0027s optional and not used/needed in most cases I thought.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"50207133ed03a9a1cb5d2ffae5b82b207b290db0","unresolved":false,"context_lines":[{"line_number":191,"context_line":"        mock_count.side_effect \u003d fake_count"},{"line_number":192,"context_line":"        deltas \u003d {\u0027key_pairs\u0027: 0, \u0027server_group_members\u0027: 0}"},{"line_number":193,"context_line":"        project_id \u003d \u0027fake-other-project\u0027"},{"line_number":194,"context_line":"        user_id \u003d \u0027fake-other-user\u0027"},{"line_number":195,"context_line":"        self.assertRaises(exception.OverQuota, quotas_obj.Quotas.check_deltas,"},{"line_number":196,"context_line":"                          self.context, deltas,"},{"line_number":197,"context_line":"                          check_project_id\u003dproject_id,"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_7779c791","line":194,"in_reply_to":"ff0f0b1f_09203549","updated":"2017-05-25 20:21:14.000000000","message":"Yeah, good point. We want to verify whether these get passed along as expected to limit_check_project_and_user.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b8e58219bc903b2b23741f6de05c19e3638d499e","unresolved":false,"context_lines":[{"line_number":232,"context_line":"        mock_count.assert_has_calls([call1, call2], any_order\u003dTrue)"},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"    @mock.patch(\u0027nova.objects.Quotas.count_as_dict\u0027)"},{"line_number":235,"context_line":"    def test_check_deltas_negative(self, mock_count):"},{"line_number":236,"context_line":"        self.flags(key_pairs\u003d3, group\u003d\u0027quota\u0027)"},{"line_number":237,"context_line":"        mock_count.return_value \u003d {\u0027user\u0027: {\u0027key_pairs\u0027: 4}}"},{"line_number":238,"context_line":"        deltas \u003d {\u0027key_pairs\u0027: -1}"}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_1ca999de","line":235,"range":{"start_line":235,"start_character":8,"end_line":235,"end_character":34},"updated":"2017-05-27 14:14:22.000000000","message":"Based on your previous comment, it might be worth putting a docstring in this one explaining negative deltas aren\u0027t a thing in the brave new world of counting quotas, but this is here as a sanity check.","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7861577ff19cfa5f2ff1e387bbf0b854a547b294","unresolved":false,"context_lines":[{"line_number":232,"context_line":"        mock_count.assert_has_calls([call1, call2], any_order\u003dTrue)"},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"    @mock.patch(\u0027nova.objects.Quotas.count_as_dict\u0027)"},{"line_number":235,"context_line":"    def test_check_deltas_negative(self, mock_count):"},{"line_number":236,"context_line":"        self.flags(key_pairs\u003d3, group\u003d\u0027quota\u0027)"},{"line_number":237,"context_line":"        mock_count.return_value \u003d {\u0027user\u0027: {\u0027key_pairs\u0027: 4}}"},{"line_number":238,"context_line":"        deltas \u003d {\u0027key_pairs\u0027: -1}"}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_6d18ddd2","line":235,"range":{"start_line":235,"start_character":8,"end_line":235,"end_character":34},"in_reply_to":"df140735_1ca999de","updated":"2017-05-28 00:53:06.000000000","message":"Ack, can do that.","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"950fc2fbb513907566bdf641f3ddcca5c7da7bdc","unresolved":false,"context_lines":[{"line_number":235,"context_line":"    def test_check_deltas_negative(self, mock_count):"},{"line_number":236,"context_line":"        \"\"\"Test check_deltas with a negative delta."},{"line_number":237,"context_line":""},{"line_number":238,"context_line":"        Negative deltas probably won\u0027t be used going forward for countable"},{"line_number":239,"context_line":"        resources because there are no usage records to decrement and there"},{"line_number":240,"context_line":"        won\u0027t be quota operations done when deleting resources. When resources"},{"line_number":241,"context_line":"        are deleted, they will no longer be reflected in the count."},{"line_number":242,"context_line":"        \"\"\""},{"line_number":243,"context_line":"        self.flags(key_pairs\u003d3, group\u003d\u0027quota\u0027)"},{"line_number":244,"context_line":"        mock_count.return_value \u003d {\u0027user\u0027: {\u0027key_pairs\u0027: 4}}"}],"source_content_type":"text/x-python","patch_set":12,"id":"df140735_7e6629f0","line":241,"range":{"start_line":238,"start_character":8,"end_line":241,"end_character":67},"updated":"2017-05-30 01:23:23.000000000","message":"nit: this begs the question, then why are we testing this? I think this is sanity checking? Might be worth addressing that if you need to respin.","commit_id":"832cc4709f3c4389caf49f54c5f5f6a4e8ec32ea"}],"nova/tests/unit/test_quota.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8c0224e61a4631665cf6b890135a2262e7312e2e","unresolved":false,"context_lines":[{"line_number":1028,"context_line":"            FakeContext(\u0027test_project\u0027, \u0027test_class\u0027), resources,"},{"line_number":1029,"context_line":"            \u0027test_project\u0027)"},{"line_number":1030,"context_line":"        # key_pairs, server_group_members, and security_group_rules are never"},{"line_number":1031,"context_line":"        # counted as a usage. Their counts are only for quota limit checking."},{"line_number":1032,"context_line":"        expected \u003d {\u0027key_pairs\u0027: {\u0027in_use\u0027: 0},"},{"line_number":1033,"context_line":"                    \u0027instances\u0027: {\u0027in_use\u0027: 2},"},{"line_number":1034,"context_line":"                    \u0027cores\u0027: {\u0027in_use\u0027: 4},"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_bf0fb8df","line":1031,"updated":"2017-04-26 18:45:22.000000000","message":"I\u0027m actually not sure why key pairs, server group members and security group rules are not counted \"as a usage\". Maybe because the quotas on those things were never really quotas but rather rate-limiting controls to prevent DDoS attacks. :(","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"f6b8fca4be9a9420084440c7dc77e62d9df432b3","unresolved":false,"context_lines":[{"line_number":1028,"context_line":"            FakeContext(\u0027test_project\u0027, \u0027test_class\u0027), resources,"},{"line_number":1029,"context_line":"            \u0027test_project\u0027)"},{"line_number":1030,"context_line":"        # key_pairs, server_group_members, and security_group_rules are never"},{"line_number":1031,"context_line":"        # counted as a usage. Their counts are only for quota limit checking."},{"line_number":1032,"context_line":"        expected \u003d {\u0027key_pairs\u0027: {\u0027in_use\u0027: 0},"},{"line_number":1033,"context_line":"                    \u0027instances\u0027: {\u0027in_use\u0027: 2},"},{"line_number":1034,"context_line":"                    \u0027cores\u0027: {\u0027in_use\u0027: 4},"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_beadc332","line":1031,"in_reply_to":"5ff73747_0360e031","updated":"2017-05-03 18:27:10.000000000","message":"Yeah, I looked at just adding their usages into the mix but it\u0027s not straightforward since they\u0027re counting functions don\u0027t match the pattern of the other ones.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"cb9b8fcba1421222f2f71d6a36b6ea3624b0b84b","unresolved":false,"context_lines":[{"line_number":1028,"context_line":"            FakeContext(\u0027test_project\u0027, \u0027test_class\u0027), resources,"},{"line_number":1029,"context_line":"            \u0027test_project\u0027)"},{"line_number":1030,"context_line":"        # key_pairs, server_group_members, and security_group_rules are never"},{"line_number":1031,"context_line":"        # counted as a usage. Their counts are only for quota limit checking."},{"line_number":1032,"context_line":"        expected \u003d {\u0027key_pairs\u0027: {\u0027in_use\u0027: 0},"},{"line_number":1033,"context_line":"                    \u0027instances\u0027: {\u0027in_use\u0027: 2},"},{"line_number":1034,"context_line":"                    \u0027cores\u0027: {\u0027in_use\u0027: 4},"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_0360e031","line":1031,"in_reply_to":"5ff73747_03e100ff","updated":"2017-05-03 17:50:04.000000000","message":"Is this not just a scope thing?\n\nthey are counted at a different scope to where the limit is set, i.e. key_pairs are counted per user. server_group_members are counted per server_group.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"4102da34ee386a6296c2d31bafe2105d7cf02b8d","unresolved":false,"context_lines":[{"line_number":1028,"context_line":"            FakeContext(\u0027test_project\u0027, \u0027test_class\u0027), resources,"},{"line_number":1029,"context_line":"            \u0027test_project\u0027)"},{"line_number":1030,"context_line":"        # key_pairs, server_group_members, and security_group_rules are never"},{"line_number":1031,"context_line":"        # counted as a usage. Their counts are only for quota limit checking."},{"line_number":1032,"context_line":"        expected \u003d {\u0027key_pairs\u0027: {\u0027in_use\u0027: 0},"},{"line_number":1033,"context_line":"                    \u0027instances\u0027: {\u0027in_use\u0027: 2},"},{"line_number":1034,"context_line":"                    \u0027cores\u0027: {\u0027in_use\u0027: 4},"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_d5d5c544","line":1031,"in_reply_to":"5ff73747_bf0fb8df","updated":"2017-04-26 19:32:21.000000000","message":"Yeah, I realized while working on quota counting that keypair count for example, is never represented in the used_limits API. It\u0027s always 0 even when you have some keypairs. I implemented the new stuff so as not to change the existing behavior.\n\nThey are quotas in that if you have keypairs quota of 5, you can\u0027t create more than 5 keypairs. But they don\u0027t show up as \u0027in_use\u0027 in the used_limits API. Maybe it wasn\u0027t intentional.","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"59eda916226c9a49012d1b35693e7ad9c42a979c","unresolved":false,"context_lines":[{"line_number":1028,"context_line":"            FakeContext(\u0027test_project\u0027, \u0027test_class\u0027), resources,"},{"line_number":1029,"context_line":"            \u0027test_project\u0027)"},{"line_number":1030,"context_line":"        # key_pairs, server_group_members, and security_group_rules are never"},{"line_number":1031,"context_line":"        # counted as a usage. Their counts are only for quota limit checking."},{"line_number":1032,"context_line":"        expected \u003d {\u0027key_pairs\u0027: {\u0027in_use\u0027: 0},"},{"line_number":1033,"context_line":"                    \u0027instances\u0027: {\u0027in_use\u0027: 2},"},{"line_number":1034,"context_line":"                    \u0027cores\u0027: {\u0027in_use\u0027: 4},"}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff73747_03e100ff","line":1031,"in_reply_to":"5ff73747_d5d5c544","updated":"2017-05-03 17:40:15.000000000","message":"Yeah, highly unlikely that isn\u0027t a bug :)","commit_id":"0e2e3a8ebcef6b7dd99d8c41f802793d16801ceb"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"9cb4a5d598e0b7234e15374262869b3f62009dcf","unresolved":false,"context_lines":[{"line_number":236,"context_line":"        self.assertRaises(exception.QuotaError,"},{"line_number":237,"context_line":"                          self._create_with_injected_files, files)"},{"line_number":238,"context_line":""},{"line_number":239,"context_line":""},{"line_number":240,"context_line":"@enginefacade.transaction_context_provider"},{"line_number":241,"context_line":"class FakeContext(context.RequestContext):"},{"line_number":242,"context_line":"    def __init__(self, project_id, quota_class):"}],"source_content_type":"text/x-python","patch_set":7,"id":"ff0f0b1f_91262bce","line":239,"updated":"2017-05-22 15:18:59.000000000","message":"Looks like this was accidentally removed.","commit_id":"30b61b07f87af0a8ab163112658755354b08d528"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":236,"context_line":"        self.assertRaises(exception.QuotaError,"},{"line_number":237,"context_line":"                          self._create_with_injected_files, files)"},{"line_number":238,"context_line":""},{"line_number":239,"context_line":"    def test_reservation_expire(self):"},{"line_number":240,"context_line":"        self.useFixture(test.TimeOverride())"},{"line_number":241,"context_line":""},{"line_number":242,"context_line":"        def assertInstancesReserved(reserved):"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_89ba05df","side":"PARENT","line":239,"range":{"start_line":239,"start_character":8,"end_line":239,"end_character":31},"updated":"2017-05-25 17:59:06.000000000","message":"Why is this removed?","commit_id":"bedcf29e4586a755353b7844f8e11173e0892729"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"d9da65e2931a297ce0460232cad25c06345eda11","unresolved":false,"context_lines":[{"line_number":1070,"context_line":"    @mock.patch(\u0027nova.quota.DbQuotaDriver._get_usages\u0027)"},{"line_number":1071,"context_line":"    def test_get_user_quotas(self, mock_get_usages):"},{"line_number":1072,"context_line":""},{"line_number":1073,"context_line":"        def fake_get_usages(*a, **k):"},{"line_number":1074,"context_line":"            # These values are not realistic (they should all be 0) and are"},{"line_number":1075,"context_line":"            # only for testing that countable usages get included in the"},{"line_number":1076,"context_line":"            # results."},{"line_number":1077,"context_line":"            return {\u0027security_group_rules\u0027: {\u0027in_use\u0027: 1},"},{"line_number":1078,"context_line":"                    \u0027key_pairs\u0027: {\u0027in_use\u0027: 2},"},{"line_number":1079,"context_line":"                    \u0027server_group_members\u0027: {\u0027in_use\u0027: 3}}"},{"line_number":1080,"context_line":""},{"line_number":1081,"context_line":"        mock_get_usages.side_effect \u003d fake_get_usages"},{"line_number":1082,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_6992114e","line":1079,"range":{"start_line":1073,"start_character":8,"end_line":1079,"end_character":58},"updated":"2017-05-25 17:59:06.000000000","message":"This is repeated in several tests, can we pull it into a module-level method and just re-use it from there? I see that in some tests the values are the same, but you could pass a special kwarg to toggle that behavior, like in_use_zero\u003dFalse or something and then pop that off the kwargs.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"50207133ed03a9a1cb5d2ffae5b82b207b290db0","unresolved":false,"context_lines":[{"line_number":1070,"context_line":"    @mock.patch(\u0027nova.quota.DbQuotaDriver._get_usages\u0027)"},{"line_number":1071,"context_line":"    def test_get_user_quotas(self, mock_get_usages):"},{"line_number":1072,"context_line":""},{"line_number":1073,"context_line":"        def fake_get_usages(*a, **k):"},{"line_number":1074,"context_line":"            # These values are not realistic (they should all be 0) and are"},{"line_number":1075,"context_line":"            # only for testing that countable usages get included in the"},{"line_number":1076,"context_line":"            # results."},{"line_number":1077,"context_line":"            return {\u0027security_group_rules\u0027: {\u0027in_use\u0027: 1},"},{"line_number":1078,"context_line":"                    \u0027key_pairs\u0027: {\u0027in_use\u0027: 2},"},{"line_number":1079,"context_line":"                    \u0027server_group_members\u0027: {\u0027in_use\u0027: 3}}"},{"line_number":1080,"context_line":""},{"line_number":1081,"context_line":"        mock_get_usages.side_effect \u003d fake_get_usages"},{"line_number":1082,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ff0f0b1f_17adebe9","line":1079,"range":{"start_line":1073,"start_character":8,"end_line":1079,"end_character":58},"in_reply_to":"ff0f0b1f_6992114e","updated":"2017-05-25 20:21:14.000000000","message":"Yeah, can do that.","commit_id":"29944c06e1b151cd7cdcf0b4a233cab1c3238436"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b8e58219bc903b2b23741f6de05c19e3638d499e","unresolved":false,"context_lines":[{"line_number":1088,"context_line":"                    \u0027security_group_rules\u0027: {\u0027in_use\u0027: 0}}"},{"line_number":1089,"context_line":"        self.assertEqual(expected, actual)"},{"line_number":1090,"context_line":""},{"line_number":1091,"context_line":"    def _get_fake_get_usages(self, updates\u003dNone):"},{"line_number":1092,"context_line":"        # These values are not realistic (they should all be 0) and are"},{"line_number":1093,"context_line":"        # only for testing that countable usages get included in the"},{"line_number":1094,"context_line":"        # results."}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_1c82b950","line":1091,"updated":"2017-05-27 14:14:22.000000000","message":"nit: this could be module-level scoped since self isn\u0027t used. Then in all of your mocks that use this, in the decorator mock form, you can just do side_effect\u003d_get_fake_get_usages, so you don\u0027t need the additional self.mock_get_usages \u003d self._get_fake_get_usages.\n\nMostly a style thing for me.","commit_id":"29284591eb6223e947f65323770a14c69c32b173"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7861577ff19cfa5f2ff1e387bbf0b854a547b294","unresolved":false,"context_lines":[{"line_number":1088,"context_line":"                    \u0027security_group_rules\u0027: {\u0027in_use\u0027: 0}}"},{"line_number":1089,"context_line":"        self.assertEqual(expected, actual)"},{"line_number":1090,"context_line":""},{"line_number":1091,"context_line":"    def _get_fake_get_usages(self, updates\u003dNone):"},{"line_number":1092,"context_line":"        # These values are not realistic (they should all be 0) and are"},{"line_number":1093,"context_line":"        # only for testing that countable usages get included in the"},{"line_number":1094,"context_line":"        # results."}],"source_content_type":"text/x-python","patch_set":10,"id":"df140735_2d12e5b2","line":1091,"in_reply_to":"df140735_1c82b950","updated":"2017-05-28 00:53:06.000000000","message":"K, can do that.","commit_id":"29284591eb6223e947f65323770a14c69c32b173"}]}
