Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

task/install: Fix AssertionError #1942

Merged
merged 1 commit into from
May 28, 2024
Merged

Conversation

VallariAg
Copy link
Member

Fixes: https://tracker.ceph.com/issues/66093

Before: https://pulpito.ceph.com/vallariag-2024-05-17_08:56:03-rbd:nvmeof-main-distro-default-smithi/

2024-05-17T09:14:05.402 INFO:teuthology.run_tasks:Running task install...
2024-05-17T09:14:05.410 DEBUG:teuthology.task.install:project ceph
2024-05-17T09:14:05.410 DEBUG:teuthology.task.install:INSTALL overrides: {'ceph': {'flavor': 'default', 'sha1': '81a3c1e6c488116ab9844fe5ad8db3ce6128ccce'}}
2024-05-17T09:14:05.410 ERROR:teuthology.run_tasks:Saw exception from tasks.
Traceback (most recent call last):
  File "/home/teuthworker/src/git.ceph.com_teuthology_a4b16c58a5d7aa60dee491f6f096b7509e2f1269/teuthology/run_tasks.py", line 109, in run_tasks
    manager.__enter__()
  File "/usr/lib/python3.10/contextlib.py", line 135, in __enter__
    return next(self.gen)
  File "/home/teuthworker/src/git.ceph.com_teuthology_a4b16c58a5d7aa60dee491f6f096b7509e2f1269/teuthology/task/install/__init__.py", line 574, in task
    teuthology.deep_merge(extra_system_packages, install_overrides.get('extra_system_packages', {}))
  File "/home/teuthworker/src/git.ceph.com_teuthology_a4b16c58a5d7aa60dee491f6f096b7509e2f1269/teuthology/misc.py", line 1012, in deep_merge
    assert isinstance(b, list)
AssertionError

After: https://pulpito.ceph.com/vallariag-2024-05-17_10:54:43-rbd:nvmeof-main-distro-default-smithi/

024-05-17T11:16:08.809 INFO:teuthology.run_tasks:Running task install...
2024-05-17T11:16:08.816 DEBUG:teuthology.task.install:project ceph
2024-05-17T11:16:08.817 DEBUG:teuthology.task.install:INSTALL overrides: {'ceph': {'flavor': 'default', 'sha1': 'c2fb93636ebe325b2c93b199bfbcf8e59451a24d'}}
2024-05-17T11:16:08.817 DEBUG:teuthology.task.install:config {'flavor': 'default', 'sha1': 'c2fb93636ebe325b2c93b199bfbcf8e59451a24d'}
2024-05-17T11:16:08.817 INFO:teuthology.task.install:Using flavor: default
2024-05-17T11:16:08.842 DEBUG:teuthology.task.install:Package list is: {'deb': ['ceph', 'cephadm', 'ceph-mds', 'ceph-mgr', 'ceph-common', 'ceph-fuse', 'ceph-test', 'ceph-volume', 'radosgw', 'python3-rados', 'python3-rgw', 'python3-cephfs', 'python3-rbd', 'libcephfs2', 'libcephfs-dev', 'librados2', 'librbd1', 'rbd-fuse'], 'rpm': ['ceph-radosgw', 'ceph-test', 'ceph', 'ceph-base', 'cephadm', 'ceph-immutable-object-cache', 'ceph-mgr', 'ceph-mgr-dashboard', 'ceph-mgr-diskprediction-local', 'ceph-mgr-rook', 'ceph-mgr-cephadm', 'ceph-fuse', 'ceph-volume', 'librados-devel', 'libcephfs2', 'libcephfs-devel', 'librados2', 'librbd1', 'python3-rados', 'python3-rgw', 'python3-cephfs', 'python3-rbd', 'rbd-fuse', 'rbd-mirror', 'rbd-nbd']}
2024-05-17T11:16:08.842 INFO:teuthology.task.install:extra packages: []
2024-05-17T11:16:08.843 DEBUG:teuthology.task.install.rpm:_update_package_list_and_install: config is {'branch': None, 'cleanup': None, 'debuginfo': None, 'downgrade_packages': [], 'exclude_packages': [], 'extra_packages': [], 'extra_system_packages': [], 'extras': None, 'enable_coprs': [], 'flavor': 'default', 'install_ceph_packages': True, 'packages': {}, 'project': 'ceph', 'repos_only': False, 'sha1': 'c2fb93636ebe325b2c93b199bfbcf8e59451a24d', 'tag': None, 'wait_for_package': False}
2024-05-17T11:16:08.843 DEBUG:teuthology.packaging:Querying https://shaman.ceph.com/api/search?status=ready&project=ceph&flavor=default&distros=centos%2F9%2Fx86_64&sha1=c2fb93636ebe325b2c93b199bfbcf8e59451a24d
2024-05-17T11:16:08.845 DEBUG:teuthology.task.install.rpm:_update_package_list_and_install: config is {'branch': None, 'cleanup': None, 'debuginfo': None, 'downgrade_packages': [], 'exclude_packages': [], 'extra_packages': [], 'extra_system_packages': [], 'extras': None, 'enable_coprs': [], 'flavor': 'default', 'install_ceph_packages': True, 'packages': {}, 'project': 'ceph', 'repos_only': False, 'sha1': 'c2fb93636ebe325b2c93b199bfbcf8e59451a24d', 'tag': None, 'wait_for_package': False}
2024-05-17T11:16:08.846 DEBUG:teuthology.packaging:Querying https://shaman.ceph.com/api/search?status=ready&project=ceph&flavor=default&distros=centos%2F9%2Fx86_64&sha1=c2fb93636ebe325b2c93b199bfbcf8e59451a24d
2024-05-17T11:16:08.847 DEBUG:teuthology.task.install.rpm:_update_package_list_and_install: config is {'branch': None, 'cleanup': None, 'debuginfo': None, 'downgrade_packages': [], 'exclude_packages': [], 'extra_packages': [], 'extra_system_packages': [], 'extras': None, 'enable_coprs': [], 'flavor': 'default', 'install_ceph_packages': True, 'packages': {}, 'project': 'ceph', 'repos_only': False, 'sha1': 'c2fb93636ebe325b2c93b199bfbcf8e59451a24d', 'tag': None, 'wait_for_package': False}
2024-05-17T11:16:08.847 DEBUG:teuthology.packaging:Querying https://shaman.ceph.com/api/search?status=ready&project=ceph&flavor=default&distros=centos%2F9%2Fx86_64&sha1=c2fb93636ebe325b2c93b199bfbcf8e59451a24d
2024-05-17T11:16:08.848 DEBUG:teuthology.task.install.rpm:_update_package_list_and_install: config is {'branch': None, 'cleanup': None, 'debuginfo': None, 'downgrade_packages': [], 'exclude_packages': [], 'extra_packages': [], 'extra_system_packages': [], 'extras': None, 'enable_coprs': [], 'flavor': 'default', 'install_ceph_packages': True, 'packages': {}, 'project': 'ceph', 'repos_only': False, 'sha1': 'c2fb93636ebe325b2c93b199bfbcf8e59451a24d', 'tag': None, 'wait_for_package': False}

@@ -571,7 +571,7 @@ def task(ctx, config):
install_overrides = overrides.get('install', {})
log.debug('INSTALL overrides: %s' % install_overrides)
teuthology.deep_merge(config, install_overrides.get(project, {}))
teuthology.deep_merge(extra_system_packages, install_overrides.get('extra_system_packages', {}))
teuthology.deep_merge(extra_system_packages, install_overrides.get('extra_system_packages', []))
Copy link
Contributor

@idryomov idryomov May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is going to work in all cases.

extra_system_packages is weird -- it can be either a list or a dictionary (with deb and rpm lists in it). So, if a dictionary is supplied in the config (i.e. extra_system_packages variable at this point contains a dictionary instead of an empty list), deep_merge() would refuse to merge it with an empty list throwing a similar assert.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, this stinks. So if it's a list then the packages should be appended to both deb and rpm? I suppose that's what teuthology should do?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is a list, install task just passes the list verbatim to the package installation command. If it is a dictionary, install task fetches one of the lists from the dictionary and passes that. The list is never preprocessed/expanded into a dictionary, if that is what you are asking -- install task is prepared to deal with both a list and a dictionary:

system_pkglist = config.get('extra_system_packages')
if system_pkglist:
if isinstance(system_pkglist, dict):
system_pkglist = system_pkglist.get('deb')

system_pkglist = config.get('extra_system_packages')
if system_pkglist:
if isinstance(system_pkglist, dict):
rpm += system_pkglist.get('rpm')
else:
rpm += system_pkglist

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@idryomov, do you think this would cover all cases?

Suggested change
teuthology.deep_merge(extra_system_packages, install_overrides.get('extra_system_packages', []))
teuthology.deep_merge(extra_system_packages, install_overrides.get('extra_system_packages', type(extra_system_packages)()))

Even if extra_system_packages config is None, deep_merge() function handles the case if b is None.

Copy link
Contributor

@idryomov idryomov May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As to what the override behavior should be, it's a choice that we need to make. I see at least three options:

  1. Require that the form is the same for the original and the override and otherwise treat the job as malformed (i.e. check that both are lists or both are dictionaries before merging).
  2. Make the override win, both in form and content (i.e. don't attempt to merge anything).
  3. Introduce a preprocessing step and transform both the original and the override into a canonical dictionary first, then merge and hand over the resulting dictionary to install task.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@idryomov, do you think this would cover all cases?

No, I think it would blow up in case the job specifies e.g. a list in the original and a dictionary in the override (i.e. when the defaults don't kick in at all).

This is actually option 1 from a previous comment. If folks think it's good enough, I'm all for it ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that works but perhaps even better would be:

overrides_extra_system_packages = install_overrides.get('extra_system_packages')
if overrides_extra_system_packages:
    teuthology.deep_merge(extra_system_packages, overrides_extra_system_packages)

It is more verbose but the type(...) solution would look baffling to someone unfamiliar with this problem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think a try/except with a helpful error message would be good. An error from deep_merge does not necessarily indicate an error in the job config to a novice.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, those are 3 great option! I think option 3 adds some additional flexibility whereas option 1 would throw an error and ask the person editing the config to do the same thing teuthology could (make both config into same type format). What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works for me

@batrick
Copy link
Member

batrick commented May 17, 2024

Intermediate fix #1943 is done to get QA runs green again.

@VallariAg
Copy link
Member Author

VallariAg commented May 20, 2024

Went with option 1 (with proper try/except message) because existing code reads extra_system_packages overrides from two place: overrides.install.ceph.extra_system_packages and overrides.install.extra_system_packages and preprocessing might cause unexpected problems.

Also fixes: https://tracker.ceph.com/issues/66133

Tested with diff config:

Copy link
Member

@batrick batrick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherwise LGTM!

overrides_extra_system_packages = install_overrides.get('extra_system_packages')
if overrides_extra_system_packages:
extra_system_packages = config.get('extra_system_packages')
config['extra_system_packages'] = teuthology.deep_merge(extra_system_packages, overrides_extra_system_packages)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
config['extra_system_packages'] = teuthology.deep_merge(extra_system_packages, overrides_extra_system_packages)
teuthology.deep_merge(extra_system_packages, overrides_extra_system_packages)

? (This one confused me.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result of the deep merge should be stored in config because later we do this extra_system_packages=config.get('extra_system_packages', []),

Using config.get('extra_system_packages') is better than directly using variable extra_system_packages because when we log whole config there would be no doubt what the actual config would look like.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result of the deep merge should be stored in config because later we do this extra_system_packages=config.get('extra_system_packages', []),

The dictionary referenced by extra_system_packages should be the same as config['extra_system_packages'], no?

Copy link
Member Author

@VallariAg VallariAg May 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'll only be the same if config.get('extra_system_packages') is a list or a dictionary. If it's None (case:extra_system_packages not mentioned in install task definition and only in overrides), then extra_system_packages wouldn't reference it.

I think the regression (https://tracker.ceph.com/issues/66133) happened because of the above case:
"python3-pytest" package was defined in overrides.install.ceph.extra_system_packages and there was no "extra_system_packages" in install task definition config. So the extra_system_packages variable was an empty list which didn't reference the config value.
Then teuthology.deep_merge(config, install_overrides.get(project, {})) added the package to config["extra_system_packages"] (but not in extra_system_packages variable). We could see the package when config was logged but since we were using extra_system_package variable to makeup the final config, the package never got added to final config and so it was not installed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'll only be the same if config.get('extra_system_packages') is a list or a dictionary. If it's None (case:extra_system_packages not mentioned in install task definition and only in overrides), then extra_system_packages wouldn't reference it.

Ah, of course.

idryomov added a commit to idryomov/ceph that referenced this pull request May 27, 2024
[1] and [2] added support for applying extra_system_packages overrides
directly on install task, but at the same time broke our long standing
workaround where we sneaked extra_system_packages directive in through
an override on ceph task.  This is likely getting addressed in [3], but
it's better to not rely on this odd feature in the first place.

[1] ceph/teuthology#1941
[2] ceph/teuthology#1943
[3] ceph/teuthology#1942

Fixes: https://tracker.ceph.com/issues/66232
Signed-off-by: Ilya Dryomov <[email protected]>
overrides_extra_system_packages = install_overrides.get('extra_system_packages')
if overrides_extra_system_packages:
extra_system_packages = config.get('extra_system_packages')
config['extra_system_packages'] = teuthology.deep_merge(extra_system_packages, overrides_extra_system_packages)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'll only be the same if config.get('extra_system_packages') is a list or a dictionary. If it's None (case:extra_system_packages not mentioned in install task definition and only in overrides), then extra_system_packages wouldn't reference it.

Ah, of course.

@VallariAg VallariAg merged commit b853422 into ceph:main May 28, 2024
8 checks passed
idryomov added a commit to idryomov/ceph that referenced this pull request May 29, 2024
[1] and [2] added support for applying extra_system_packages overrides
directly on install task, but at the same time broke our long standing
workaround where we sneaked extra_system_packages directive in through
an override on ceph task.  This is likely getting addressed in [3], but
it's better to not rely on this odd feature in the first place.

[1] ceph/teuthology#1941
[2] ceph/teuthology#1943
[3] ceph/teuthology#1942

Fixes: https://tracker.ceph.com/issues/66232
Signed-off-by: Ilya Dryomov <[email protected]>
(cherry picked from commit c61cb16)
idryomov added a commit to idryomov/ceph that referenced this pull request May 29, 2024
[1] and [2] added support for applying extra_system_packages overrides
directly on install task, but at the same time broke our long standing
workaround where we sneaked extra_system_packages directive in through
an override on ceph task.  This is likely getting addressed in [3], but
it's better to not rely on this odd feature in the first place.

[1] ceph/teuthology#1941
[2] ceph/teuthology#1943
[3] ceph/teuthology#1942

Fixes: https://tracker.ceph.com/issues/66232
Signed-off-by: Ilya Dryomov <[email protected]>
(cherry picked from commit c61cb16)
idryomov added a commit to idryomov/ceph that referenced this pull request May 29, 2024
[1] and [2] added support for applying extra_system_packages overrides
directly on install task, but at the same time broke our long standing
workaround where we sneaked extra_system_packages directive in through
an override on ceph task.  This is likely getting addressed in [3], but
it's better to not rely on this odd feature in the first place.

[1] ceph/teuthology#1941
[2] ceph/teuthology#1943
[3] ceph/teuthology#1942

Fixes: https://tracker.ceph.com/issues/66232
Signed-off-by: Ilya Dryomov <[email protected]>
(cherry picked from commit c61cb16)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants