)]}'
{"nova/api/openstack/placement/objects/resource_provider.py":[{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"67ee18c6bf5ecc3e351e9a7c101b2a1174692162","unresolved":false,"context_lines":[{"line_number":61,"context_line":""},{"line_number":62,"context_line":"CONF \u003d cfg.CONF"},{"line_number":63,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":64,"context_line":"CONSUMER_MISSING_SENTINEL \u003d \u002700000000-0000-0000-0000-0000000000000\u0027"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"@db_api.api_context_manager.reader"}],"source_content_type":"text/x-python","patch_set":17,"id":"5f7c97a3_de170751","line":64,"updated":"2018-05-09 18:28:49.000000000","message":"We discussed on IRC, but just for posterity:\n\nI was hoping we could make configurable the user and project that get allocations if we have no other information. That can default to the zero uuid like this here, but I think it would be nice for ops to be able to put anonymous allocations into a real tenant/user if they wish, so they can track those more easily.\n\nIn IRC, Jay said he\u0027d do it this afternoon.","commit_id":"71d8f67b6198c65b4112eae32090a827bafa787e"}],"nova/conf/placement.py":[{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"09e6b8915736b6676a52689fb6e28d37836ba0be","unresolved":false,"context_lines":[{"line_number":37,"context_line":"is determined."},{"line_number":38,"context_line":"\"\"\"),"},{"line_number":39,"context_line":"    cfg.StrOpt(\"incomplete_consumer_project_id\","},{"line_number":40,"context_line":"        default\u003dDEFAULT_CONSUMER_MISSING_SENTINEL,"},{"line_number":41,"context_line":"        help\u003d\"\"\""},{"line_number":42,"context_line":"Early API microversions (\u003c1.8) allowed creating allocations and not specifying"},{"line_number":43,"context_line":"a project or user identifier for the consumer. In cleaning up the data"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_b1f02bff","line":40,"updated":"2018-05-10 13:14:40.000000000","message":"Happy that there is a reasonable default so anybody who doesn\u0027t care can just carry on without thinking about these config items.","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"}],"nova/db/sqlalchemy/api_migrations/migrate_repo/versions/059_add_consumer_generation.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"24bddc2b245a97840bc005b3cafb6597c1197c98","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    consumers \u003d Table(\u0027consumers\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \u0027generation\u0027):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\u0027generation\u0027, Integer, default\u003d0))"}],"source_content_type":"text/x-python","patch_set":1,"id":"bf659307_5fc41191","line":26,"range":{"start_line":26,"start_character":62,"end_line":26,"end_character":71},"updated":"2018-03-30 18:16:16.000000000","message":"note that this won\u0027t do anything server-side -- in other words, it won\u0027t add a DEFAULT 0 clause to the ALTER TABLE output.\n\nTo do that, you need server_default\u003d0.\n\nhttp://docs.sqlalchemy.org/en/latest/core/defaults.html#server-side-defaults","commit_id":"b0fda1b368276b475a10e64fabdf96b96183fa4b"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2651ea1f40158b9164aa8a6e6b31e2b98a5a5c19","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    consumers \u003d Table(\u0027consumers\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \u0027generation\u0027):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\u0027generation\u0027, Integer, default\u003d0))"}],"source_content_type":"text/x-python","patch_set":1,"id":"bf659307_0b82c6c8","line":26,"range":{"start_line":26,"start_character":62,"end_line":26,"end_character":71},"in_reply_to":"bf659307_0b0de68e","updated":"2018-04-02 18:12:04.000000000","message":"There\u0027s no point in having default\u003d0, then, and leaving it there is confusing IMHO.\n\nFor the record, the server default for nullable columns (which this is, since Column.nullable\u003dTrue by default) is to insert NULL for existing columns, so leaving server_default and default kwargs out of the Column() constructor produces the appropriate behaviour.","commit_id":"b0fda1b368276b475a10e64fabdf96b96183fa4b"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"2563a918733c3c1e98f594f620f08d7fa13269b5","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    consumers \u003d Table(\u0027consumers\u0027, meta, autoload\u003dTrue)"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \u0027generation\u0027):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\u0027generation\u0027, Integer, default\u003d0))"}],"source_content_type":"text/x-python","patch_set":1,"id":"bf659307_0b0de68e","line":26,"range":{"start_line":26,"start_character":62,"end_line":26,"end_character":71},"in_reply_to":"bf659307_5fc41191","updated":"2018-04-02 18:06:58.000000000","message":"I don\u0027t want it to be added as zero; I want it to be None. If the consumer record doesn\u0027t exist, it will always fail, as the allocation shouldn\u0027t be validated until the generation of both Consumer and Allocation are populated.","commit_id":"b0fda1b368276b475a10e64fabdf96b96183fa4b"},{"author":{"_account_id":17190,"name":"Arvind Nadendla","email":"arvindn05@gmail.com","username":"arvindn05"},"change_message_id":"db5664c166f55c133008cb14128f72e2aa3751ed","unresolved":false,"context_lines":[{"line_number":25,"context_line":"        consumers.create_column(Column(\u0027generation\u0027, Integer))"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"    allocations \u003d Table(\u0027allocations\u0027, meta, autoload\u003dTrue)"},{"line_number":28,"context_line":"    if not hasattr(allocations.c, \u0027generation\u0027):"},{"line_number":29,"context_line":"        allocations.create_column(Column(\u0027consumer_generation\u0027, Integer))"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_6c47bc78","line":28,"updated":"2018-04-03 21:29:14.000000000","message":"should we be checking for consumer_generation?","commit_id":"b89386fca5fe7fc35197ca78becd5ec3d8185568"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"2dc8abe11850ff6586a317f502ced1fcf2dc3036","unresolved":false,"context_lines":[{"line_number":25,"context_line":"        consumers.create_column(Column(\u0027generation\u0027, Integer))"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"    allocations \u003d Table(\u0027allocations\u0027, meta, autoload\u003dTrue)"},{"line_number":28,"context_line":"    if not hasattr(allocations.c, \u0027generation\u0027):"},{"line_number":29,"context_line":"        allocations.create_column(Column(\u0027consumer_generation\u0027, Integer))"}],"source_content_type":"text/x-python","patch_set":3,"id":"bf659307_074e1937","line":28,"in_reply_to":"bf659307_6c47bc78","updated":"2018-04-03 21:52:21.000000000","message":"No, there shouldn\u0027t be a consumer_generation or generation field in the allocations table at all.","commit_id":"b89386fca5fe7fc35197ca78becd5ec3d8185568"},{"author":{"_account_id":17190,"name":"Arvind Nadendla","email":"arvindn05@gmail.com","username":"arvindn05"},"change_message_id":"02f527595abf9b4e292baea823ca83db7a13182e","unresolved":false,"context_lines":[{"line_number":22,"context_line":""},{"line_number":23,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":24,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":25,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":26,"context_line":"                server_default\u003d\"0\", nullable\u003dFalse))"},{"line_number":27,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":28,"context_line":"    # even with allocations created before these fields were added as required."}],"source_content_type":"text/x-python","patch_set":4,"id":"bf659307_331d7f0f","line":25,"updated":"2018-04-05 00:33:01.000000000","message":"nit: maybe ocd but use same order as in api_models\n\nColumn(Integer, nullable\u003dFalse, server_default\u003d\"0\", default\u003d0)","commit_id":"a642bc6520e2981e9e779199c58e00db54a0de23"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"98cdfc2d6e9be9d5dcb05c63ac1222a69183609d","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":24,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":25,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":26,"context_line":"                server_default\u003d\"0\", nullable\u003dFalse))"},{"line_number":27,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":28,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":29,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":4,"id":"bf659307_65d6782a","line":26,"updated":"2018-04-10 00:01:33.000000000","message":"OKey doke, this is what\u0027s happening here.   The server default is getting quoted, so this emits like this:\n\n    ALTER TABLE consumers ADD generation INTEGER DEFAULT \u00270\u0027 NOT NULL\n\nI *think* this is SQLAlchemy-migrate doing that, not sure.  It shouldn\u0027t be quoting like that.  Might be happening on my end (e.g. in SQLAlchemy).\n\nAnyway, when we go to reflect it later from SQLite, SQLite maintains the quotes, because it has no table-level typing rules attached to the word \"integer\":\n\n\tsqlite\u003e CREATE TABLE foo (data integer default \u00270\u0027);\n\tsqlite\u003e pragma table_info(foo);\n\t0|data|integer|0|\u00270\u0027|0\n\nand that\u0027s what causes the mismatch.   \n\nIn this case we can tell SQLAlchemy and whoever, hey here is exactly what to put here, don\u0027t mess with it, using text(\u00270\u0027), I\u0027ll push that up now.","commit_id":"a642bc6520e2981e9e779199c58e00db54a0de23"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"43091a002bf546bc24a10e1b4b61dbd0181b572b","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":24,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":25,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":26,"context_line":"                server_default\u003d\"0\", nullable\u003dFalse))"},{"line_number":27,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":28,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":29,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":4,"id":"bf659307_bd9ed504","line":26,"in_reply_to":"bf659307_65d6782a","updated":"2018-04-10 15:07:59.000000000","message":"And server_default\u003d0 (pass an integer rather than a string) didn\u0027t solve it?","commit_id":"a642bc6520e2981e9e779199c58e00db54a0de23"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"80a50c7d7b63bb2649654342e82a9a3e70ee9334","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":24,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":25,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":26,"context_line":"                server_default\u003d\"0\", nullable\u003dFalse))"},{"line_number":27,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":28,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":29,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":4,"id":"bf659307_088a211a","line":26,"in_reply_to":"bf659307_bd9ed504","updated":"2018-04-10 15:28:15.000000000","message":"reading my own docs at http://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.Column.params.server_default\n\n\"String types will be emitted as-is, surrounded by single quotes:\"  \"A text() expression will be rendered as-is, without quotes:\"\n\nso yes the quotes are from SQLAlchemy.    A literal 0 is not accepted:\n\n\t\u003e\u003e\u003e from sqlalchemy import *\n\t\u003e\u003e\u003e Column(\u0027q\u0027, Integer, server_default\u003d0)\n\tTraceback (most recent call last):\n\t...\n\t\n\tsqlalchemy.exc.ArgumentError: Argument \u0027arg\u0027 is expected to be one of type \u0027\u003cclass \u0027str\u0027\u003e\u0027 or \u0027\u003cclass \u0027sqlalchemy.sql.elements.ClauseElement\u0027\u003e\u0027 or \u0027\u003cclass \u0027sqlalchemy.sql.elements.TextClause\u0027\u003e\u0027, got \u0027\u003cclass \u0027int\u0027\u003e\u0027","commit_id":"a642bc6520e2981e9e779199c58e00db54a0de23"},{"author":{"_account_id":15888,"name":"Zhenyu Zheng","email":"zheng.zhenyu@outlook.com","username":"Kevin_Zheng"},"change_message_id":"4c795064b64ef2505d4f3ed6bbcf8570f07af94c","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":5,"id":"bf659307_86c06f2c","line":27,"range":{"start_line":26,"start_character":8,"end_line":27,"end_character":58},"updated":"2018-04-10 07:04:11.000000000","message":"Hi, could you explain why the default is Integer but the server_default is text? Though Michael did some explanation, I still couldn\u0027t understand well.","commit_id":"359d6d0d2b0f116812e67a01d32097118faca7eb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"80e28ef86f40a1dd4da681da53ca3c9d020e14a8","unresolved":false,"context_lines":[{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_94ddca71","line":32,"range":{"start_line":28,"start_character":0,"end_line":32,"end_character":57},"updated":"2018-04-11 14:30:23.000000000","message":"I actually don\u0027t understand this. I\u0027ve thought about it quite a bit now and just don\u0027t understand the reasoning behind this change.\n\nCan you explain it? We aren\u0027t \"creating consumer records even with allocations created before these fields were added as required\".","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"56aebde0e9619a0e7bff2d3cb1830868979c47ec","unresolved":false,"context_lines":[{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_15d3f1d6","line":32,"range":{"start_line":28,"start_character":0,"end_line":32,"end_character":57},"in_reply_to":"bf659307_1537714f","updated":"2018-04-11 18:02:10.000000000","message":"Chris, the consumer generation is to allow concurrent *modification* to single consumer\u0027s allocations.\n\nWhat, specifically, does making the consumers table\u0027s project_id and user_id columns nullable here accomplish?","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"766423e598b8615837027d27742ece274710f96f","unresolved":false,"context_lines":[{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_b013335c","line":32,"range":{"start_line":28,"start_character":0,"end_line":32,"end_character":57},"in_reply_to":"bf659307_15d3f1d6","updated":"2018-04-11 18:13:34.000000000","message":"From placement\u0027s point of view we don\u0027t modify allocations, we replace them. We allow replacing them at all current microversions.  If an allocation is written at microversion \u003c1.8 in the code currently in master, no row is created in the consumer table.\n\nEric and Ed have expressed a desire to be able to write a consumer generation for an allocation no matter what microversion was used when that allocation was written.  So that a future request can get back a view marker for that allocation if it uses a more modern microversion. This is a thing that our use of microversions allows and even encourages.\n\n(Since we are already using None to signal something when including consumer generations, returning None for an allocation written at old microversion but requested at a new seems off.)\n\nIn order to write that generation in the first place, a row needs to go in the consumer table, when no project id or user id has been supplied. We\u0027ve got a few different options:\n\n* store the generation somewhere else\n* store fake project and user id (maybe this is fine and would avoid the funky migration?)\n* allow project id and user id to be null\n\nBy the way I\u0027m not trying to talk about use cases, but rather what the presence of microversions enables and we have to deal with (and one of the many reasons people hate them).","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"a62d17aa6daa1560a2e90d42ddf45b0fc2a04d3e","unresolved":false,"context_lines":[{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_d431025b","line":32,"range":{"start_line":28,"start_character":0,"end_line":32,"end_character":57},"in_reply_to":"bf659307_94ddca71","updated":"2018-04-11 14:45:49.000000000","message":"Here\u0027s the use case: an older (pre-project/user id) creates allocations. We create the consumer record with a generation of 0 and null project_id and user_id. Later another attempt is made to set allocations with the newer microversion, and it doesn\u0027t check that there are existing allocations, so it passes None for consumer_generation. We want that to fail so it doesn\u0027t overwrite the existing allocations. Without creating the consumer record for the first allocation, there is no way to fail the second.","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"64a1ea38fe56acc0e987f2dd91ea27bda8c290ab","unresolved":false,"context_lines":[{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_8b4924b8","line":32,"range":{"start_line":28,"start_character":0,"end_line":32,"end_character":57},"in_reply_to":"bf659307_b013335c","updated":"2018-04-11 19:28:21.000000000","message":"++ what Chris said.  Thanks for explaining that.","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"12c445dbe94c2289bb5fb82ef09e12b559df03b7","unresolved":false,"context_lines":[{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_1537714f","line":32,"range":{"start_line":28,"start_character":0,"end_line":32,"end_character":57},"in_reply_to":"bf659307_ba6d5433","updated":"2018-04-11 17:57:52.000000000","message":"It\u0027s perfectly reasonable (in fact I would encourage some use cases where it was done) for people to continue submitting allocations that are version 1.0 so they don\u0027t have to think about any of project id, consumer id, and consumer generation.\n\nExactly so they don\u0027t have to worry about that stuff.  Cases where project and user id are meaningless, and consumer generation is overhead because we know that only process X is thinking about instance Y.\n\nI don\u0027t know what the full and correct solution for this stuff is, but it is definitely the case that we need to continue supporting writing allocations in each of the 3 forms we\u0027re talking about, for ever.","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"ae97085a5dd6e489b4b8c51e8ee7fa581deafe8b","unresolved":false,"context_lines":[{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_04e429df","line":32,"range":{"start_line":28,"start_character":0,"end_line":32,"end_character":57},"in_reply_to":"bf659307_d431025b","updated":"2018-04-11 16:18:00.000000000","message":"I wrote it up here: https://review.openstack.org/#/c/560174/","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"7dc6ff0abcaa634732a7a5bbc2e7d6e88ab36c8d","unresolved":false,"context_lines":[{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_ba6d5433","line":32,"range":{"start_line":28,"start_character":0,"end_line":32,"end_character":57},"in_reply_to":"bf659307_d431025b","updated":"2018-04-11 17:27:18.000000000","message":"That\u0027s not a valid use case. The only valid use case involving allocations that have no project or user ID are for allocations that have *already* been created a long time ago and new code (after your microversion addition) attempt to *modify* those old allocations.\n\nThe lack of existence of the instance UUID in the consumers table should be perfectly capable of signaling the allocation was \"old\" and in that case we should just return a 409 Conflict to the caller who is attempting to modify those old (really old) allocations.","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"8de2f331020b9ca12bb6c7e91729f21efe93caec","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_eb0feb2b","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"updated":"2018-04-17 12:48:53.000000000","message":"you know, after looking at the following patch in the series, it occurred to me that maybe we should make the default -1 here.\n\nThat way, we\u0027d have the following situation:\n\n1) Want to find all the consumers that have not been updated ever? SELECT * FROM consumers WHERE generation \u003d -1\n\n2) Want to find all consumers that have been created or updated after the 1.2X microversion that adds generations? SELECT * FROM consumers WHERE generation \u003e\u003d 0\n\nAnd then we will need no special logic in the Consumer create/update/get methods to handle \"data migration\". We will just simply increment the generation for existing records by one. And new consumer records will get a generation of 0.\n\nThoughts?\n\n-jay","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2baa5f637cebf1daa6ae88e8f013e8b97748b459","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_985f9640","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_18bce6da","updated":"2018-04-17 20:51:53.000000000","message":"Agree; and I wouldn\u0027t be -1 on (a) 0 if we didn\u0027t have two other options that allow us to remain consistent with RPs on this front.","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"32e499babda3efa9e5abcb7c4bfa525945449fc0","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_18bce6da","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_3dc3dcef","updated":"2018-04-17 20:24:58.000000000","message":"The opaque quality of the generation, which you argued strongly for, means who really cares what the value is? We could start each consumer at 99, or random.randint(47, 873) or anything else.","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"88a5304cd138d1c6b3c09fbed6dcb6184acc5a11","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_3dc3dcef","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_5df010ca","updated":"2018-04-17 19:57:46.000000000","message":"So this is effectively what I espoused in earlier reviews.  Basically we have some temporary generation value, that only exists in mid-transaction while we\u0027re creating a Consumer.  If the transaction succeeds, that temporary value is \"incremented\" to 0 (or whatever the initial externally-visible generation will be); if the transaction fails, that record disappears as if it never existed.\n\nSo really the questions are (a) what should that temporary value be?  None, -1, or 0? and (b) what should the db default be - which IIUC only affects old migrated records.  I believe (b) is driven by (a) (see below); so...\n\nIf we use (a) None, we can compare the request generation to the record\u0027s generation without special-casing (because None \u003d\u003d None and None !\u003d \u003cintegers\u003e).  But then we have to special-case \"incrementing\" None to 0.\n\nIf we use (a) -1 then we have to special-case the comparison (-1 \u003d\u003d None) as you\u0027ve done a couple patches up; but we can increment without special-casing.\n\nIf we use (a) 0, it\u0027s the same as ^, but the initial generation the user sees is 1, which isn\u0027t the same as for RPs.  Not that that\u0027s a big deal, because they\u0027re supposed to be opaque anyway, but consistency is nice.\n\nNow (b) has to be whatever the external user sees as the initial generation, right?  So (a) None or -1 \u003d\u003e (b) 0; and (a) 0 \u003d\u003e (b) 1.\n\nDo I have that right?\n\nIf so, I\u0027m -1 on the third option - (a) 0.\n\nAnd I\u0027m coin-flip on (a) None or -1, since both result in a special case (just in different places) and the same (b).","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"32e499babda3efa9e5abcb7c4bfa525945449fc0","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_d8274e64","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_5df010ca","updated":"2018-04-17 20:24:58.000000000","message":"The -1 value only ever happens *within a transaction*. The end of that transaction calls increment_generation(), which sets it to 0. If the transaction fails, there is no record. There can never be a record with a value of -1.","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"b47c2b9533611a2ab4b31f672592bc43f2435b25","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_c29f614e","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_a24a6d24","updated":"2018-04-17 18:56:19.000000000","message":"The advantage is that for the consumers and the resource providers, newly-created records would always have a 0 generation. Just thought it would be useful to have that be consistent.","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"915e8d3b5cd72b44337e748a991d055c2aff1391","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_a24a6d24","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_b9a2a999","updated":"2018-04-17 18:44:40.000000000","message":"@Jay - I don\u0027t see the advantage. If the queries you note are things that we need, keep the default at zero, and instead of creating new records with -1, I\u0027ll create \u0027em with 0. Then the first saved consumer will have its generation at 1. Your queries then work if you just change the -1 to 0, and the \u003e\u003d0 to \u003e\u003d1.","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"9794e5923c0d3c3260526d4eb423568cd5b5d5e9","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_dd566007","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_c29f614e","updated":"2018-04-17 19:21:29.000000000","message":"Newly-created records *will* have a value of 0 in the current scheme. If you insert them manually, the DB will start them at zero. If you go through the code, increment_generation will be called, changing the temporary -1 to 0 if the transaction succeeds, and deleting the record (and the -1) if the transaction fails.","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"2baa5f637cebf1daa6ae88e8f013e8b97748b459","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_38368a05","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_d8274e64","updated":"2018-04-17 20:51:53.000000000","message":"\u003e The -1 value only ever happens *within a transaction*. The end of\n \u003e that transaction calls increment_generation(), which sets it to 0.\n \u003e If the transaction fails, there is no record. There can never be a\n \u003e record with a value of -1.\n\n \u003d\u003d\n\n \u003e Basically we have some temporary generation value, that only exists\n \u003e in mid-transaction while we\u0027re creating a Consumer.  If the\n \u003e transaction succeeds, that temporary value is \"incremented\" to 0\n \u003e (or whatever the initial externally-visible generation will be); if\n \u003e the transaction fails, that record disappears as if it never\n \u003e existed.\n\nWe are violently in agreement.","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"09b8905f6fa930677983deeee5a96859193d43b2","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_5df010ca","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_dd566007","updated":"2018-04-17 19:38:11.000000000","message":"\u003e Newly-created records *will* have a value of 0 in the current\n \u003e scheme. If you insert them manually, the DB will start them at\n \u003e zero. If you go through the code, increment_generation will be\n \u003e called, changing the temporary -1 to 0 if the transaction succeeds,\n \u003e and deleting the record (and the -1) if the transaction fails.\n\nIn the following patch [1], you have this:\n\n # We don\u0027t ever want to store nulls for generation. So we will adopt\n # the convention that objects created for new records will have a\n # generation of -1, to distinguish them from objects from existing\n # records that have a generation of 0.\n \"generation\": fields.IntegerField(nullable\u003dFalse),\n\nSo which is it? Will newly-created records have a 0 or a -1 for the generation?\n\n[1] https://review.openstack.org/#/c/561406/2/nova/api/openstack/placement/objects/resource_provider.py","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"003bdfb9fb78c43c1866e7300c62a532cac5c446","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"},{"line_number":28,"context_line":"    # These are being made nullable because we want to create consumer records"},{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"}],"source_content_type":"text/x-python","patch_set":7,"id":"9f6a8fd7_b9a2a999","line":27,"range":{"start_line":26,"start_character":70,"end_line":27,"end_character":40},"in_reply_to":"9f6a8fd7_eb0feb2b","updated":"2018-04-17 14:20:34.000000000","message":"++","commit_id":"05c4778cc89fbd701cafbf5e3bc43da75f0234d1"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"e1187f96aecc47a7aeb949a959353c55e7663c24","unresolved":false,"context_lines":[{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":11,"id":"9f6a8fd7_450d9633","line":32,"updated":"2018-04-30 15:57:55.000000000","message":"This seems like a step backwards to me. If we need to support creating allocations with older microversions that don\u0027t have these, wouldn\u0027t it be better to store some sentinel here like the all-zero uuid? Just because once we do this, we have to go through another schema and data migration to get this constraint back, if/when we ever raise the minimum microversion.\n\nMaybe it would be better to just let the operator configure a \"if no user/project, use $this one\" option? That way they could cause anything created with non-multitenant-aware stuff to end up in a single known tenant.","commit_id":"ed2b6f4abd273cd9b40e78b6bd35a760c223ea72"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"fd79ebd608146e8aac68d91c7c8e0a7279c9ad42","unresolved":false,"context_lines":[{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":11,"id":"9f6a8fd7_a8624715","line":32,"in_reply_to":"9f6a8fd7_450d9633","updated":"2018-04-30 17:51:28.000000000","message":"These columns are integer IDs, so maybe insert -1 for the project/user ids when they aren\u0027t provided?","commit_id":"ed2b6f4abd273cd9b40e78b6bd35a760c223ea72"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"6751265a4a2026d6180c24adabfdf47ced9e6615","unresolved":false,"context_lines":[{"line_number":29,"context_line":"    # even with allocations created before these fields were added as required."},{"line_number":30,"context_line":"    columns_to_nullify \u003d (\"project_id\", \"user_id\")"},{"line_number":31,"context_line":"    for column in columns_to_nullify:"},{"line_number":32,"context_line":"        getattr(consumers.c, column).alter(nullable\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":11,"id":"9f6a8fd7_0ed57be5","line":32,"in_reply_to":"9f6a8fd7_a8624715","updated":"2018-04-30 20:09:04.000000000","message":"Ah, I see. And no FKR between these and a row in Project/User. That sucks :(\n\nWhat are they set to now in the case where we created an allocation without user/project? Maybe we have no consumer row at all in that case?\n\nEither way, I\u0027d say these should grow a FKR to user/project, and we should have rows in there for zero-uuid, or for CONF.what_project_if_not_specified.\n\nThat makes this a lot less confusing of a data model, IMHO. Right now, we have a bunch of missing data if the allocation was created with an early microversion (even if it\u0027s done today). That makes our data model inconsistent because of the API. What we should do, whenever possible, is make the data model consistent *in spite* of the API needing to span versions.","commit_id":"ed2b6f4abd273cd9b40e78b6bd35a760c223ea72"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"09e6b8915736b6676a52689fb6e28d37836ba0be","unresolved":false,"context_lines":[{"line_number":18,"context_line":"from sqlalchemy import Table"},{"line_number":19,"context_line":"from sqlalchemy import text"},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"from nova.api.openstack.placement.objects import resource_provider as rp_obj"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"CONF \u003d cfg.CONF"},{"line_number":24,"context_line":""}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_51baf709","line":21,"updated":"2018-05-10 13:14:40.000000000","message":"Based on my experiences with extracting placement and trying to create low footprint containers (or otherwise isolated services), importing from the \"active code\" in migrations has unintended side effects, especially with regard to unintended imports of all the packages that contain the target of the imported thing.\n\nIt also means that it is impossible to package migrations separate from \"active code\", which I think would be really handy.\n\nSo in this case since we\u0027ve already got schema specific information in this file, I don\u0027t really see the value in import the *_TBL stuff in here. Was there some particular reason you did it?","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"10bca03372f76f63dcfa207905f5edfae3fb3fdc","unresolved":false,"context_lines":[{"line_number":18,"context_line":"from sqlalchemy import Table"},{"line_number":19,"context_line":"from sqlalchemy import text"},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"from nova.api.openstack.placement.objects import resource_provider as rp_obj"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"CONF \u003d cfg.CONF"},{"line_number":24,"context_line":""}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_b1e7cbac","line":21,"in_reply_to":"5f7c97a3_51baf709","updated":"2018-05-10 13:41:06.000000000","message":"Yeah, we shouldn\u0027t do this. The last time we did, we ended up with a migration that did different things depending on config, which ended up with a fork of what people in the wild could have.\n\nThese should stand alone.","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"10bca03372f76f63dcfa207905f5edfae3fb3fdc","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    sel \u003d sel.where(rp_obj._CONSUMER_TBL.c.id.is_(None))"},{"line_number":81,"context_line":"    target_cols \u003d [\u0027uuid\u0027, \u0027project_id\u0027, \u0027user_id\u0027]"},{"line_number":82,"context_line":"    ins_stmt \u003d rp_obj._CONSUMER_TBL.insert().from_select(target_cols, sel)"},{"line_number":83,"context_line":"    migrate_engine.execute(ins_stmt)"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_7105b345","line":83,"updated":"2018-05-10 13:41:06.000000000","message":"This is a data migration, which we don\u0027t do in schema migrations anymore. This needs to be in an online migration that we push after the schema is done. Otherwise, we require everything to be down while this runs (and iterates all the existing non-consumer-having records), and everything to be upgraded after it has completed.","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"b228b52b2c51149d659592d1924a6ee241b0da34","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    sel \u003d sel.where(rp_obj._CONSUMER_TBL.c.id.is_(None))"},{"line_number":81,"context_line":"    target_cols \u003d [\u0027uuid\u0027, \u0027project_id\u0027, \u0027user_id\u0027]"},{"line_number":82,"context_line":"    ins_stmt \u003d rp_obj._CONSUMER_TBL.insert().from_select(target_cols, sel)"},{"line_number":83,"context_line":"    migrate_engine.execute(ins_stmt)"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_42e4633c","line":83,"in_reply_to":"5f7c97a3_7105b345","updated":"2018-05-10 15:09:27.000000000","message":"\u003e This is a data migration, which we don\u0027t do in schema migrations\n \u003e anymore. This needs to be in an online migration that we push after\n \u003e the schema is done.\n\nActually, come to think of it this data migration has little to do with the schema migration being performed here, technically.\n\nWe can (and probably should) do the data migration to ensure consumer/project/user records *before* doing the schema migration here for adding the generation column.\n\nThoughts?","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"f58f0502c024000266cab9cc48df24e57f8d7474","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    sel \u003d sel.where(rp_obj._CONSUMER_TBL.c.id.is_(None))"},{"line_number":81,"context_line":"    target_cols \u003d [\u0027uuid\u0027, \u0027project_id\u0027, \u0027user_id\u0027]"},{"line_number":82,"context_line":"    ins_stmt \u003d rp_obj._CONSUMER_TBL.insert().from_select(target_cols, sel)"},{"line_number":83,"context_line":"    migrate_engine.execute(ins_stmt)"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_c4bac36c","line":83,"in_reply_to":"5f7c97a3_7105b345","updated":"2018-05-10 14:22:29.000000000","message":"It is a single INSERT statement. It\u0027s not iterating over anything.","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"81032c0d3a5522e9802d75db2d034cf1c9461f31","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    sel \u003d sel.where(rp_obj._CONSUMER_TBL.c.id.is_(None))"},{"line_number":81,"context_line":"    target_cols \u003d [\u0027uuid\u0027, \u0027project_id\u0027, \u0027user_id\u0027]"},{"line_number":82,"context_line":"    ins_stmt \u003d rp_obj._CONSUMER_TBL.insert().from_select(target_cols, sel)"},{"line_number":83,"context_line":"    migrate_engine.execute(ins_stmt)"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_b1b58b80","line":83,"in_reply_to":"5f7c97a3_7105b345","updated":"2018-05-10 13:42:53.000000000","message":"https://docs.openstack.org/nova/ocata/upgrade.html#migration-policy","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"23b5f0363324752f0688d849b3c19539ff19bd79","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    sel \u003d sel.where(rp_obj._CONSUMER_TBL.c.id.is_(None))"},{"line_number":81,"context_line":"    target_cols \u003d [\u0027uuid\u0027, \u0027project_id\u0027, \u0027user_id\u0027]"},{"line_number":82,"context_line":"    ins_stmt \u003d rp_obj._CONSUMER_TBL.insert().from_select(target_cols, sel)"},{"line_number":83,"context_line":"    migrate_engine.execute(ins_stmt)"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_c70ba521","line":83,"in_reply_to":"5f7c97a3_a438e7ed","updated":"2018-05-10 14:29:23.000000000","message":"should I be creating the missing project/user records in a separate data migration as well?","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"579a91aa70f6991bd39bc20c136d1348f7161eff","unresolved":false,"context_lines":[{"line_number":80,"context_line":"    sel \u003d sel.where(rp_obj._CONSUMER_TBL.c.id.is_(None))"},{"line_number":81,"context_line":"    target_cols \u003d [\u0027uuid\u0027, \u0027project_id\u0027, \u0027user_id\u0027]"},{"line_number":82,"context_line":"    ins_stmt \u003d rp_obj._CONSUMER_TBL.insert().from_select(target_cols, sel)"},{"line_number":83,"context_line":"    migrate_engine.execute(ins_stmt)"}],"source_content_type":"text/x-python","patch_set":18,"id":"5f7c97a3_a438e7ed","line":83,"in_reply_to":"5f7c97a3_c4bac36c","updated":"2018-05-10 14:26:34.000000000","message":"The database is...","commit_id":"b5d4d937dc1f3cc8ed1b1c48009da504a382bda4"},{"author":{"_account_id":7730,"name":"Sahid Orentino Ferdjaoui","email":"sahid.ferdjaoui@industrialdiscipline.com","username":"sahid"},"change_message_id":"265e364eafd584c67ec668526a8f863a4f115066","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"}],"source_content_type":"text/x-python","patch_set":21,"id":"5f7c97a3_921956d8","line":26,"range":{"start_line":26,"start_character":53,"end_line":26,"end_character":60},"updated":"2018-05-29 07:29:33.000000000","message":"Is that not just going to be incremented? why not to use an \u0027Integer(unsigned\u003dTrue)\u0027","commit_id":"9ee915294d296c5c52eb52ad07ef6a6c4bb08159"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"4a24eea9ea33a5f4b32de9f54f24090efc81a90c","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"}],"source_content_type":"text/x-python","patch_set":21,"id":"5f7c97a3_f7666fed","line":26,"range":{"start_line":26,"start_character":53,"end_line":26,"end_character":60},"in_reply_to":"5f7c97a3_921956d8","updated":"2018-05-29 17:48:00.000000000","message":"probably just copy/paste from the patch that added resource_providers.generation... we can change them to unsigned in a later patch probably.","commit_id":"9ee915294d296c5c52eb52ad07ef6a6c4bb08159"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ab699fa9a6d4b3ca6fb8a40fac01d12bdd2018ac","unresolved":false,"context_lines":[{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"}],"source_content_type":"text/x-python","patch_set":27,"id":"5f7c97a3_e88452b3","line":27,"range":{"start_line":27,"start_character":16,"end_line":27,"end_character":40},"updated":"2018-06-11 16:28:06.000000000","message":"Why is this needed? We don\u0027t have it in the 016 migration for resource_providers...","commit_id":"e6e3c459522ae8ced5cf7b63535e51e738dffeeb"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"09aef2204cd96e679e78ad476b1ec4293b095206","unresolved":false,"context_lines":[{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"}],"source_content_type":"text/x-python","patch_set":27,"id":"5f7c97a3_6b935c50","line":27,"range":{"start_line":27,"start_character":16,"end_line":27,"end_character":40},"in_reply_to":"5f7c97a3_0b23c859","updated":"2018-06-11 17:17:42.000000000","message":"Adding jroll\u0027s comment in here for posterity.","commit_id":"e6e3c459522ae8ced5cf7b63535e51e738dffeeb"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"1e4620bea4782ac5da1334fdec515c9f9f8a4529","unresolved":false,"context_lines":[{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"}],"source_content_type":"text/x-python","patch_set":27,"id":"5f7c97a3_46d9ae80","line":27,"range":{"start_line":27,"start_character":16,"end_line":27,"end_character":40},"in_reply_to":"5f7c97a3_6b935c50","updated":"2018-06-12 01:33:40.000000000","message":"See Mike Bayer\u0027s comment from PS4:\n\nhttps://review.openstack.org/#/c/557958/4..27/nova/db/sqlalchemy/api_migrations/migrate_repo/versions/059_add_consumer_generation.py","commit_id":"e6e3c459522ae8ced5cf7b63535e51e738dffeeb"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"a0e37f3152f15e0f767dcc1e8da19f45c997ff15","unresolved":false,"context_lines":[{"line_number":24,"context_line":"    consumers \u003d Table(\"consumers\", meta, autoload\u003dTrue)"},{"line_number":25,"context_line":"    if not hasattr(consumers.c, \"generation\"):"},{"line_number":26,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":27,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"}],"source_content_type":"text/x-python","patch_set":27,"id":"5f7c97a3_0b23c859","line":27,"range":{"start_line":27,"start_character":16,"end_line":27,"end_character":40},"in_reply_to":"5f7c97a3_e88452b3","updated":"2018-06-11 16:39:24.000000000","message":"(11:36:42 AM) jroll: mriedem: this is adding a column to an existing table, so the server_default bit will make existing rows 0 for that column","commit_id":"e6e3c459522ae8ced5cf7b63535e51e738dffeeb"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"56362339f16a902ad866bb7e4f05eb0f8e57477f","unresolved":false,"context_lines":[{"line_number":26,"context_line":"        # This is adding a column to an existing table, so the server_default"},{"line_number":27,"context_line":"        # bit will make existing rows 0 for that column."},{"line_number":28,"context_line":"        consumers.create_column(Column(\"generation\", Integer, default\u003d0,"},{"line_number":29,"context_line":"                server_default\u003dtext(\"0\"), nullable\u003dFalse))"}],"source_content_type":"text/x-python","patch_set":28,"id":"5f7c97a3_994716a4","line":29,"updated":"2018-06-12 17:29:22.000000000","message":"a fix for this issue up in review at https://review.openstack.org/#/c/574818/","commit_id":"22adbe96524243dd9d126e8dab08427a874c7ab1"}],"nova/db/sqlalchemy/api_models.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ab699fa9a6d4b3ca6fb8a40fac01d12bdd2018ac","unresolved":false,"context_lines":[{"line_number":642,"context_line":"    uuid \u003d Column(String(36), nullable\u003dFalse)"},{"line_number":643,"context_line":"    project_id \u003d Column(Integer, nullable\u003dFalse)"},{"line_number":644,"context_line":"    user_id \u003d Column(Integer, nullable\u003dFalse)"},{"line_number":645,"context_line":"    generation \u003d Column(Integer, nullable\u003dFalse, server_default\u003d\"0\", default\u003d0)"}],"source_content_type":"text/x-python","patch_set":27,"id":"5f7c97a3_28b80a73","line":645,"range":{"start_line":645,"start_character":64,"end_line":645,"end_character":67},"updated":"2018-06-11 16:28:06.000000000","message":"Why not text(\"0\") to match the script?","commit_id":"e6e3c459522ae8ced5cf7b63535e51e738dffeeb"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"09aef2204cd96e679e78ad476b1ec4293b095206","unresolved":false,"context_lines":[{"line_number":642,"context_line":"    uuid \u003d Column(String(36), nullable\u003dFalse)"},{"line_number":643,"context_line":"    project_id \u003d Column(Integer, nullable\u003dFalse)"},{"line_number":644,"context_line":"    user_id \u003d Column(Integer, nullable\u003dFalse)"},{"line_number":645,"context_line":"    generation \u003d Column(Integer, nullable\u003dFalse, server_default\u003d\"0\", default\u003d0)"}],"source_content_type":"text/x-python","patch_set":27,"id":"5f7c97a3_2b99e46b","line":645,"range":{"start_line":645,"start_character":64,"end_line":645,"end_character":67},"in_reply_to":"5f7c97a3_28b80a73","updated":"2018-06-11 17:17:42.000000000","message":"Done","commit_id":"e6e3c459522ae8ced5cf7b63535e51e738dffeeb"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"b079587f333a2549e7a8089cec1c0fe53dd1e9db","unresolved":false,"context_lines":[{"line_number":26,"context_line":"from sqlalchemy.orm import backref"},{"line_number":27,"context_line":"from sqlalchemy import schema"},{"line_number":28,"context_line":"from sqlalchemy import String"},{"line_number":29,"context_line":"from sqlalchemy import text"},{"line_number":30,"context_line":"from sqlalchemy import Text"},{"line_number":31,"context_line":"from sqlalchemy import Unicode"},{"line_number":32,"context_line":""}],"source_content_type":"text/x-python","patch_set":30,"id":"5f7c97a3_0a7ba27a","line":29,"updated":"2018-06-12 19:16:26.000000000","message":"rebase failure","commit_id":"f705e6af43b80747fc0364d31fa113ca71d987e9"}],"nova/tests/functional/db/api/test_migrations.py":[{"author":{"_account_id":17190,"name":"Arvind Nadendla","email":"arvindn05@gmail.com","username":"arvindn05"},"change_message_id":"40a260699fc84cb788369e872fc9e3da76985009","unresolved":false,"context_lines":[{"line_number":690,"context_line":"        self.assertColumnExists(engine, \u0027cell_mappings\u0027, \u0027disabled\u0027)"},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"    def _check_059(self, engine, data):"},{"line_number":693,"context_line":"        self.assertColumnExists(engine, \"consumers\", \"generation\")"},{"line_number":694,"context_line":"        consumer_table \u003d db_utils.get_table(engine, \"consumers\")"},{"line_number":695,"context_line":"        self.assertTrue(consumer_table.columns[\"project_id\"].nullable)"},{"line_number":696,"context_line":"        self.assertTrue(consumer_table.columns[\"user_id\"].nullable)"},{"line_number":697,"context_line":""},{"line_number":698,"context_line":""},{"line_number":699,"context_line":"class TestNovaAPIMigrationsWalkSQLite(NovaAPIMigrationsWalk,"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_486a4fb3","line":696,"range":{"start_line":693,"start_character":8,"end_line":696,"end_character":67},"updated":"2018-04-10 21:56:15.000000000","message":"style nit: Consistently with rest of the file, use single quotes.","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"a62d17aa6daa1560a2e90d42ddf45b0fc2a04d3e","unresolved":false,"context_lines":[{"line_number":690,"context_line":"        self.assertColumnExists(engine, \u0027cell_mappings\u0027, \u0027disabled\u0027)"},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"    def _check_059(self, engine, data):"},{"line_number":693,"context_line":"        self.assertColumnExists(engine, \"consumers\", \"generation\")"},{"line_number":694,"context_line":"        consumer_table \u003d db_utils.get_table(engine, \"consumers\")"},{"line_number":695,"context_line":"        self.assertTrue(consumer_table.columns[\"project_id\"].nullable)"},{"line_number":696,"context_line":"        self.assertTrue(consumer_table.columns[\"user_id\"].nullable)"},{"line_number":697,"context_line":""},{"line_number":698,"context_line":""},{"line_number":699,"context_line":"class TestNovaAPIMigrationsWalkSQLite(NovaAPIMigrationsWalk,"}],"source_content_type":"text/x-python","patch_set":6,"id":"bf659307_744276ad","line":696,"range":{"start_line":693,"start_character":8,"end_line":696,"end_character":67},"in_reply_to":"bf659307_486a4fb3","updated":"2018-04-11 14:45:49.000000000","message":"There is no consistency in this file. Look at L679-682 for a nearby example.","commit_id":"787e09cb4017aea4ede68d488b6eee0a26fec614"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8cbc5fd9a0bcdef41f7c91aeac572f89b97c26a6","unresolved":false,"context_lines":[{"line_number":748,"context_line":"        missing_c1 \u003d consumers.select("},{"line_number":749,"context_line":"            consumers.c.uuid \u003d\u003d uuids.c1_missing).execute().first()"},{"line_number":750,"context_line":"        self.assertEqual(sentinel_proj_id, missing_c1[\u0027project_id\u0027])"},{"line_number":751,"context_line":"        missing_c1 \u003d consumers.select("},{"line_number":752,"context_line":"            consumers.c.uuid \u003d\u003d uuids.c1_missing).execute().first()"},{"line_number":753,"context_line":"        self.assertEqual(sentinel_user_id, missing_c1[\u0027user_id\u0027])"},{"line_number":754,"context_line":"        missing_c2 \u003d consumers.select("},{"line_number":755,"context_line":"            consumers.c.uuid \u003d\u003d uuids.c2_missing).execute().first()"}],"source_content_type":"text/x-python","patch_set":14,"id":"5f7c97a3_11a7e451","line":752,"range":{"start_line":751,"start_character":0,"end_line":752,"end_character":67},"updated":"2018-05-07 21:30:22.000000000","message":"is it necessary to do this again?","commit_id":"a497e1edf2050b6439c7a3220233b92f8604a221"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"f8096b4c933d6098de658812c343c16bcb6746f1","unresolved":false,"context_lines":[{"line_number":748,"context_line":"        missing_c1 \u003d consumers.select("},{"line_number":749,"context_line":"            consumers.c.uuid \u003d\u003d uuids.c1_missing).execute().first()"},{"line_number":750,"context_line":"        self.assertEqual(sentinel_proj_id, missing_c1[\u0027project_id\u0027])"},{"line_number":751,"context_line":"        missing_c1 \u003d consumers.select("},{"line_number":752,"context_line":"            consumers.c.uuid \u003d\u003d uuids.c1_missing).execute().first()"},{"line_number":753,"context_line":"        self.assertEqual(sentinel_user_id, missing_c1[\u0027user_id\u0027])"},{"line_number":754,"context_line":"        missing_c2 \u003d consumers.select("},{"line_number":755,"context_line":"            consumers.c.uuid \u003d\u003d uuids.c2_missing).execute().first()"}],"source_content_type":"text/x-python","patch_set":14,"id":"5f7c97a3_cc9eafb7","line":752,"range":{"start_line":751,"start_character":0,"end_line":752,"end_character":67},"in_reply_to":"5f7c97a3_11a7e451","updated":"2018-05-07 21:50:53.000000000","message":"lol, no, copy/pasta","commit_id":"a497e1edf2050b6439c7a3220233b92f8604a221"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"8cbc5fd9a0bcdef41f7c91aeac572f89b97c26a6","unresolved":false,"context_lines":[{"line_number":754,"context_line":"        missing_c2 \u003d consumers.select("},{"line_number":755,"context_line":"            consumers.c.uuid \u003d\u003d uuids.c2_missing).execute().first()"},{"line_number":756,"context_line":"        self.assertEqual(sentinel_proj_id, missing_c2[\u0027project_id\u0027])"},{"line_number":757,"context_line":"        missing_c2 \u003d consumers.select("},{"line_number":758,"context_line":"            consumers.c.uuid \u003d\u003d uuids.c2_missing).execute().first()"},{"line_number":759,"context_line":"        self.assertEqual(sentinel_user_id, missing_c2[\u0027user_id\u0027])"},{"line_number":760,"context_line":""},{"line_number":761,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"5f7c97a3_b163901a","line":758,"range":{"start_line":757,"start_character":0,"end_line":758,"end_character":67},"updated":"2018-05-07 21:30:22.000000000","message":"ditto.","commit_id":"a497e1edf2050b6439c7a3220233b92f8604a221"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"ab699fa9a6d4b3ca6fb8a40fac01d12bdd2018ac","unresolved":false,"context_lines":[{"line_number":690,"context_line":"        self.assertColumnExists(engine, \u0027cell_mappings\u0027, \u0027disabled\u0027)"},{"line_number":691,"context_line":""},{"line_number":692,"context_line":"    def _check_059(self, engine, data):"},{"line_number":693,"context_line":"        self.assertColumnExists(engine, \"consumers\", \"generation\")"},{"line_number":694,"context_line":""},{"line_number":695,"context_line":""},{"line_number":696,"context_line":"class TestNovaAPIMigrationsWalkSQLite(NovaAPIMigrationsWalk,"}],"source_content_type":"text/x-python","patch_set":27,"id":"5f7c97a3_48622618","line":693,"updated":"2018-06-11 16:28:06.000000000","message":"nit: we could have a pre-upgrade method that inserts a consumer record and then after we run the migration, we assert the consumer\u0027s generation is not only set, but the value is 0.","commit_id":"e6e3c459522ae8ced5cf7b63535e51e738dffeeb"}]}
