)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"8803fd8f5fc8694477d8057102c2ac0ede032f7b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"ba74185a_e427060b","updated":"2026-06-11 13:37:51.000000000","message":"Ups, abandoned by a mistake.","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"209daf11ca85fb8a0c7cc87b90b7e769c5753076","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"3f7ac562_b2311bed","updated":"2026-06-11 16:59:50.000000000","message":"recheck non-related","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"be64e5dbb2563b99197a611e16af8ab6edcf08b9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"a7084c23_09b83f16","updated":"2026-06-22 14:14:33.000000000","message":"recheck - CI fixed now","commit_id":"c1357170badc891fc7ad02870848bd3dfcdf4d0a"},{"author":{"_account_id":17669,"name":"Doug Szumski","email":"doug@stackhpc.com","username":"DougSzumski"},"change_message_id":"2302711c9d97205f9b2f6f021f37544a49381bd4","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"11445f0c_cd71962c","updated":"2026-07-02 10:13:25.000000000","message":"It looks good overall. Some minor tweaks to the tests would be useful.","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"eacf8a64d49d91229be7638b521f890775ac1bc7","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":10,"id":"70255fea_5260bb75","updated":"2026-06-30 08:15:19.000000000","message":"This is also ready, can u please review ? Thanks","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"}],"doc/source/admin/kolla_api.rst":[{"author":{"_account_id":22629,"name":"Michal Nasiadka","email":"mnasiadka@gmail.com","username":"mnasiadka"},"change_message_id":"f0d57d05ca7d618dbb71c7ec05f1b57cee6b4c54","unresolved":true,"context_lines":[{"line_number":64,"context_line":"  * **perm** (required): the unix permissions to set to the directory."},{"line_number":65,"context_line":"    Must be passed in the numeric octal form."},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"* **files**: create files inside the container if they do not exist, and set"},{"line_number":68,"context_line":"  their ownership and permissions. A list of dicts, each containing the"},{"line_number":69,"context_line":"  following attributes:"},{"line_number":70,"context_line":""}],"source_content_type":"text/x-rst","patch_set":5,"id":"fe45da1c_97d8276e","line":67,"range":{"start_line":67,"start_character":13,"end_line":67,"end_character":25},"updated":"2026-06-15 14:36:24.000000000","message":"nit: empty?","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"31f3d30044fdabd65ef151110cb7a90bd6522bbb","unresolved":false,"context_lines":[{"line_number":64,"context_line":"  * **perm** (required): the unix permissions to set to the directory."},{"line_number":65,"context_line":"    Must be passed in the numeric octal form."},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"* **files**: create files inside the container if they do not exist, and set"},{"line_number":68,"context_line":"  their ownership and permissions. A list of dicts, each containing the"},{"line_number":69,"context_line":"  following attributes:"},{"line_number":70,"context_line":""}],"source_content_type":"text/x-rst","patch_set":5,"id":"fd799ee2_f1ce2d49","line":67,"range":{"start_line":67,"start_character":13,"end_line":67,"end_character":25},"in_reply_to":"fe45da1c_97d8276e","updated":"2026-06-21 19:29:43.000000000","message":"Done","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"}],"docker/base/set_configs.py":[{"author":{"_account_id":22629,"name":"Michal Nasiadka","email":"mnasiadka@gmail.com","username":"mnasiadka"},"change_message_id":"f0d57d05ca7d618dbb71c7ec05f1b57cee6b4c54","unresolved":true,"context_lines":[{"line_number":258,"context_line":"def validate_config(config):"},{"line_number":259,"context_line":"    required_keys \u003d {\u0027source\u0027, \u0027dest\u0027}"},{"line_number":260,"context_line":"    required_dir_keys \u003d {\u0027path\u0027, \u0027owner\u0027, \u0027perm\u0027}"},{"line_number":261,"context_line":"    required_file_keys \u003d {\u0027path\u0027, \u0027owner\u0027, \u0027perm\u0027}"},{"line_number":262,"context_line":""},{"line_number":263,"context_line":"    if \u0027command\u0027 not in config:"},{"line_number":264,"context_line":"        raise InvalidConfig(\u0027Config is missing required \"command\" key\u0027)"}],"source_content_type":"text/x-python","patch_set":5,"id":"f7566627_337715da","line":261,"updated":"2026-06-15 14:36:24.000000000","message":"We could collapse both into required_path_keys?","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"31f3d30044fdabd65ef151110cb7a90bd6522bbb","unresolved":false,"context_lines":[{"line_number":258,"context_line":"def validate_config(config):"},{"line_number":259,"context_line":"    required_keys \u003d {\u0027source\u0027, \u0027dest\u0027}"},{"line_number":260,"context_line":"    required_dir_keys \u003d {\u0027path\u0027, \u0027owner\u0027, \u0027perm\u0027}"},{"line_number":261,"context_line":"    required_file_keys \u003d {\u0027path\u0027, \u0027owner\u0027, \u0027perm\u0027}"},{"line_number":262,"context_line":""},{"line_number":263,"context_line":"    if \u0027command\u0027 not in config:"},{"line_number":264,"context_line":"        raise InvalidConfig(\u0027Config is missing required \"command\" key\u0027)"}],"source_content_type":"text/x-python","patch_set":5,"id":"10924fef_84fd9534","line":261,"in_reply_to":"f7566627_337715da","updated":"2026-06-21 19:29:43.000000000","message":"Done","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":22629,"name":"Michal Nasiadka","email":"mnasiadka@gmail.com","username":"mnasiadka"},"change_message_id":"f0d57d05ca7d618dbb71c7ec05f1b57cee6b4c54","unresolved":true,"context_lines":[{"line_number":280,"context_line":"                       % (required_dir_keys - set(data.keys())))"},{"line_number":281,"context_line":"            raise InvalidConfig(message)"},{"line_number":282,"context_line":""},{"line_number":283,"context_line":"    for data in config.get(\u0027files\u0027, list()):"},{"line_number":284,"context_line":"        if not set(data.keys()) \u003e\u003d required_file_keys:"},{"line_number":285,"context_line":"            message \u003d (\u0027files config is missing required keys: %s\u0027"},{"line_number":286,"context_line":"                       % (required_file_keys - set(data.keys())))"}],"source_content_type":"text/x-python","patch_set":5,"id":"6e9bd1ea_5be92479","line":283,"updated":"2026-06-15 14:36:24.000000000","message":"What happens if owner or perm are null?","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"31f3d30044fdabd65ef151110cb7a90bd6522bbb","unresolved":false,"context_lines":[{"line_number":280,"context_line":"                       % (required_dir_keys - set(data.keys())))"},{"line_number":281,"context_line":"            raise InvalidConfig(message)"},{"line_number":282,"context_line":""},{"line_number":283,"context_line":"    for data in config.get(\u0027files\u0027, list()):"},{"line_number":284,"context_line":"        if not set(data.keys()) \u003e\u003d required_file_keys:"},{"line_number":285,"context_line":"            message \u003d (\u0027files config is missing required keys: %s\u0027"},{"line_number":286,"context_line":"                       % (required_file_keys - set(data.keys())))"}],"source_content_type":"text/x-python","patch_set":5,"id":"49f10bd7_f79369d3","line":283,"in_reply_to":"6e9bd1ea_5be92479","updated":"2026-06-21 19:29:43.000000000","message":"Done","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":22629,"name":"Michal Nasiadka","email":"mnasiadka@gmail.com","username":"mnasiadka"},"change_message_id":"f0d57d05ca7d618dbb71c7ec05f1b57cee6b4c54","unresolved":true,"context_lines":[{"line_number":285,"context_line":"            message \u003d (\u0027files config is missing required keys: %s\u0027"},{"line_number":286,"context_line":"                       % (required_file_keys - set(data.keys())))"},{"line_number":287,"context_line":"            raise InvalidConfig(message)"},{"line_number":288,"context_line":"        if glob.has_magic(data[\u0027path\u0027]):"},{"line_number":289,"context_line":"            raise InvalidConfig("},{"line_number":290,"context_line":"                \u0027files config does not support glob paths: %s\u0027 %"},{"line_number":291,"context_line":"                data[\u0027path\u0027])"}],"source_content_type":"text/x-python","patch_set":5,"id":"162b847b_06930594","line":288,"updated":"2026-06-15 14:36:24.000000000","message":"Probably doing the same in directories creation might make sense?","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"31f3d30044fdabd65ef151110cb7a90bd6522bbb","unresolved":false,"context_lines":[{"line_number":285,"context_line":"            message \u003d (\u0027files config is missing required keys: %s\u0027"},{"line_number":286,"context_line":"                       % (required_file_keys - set(data.keys())))"},{"line_number":287,"context_line":"            raise InvalidConfig(message)"},{"line_number":288,"context_line":"        if glob.has_magic(data[\u0027path\u0027]):"},{"line_number":289,"context_line":"            raise InvalidConfig("},{"line_number":290,"context_line":"                \u0027files config does not support glob paths: %s\u0027 %"},{"line_number":291,"context_line":"                data[\u0027path\u0027])"}],"source_content_type":"text/x-python","patch_set":5,"id":"0d218efd_2c7f87fc","line":288,"in_reply_to":"162b847b_06930594","updated":"2026-06-21 19:29:43.000000000","message":"Done","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":22629,"name":"Michal Nasiadka","email":"mnasiadka@gmail.com","username":"mnasiadka"},"change_message_id":"f0d57d05ca7d618dbb71c7ec05f1b57cee6b4c54","unresolved":true,"context_lines":[{"line_number":365,"context_line":"        handle_permissions({\u0027permissions\u0027: [data]})"},{"line_number":366,"context_line":""},{"line_number":367,"context_line":""},{"line_number":368,"context_line":"def create_files(config):"},{"line_number":369,"context_line":"    if \u0027files\u0027 not in config:"},{"line_number":370,"context_line":"        return"},{"line_number":371,"context_line":"    LOG.info(\u0027Creating files\u0027)"}],"source_content_type":"text/x-python","patch_set":5,"id":"84a02a9d_011109d9","line":368,"updated":"2026-06-15 14:36:24.000000000","message":"What happens if path is a link already?","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"8365c6164b4ec9a353a6ebe622299797538a9537","unresolved":false,"context_lines":[{"line_number":365,"context_line":"        handle_permissions({\u0027permissions\u0027: [data]})"},{"line_number":366,"context_line":""},{"line_number":367,"context_line":""},{"line_number":368,"context_line":"def create_files(config):"},{"line_number":369,"context_line":"    if \u0027files\u0027 not in config:"},{"line_number":370,"context_line":"        return"},{"line_number":371,"context_line":"    LOG.info(\u0027Creating files\u0027)"}],"source_content_type":"text/x-python","patch_set":5,"id":"66ff25b7_fe606fb7","line":368,"in_reply_to":"84a02a9d_011109d9","updated":"2026-06-23 07:25:08.000000000","message":"Now, it will fail as it should with proper Exception. Thanks.","commit_id":"be827bc6a8378f3caae5943ecdda69cf6110c279"},{"author":{"_account_id":17669,"name":"Doug Szumski","email":"doug@stackhpc.com","username":"DougSzumski"},"change_message_id":"2302711c9d97205f9b2f6f021f37544a49381bd4","unresolved":true,"context_lines":[{"line_number":288,"context_line":"                        \u0027%s config key \"%s\" must not be null\u0027"},{"line_number":289,"context_line":"                        % (section, key))"},{"line_number":290,"context_line":""},{"line_number":291,"context_line":"            if glob.has_magic(data[\u0027path\u0027]):"},{"line_number":292,"context_line":"                raise InvalidConfig("},{"line_number":293,"context_line":"                    \u0027%s config does not support glob paths: %s\u0027"},{"line_number":294,"context_line":"                    % (section, data[\u0027path\u0027]))"}],"source_content_type":"text/x-python","patch_set":10,"id":"e40dd3f6_4fc8a858","line":291,"updated":"2026-07-02 10:13:25.000000000","message":"micronit: ``if section \u003d\u003d \u0027files\u0027 and glob.has_magic(data[\u0027path\u0027]):``\n\nTo avoid checking directories for the chars in the magic check:\n```\nmagic_check \u003d re.compile(\u0027[*?[]\u0027)\n```\n\n(none of which are remotely likely)\n\n[1] https://tedboy.github.io/python_stdlib/_modules/glob.html#has_magic","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"},{"author":{"_account_id":17669,"name":"Doug Szumski","email":"doug@stackhpc.com","username":"DougSzumski"},"change_message_id":"00cc475b6b8c767991c422212e189390cb99fdf0","unresolved":false,"context_lines":[{"line_number":288,"context_line":"                        \u0027%s config key \"%s\" must not be null\u0027"},{"line_number":289,"context_line":"                        % (section, key))"},{"line_number":290,"context_line":""},{"line_number":291,"context_line":"            if glob.has_magic(data[\u0027path\u0027]):"},{"line_number":292,"context_line":"                raise InvalidConfig("},{"line_number":293,"context_line":"                    \u0027%s config does not support glob paths: %s\u0027"},{"line_number":294,"context_line":"                    % (section, data[\u0027path\u0027]))"}],"source_content_type":"text/x-python","patch_set":10,"id":"e7ab3fd4_40c99766","line":291,"in_reply_to":"70f97f18_4d6f13c1","updated":"2026-07-02 15:26:26.000000000","message":"I\u0027m fine with that","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"4cf729cb114863b609dce198727c60275af384c0","unresolved":false,"context_lines":[{"line_number":288,"context_line":"                        \u0027%s config key \"%s\" must not be null\u0027"},{"line_number":289,"context_line":"                        % (section, key))"},{"line_number":290,"context_line":""},{"line_number":291,"context_line":"            if glob.has_magic(data[\u0027path\u0027]):"},{"line_number":292,"context_line":"                raise InvalidConfig("},{"line_number":293,"context_line":"                    \u0027%s config does not support glob paths: %s\u0027"},{"line_number":294,"context_line":"                    % (section, data[\u0027path\u0027]))"}],"source_content_type":"text/x-python","patch_set":10,"id":"70f97f18_4d6f13c1","line":291,"in_reply_to":"e40dd3f6_4fc8a858","updated":"2026-07-02 14:39:25.000000000","message":"Doug, please check comment from @mnasiadka@gmail.com here https://review.opendev.org/c/openstack/kolla/+/989936/comment/162b847b_06930594/ .\n\nOriginaly it was only for files path of the code ... Michal asked me to do for directories also, and it of course make a sense. Marking as resolved, please reopen if you think it should be reworked.","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"}],"tests/test_set_config.py":[{"author":{"_account_id":17669,"name":"Doug Szumski","email":"doug@stackhpc.com","username":"DougSzumski"},"change_message_id":"2302711c9d97205f9b2f6f021f37544a49381bd4","unresolved":true,"context_lines":[{"line_number":1078,"context_line":"            \u0027files\u0027: [{\u0027path\u0027: \u0027/var/log/*.log\u0027,"},{"line_number":1079,"context_line":"                       \u0027owner\u0027: \u0027myuser\u0027, \u0027perm\u0027: \u00270644\u0027}]"},{"line_number":1080,"context_line":"        }"},{"line_number":1081,"context_line":"        self.assertRaises(set_configs.InvalidConfig,"},{"line_number":1082,"context_line":"                          set_configs.validate_config, config)"},{"line_number":1083,"context_line":""},{"line_number":1084,"context_line":"    def test_validate_config_files_valid(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"b8a51f06_4af5ee90","line":1081,"updated":"2026-07-02 10:13:25.000000000","message":"nit: ``assertRaisesRegex`` would ensure this is raising an exception in the correct place, eg. something like:\n\n```\nself.assertRaises(set_configs.InvalidConfig, \"does not support glob paths\", set_configs.validate_config, config)\n```\n\nOtherwise it could pass with a missing key for example. Similar for the test above.","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"b653be21f2aba0fab4684cc10002f010633fc221","unresolved":false,"context_lines":[{"line_number":1078,"context_line":"            \u0027files\u0027: [{\u0027path\u0027: \u0027/var/log/*.log\u0027,"},{"line_number":1079,"context_line":"                       \u0027owner\u0027: \u0027myuser\u0027, \u0027perm\u0027: \u00270644\u0027}]"},{"line_number":1080,"context_line":"        }"},{"line_number":1081,"context_line":"        self.assertRaises(set_configs.InvalidConfig,"},{"line_number":1082,"context_line":"                          set_configs.validate_config, config)"},{"line_number":1083,"context_line":""},{"line_number":1084,"context_line":"    def test_validate_config_files_valid(self):"}],"source_content_type":"text/x-python","patch_set":10,"id":"f2db81c0_4f1b3fce","line":1081,"in_reply_to":"b8a51f06_4af5ee90","updated":"2026-07-02 15:30:26.000000000","message":"Done","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"},{"author":{"_account_id":17669,"name":"Doug Szumski","email":"doug@stackhpc.com","username":"DougSzumski"},"change_message_id":"2302711c9d97205f9b2f6f021f37544a49381bd4","unresolved":true,"context_lines":[{"line_number":1124,"context_line":"    @mock.patch(\u0027os.path.isdir\u0027)"},{"line_number":1125,"context_line":"    def test_create_file_already_exists(self, mock_isdir, mock_exists,"},{"line_number":1126,"context_line":"                                        mock_open,"},{"line_number":1127,"context_line":"                                        mock_handle_permissions):"},{"line_number":1128,"context_line":"        mock_isdir.side_effect \u003d [False, True]"},{"line_number":1129,"context_line":"        mock_exists.return_value \u003d True"},{"line_number":1130,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"0fa1ea08_76009b31","line":1127,"updated":"2026-07-02 10:13:25.000000000","message":"Some coverage of the exceptions would be handy eg.  OSError","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"},{"author":{"_account_id":27339,"name":"Michal Arbet","email":"michal.arbet@ultimum.io","username":"michalarbet"},"change_message_id":"b653be21f2aba0fab4684cc10002f010633fc221","unresolved":false,"context_lines":[{"line_number":1124,"context_line":"    @mock.patch(\u0027os.path.isdir\u0027)"},{"line_number":1125,"context_line":"    def test_create_file_already_exists(self, mock_isdir, mock_exists,"},{"line_number":1126,"context_line":"                                        mock_open,"},{"line_number":1127,"context_line":"                                        mock_handle_permissions):"},{"line_number":1128,"context_line":"        mock_isdir.side_effect \u003d [False, True]"},{"line_number":1129,"context_line":"        mock_exists.return_value \u003d True"},{"line_number":1130,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"5432ae2d_351d3195","line":1127,"in_reply_to":"0fa1ea08_76009b31","updated":"2026-07-02 15:30:26.000000000","message":"Done","commit_id":"c4983b515a83fc11b979c0d7ebea598f7210b0a8"}]}
