)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":2218,"name":"Adam Young","email":"adam@younglogic.com","username":"ayoung"},"change_message_id":"38e9f130f2ccaab3f8a8006234544276c12e8c76","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add domain_id to the user table"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"All users (included federated) should belong to a single domain."},{"line_number":10,"context_line":"Currently, the domain is being populated in the local_user and"},{"line_number":11,"context_line":"nonlocal_user (ldap) tables. However, it isn\u0027t being set for"},{"line_number":12,"context_line":"federated users. This patch moves the domain_id up to the user table,"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":37,"id":"7a3c09a3_4cf190cc","line":9,"updated":"2017-01-18 01:33:29.000000000","message":"remove the word \u0027single.\u0027 All users should belong to some domain. Better to say there is a required one-to-many relatinship between domain and users.","commit_id":"1e827d1a335ce991268f1bd3e08d01e7b80e3334"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"5bcbc6f417926283f3892c3445a84b2557bf4d93","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add domain_id to the user table"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"All users (included federated) should belong to a single domain."},{"line_number":10,"context_line":"Currently, the domain is being populated in the local_user and"},{"line_number":11,"context_line":"nonlocal_user (ldap) tables. However, it isn\u0027t being set for"},{"line_number":12,"context_line":"federated users. This patch moves the domain_id up to the user table,"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":37,"id":"7a3c09a3_8715119d","line":9,"in_reply_to":"7a3c09a3_4cf190cc","updated":"2017-01-18 02:10:02.000000000","message":"Done, however it is a 1:1 relationship, isn\u0027t it? A user is only created within a single domain (currently). I recognize that it\u0027s likely that this could change in the future.","commit_id":"1e827d1a335ce991268f1bd3e08d01e7b80e3334"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":25,"context_line":"| (pk) id        |"},{"line_number":26,"context_line":"| (fk) user_id   |"},{"line_number":27,"context_line":"| (fk) domain_id |"},{"line_number":28,"context_line":"+----------------+"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"This will allow us to set the domain_id in the user table and ensure"},{"line_number":31,"context_line":"that it is in sync with the local_user and nonlocal_user tables, such"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":46,"id":"5a3905b3_5db22c95","line":28,"updated":"2017-01-23 16:58:01.000000000","message":"note here for clarity that you are creating a UNIQUE constraint on user (id, domain_id) otherwise this composite FK would not be possible.  Why is the PK of user not (id, domain_id) ?","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"bf85319c2c610f86233f836f1a9a1fe51a73e6d3","unresolved":false,"context_lines":[{"line_number":25,"context_line":"| (pk) id        |"},{"line_number":26,"context_line":"| (fk) user_id   |"},{"line_number":27,"context_line":"| (fk) domain_id |"},{"line_number":28,"context_line":"+----------------+"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"This will allow us to set the domain_id in the user table and ensure"},{"line_number":31,"context_line":"that it is in sync with the local_user and nonlocal_user tables, such"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":46,"id":"5a3905b3_8fcd3133","line":28,"in_reply_to":"5a3905b3_5db22c95","updated":"2017-01-23 18:40:12.000000000","message":"Done","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"f4667292b970d36af70e45fbc71833a04f61dcf0","unresolved":false,"context_lines":[{"line_number":25,"context_line":"| (pk) id        |"},{"line_number":26,"context_line":"| (fk) user_id   |"},{"line_number":27,"context_line":"| (fk) domain_id |"},{"line_number":28,"context_line":"+----------------+"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"This will allow us to set the domain_id in the user table and ensure"},{"line_number":31,"context_line":"that it is in sync with the local_user and nonlocal_user tables, such"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":46,"id":"5a3905b3_98e741ab","line":28,"in_reply_to":"5a3905b3_5db22c95","updated":"2017-01-23 17:13:26.000000000","message":"Yes, creating the unique constraint for the composite fk. The reason the pk is not (id, domain_id) is for current referential integrity, which is based on the id.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"}],"keystone/common/sql/contract_repo/versions/014_contract_add_domain_id_to_user.py":[{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"bfc2f74a25c6c5b68a823edbd41af835b90e7a7b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":38,"id":"5a3905b3_933ee9b6","updated":"2017-01-19 13:32:57.000000000","message":"remove \"contract\" from the file name","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"d131c344e32095554546a380d65138d42a432210","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":38,"id":"5a3905b3_770c0495","in_reply_to":"5a3905b3_933ee9b6","updated":"2017-01-19 14:50:10.000000000","message":"If the files are the files are not unique, I get the below error, where I\u0027m doing an expand, yet it\u0027s calling the file in the contract repo. This was an issue we had early on when we created the 3 repos.\n\nTraceback (most recent call last):\n  File \"keystone/tests/unit/test_sql_upgrade.py\", line 1964, in test_migration_013_contract_add_domain_id_to_user\n    self.expand(13)\n  File \"keystone/tests/unit/test_sql_upgrade.py\", line 228, in expand\n    self.repos[EXPAND_REPO].upgrade(*args, **kwargs)\n  File \"keystone/common/sql/upgrades.py\", line 63, in upgrade\n    self.schema_.runchange(ver, change, changeset.step)\n  File \"/home/jenkins/workspace/gate-keystone-python27-db-ubuntu-xenial/.tox/py27/local/lib/python2.7/site-packages/migrate/versioning/schema.py\", line 93, in runchange\n    change.run(self.engine, step)\n  File \"/home/jenkins/workspace/gate-keystone-python27-db-ubuntu-xenial/.tox/py27/local/lib/python2.7/site-packages/migrate/versioning/script/py.py\", line 148, in run\n    script_func(engine)\n  File \"/home/jenkins/workspace/gate-keystone-python27-db-ubuntu-xenial/keystone/common/sql/contract_repo/versions/013_add_domain_id_to_user.py\", line 43, in upgrade\n    migrate.UniqueConstraint(user.c.id, user.c.domain_id,\n  File \"/home/jenkins/workspace/gate-keystone-python27-db-ubuntu-xenial/.tox/py27/local/lib/python2.7/site-packages/sqlalchemy/util/_collections.py\", line 212, in __getattr__\n    raise AttributeError(key)\nAttributeError: domain_id","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ff9457db72be175b9f5704d5c8a92d778ce22545","unresolved":false,"context_lines":[{"line_number":27,"context_line":"    nonlocal_user \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"    # drop previous fk constraints"},{"line_number":30,"context_line":"    fk_name \u003d _get_fk_name(inspector, \u0027local_user\u0027, \u0027user_id\u0027)"},{"line_number":31,"context_line":"    if fk_name:"},{"line_number":32,"context_line":"        migrate.ForeignKeyConstraint(columns\u003d[local_user.c.user_id],"},{"line_number":33,"context_line":"                                     refcolumns\u003d[user.c.id],"}],"source_content_type":"text/x-python","patch_set":38,"id":"7a3c09a3_641c6314","line":30,"updated":"2017-01-18 21:47:32.000000000","message":"Why don\u0027t we need this anymore? User IDs should be unique whether or not they are in the user table or the local_user table or the nonlocal_user table, right?","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3a1b5f8bba4aad893b55491597540bdebe5d4052","unresolved":false,"context_lines":[{"line_number":27,"context_line":"    nonlocal_user \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"    # drop previous fk constraints"},{"line_number":30,"context_line":"    fk_name \u003d _get_fk_name(inspector, \u0027local_user\u0027, \u0027user_id\u0027)"},{"line_number":31,"context_line":"    if fk_name:"},{"line_number":32,"context_line":"        migrate.ForeignKeyConstraint(columns\u003d[local_user.c.user_id],"},{"line_number":33,"context_line":"                                     refcolumns\u003d[user.c.id],"}],"source_content_type":"text/x-python","patch_set":38,"id":"5a3905b3_2dc16d81","line":30,"in_reply_to":"7a3c09a3_641c6314","updated":"2017-01-19 01:36:53.000000000","message":"User IDs will be unique, but now I\u0027m combining it with the domain_id to create a composite foreign key constraint. Thus, user_id + domain_id will still enforce uniqueness in the local_user and nonlocal_user tables. So the current fk is not needed and I don\u0027t think you can have multiple fk constraints on the same column.","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ff9457db72be175b9f5704d5c8a92d778ce22545","unresolved":false,"context_lines":[{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    # create user unique constraint needed for the new composite fk constraint"},{"line_number":43,"context_line":"    migrate.UniqueConstraint(user.c.id, user.c.domain_id,"},{"line_number":44,"context_line":"                             name\u003d\u0027ixu_user_id_domain_id\u0027).create()"},{"line_number":45,"context_line":"    # create new composite fk constraints"},{"line_number":46,"context_line":"    migrate.ForeignKeyConstraint("},{"line_number":47,"context_line":"        columns\u003d[local_user.c.user_id, local_user.c.domain_id],"}],"source_content_type":"text/x-python","patch_set":38,"id":"7a3c09a3_84f06fcb","line":44,"updated":"2017-01-18 21:47:32.000000000","message":"Does each type of user support the a name attribute? If so, do we need to have a constraint that enforces user names are unique within a domain in order to be backwards compatible?","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3a1b5f8bba4aad893b55491597540bdebe5d4052","unresolved":false,"context_lines":[{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    # create user unique constraint needed for the new composite fk constraint"},{"line_number":43,"context_line":"    migrate.UniqueConstraint(user.c.id, user.c.domain_id,"},{"line_number":44,"context_line":"                             name\u003d\u0027ixu_user_id_domain_id\u0027).create()"},{"line_number":45,"context_line":"    # create new composite fk constraints"},{"line_number":46,"context_line":"    migrate.ForeignKeyConstraint("},{"line_number":47,"context_line":"        columns\u003d[local_user.c.user_id, local_user.c.domain_id],"}],"source_content_type":"text/x-python","patch_set":38,"id":"5a3905b3_ede12500","line":44,"in_reply_to":"7a3c09a3_84f06fcb","updated":"2017-01-19 01:36:53.000000000","message":"local_user and nonlocal_user have a unique constraint with domain_id, which yes, is needed to be backwards compatible. federated_user has unique_id, that is unique within the IdP. At one point I was trying to generalize this into a single table, but it didn\u0027t work in some scenarios.","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"}],"keystone/common/sql/contract_repo/versions/014_contract_add_domain_id_to_user_table.py":[{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    # drop triggers"},{"line_number":56,"context_line":"    if upgrades.USE_TRIGGERS:"},{"line_number":57,"context_line":"        if migrate_engine.name \u003d\u003d \u0027postgresql\u0027:"},{"line_number":58,"context_line":"            drop_local_user_insert_trigger \u003d ("},{"line_number":59,"context_line":"                \u0027DROP TRIGGER local_user_after_insert_trigger on local_user;\u0027)"},{"line_number":60,"context_line":"            drop_local_user_update_trigger \u003d ("}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_552f643e","line":57,"updated":"2017-01-23 16:58:01.000000000","message":"stylistically, I\u0027d have made a drop_trigger() function and used oslo.db\u0027s dispatch_for() feature: http://docs.openstack.org/developer/oslo.db/api/oslo_db.sqlalchemy.utils.html#oslo_db.sqlalchemy.utils.DialectFunctionDispatcher.dispatch_for   would greatly reduce the verbosity here","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":59,"context_line":"                \u0027DROP TRIGGER local_user_after_insert_trigger on local_user;\u0027)"},{"line_number":60,"context_line":"            drop_local_user_update_trigger \u003d ("},{"line_number":61,"context_line":"                \u0027DROP TRIGGER local_user_after_update_trigger on local_user;\u0027)"},{"line_number":62,"context_line":"            drop_nonlocal_user_insert_trigger \u003d ("},{"line_number":63,"context_line":"                \u0027DROP TRIGGER nonlocal_user_after_insert_trigger \u0027)"},{"line_number":64,"context_line":"            drop_nonlocal_user_insert_trigger +\u003d \u0027on nonlocal_user;\u0027"},{"line_number":65,"context_line":"            drop_nonlocal_user_update_trigger \u003d ("}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_151ddc65","line":62,"updated":"2017-01-23 16:58:01.000000000","message":"this is hard to read, why not assign the variable in one statement ?  \n\n\tdrop_nonlocal_user_insert_trigger \u003d (\n\t    \u0027DROP TRIGGER nonlocal_user_after_insert_trigger \u0027\n\t    \u0027on nonlocal_user;\n\t)","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"f4667292b970d36af70e45fbc71833a04f61dcf0","unresolved":false,"context_lines":[{"line_number":59,"context_line":"                \u0027DROP TRIGGER local_user_after_insert_trigger on local_user;\u0027)"},{"line_number":60,"context_line":"            drop_local_user_update_trigger \u003d ("},{"line_number":61,"context_line":"                \u0027DROP TRIGGER local_user_after_update_trigger on local_user;\u0027)"},{"line_number":62,"context_line":"            drop_nonlocal_user_insert_trigger \u003d ("},{"line_number":63,"context_line":"                \u0027DROP TRIGGER nonlocal_user_after_insert_trigger \u0027)"},{"line_number":64,"context_line":"            drop_nonlocal_user_insert_trigger +\u003d \u0027on nonlocal_user;\u0027"},{"line_number":65,"context_line":"            drop_nonlocal_user_update_trigger \u003d ("}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_9b081b2a","line":62,"in_reply_to":"5a3905b3_151ddc65","updated":"2017-01-23 17:13:26.000000000","message":"++","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"1f2921ae64901cf6837b4b2f06c6d4ff33ce9496","unresolved":false,"context_lines":[{"line_number":59,"context_line":"                \u0027DROP TRIGGER local_user_after_insert_trigger on local_user;\u0027)"},{"line_number":60,"context_line":"            drop_local_user_update_trigger \u003d ("},{"line_number":61,"context_line":"                \u0027DROP TRIGGER local_user_after_update_trigger on local_user;\u0027)"},{"line_number":62,"context_line":"            drop_nonlocal_user_insert_trigger \u003d ("},{"line_number":63,"context_line":"                \u0027DROP TRIGGER nonlocal_user_after_insert_trigger \u0027)"},{"line_number":64,"context_line":"            drop_nonlocal_user_insert_trigger +\u003d \u0027on nonlocal_user;\u0027"},{"line_number":65,"context_line":"            drop_nonlocal_user_update_trigger \u003d ("}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_29c43d3e","line":62,"in_reply_to":"5a3905b3_151ddc65","updated":"2017-01-23 18:36:54.000000000","message":"Done","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":91,"context_line":""},{"line_number":92,"context_line":"def _get_fk_name(inspector, table, fk_column):"},{"line_number":93,"context_line":"    for fk in inspector.get_foreign_keys(table):"},{"line_number":94,"context_line":"        if fk_column in fk[\u0027constrained_columns\u0027]:"},{"line_number":95,"context_line":"            return fk[\u0027name\u0027]"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_3d3e40da","line":94,"updated":"2017-01-23 16:58:01.000000000","message":"keystone not using naming conventions for constraints?","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"f4667292b970d36af70e45fbc71833a04f61dcf0","unresolved":false,"context_lines":[{"line_number":91,"context_line":""},{"line_number":92,"context_line":"def _get_fk_name(inspector, table, fk_column):"},{"line_number":93,"context_line":"    for fk in inspector.get_foreign_keys(table):"},{"line_number":94,"context_line":"        if fk_column in fk[\u0027constrained_columns\u0027]:"},{"line_number":95,"context_line":"            return fk[\u0027name\u0027]"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_9b6d7bce","line":94,"in_reply_to":"5a3905b3_3d3e40da","updated":"2017-01-23 17:13:26.000000000","message":"No, not guaranteed.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"713c2d7783e029d1e6351a4d7773eea93f9039a4","unresolved":false,"context_lines":[{"line_number":91,"context_line":""},{"line_number":92,"context_line":"def _get_fk_name(inspector, table, fk_column):"},{"line_number":93,"context_line":"    for fk in inspector.get_foreign_keys(table):"},{"line_number":94,"context_line":"        if fk_column in fk[\u0027constrained_columns\u0027]:"},{"line_number":95,"context_line":"            return fk[\u0027name\u0027]"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_1b818b8f","line":94,"in_reply_to":"5a3905b3_9b6d7bce","updated":"2017-01-23 17:25:29.000000000","message":"so SQLAlchemy now has a feature to ensure a name is created for constraints, but if keystone isn\u0027t using that it would be a good idea to give them names so that we don\u0027t need to do this kind of fishing","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"9c11d98b63320ae1a0493f410c69fc276fdf0c10","unresolved":false,"context_lines":[{"line_number":17,"context_line":"from keystone.common.sql import upgrades"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"def upgrade(migrate_engine):"},{"line_number":21,"context_line":"    meta \u003d sql.MetaData()"},{"line_number":22,"context_line":"    meta.bind \u003d migrate_engine"},{"line_number":23,"context_line":"    inspector \u003d reflection.Inspector.from_engine(migrate_engine)"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_3c29abe6","line":20,"updated":"2017-01-24 15:37:23.000000000","message":"Should the user.domain_id be change to not nullable in here?","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"5a5f382d13ada51454a4aa7d2e8b9e7ee69b659d","unresolved":false,"context_lines":[{"line_number":17,"context_line":"from keystone.common.sql import upgrades"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"def upgrade(migrate_engine):"},{"line_number":21,"context_line":"    meta \u003d sql.MetaData()"},{"line_number":22,"context_line":"    meta.bind \u003d migrate_engine"},{"line_number":23,"context_line":"    inspector \u003d reflection.Inspector.from_engine(migrate_engine)"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_13221da3","line":20,"in_reply_to":"5a3905b3_3c29abe6","updated":"2017-01-24 15:42:12.000000000","message":"I just saw why in your federation review.","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"6fad65792c1f6a275b632f73e3676e2dee867073","unresolved":false,"context_lines":[{"line_number":50,"context_line":"    migrate.ForeignKeyConstraint("},{"line_number":51,"context_line":"        columns\u003d[nonlocal_user.c.user_id, nonlocal_user.c.domain_id],"},{"line_number":52,"context_line":"        refcolumns\u003d[user.c.id, user.c.domain_id],"},{"line_number":53,"context_line":"        onupdate\u003d\u0027CASCADE\u0027, ondelete\u003d\u0027CASCADE\u0027).create()"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    # drop triggers"},{"line_number":56,"context_line":"    if upgrades.USE_TRIGGERS:"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_e10a1cd1","line":53,"updated":"2017-01-24 15:05:43.000000000","message":"We have a race condition here where something could happen on the database after the previous fk constrain was removed and before the new composite fk constraint was created. Is there a way to create the composite one before we remove the old one and rename it so that we always have the constraint in place?","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"9c11d98b63320ae1a0493f410c69fc276fdf0c10","unresolved":false,"context_lines":[{"line_number":50,"context_line":"    migrate.ForeignKeyConstraint("},{"line_number":51,"context_line":"        columns\u003d[nonlocal_user.c.user_id, nonlocal_user.c.domain_id],"},{"line_number":52,"context_line":"        refcolumns\u003d[user.c.id, user.c.domain_id],"},{"line_number":53,"context_line":"        onupdate\u003d\u0027CASCADE\u0027, ondelete\u003d\u0027CASCADE\u0027).create()"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    # drop triggers"},{"line_number":56,"context_line":"    if upgrades.USE_TRIGGERS:"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_3042afae","line":53,"in_reply_to":"5a3905b3_3c98cb77","updated":"2017-01-24 15:37:23.000000000","message":"I think the risk here is really low. There would have to be a bug in the code or manual SQL inserts to trigger a race here.  The triggers should help with the bug since they control the data being inserted.","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"d1c58d4aabda4a9f0c25062f8949261a419e4544","unresolved":false,"context_lines":[{"line_number":50,"context_line":"    migrate.ForeignKeyConstraint("},{"line_number":51,"context_line":"        columns\u003d[nonlocal_user.c.user_id, nonlocal_user.c.domain_id],"},{"line_number":52,"context_line":"        refcolumns\u003d[user.c.id, user.c.domain_id],"},{"line_number":53,"context_line":"        onupdate\u003d\u0027CASCADE\u0027, ondelete\u003d\u0027CASCADE\u0027).create()"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    # drop triggers"},{"line_number":56,"context_line":"    if upgrades.USE_TRIGGERS:"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_3c98cb77","line":53,"in_reply_to":"5a3905b3_e10a1cd1","updated":"2017-01-24 15:17:32.000000000","message":"No, I can\u0027t create the new one before deleting the old one, as you can\u0027t have multiple fk constraints for the same column.","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"}],"keystone/common/sql/data_migration_repo/versions/014_migrate_add_domain_id_to_user.py":[{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"bfc2f74a25c6c5b68a823edbd41af835b90e7a7b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":38,"id":"5a3905b3_b34be558","updated":"2017-01-19 13:32:57.000000000","message":"remove \"migrate\" from the file name","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"}],"keystone/common/sql/data_migration_repo/versions/014_migrate_add_domain_id_to_user_table.py":[{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"bab7c7b7993504ca3d6f84f71fa7b7e341ef0613","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    nonlocal_user_table \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    # update the user.domain_id from the local_user table"},{"line_number":26,"context_line":"    local_users \u003d list(local_user_table.select().execute())"},{"line_number":27,"context_line":"    for local_user in local_users:"},{"line_number":28,"context_line":"        values \u003d {\u0027domain_id\u0027: local_user.domain_id}"},{"line_number":29,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_1edca211","line":26,"updated":"2017-01-19 22:09:26.000000000","message":"This will load all users in memory. Will this break for big installations? Should this be paginated?","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"7cce85da3c33e9eedc362e694764212f6fd05d8c","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    nonlocal_user_table \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    # update the user.domain_id from the local_user table"},{"line_number":26,"context_line":"    local_users \u003d list(local_user_table.select().execute())"},{"line_number":27,"context_line":"    for local_user in local_users:"},{"line_number":28,"context_line":"        values \u003d {\u0027domain_id\u0027: local_user.domain_id}"},{"line_number":29,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_3c1ec6ba","line":26,"in_reply_to":"5a3905b3_1edca211","updated":"2017-01-19 23:03:59.000000000","message":"Even if a deployer has millions of users, this shouldn\u0027t be an issue on standard hardware. It would just obviously take longer.","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3d922723fa7376c8fdd2228f684e31d4346359b3","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    nonlocal_user_table \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    # update the user.domain_id from the local_user table"},{"line_number":26,"context_line":"    local_users \u003d list(local_user_table.select().execute())"},{"line_number":27,"context_line":"    for local_user in local_users:"},{"line_number":28,"context_line":"        values \u003d {\u0027domain_id\u0027: local_user.domain_id}"},{"line_number":29,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_f93447fc","line":26,"in_reply_to":"5a3905b3_372d01a8","updated":"2017-01-20 02:24:53.000000000","message":"No, the update statements are happening for each record; auto-committing via sqlalchemy. And memory-wise, this should be fine. My preference would to not do any batching, but let me know if you feel strongly otherwise.","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"fcce9610a8bc3f17f5853bb4cc38e1b36070af05","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    nonlocal_user_table \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    # update the user.domain_id from the local_user table"},{"line_number":26,"context_line":"    local_users \u003d list(local_user_table.select().execute())"},{"line_number":27,"context_line":"    for local_user in local_users:"},{"line_number":28,"context_line":"        values \u003d {\u0027domain_id\u0027: local_user.domain_id}"},{"line_number":29,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_372d01a8","line":26,"in_reply_to":"5a3905b3_3c1ec6ba","updated":"2017-01-19 23:22:46.000000000","message":"Is that actually true? Wouldn\u0027t all of the changes commit in one big transaction?","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"70560a023a0f9476e4554ec4be12b7f4ce2164d5","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    nonlocal_user_table \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    # update the user.domain_id from the local_user table"},{"line_number":26,"context_line":"    local_users \u003d list(local_user_table.select().execute())"},{"line_number":27,"context_line":"    for local_user in local_users:"},{"line_number":28,"context_line":"        values \u003d {\u0027domain_id\u0027: local_user.domain_id}"},{"line_number":29,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_14234757","line":26,"in_reply_to":"5a3905b3_f93447fc","updated":"2017-01-22 18:41:10.000000000","message":"I changed this to a select statement:\nfor user in sel.execute()\n\nSo now it would not all be pulled into memory as a list (cursor instead) and thus, not a problem for big installations.\n\nPlease take a look at the latest patch when you have time.","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"bab7c7b7993504ca3d6f84f71fa7b7e341ef0613","unresolved":false,"context_lines":[{"line_number":33,"context_line":"        stmt.execute()"},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"    # update the user.domain_id from the nonlocal_user table"},{"line_number":36,"context_line":"    nonlocal_users \u003d list(nonlocal_user_table.select().execute())"},{"line_number":37,"context_line":"    for nonlocal_user in nonlocal_users:"},{"line_number":38,"context_line":"        values \u003d {\u0027domain_id\u0027: nonlocal_user.domain_id}"},{"line_number":39,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_be038e72","line":36,"updated":"2017-01-19 22:09:26.000000000","message":"Same here.","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"7cce85da3c33e9eedc362e694764212f6fd05d8c","unresolved":false,"context_lines":[{"line_number":33,"context_line":"        stmt.execute()"},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"    # update the user.domain_id from the nonlocal_user table"},{"line_number":36,"context_line":"    nonlocal_users \u003d list(nonlocal_user_table.select().execute())"},{"line_number":37,"context_line":"    for nonlocal_user in nonlocal_users:"},{"line_number":38,"context_line":"        values \u003d {\u0027domain_id\u0027: nonlocal_user.domain_id}"},{"line_number":39,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_9c833acc","line":36,"in_reply_to":"5a3905b3_be038e72","updated":"2017-01-19 23:03:59.000000000","message":"See response above.","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"995a47e2eb1561d0f87cf49851d23b6a1b9d8a7c","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    nonlocal_user_table \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    # update the user.domain_id from the local_user table"},{"line_number":26,"context_line":"    local_users \u003d list(local_user_table.select().execute())"},{"line_number":27,"context_line":"    for local_user in local_users:"},{"line_number":28,"context_line":"        values \u003d {\u0027domain_id\u0027: local_user.domain_id}"},{"line_number":29,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":42,"id":"5a3905b3_e0e36ca2","line":26,"range":{"start_line":26,"start_character":4,"end_line":26,"end_character":59},"updated":"2017-01-21 05:48:34.000000000","message":"this and the one below still scare me a bit, adding MikeBayer to the review since he\u0027s the SME in all things sqlalchemry","commit_id":"499a516624ca0ba2ecc52f10d81fac8f7a5586d2"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"58320201ba5f354a2bf55a7ada26d136e966afc5","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    nonlocal_user_table \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    # update the user.domain_id from the local_user table"},{"line_number":26,"context_line":"    local_users \u003d list(local_user_table.select().execute())"},{"line_number":27,"context_line":"    for local_user in local_users:"},{"line_number":28,"context_line":"        values \u003d {\u0027domain_id\u0027: local_user.domain_id}"},{"line_number":29,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":42,"id":"5a3905b3_74ff2baa","line":26,"range":{"start_line":26,"start_character":4,"end_line":26,"end_character":59},"in_reply_to":"5a3905b3_e0e36ca2","updated":"2017-01-22 18:39:49.000000000","message":"Changed this to a select statement:\nfor user in sel.execute()\n\nSo now it would not all be pulled into memory as a list (cursor instead) and thus, not a problem for big installations.\n\nPlease take a look at the latest patch when you have time.","commit_id":"499a516624ca0ba2ecc52f10d81fac8f7a5586d2"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"6e14bf82a1f95f51b59d7734b2aadf5a9a3e4add","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    nonlocal_user_table \u003d sql.Table(\u0027nonlocal_user\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    # update the user.domain_id from the local_user table"},{"line_number":26,"context_line":"    local_users \u003d list(local_user_table.select().execute())"},{"line_number":27,"context_line":"    for local_user in local_users:"},{"line_number":28,"context_line":"        values \u003d {\u0027domain_id\u0027: local_user.domain_id}"},{"line_number":29,"context_line":"        stmt \u003d user_table.update().where("}],"source_content_type":"text/x-python","patch_set":42,"id":"5a3905b3_6967604d","line":26,"range":{"start_line":26,"start_character":4,"end_line":26,"end_character":59},"in_reply_to":"5a3905b3_e0e36ca2","updated":"2017-01-21 17:19:23.000000000","message":"Sounds good Steve. I first tried to do this in a single update statement (update from select), but ran into table locking issues. I\u0027d also add that this isn\u0027t the first time that we\u0027ve done this:\nhttps://github.com/openstack/keystone/blob/master/keystone/common/sql/migrate_repo/versions/093_migrate_domains_to_projects.py#L111","commit_id":"499a516624ca0ba2ecc52f10d81fac8f7a5586d2"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_95d0ecca","line":40,"updated":"2017-01-23 16:58:01.000000000","message":"iterating through a SELECT and running an UPDATE for every row should really be in a transaction:\n\n    with migrate_engine.begin() as conn:\n        for user in conn.execute(sel):\n            values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}\n            stmt \u003d user_table.update().where(\n                user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)\n            conn.execute(stmt)\n\nbut also, how many rows are we talking about for this table?   doing an UPDATE for every row in a SELECT suggests a single UPDATE that could do the whole thing with a correlated SELECT, should be much faster:\n\n    UPDATE user_table SET domain_id\u003d\n    (SELECT domain_id FROM child_user_table WHERE user_id\u003duser_table.id)\n    WHERE user_table.domain_id IS NULL","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"0a8aa9eb7d4ba3fc8c360cce787a947a3280bd85","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_e6b8962c","line":40,"in_reply_to":"5a3905b3_43379cfe","updated":"2017-01-23 23:15:47.000000000","message":"the \"batching\" here just means using the \"executemany()\" API so that we send many rows to the database driver at once instead of one execute() at a time.  would still be in a transaction and all that.   it\u0027s not critical here.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"1f2921ae64901cf6837b4b2f06c6d4ff33ce9496","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_096ce133","line":40,"in_reply_to":"5a3905b3_95d0ecca","updated":"2017-01-23 18:36:54.000000000","message":"Changed this to doing it as a transaction. Thanks Mike.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"f4667292b970d36af70e45fbc71833a04f61dcf0","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_bbccf7bb","line":40,"in_reply_to":"5a3905b3_95d0ecca","updated":"2017-01-23 17:13:26.000000000","message":"Tried single update first and ran into table locking when running tests. I\u0027ll change it to a transaction. Thanks Mike.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"713c2d7783e029d1e6351a4d7773eea93f9039a4","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_fb23dfba","line":40,"in_reply_to":"5a3905b3_bbccf7bb","updated":"2017-01-23 17:25:29.000000000","message":"really what kind of locking?  what backends?   we can turn down transaction isolation and/or try to LOCK TABLE, something like that?   how many rows do we need to expect here?","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"081af8b3ee5af4b277b86c5324d96c0a5fb52258","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_c3d9ccf4","line":40,"in_reply_to":"5a3905b3_be9b0565","updated":"2017-01-23 23:05:16.000000000","message":"well, that paste shows you running an INSERT statement, you\u0027re saying that INSERT failed because it tried to run while you ran this UPDATE elsewhere, right?  that would make sense.   thousands is not terrible although you could run the UPDATE against a batch of say 1000 rows at a time which would decrease the Python overhead to a significant degree, though not the number of round trips.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"36cfc1d47005cd47ffd6451eb095609547718e56","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_43379cfe","line":40,"in_reply_to":"5a3905b3_c3d9ccf4","updated":"2017-01-23 23:12:10.000000000","message":"True, but I\u0027m happy with doing a transaction, as opposed to batching. Unless, you see a problem with that approach.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"631f3de6720d6c17baefba20db5633cce02623b8","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_a6c76e94","line":40,"in_reply_to":"5a3905b3_e6b8962c","updated":"2017-01-23 23:17:46.000000000","message":"I see, okay.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"4b97eb28d3bc5fa5a922ecb2e108026a74da5619","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        sql.select([user_table.c.id, child_user_table.c.domain_id])"},{"line_number":38,"context_line":"           .select_from(join).where(where)"},{"line_number":39,"context_line":"    )"},{"line_number":40,"context_line":"    for user in sel.execute():"},{"line_number":41,"context_line":"        values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":42,"context_line":"        stmt \u003d user_table.update().where("},{"line_number":43,"context_line":"            user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_be9b0565","line":40,"in_reply_to":"5a3905b3_fb23dfba","updated":"2017-01-23 17:36:08.000000000","message":"Depends on the operator, large deployments could have thousands (number of users), or even more I suppose. And we need to allow for create/update user during the migration. Here is an example of the table lock error I was getting with a single update:\nhttp://paste.openstack.org/show/596103/","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"6fad65792c1f6a275b632f73e3676e2dee867073","unresolved":false,"context_lines":[{"line_number":42,"context_line":"            values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":43,"context_line":"            stmt \u003d user_table.update().where("},{"line_number":44,"context_line":"                user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"},{"line_number":45,"context_line":"            conn.execute(stmt)"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_b61a1c7b","line":45,"updated":"2017-01-24 15:05:43.000000000","message":"So this updates all domain_ids using a single transaction because we\u0027re executing it on the connection level (as opposed to the statement level)?","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"d1c58d4aabda4a9f0c25062f8949261a419e4544","unresolved":false,"context_lines":[{"line_number":42,"context_line":"            values \u003d {\u0027domain_id\u0027: user[\u0027domain_id\u0027]}"},{"line_number":43,"context_line":"            stmt \u003d user_table.update().where("},{"line_number":44,"context_line":"                user_table.c.id \u003d\u003d user[\u0027id\u0027]).values(values)"},{"line_number":45,"context_line":"            conn.execute(stmt)"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_9c99bf7b","line":45,"in_reply_to":"5a3905b3_b61a1c7b","updated":"2017-01-24 15:17:32.000000000","message":"Correct","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"}],"keystone/common/sql/expand_repo/versions/014_expand_add_domain_id_to_user.py":[{"author":{"_account_id":6482,"name":"Steve Martinelli","email":"s.martinelli@gmail.com","username":"stevemar"},"change_message_id":"bfc2f74a25c6c5b68a823edbd41af835b90e7a7b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":38,"id":"5a3905b3_13791994","updated":"2017-01-19 13:32:57.000000000","message":"remove \"expand\" from the file name,\n\nalso, it should be named \"add_domain_id_to_user_table\"","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"4b2e0f78c9461e8801d6c8f9cbd8531cdc70dff5","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":38,"id":"5a3905b3_601d1873","in_reply_to":"5a3905b3_13791994","updated":"2017-01-19 15:29:00.000000000","message":"Changed the name, added table at the end. Keeping the \u0027expand\u0027 for now due to the reason indicated earlier.","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"}],"keystone/common/sql/expand_repo/versions/014_expand_add_domain_id_to_user_table.py":[{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":13,"context_line":"import sqlalchemy as sql"},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"from keystone.common.sql import upgrades"},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"# define the local_user triggers for insert and update"},{"line_number":18,"context_line":"MYSQL_LOCAL_USER_INSERT_TRIGGER \u003d \"\"\""},{"line_number":19,"context_line":"CREATE TRIGGER local_user_after_insert_trigger"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_783d358e","line":16,"updated":"2017-01-23 16:58:01.000000000","message":"no easy win for the verbosity here.  would be nice if we had some trigger-creation utilities but that\u0027s out of scope for this.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"f4667292b970d36af70e45fbc71833a04f61dcf0","unresolved":false,"context_lines":[{"line_number":13,"context_line":"import sqlalchemy as sql"},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"from keystone.common.sql import upgrades"},{"line_number":16,"context_line":""},{"line_number":17,"context_line":"# define the local_user triggers for insert and update"},{"line_number":18,"context_line":"MYSQL_LOCAL_USER_INSERT_TRIGGER \u003d \"\"\""},{"line_number":19,"context_line":"CREATE TRIGGER local_user_after_insert_trigger"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_bb431712","line":16,"in_reply_to":"5a3905b3_783d358e","updated":"2017-01-23 17:13:26.000000000","message":"Yeah, totally agree.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"9c11d98b63320ae1a0493f410c69fc276fdf0c10","unresolved":false,"context_lines":[{"line_number":30,"context_line":"AFTER UPDATE"},{"line_number":31,"context_line":"    ON local_user FOR EACH ROW"},{"line_number":32,"context_line":"BEGIN"},{"line_number":33,"context_line":"    UPDATE user SET domain_id \u003d NEW.domain_id"},{"line_number":34,"context_line":"        WHERE id \u003d NEW.user_id and domain_id \u003c\u003e NEW.domain_id;"},{"line_number":35,"context_line":"END;"},{"line_number":36,"context_line":"\"\"\""}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_9c29bf9d","line":33,"updated":"2017-01-24 15:37:23.000000000","message":"Based on the recent IRC conversations do we still need to worry about trying to change the domain on an existing user?","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"62a841cbc3072138bdaaf6f0c857f37c72de797c","unresolved":false,"context_lines":[{"line_number":30,"context_line":"AFTER UPDATE"},{"line_number":31,"context_line":"    ON local_user FOR EACH ROW"},{"line_number":32,"context_line":"BEGIN"},{"line_number":33,"context_line":"    UPDATE user SET domain_id \u003d NEW.domain_id"},{"line_number":34,"context_line":"        WHERE id \u003d NEW.user_id and domain_id \u003c\u003e NEW.domain_id;"},{"line_number":35,"context_line":"END;"},{"line_number":36,"context_line":"\"\"\""}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_9348cdb4","line":33,"in_reply_to":"5a3905b3_9c29bf9d","updated":"2017-01-24 15:51:26.000000000","message":"Because you can\u0027t change the domain? We still allow domain changes, as it just logs a warning. But happy to take this out if it\u0027s not needed. However, at this point it\u0027s not hurting anything by keeping it.","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"}],"keystone/identity/backends/sql_model.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ff9457db72be175b9f5704d5c8a92d778ce22545","unresolved":false,"context_lines":[{"line_number":260,"context_line":"    domain_id \u003d sql.Column(sql.String(64), primary_key\u003dTrue)"},{"line_number":261,"context_line":"    name \u003d sql.Column(sql.String(255), primary_key\u003dTrue)"},{"line_number":262,"context_line":"    user_id \u003d sql.Column(sql.String(64), unique\u003dTrue)"},{"line_number":263,"context_line":"    __table_args__ \u003d ("},{"line_number":264,"context_line":"        sqlalchemy.ForeignKeyConstraint("},{"line_number":265,"context_line":"            [\u0027user_id\u0027, \u0027domain_id\u0027], [\u0027user.id\u0027, \u0027user.domain_id\u0027],"},{"line_number":266,"context_line":"            onupdate\u003d\u0027CASCADE\u0027, ondelete\u003d\u0027CASCADE\u0027),)"}],"source_content_type":"text/x-python","patch_set":38,"id":"7a3c09a3_64cd435d","line":263,"updated":"2017-01-18 21:47:32.000000000","message":"This one doesn\u0027t need a UniqueConstraint like LocalUser does?","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3a1b5f8bba4aad893b55491597540bdebe5d4052","unresolved":false,"context_lines":[{"line_number":260,"context_line":"    domain_id \u003d sql.Column(sql.String(64), primary_key\u003dTrue)"},{"line_number":261,"context_line":"    name \u003d sql.Column(sql.String(255), primary_key\u003dTrue)"},{"line_number":262,"context_line":"    user_id \u003d sql.Column(sql.String(64), unique\u003dTrue)"},{"line_number":263,"context_line":"    __table_args__ \u003d ("},{"line_number":264,"context_line":"        sqlalchemy.ForeignKeyConstraint("},{"line_number":265,"context_line":"            [\u0027user_id\u0027, \u0027domain_id\u0027], [\u0027user.id\u0027, \u0027user.domain_id\u0027],"},{"line_number":266,"context_line":"            onupdate\u003d\u0027CASCADE\u0027, ondelete\u003d\u0027CASCADE\u0027),)"}],"source_content_type":"text/x-python","patch_set":38,"id":"5a3905b3_edaf6592","line":263,"in_reply_to":"7a3c09a3_64cd435d","updated":"2017-01-19 01:36:53.000000000","message":"No, because local_user has an id as the primary key. Whereas with non_local_user, the domain_id + name is the primary key. Unfortunately, I wasn\u0027t consistent with this when developing shadow users (should have been).","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"bab7c7b7993504ca3d6f84f71fa7b7e341ef0613","unresolved":false,"context_lines":[{"line_number":51,"context_line":"                                     backref\u003d\u0027user\u0027)"},{"line_number":52,"context_line":"    created_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":53,"context_line":"    last_active_at \u003d sql.Column(sql.Date, nullable\u003dTrue)"},{"line_number":54,"context_line":"    __table_args__ \u003d (sql.UniqueConstraint(\u0027id\u0027, \u0027domain_id\u0027), {})"},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    # NOTE(stevemar): we use a hybrid property here because we leverage the"},{"line_number":57,"context_line":"    # expression method, see `@name.expression` and `LocalUser.name` below."}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_8bd85255","line":54,"updated":"2017-01-19 22:09:26.000000000","message":"This was confusing when I looked at it since it\u0027s not necessary by itself and only exists for the FK relationships below. I think a comment would be useful.","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"7cce85da3c33e9eedc362e694764212f6fd05d8c","unresolved":false,"context_lines":[{"line_number":51,"context_line":"                                     backref\u003d\u0027user\u0027)"},{"line_number":52,"context_line":"    created_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":53,"context_line":"    last_active_at \u003d sql.Column(sql.Date, nullable\u003dTrue)"},{"line_number":54,"context_line":"    __table_args__ \u003d (sql.UniqueConstraint(\u0027id\u0027, \u0027domain_id\u0027), {})"},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    # NOTE(stevemar): we use a hybrid property here because we leverage the"},{"line_number":57,"context_line":"    # expression method, see `@name.expression` and `LocalUser.name` below."}],"source_content_type":"text/x-python","patch_set":40,"id":"5a3905b3_5cbc726c","line":54,"in_reply_to":"5a3905b3_8bd85255","updated":"2017-01-19 23:03:59.000000000","message":"Done","commit_id":"656b82f6bdf6e04cd4a68b8210524273d4529856"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"6e7cd63be423ed2355d6fc2733d8113c44e2f8d9","unresolved":false,"context_lines":[{"line_number":51,"context_line":"                                     backref\u003d\u0027user\u0027)"},{"line_number":52,"context_line":"    created_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":53,"context_line":"    last_active_at \u003d sql.Column(sql.Date, nullable\u003dTrue)"},{"line_number":54,"context_line":"    # unique constraint needed here to support composite foreign key constraints"},{"line_number":55,"context_line":"    __table_args__ \u003d (sql.UniqueConstraint(\u0027id\u0027, \u0027domain_id\u0027), {})"},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"    # NOTE(stevemar): we use a hybrid property here because we leverage the"}],"source_content_type":"text/x-python","patch_set":41,"id":"5a3905b3_25d5c6b8","line":54,"updated":"2017-01-20 00:33:31.000000000","message":"Looks like this is breaking pep8","commit_id":"287d1754c0e7b78965e1c658bbe37e0bcd1d3e75"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":52,"context_line":"    created_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":53,"context_line":"    last_active_at \u003d sql.Column(sql.Date, nullable\u003dTrue)"},{"line_number":54,"context_line":"    # unique constraint needed here to support composite fk constraints"},{"line_number":55,"context_line":"    __table_args__ \u003d (sql.UniqueConstraint(\u0027id\u0027, \u0027domain_id\u0027), {})"},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"    # NOTE(stevemar): we use a hybrid property here because we leverage the"},{"line_number":58,"context_line":"    # expression method, see `@name.expression` and `LocalUser.name` below."}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_d8fc69ba","line":55,"updated":"2017-01-23 16:58:01.000000000","message":"does the \"Base.metadata\" have a naming_convention dictionary in place?  otherwise giving constraints explicit names would be handy","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"f4667292b970d36af70e45fbc71833a04f61dcf0","unresolved":false,"context_lines":[{"line_number":52,"context_line":"    created_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":53,"context_line":"    last_active_at \u003d sql.Column(sql.Date, nullable\u003dTrue)"},{"line_number":54,"context_line":"    # unique constraint needed here to support composite fk constraints"},{"line_number":55,"context_line":"    __table_args__ \u003d (sql.UniqueConstraint(\u0027id\u0027, \u0027domain_id\u0027), {})"},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"    # NOTE(stevemar): we use a hybrid property here because we leverage the"},{"line_number":58,"context_line":"    # expression method, see `@name.expression` and `LocalUser.name` below."}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_9b257b5d","line":55,"in_reply_to":"5a3905b3_d8fc69ba","updated":"2017-01-23 17:13:26.000000000","message":"Agree, but not that I am aware of.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":209,"context_line":"    __tablename__ \u003d \u0027local_user\u0027"},{"line_number":210,"context_line":"    attributes \u003d [\u0027id\u0027, \u0027user_id\u0027, \u0027domain_id\u0027, \u0027name\u0027]"},{"line_number":211,"context_line":"    id \u003d sql.Column(sql.Integer, primary_key\u003dTrue)"},{"line_number":212,"context_line":"    user_id \u003d sql.Column(sql.String(64), unique\u003dTrue)"},{"line_number":213,"context_line":"    domain_id \u003d sql.Column(sql.String(64), nullable\u003dFalse)"},{"line_number":214,"context_line":"    name \u003d sql.Column(sql.String(255), nullable\u003dFalse)"},{"line_number":215,"context_line":"    passwords \u003d orm.relationship(\u0027Password\u0027,"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_38156de4","line":212,"updated":"2017-01-23 16:58:01.000000000","message":"I\u0027d not use unique\u003dTrue and use UniqueConstraint for clarity/consistency/explicit naming","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"1f2921ae64901cf6837b4b2f06c6d4ff33ce9496","unresolved":false,"context_lines":[{"line_number":209,"context_line":"    __tablename__ \u003d \u0027local_user\u0027"},{"line_number":210,"context_line":"    attributes \u003d [\u0027id\u0027, \u0027user_id\u0027, \u0027domain_id\u0027, \u0027name\u0027]"},{"line_number":211,"context_line":"    id \u003d sql.Column(sql.Integer, primary_key\u003dTrue)"},{"line_number":212,"context_line":"    user_id \u003d sql.Column(sql.String(64), unique\u003dTrue)"},{"line_number":213,"context_line":"    domain_id \u003d sql.Column(sql.String(64), nullable\u003dFalse)"},{"line_number":214,"context_line":"    name \u003d sql.Column(sql.String(255), nullable\u003dFalse)"},{"line_number":215,"context_line":"    passwords \u003d orm.relationship(\u0027Password\u0027,"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_a48214c6","line":212,"in_reply_to":"5a3905b3_38156de4","updated":"2017-01-23 18:36:54.000000000","message":"Done, just not explicitly naming at this point. It hasn\u0027t been a practice in Keystone to name constraints in the model modules. However, they are typically given names in the migration files. I\u0027ll propose a different patch to address this.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"081af8b3ee5af4b277b86c5324d96c0a5fb52258","unresolved":false,"context_lines":[{"line_number":209,"context_line":"    __tablename__ \u003d \u0027local_user\u0027"},{"line_number":210,"context_line":"    attributes \u003d [\u0027id\u0027, \u0027user_id\u0027, \u0027domain_id\u0027, \u0027name\u0027]"},{"line_number":211,"context_line":"    id \u003d sql.Column(sql.Integer, primary_key\u003dTrue)"},{"line_number":212,"context_line":"    user_id \u003d sql.Column(sql.String(64), unique\u003dTrue)"},{"line_number":213,"context_line":"    domain_id \u003d sql.Column(sql.String(64), nullable\u003dFalse)"},{"line_number":214,"context_line":"    name \u003d sql.Column(sql.String(255), nullable\u003dFalse)"},{"line_number":215,"context_line":"    passwords \u003d orm.relationship(\u0027Password\u0027,"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_a305a046","line":212,"in_reply_to":"5a3905b3_a48214c6","updated":"2017-01-23 23:05:16.000000000","message":"well right as long as the name gets into the DB, is the main thing.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":221,"context_line":"    failed_auth_count \u003d sql.Column(sql.Integer, nullable\u003dTrue)"},{"line_number":222,"context_line":"    failed_auth_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":223,"context_line":"    __table_args__ \u003d ("},{"line_number":224,"context_line":"        sql.UniqueConstraint(\u0027domain_id\u0027, \u0027name\u0027),"},{"line_number":225,"context_line":"        sqlalchemy.ForeignKeyConstraint([\u0027user_id\u0027, \u0027domain_id\u0027],"},{"line_number":226,"context_line":"                                        [\u0027user.id\u0027, \u0027user.domain_id\u0027],"},{"line_number":227,"context_line":"                                        onupdate\u003d\u0027CASCADE\u0027, ondelete\u003d\u0027CASCADE\u0027)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_38fe4dae","line":224,"updated":"2017-01-23 16:58:01.000000000","message":"same w/ naming here","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"1f2921ae64901cf6837b4b2f06c6d4ff33ce9496","unresolved":false,"context_lines":[{"line_number":221,"context_line":"    failed_auth_count \u003d sql.Column(sql.Integer, nullable\u003dTrue)"},{"line_number":222,"context_line":"    failed_auth_at \u003d sql.Column(sql.DateTime, nullable\u003dTrue)"},{"line_number":223,"context_line":"    __table_args__ \u003d ("},{"line_number":224,"context_line":"        sql.UniqueConstraint(\u0027domain_id\u0027, \u0027name\u0027),"},{"line_number":225,"context_line":"        sqlalchemy.ForeignKeyConstraint([\u0027user_id\u0027, \u0027domain_id\u0027],"},{"line_number":226,"context_line":"                                        [\u0027user.id\u0027, \u0027user.domain_id\u0027],"},{"line_number":227,"context_line":"                                        onupdate\u003d\u0027CASCADE\u0027, ondelete\u003d\u0027CASCADE\u0027)"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_e4709c0d","line":224,"in_reply_to":"5a3905b3_38fe4dae","updated":"2017-01-23 18:36:54.000000000","message":"reason above.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"a035fa14834ea9c20fd54875a6683460b3aba331","unresolved":false,"context_lines":[{"line_number":271,"context_line":"    attributes \u003d [\u0027domain_id\u0027, \u0027name\u0027, \u0027user_id\u0027]"},{"line_number":272,"context_line":"    domain_id \u003d sql.Column(sql.String(64), primary_key\u003dTrue)"},{"line_number":273,"context_line":"    name \u003d sql.Column(sql.String(255), primary_key\u003dTrue)"},{"line_number":274,"context_line":"    user_id \u003d sql.Column(sql.String(64), unique\u003dTrue)"},{"line_number":275,"context_line":"    __table_args__ \u003d ("},{"line_number":276,"context_line":"        sqlalchemy.ForeignKeyConstraint("},{"line_number":277,"context_line":"            [\u0027user_id\u0027, \u0027domain_id\u0027], [\u0027user.id\u0027, \u0027user.domain_id\u0027],"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_b8287d34","line":274,"updated":"2017-01-23 16:58:01.000000000","message":"I\u0027d not use unique\u003dTrue and use UniqueConstraint instead for clarity/consistency/explicit naming","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"1f2921ae64901cf6837b4b2f06c6d4ff33ce9496","unresolved":false,"context_lines":[{"line_number":271,"context_line":"    attributes \u003d [\u0027domain_id\u0027, \u0027name\u0027, \u0027user_id\u0027]"},{"line_number":272,"context_line":"    domain_id \u003d sql.Column(sql.String(64), primary_key\u003dTrue)"},{"line_number":273,"context_line":"    name \u003d sql.Column(sql.String(255), primary_key\u003dTrue)"},{"line_number":274,"context_line":"    user_id \u003d sql.Column(sql.String(64), unique\u003dTrue)"},{"line_number":275,"context_line":"    __table_args__ \u003d ("},{"line_number":276,"context_line":"        sqlalchemy.ForeignKeyConstraint("},{"line_number":277,"context_line":"            [\u0027user_id\u0027, \u0027domain_id\u0027], [\u0027user.id\u0027, \u0027user.domain_id\u0027],"}],"source_content_type":"text/x-python","patch_set":46,"id":"5a3905b3_0453e86b","line":274,"in_reply_to":"5a3905b3_b8287d34","updated":"2017-01-23 18:36:54.000000000","message":"Done, but not explicitly naming.","commit_id":"acac340b84fd5d0ac070ef82f09ac6c91e54d6ad"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"9c11d98b63320ae1a0493f410c69fc276fdf0c10","unresolved":false,"context_lines":[{"line_number":31,"context_line":"                  \u0027default_project_id\u0027, \u0027password_expires_at\u0027]"},{"line_number":32,"context_line":"    readonly_attributes \u003d [\u0027id\u0027, \u0027password_expires_at\u0027]"},{"line_number":33,"context_line":"    id \u003d sql.Column(sql.String(64), primary_key\u003dTrue)"},{"line_number":34,"context_line":"    domain_id \u003d sql.Column(sql.String(64), nullable\u003dTrue)"},{"line_number":35,"context_line":"    _enabled \u003d sql.Column(\u0027enabled\u0027, sql.Boolean)"},{"line_number":36,"context_line":"    extra \u003d sql.Column(sql.JsonBlob())"},{"line_number":37,"context_line":"    default_project_id \u003d sql.Column(sql.String(64))"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_dce267d4","line":34,"updated":"2017-01-24 15:37:23.000000000","message":"Why is this nullable here?","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"},{"author":{"_account_id":7725,"name":"David Stanek","email":"dstanek@dstanek.com","username":"dstanek"},"change_message_id":"5a5f382d13ada51454a4aa7d2e8b9e7ee69b659d","unresolved":false,"context_lines":[{"line_number":31,"context_line":"                  \u0027default_project_id\u0027, \u0027password_expires_at\u0027]"},{"line_number":32,"context_line":"    readonly_attributes \u003d [\u0027id\u0027, \u0027password_expires_at\u0027]"},{"line_number":33,"context_line":"    id \u003d sql.Column(sql.String(64), primary_key\u003dTrue)"},{"line_number":34,"context_line":"    domain_id \u003d sql.Column(sql.String(64), nullable\u003dTrue)"},{"line_number":35,"context_line":"    _enabled \u003d sql.Column(\u0027enabled\u0027, sql.Boolean)"},{"line_number":36,"context_line":"    extra \u003d sql.Column(sql.JsonBlob())"},{"line_number":37,"context_line":"    default_project_id \u003d sql.Column(sql.String(64))"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_f3075115","line":34,"in_reply_to":"5a3905b3_dce267d4","updated":"2017-01-24 15:42:12.000000000","message":"I just saw why in your federation review.","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"62a841cbc3072138bdaaf6f0c857f37c72de797c","unresolved":false,"context_lines":[{"line_number":31,"context_line":"                  \u0027default_project_id\u0027, \u0027password_expires_at\u0027]"},{"line_number":32,"context_line":"    readonly_attributes \u003d [\u0027id\u0027, \u0027password_expires_at\u0027]"},{"line_number":33,"context_line":"    id \u003d sql.Column(sql.String(64), primary_key\u003dTrue)"},{"line_number":34,"context_line":"    domain_id \u003d sql.Column(sql.String(64), nullable\u003dTrue)"},{"line_number":35,"context_line":"    _enabled \u003d sql.Column(\u0027enabled\u0027, sql.Boolean)"},{"line_number":36,"context_line":"    extra \u003d sql.Column(sql.JsonBlob())"},{"line_number":37,"context_line":"    default_project_id \u003d sql.Column(sql.String(64))"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_33eab9db","line":34,"in_reply_to":"5a3905b3_f3075115","updated":"2017-01-24 15:51:26.000000000","message":"Yeah, so once the domain is set for federated users, it will be set now for all users. And really it shouldn\u0027t be nullable, as all users should belong to a domain.","commit_id":"17af4797b398fce16ee82b1abef4da5d77c67b5e"}],"keystone/tests/unit/test_backend_sql.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ff9457db72be175b9f5704d5c8a92d778ce22545","unresolved":false,"context_lines":[{"line_number":144,"context_line":"        cols \u003d ((\u0027id\u0027, sql.Integer, None),"},{"line_number":145,"context_line":"                (\u0027user_id\u0027, sql.String, 64),"},{"line_number":146,"context_line":"                (\u0027name\u0027, sql.String, 255),"},{"line_number":147,"context_line":"                (\u0027domain_id\u0027, sql.String, 64),"},{"line_number":148,"context_line":"                (\u0027failed_auth_count\u0027, sql.Integer, None),"},{"line_number":149,"context_line":"                (\u0027failed_auth_at\u0027, sql.DateTime, None))"},{"line_number":150,"context_line":"        self.assertExpectedSchema(\u0027local_user\u0027, cols)"}],"source_content_type":"text/x-python","patch_set":38,"id":"7a3c09a3_04347f48","side":"PARENT","line":147,"updated":"2017-01-18 21:47:32.000000000","message":"We keep this here because it\u0027s testing the attribute is pulled from the User table instead of the LocalUser table, right?","commit_id":"4e31ab988e1f37c3d5ceff9e6f4c5e9c0c8310c8"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3a1b5f8bba4aad893b55491597540bdebe5d4052","unresolved":false,"context_lines":[{"line_number":144,"context_line":"        cols \u003d ((\u0027id\u0027, sql.Integer, None),"},{"line_number":145,"context_line":"                (\u0027user_id\u0027, sql.String, 64),"},{"line_number":146,"context_line":"                (\u0027name\u0027, sql.String, 255),"},{"line_number":147,"context_line":"                (\u0027domain_id\u0027, sql.String, 64),"},{"line_number":148,"context_line":"                (\u0027failed_auth_count\u0027, sql.Integer, None),"},{"line_number":149,"context_line":"                (\u0027failed_auth_at\u0027, sql.DateTime, None))"},{"line_number":150,"context_line":"        self.assertExpectedSchema(\u0027local_user\u0027, cols)"}],"source_content_type":"text/x-python","patch_set":38,"id":"5a3905b3_cd81c9fd","side":"PARENT","line":147,"in_reply_to":"7a3c09a3_04347f48","updated":"2017-01-19 01:36:53.000000000","message":"The domain_id is in both tables. It\u0027s a foreign key in the local_user table, which does 2 things:\n* Keeps it in sync with the user table\n* Allows us to have a unique constraint on the domain_id + name","commit_id":"4e31ab988e1f37c3d5ceff9e6f4c5e9c0c8310c8"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ff9457db72be175b9f5704d5c8a92d778ce22545","unresolved":false,"context_lines":[{"line_number":168,"context_line":"        self.assertExpectedSchema(\u0027federated_user\u0027, cols)"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    def test_nonlocal_user_model(self):"},{"line_number":171,"context_line":"        cols \u003d ((\u0027domain_id\u0027, sql.String, 64),"},{"line_number":172,"context_line":"                (\u0027name\u0027, sql.String, 255),"},{"line_number":173,"context_line":"                (\u0027user_id\u0027, sql.String, 64))"},{"line_number":174,"context_line":"        self.assertExpectedSchema(\u0027nonlocal_user\u0027, cols)"}],"source_content_type":"text/x-python","patch_set":38,"id":"7a3c09a3_a4456bb4","side":"PARENT","line":171,"updated":"2017-01-18 21:47:32.000000000","message":"Same comment here.","commit_id":"4e31ab988e1f37c3d5ceff9e6f4c5e9c0c8310c8"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3a1b5f8bba4aad893b55491597540bdebe5d4052","unresolved":false,"context_lines":[{"line_number":168,"context_line":"        self.assertExpectedSchema(\u0027federated_user\u0027, cols)"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"    def test_nonlocal_user_model(self):"},{"line_number":171,"context_line":"        cols \u003d ((\u0027domain_id\u0027, sql.String, 64),"},{"line_number":172,"context_line":"                (\u0027name\u0027, sql.String, 255),"},{"line_number":173,"context_line":"                (\u0027user_id\u0027, sql.String, 64))"},{"line_number":174,"context_line":"        self.assertExpectedSchema(\u0027nonlocal_user\u0027, cols)"}],"source_content_type":"text/x-python","patch_set":38,"id":"5a3905b3_4d76b93f","side":"PARENT","line":171,"in_reply_to":"7a3c09a3_a4456bb4","updated":"2017-01-19 01:36:53.000000000","message":"Same answer","commit_id":"4e31ab988e1f37c3d5ceff9e6f4c5e9c0c8310c8"}],"keystone/tests/unit/test_sql_upgrade.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ff9457db72be175b9f5704d5c8a92d778ce22545","unresolved":false,"context_lines":[{"line_number":2041,"context_line":"        user_table_name \u003d \u0027user\u0027"},{"line_number":2042,"context_line":"        self.expand(13)"},{"line_number":2043,"context_line":"        self.migrate(13)"},{"line_number":2044,"context_line":"        self.contract(13)"},{"line_number":2045,"context_line":"        self.assertTableColumns("},{"line_number":2046,"context_line":"            user_table_name, [\u0027id\u0027, \u0027extra\u0027, \u0027enabled\u0027, \u0027default_project_id\u0027,"},{"line_number":2047,"context_line":"                              \u0027created_at\u0027, \u0027last_active_at\u0027])"}],"source_content_type":"text/x-python","patch_set":38,"id":"7a3c09a3_c4c5170b","line":2044,"updated":"2017-01-18 21:47:32.000000000","message":"We could add some local and nonlocal users here to test that the migration moves the domain ID to the user table. I think we\u0027re just testing that the triggers work properly (which is good!)","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3a1b5f8bba4aad893b55491597540bdebe5d4052","unresolved":false,"context_lines":[{"line_number":2041,"context_line":"        user_table_name \u003d \u0027user\u0027"},{"line_number":2042,"context_line":"        self.expand(13)"},{"line_number":2043,"context_line":"        self.migrate(13)"},{"line_number":2044,"context_line":"        self.contract(13)"},{"line_number":2045,"context_line":"        self.assertTableColumns("},{"line_number":2046,"context_line":"            user_table_name, [\u0027id\u0027, \u0027extra\u0027, \u0027enabled\u0027, \u0027default_project_id\u0027,"},{"line_number":2047,"context_line":"                              \u0027created_at\u0027, \u0027last_active_at\u0027])"}],"source_content_type":"text/x-python","patch_set":38,"id":"5a3905b3_ad08fd92","line":2044,"in_reply_to":"7a3c09a3_c4c5170b","updated":"2017-01-19 01:36:53.000000000","message":"Ah, good point ++","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"4b2e0f78c9461e8801d6c8f9cbd8531cdc70dff5","unresolved":false,"context_lines":[{"line_number":2041,"context_line":"        user_table_name \u003d \u0027user\u0027"},{"line_number":2042,"context_line":"        self.expand(13)"},{"line_number":2043,"context_line":"        self.migrate(13)"},{"line_number":2044,"context_line":"        self.contract(13)"},{"line_number":2045,"context_line":"        self.assertTableColumns("},{"line_number":2046,"context_line":"            user_table_name, [\u0027id\u0027, \u0027extra\u0027, \u0027enabled\u0027, \u0027default_project_id\u0027,"},{"line_number":2047,"context_line":"                              \u0027created_at\u0027, \u0027last_active_at\u0027])"}],"source_content_type":"text/x-python","patch_set":38,"id":"5a3905b3_c077acd2","line":2044,"in_reply_to":"7a3c09a3_c4c5170b","updated":"2017-01-19 15:29:00.000000000","message":"Done","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"ff9457db72be175b9f5704d5c8a92d778ce22545","unresolved":false,"context_lines":[{"line_number":2082,"context_line":"                self.does_index_exist(\u0027user\u0027, \u0027ixu_user_id_domain_id\u0027))"},{"line_number":2083,"context_line":"        else:"},{"line_number":2084,"context_line":"            self.assertTrue("},{"line_number":2085,"context_line":"                self.does_constraint_exist(\u0027user\u0027, \u0027ixu_user_id_domain_id\u0027))"},{"line_number":2086,"context_line":"        self.assertTrue(self.does_fk_exist(\u0027local_user\u0027, \u0027user_id\u0027))"},{"line_number":2087,"context_line":"        self.assertTrue(self.does_fk_exist(\u0027local_user\u0027, \u0027domain_id\u0027))"},{"line_number":2088,"context_line":"        self.assertTrue(self.does_fk_exist(\u0027nonlocal_user\u0027, \u0027user_id\u0027))"}],"source_content_type":"text/x-python","patch_set":38,"id":"7a3c09a3_c49357ff","line":2085,"updated":"2017-01-18 21:47:32.000000000","message":"This is the same condition for both postgres and sqlite?","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"},{"author":{"_account_id":18338,"name":"Ron De Rose","email":"ronald.de.rose@intel.com","username":"derosenet"},"change_message_id":"3a1b5f8bba4aad893b55491597540bdebe5d4052","unresolved":false,"context_lines":[{"line_number":2082,"context_line":"                self.does_index_exist(\u0027user\u0027, \u0027ixu_user_id_domain_id\u0027))"},{"line_number":2083,"context_line":"        else:"},{"line_number":2084,"context_line":"            self.assertTrue("},{"line_number":2085,"context_line":"                self.does_constraint_exist(\u0027user\u0027, \u0027ixu_user_id_domain_id\u0027))"},{"line_number":2086,"context_line":"        self.assertTrue(self.does_fk_exist(\u0027local_user\u0027, \u0027user_id\u0027))"},{"line_number":2087,"context_line":"        self.assertTrue(self.does_fk_exist(\u0027local_user\u0027, \u0027domain_id\u0027))"},{"line_number":2088,"context_line":"        self.assertTrue(self.does_fk_exist(\u0027nonlocal_user\u0027, \u0027user_id\u0027))"}],"source_content_type":"text/x-python","patch_set":38,"id":"5a3905b3_0dcaf14f","line":2085,"in_reply_to":"7a3c09a3_c49357ff","updated":"2017-01-19 01:36:53.000000000","message":"Yeah, I think so. At least this is how we\u0027ve called the does_constraint_exist method in other migrations. So I just copied that.","commit_id":"5408445a3997e2a109067b6382f8cd1e08343608"}]}
