From 2db9328f657a419a9f9031a76bbdced6ea92d7b1 Mon Sep 17 00:00:00 2001 From: Mike Shriver Date: Tue, 22 Dec 2020 03:09:53 -0500 Subject: [PATCH] Remove long deprecated entities and Version based logic blocks (#767) Version logic blocks based on Sat 6.1 and 6.2, as well as long deprecated System and SystemPackge entities removed Eliminate server_modes no longer valid for katello/satellite Update and remove unit tests --- nailgun/entities.py | 326 ++++++--------------------------------- nailgun/entity_mixins.py | 3 +- tests/test_entities.py | 307 +++++++----------------------------- 3 files changed, 100 insertions(+), 536 deletions(-) diff --git a/nailgun/entities.py b/nailgun/entities.py index 45f97fe9..07ab5099 100644 --- a/nailgun/entities.py +++ b/nailgun/entities.py @@ -219,7 +219,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/activation_keys', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -433,7 +432,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/architectures', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -535,7 +533,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/audits', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -581,7 +578,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/auth_source_ldaps', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -644,7 +640,7 @@ def __init__(self, server_config=None, **kwargs): 'public': entity_fields.BooleanField(), 'query': entity_fields.StringField(required=True), } - self._meta = {'api_path': 'api/v2/bookmarks', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/bookmarks'} super().__init__(server_config, **kwargs) @@ -665,7 +661,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/capsules', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -778,7 +773,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/common_parameters', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -803,7 +797,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/compute_attributes', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -827,7 +820,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/compute_profiles', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -885,7 +877,6 @@ def __init__(self, server_config=None, **kwargs): self._fields = fields self._meta = { 'api_path': 'api/v2/compute_resources', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -1075,7 +1066,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': '/api/v2/discovered_hosts', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -1272,7 +1262,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': '/api/v2/discovery_rules', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -1436,7 +1425,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/status', - 'server_modes': ('sat'), 'read_type': 'base', } super().__init__(server_config, **kwargs) @@ -1561,7 +1549,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/config_groups', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -1595,7 +1582,6 @@ def __init__(self, server_config=None, **kwargs): super().__init__(server_config, **kwargs) self._meta = { 'api_path': f'/api/v2/templates/{self.template.id}/template_inputs', - 'server_modes': ('sat'), } def read(self, entity=None, attrs=None, ignore=None, params=None): @@ -1630,7 +1616,7 @@ def __init__(self, server_config=None, **kwargs): 'template_invocations': entity_fields.ListField(), 'total': entity_fields.IntegerField(), } - self._meta = {'api_path': 'api/job_invocations', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/job_invocations'} super().__init__(server_config, **kwargs) def run(self, synchronous=True, **kwargs): @@ -1703,7 +1689,7 @@ def __init__(self, server_config=None, **kwargs): 'template': entity_fields.StringField(), 'template_inputs': entity_fields.OneToManyField(TemplateInput), } - self._meta = {'api_path': 'api/v2/job_templates', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/job_templates'} super().__init__(server_config, **kwargs) def create_payload(self): @@ -1773,7 +1759,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/provisioning_templates', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -1905,7 +1890,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/report_templates', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -2053,7 +2037,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/content_credentials', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -2077,7 +2060,6 @@ def __init__(self, server_config=None, **kwargs): self._fields.pop('id') self._meta = { 'api_path': f'{self.repository.path()}/content_uploads', - 'server_modes': ('sat'), } def read(self, entity=None, attrs=None, ignore=None, params=None): @@ -2213,7 +2195,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/content_view_versions', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -2307,7 +2288,6 @@ def __init__(self, server_config=None, **kwargs): } super().__init__(server_config, **kwargs) self._meta = { - "server_modes": ("sat"), "api_path": f'{self.content_view_filter.path("self")}/rules', } @@ -2396,7 +2376,6 @@ def __init__(self, server_config=None, **kwargs): self._fields = fields self._meta = { 'api_path': 'katello/api/v2/content_view_filters', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -2466,7 +2445,6 @@ def __init__(self, server_config=None, **kwargs): } super().__init__(server_config, **kwargs) self._meta = { - "server_modes": ("sat"), "api_path": f'{self.content_view.path("self")}/content_view_puppet_modules', } @@ -2535,7 +2513,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/content_views', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -2549,14 +2526,8 @@ def read(self, entity=None, attrs=None, ignore=None, params=None): :meth:`nailgun.entity_mixins.EntityReadMixin.read` can't initialize content_view_component. """ - if attrs is None: - attrs = self.read_json() - if _get_version(self._server_config) < Version('6.1'): - org = _get_org(self._server_config, attrs['organization']['label']) - attrs['organization'] = org.get_values() - - if ignore is None: - ignore = set() + attrs = attrs or self.read_json() + ignore = ignore or set() ignore.add('content_view_component') result = super().read(entity, attrs, ignore, params) if 'content_view_components' in attrs and attrs['content_view_components']: @@ -2841,7 +2812,7 @@ def __init__(self, server_config=None, **kwargs): ), 'organization': entity_fields.OneToManyField(Organization), } - self._meta = {'api_path': 'api/v2/domains', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/domains'} super().__init__(server_config, **kwargs) def create_missing(self): @@ -2927,7 +2898,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/environments', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -3015,7 +2985,7 @@ def __init__(self, server_config=None, **kwargs): ), 'updated': entity_fields.DateField(), } - self._meta = {'api_path': '/katello/api/v2/errata', 'server_modes': ('sat')} + self._meta = {'api_path': '/katello/api/v2/errata'} super().__init__(server_config, **kwargs) def compare(self, synchronous=True, timeout=None, **kwargs): @@ -3100,7 +3070,7 @@ def __init__(self, server_config=None, **kwargs): 'override': entity_fields.BooleanField(), 'unlimited': entity_fields.BooleanField(), } - self._meta = {'api_path': 'api/v2/filters', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/filters'} super().__init__(server_config, **kwargs) def create_payload(self): @@ -3137,7 +3107,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/status', - 'server_modes': ('sat'), 'read_type': 'base', } super().__init__(server_config, **kwargs) @@ -3163,7 +3132,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'foreman_tasks/api/tasks', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -3252,7 +3220,6 @@ def __init__(self, server_config=None, **kwargs): 'katello/api/v2/organizations/:organization_id/' 'host_collections/:host_collection_id/errata' ), - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -3270,7 +3237,6 @@ def __init__(self, server_config=None, **kwargs): 'katello/api/v2/organizations/:organization_id/' 'host_collections/:host_collection_id/packages' ), - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -3306,18 +3272,8 @@ def __init__(self, server_config=None, **kwargs): ), 'unlimited_hosts': entity_fields.BooleanField(), } - # The following attributes have been renamed with Satellite - # 6.2, so we revert them to their old values if we have an - # older version of Satellite - if _get_version(server_config) < Version('6.2'): - self._fields['max_content_hosts'] = self._fields.pop('max_hosts') - self._fields['unlimited_content_hosts'] = self._fields.pop('unlimited_hosts') - self._fields['system'] = entity_fields.OneToManyField(System) - self._fields.pop('host') - self._meta = { 'api_path': 'katello/api/v2/host_collections', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -3377,14 +3333,14 @@ def __init__(self, server_config=None, **kwargs): 'subnet': entity_fields.OneToOneField(Subnet), 'group_parameters_attributes': entity_fields.ListField(), } - if _get_version(server_config) >= Version('6.1'): - self._fields.update( - { - 'content_view': entity_fields.OneToOneField(ContentView), - 'lifecycle_environment': entity_fields.OneToOneField(LifecycleEnvironment), - } - ) - self._meta = {'api_path': 'api/v2/hostgroups', 'server_modes': ('sat')} + + self._fields.update( + { + 'content_view': entity_fields.OneToOneField(ContentView), + 'lifecycle_environment': entity_fields.OneToOneField(LifecycleEnvironment), + } + ) + self._meta = {'api_path': 'api/v2/hostgroups'} super().__init__(server_config, **kwargs) def create(self, create_missing=None): @@ -3421,23 +3377,15 @@ def read(self, entity=None, attrs=None, ignore=None, params=None): `_ """ - if ignore is None: - ignore = set() + ignore = ignore or set() ignore.add('root_pass') ignore.add('kickstart_repository') ignore.add('compute_resource') - if attrs is None: - attrs = self.read_json() + attrs = attrs or self.read_json() attrs['parent_id'] = attrs.pop('ancestry') # either an ID or None attrs['group_parameters_attributes'] = attrs.pop('parameters') - version = _get_version(self._server_config) - if version >= Version('6.1') and version < Version('6.2'): - # We cannot call `self.update_json([])`, as an ID might not be - # present on self. However, `attrs` is guaranteed to have an ID. - attrs2 = HostGroup(self._server_config, id=attrs['id']).update_json([]) - for attr in ('content_source_id', 'content_view_id', 'lifecycle_environment_id'): - attrs[attr] = attrs2.get(attr) + return super().read(entity, attrs, ignore, params) def update(self, fields=None): @@ -3614,11 +3562,6 @@ class HostPackage(Entity): """A representation of a Host Package entity.""" def __init__(self, server_config=None, **kwargs): - if _get_version(server_config) < Version('6.2'): - raise NotImplementedError( - 'Your current version of Satellite does not support ' - 'HostPackage entity. Please, use SystemPackage entity instead.' - ) _check_for_value('host', kwargs) self._fields = { 'groups': entity_fields.ListField(), @@ -3628,7 +3571,6 @@ def __init__(self, server_config=None, **kwargs): super().__init__(server_config, **kwargs) self._meta = { 'api_path': f'{self.host.path()}/packages', - 'server_modes': ('sat'), } @@ -3636,11 +3578,6 @@ class HostSubscription(Entity): """A representation of a Host Subscription entity.""" def __init__(self, server_config=None, **kwargs): - if _get_version(server_config) < Version('6.2'): - raise NotImplementedError( - 'Your current version of Satellite does not support' - 'HostSubscription entity. Please, use System entity instead.' - ) _check_for_value('host', kwargs) self._fields = { 'content_label': entity_fields.StringField(), @@ -3651,7 +3588,6 @@ def __init__(self, server_config=None, **kwargs): super().__init__(server_config, **kwargs) self._meta = { 'api_path': f'{self.host.path()}/subscriptions', - 'server_modes': ('sat'), } def path(self, which=None): @@ -3790,7 +3726,7 @@ def __init__(self, server_config=None, **kwargs): 'uuid': entity_fields.StringField(), } self._owner_type = None # actual ``owner_type`` value - self._meta = {'api_path': 'api/v2/hosts', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/hosts'} super().__init__(server_config, **kwargs) # See https://github.com/SatelliteQE/nailgun/issues/258 @@ -3905,14 +3841,11 @@ def create_missing(self): if not hasattr(self, 'architecture'): self.architecture = Architecture(self._server_config).create(True) if not hasattr(self, 'ptable'): - if _get_version(self._server_config) >= Version('6.2'): - self.ptable = PartitionTable( - self._server_config, - location=[self.location], - organization=[self.organization], - ).create(True) - else: - self.ptable = PartitionTable(self._server_config).create(True) + self.ptable = PartitionTable( + self._server_config, + location=[self.location], + organization=[self.organization], + ).create(True) if not hasattr(self, 'operatingsystem'): self.operatingsystem = OperatingSystem( self._server_config, @@ -4585,7 +4518,6 @@ def __init__(self, server_config=None, **kwargs): super().__init__(server_config, **kwargs) self._meta = { "api_path": f'{self.compute_resource.path("self")}/images', - "server_modes": ("sat"), } def create_payload(self): @@ -4685,7 +4617,6 @@ def __init__(self, server_config=None, **kwargs): super().__init__(server_config, **kwargs) self._meta = { 'api_path': f'{self.host.path()}/interfaces', - 'server_modes': ('sat'), } def read(self, entity=None, attrs=None, ignore=None, params=None): @@ -4771,22 +4702,9 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/environments', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) - def create_payload(self): - """Rename the payload key "prior_id" to "prior". - - For more information, see `Bugzilla #1238757 - `_. - - """ - payload = super().create_payload() - if _get_version(self._server_config) < Version('6.1') and 'prior_id' in payload: - payload['prior'] = payload.pop('prior_id') - return payload - def create_missing(self): """Automatically populate additional instance attributes. @@ -4840,7 +4758,7 @@ def __init__(self, server_config=None, **kwargs): 'organization': entity_fields.OneToManyField(Organization), 'location': entity_fields.OneToManyField(Location), } - self._meta = {'api_path': 'api/v2/http_proxies', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/http_proxies'} super().__init__(server_config, **kwargs) def update_payload(self, fields=None): @@ -4896,7 +4814,7 @@ def __init__(self, server_config=None, **kwargs): 'subnet': entity_fields.OneToManyField(Subnet), 'user': entity_fields.OneToManyField(User), } - self._meta = {'api_path': 'api/v2/locations', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/locations'} super().__init__(server_config, **kwargs) def create_payload(self): @@ -4972,7 +4890,7 @@ def __init__(self, server_config=None, **kwargs): 'location': entity_fields.OneToManyField(Location), 'os_family': entity_fields.StringField(choices=_OPERATING_SYSTEMS), } - self._meta = {'api_path': 'api/v2/media', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/media'} super().__init__(server_config, **kwargs) def create_payload(self): @@ -5037,7 +4955,7 @@ def __init__(self, server_config=None, **kwargs): ), 'vendor_class': entity_fields.StringField(), } - self._meta = {'api_path': 'api/v2/models', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/models'} super().__init__(server_config, **kwargs) @@ -5090,7 +5008,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/operatingsystems', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -5132,7 +5049,6 @@ def __init__(self, server_config=None, **kwargs): super().__init__(server_config, **kwargs) self._meta = { "api_path": f'{self.operatingsystem.path("self")}/parameters', - "server_modes": ("sat"), } def read(self, entity=None, attrs=None, ignore=None, params=None): @@ -5194,16 +5110,15 @@ def __init__(self, server_config=None, **kwargs): 'title': entity_fields.StringField(), 'user': entity_fields.OneToManyField(User), } - if _get_version(server_config) >= Version('6.1.1'): # default: True - self._fields.update( - { - 'default_content_view': entity_fields.OneToOneField(ContentView), - 'library': entity_fields.OneToOneField(LifecycleEnvironment), - } - ) + + self._fields.update( + { + 'default_content_view': entity_fields.OneToOneField(ContentView), + 'library': entity_fields.OneToOneField(LifecycleEnvironment), + } + ) self._meta = { 'api_path': 'katello/api/v2/organizations', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -5330,7 +5245,6 @@ def __init__(self, server_config=None, **kwargs): super().__init__(server_config, **kwargs) self._meta = { "api_path": f'{self.operatingsystem.path("self")}/os_default_templates', - "server_modes": ("sat"), } def read(self, entity=None, attrs=None, ignore=None, params=None): @@ -5385,7 +5299,6 @@ def __init__(self, server_config=None, **kwargs): ) self._meta = { 'api_path': f'{partial_path}/override_values', - 'server_modes': ('sat'), } def create_payload(self): @@ -5465,7 +5378,6 @@ def __init__(self, server_config=None, **kwargs): self._parent_id = getattr(self, self._parent_type).id self._meta = { 'api_path': f'api/v2/{self._parent_type}s/{self._parent_id}/parameters', - 'server_modes': ('sat'), } def read(self, entity=None, attrs=None, ignore=None, params=None): @@ -5493,7 +5405,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/permissions', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -5504,7 +5415,6 @@ class Ping(Entity, EntitySearchMixin): def __init__(self, server_config=None, **kwargs): self._meta = { 'api_path': 'katello/api/v2/ping', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -5533,7 +5443,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/products', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -5566,9 +5475,6 @@ def read(self, entity=None, attrs=None, ignore=None, params=None): """ if attrs is None: attrs = self.read_json() - if _get_version(self._server_config) < Version('6.1'): - org = _get_org(self._server_config, attrs['organization']['label']) - attrs['organization'] = org.get_values() if ignore is None: ignore = set() ignore.add('sync_plan') @@ -5779,14 +5685,8 @@ def __init__(self, server_config=None, **kwargs): 'organization': entity_fields.OneToManyField(Organization), 'os_family': entity_fields.StringField(choices=_OPERATING_SYSTEMS), } - self._meta = {'api_path': 'api/v2/ptables', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/ptables'} super().__init__(server_config, **kwargs) - # The following fields were added in Satellite 6.2, removing them if we - # have previous version of Satellite - if _get_version(self._server_config) < Version('6.2'): - # pragma: no cover - self._fields.pop('location') - self._fields.pop('organization') class PuppetClass( @@ -5809,7 +5709,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/puppetclasses', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -5987,7 +5886,7 @@ def __init__(self, server_config=None, **kwargs): 'location': entity_fields.OneToManyField(Location), 'organization': entity_fields.OneToManyField(Organization), } - self._meta = {'api_path': 'api/v2/compliance/policies', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/compliance/policies'} super().__init__(server_config, **kwargs) def update(self, fields=None): @@ -6027,7 +5926,7 @@ def __init__(self, server_config=None, **kwargs): required=True, ), } - self._meta = {'api_path': 'api/v2/realms', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/realms'} super().__init__(server_config, **kwargs) def create(self, create_missing=None): @@ -6055,7 +5954,7 @@ def __init__(self, server_config=None, **kwargs): 'task': entity_fields.OneToManyField(ForemanTask), 'task_group_id': entity_fields.IntegerField(), } - self._meta = {'api_path': 'foreman_tasks/api/recurring_logics', 'server_modes': ('sat')} + self._meta = {'api_path': 'foreman_tasks/api/recurring_logics'} super().__init__(server_config, **kwargs) def cancel(self, synchronous=True, timeout=None, **kwargs): @@ -6101,7 +6000,7 @@ def __init__(self, server_config=None, **kwargs): 'logs': entity_fields.ListField(), 'reported_at': entity_fields.DateTimeField(required=True), } - self._meta = {'api_path': 'api/v2/reports', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/reports'} super().__init__(server_config, **kwargs) @@ -6160,20 +6059,10 @@ def __init__(self, server_config=None, **kwargs): ), 'http_proxy_id': entity_fields.IntegerField(), } - if _get_version(server_config) < Version('6.1'): - # Adjust for Satellite 6.0 - del self._fields['docker_upstream_name'] - del self._fields['upstream_username'] - del self._fields['upstream_password'] - self._fields['content_type'].choices = tuple( - set(self._fields['content_type'].choices) - {'docker'} - ) - del self._fields['checksum_type'] if self._fields['content_type'].choices == 'yum': self._fields['download_policy'].required = True self._meta = { 'api_path': 'katello/api/v2/repositories', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -6628,7 +6517,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'fusor/api/v21/deployments', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -6703,7 +6591,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/roles/:role_id/ldap_groups', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -6732,7 +6619,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/roles', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -6797,7 +6683,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/settings', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -6831,7 +6716,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/smart_proxies', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -6952,7 +6836,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/smart_class_parameters', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -6993,7 +6876,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/smart_variables', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -7051,7 +6933,6 @@ def __init__(self, server_config=None, **kwargs): super().__init__(server_config, **kwargs) self._meta = { 'api_path': f'{self.host.path("self")}/snapshots', - 'server_modes': ('sat'), } def path(self, which=None): @@ -7177,7 +7058,6 @@ class Status(Entity): def __init__(self, server_config=None, **kwargs): self._meta = { 'api_path': 'katello/api/v2/status', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -7236,7 +7116,7 @@ def __init__(self, server_config=None, **kwargs): 'tftp': entity_fields.OneToOneField(SmartProxy), 'vlanid': entity_fields.StringField(), } - self._meta = {'api_path': 'api/v2/subnets', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/subnets'} super().__init__(server_config, **kwargs) def create_payload(self): @@ -7300,7 +7180,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'katello/api/v2/subscriptions', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -7597,117 +7476,6 @@ def update_payload(self, fields=None): return data -class SystemPackage(Entity): - """A representation of a System Package entity.""" - - def __init__(self, server_config=None, **kwargs): - if _get_version(server_config) >= Version('6.2'): - raise DeprecationWarning( - 'SystemPackage entity was removed in Satellite 6.2. Please, ' - 'use HostPackage entity instead.' - ) - self._fields = { - 'groups': entity_fields.ListField(), - 'packages': entity_fields.ListField(), - 'system': entity_fields.OneToOneField(System, required=True), - } - self._meta = { - 'api_path': 'katello/api/v2/systems/:system_id/packages', - 'server_modes': ('sat'), - } - super().__init__(server_config, **kwargs) - - -class System(Entity, EntityCreateMixin, EntityDeleteMixin, EntityReadMixin, EntitySearchMixin): - """A representation of a System entity.""" - - def __init__(self, server_config=None, **kwargs): - if _get_version(server_config) >= Version('6.2'): - raise DeprecationWarning( - 'System entity was removed in Satellite 6.2. Please, use Host entity instead.' - ) - self._fields = { - 'content_view': entity_fields.OneToOneField(ContentView), - 'description': entity_fields.StringField(), - 'environment': entity_fields.OneToOneField(LifecycleEnvironment), - 'facts': entity_fields.DictField( - default={'uname.machine': 'unknown'}, - required=True, - ), - 'host_collection': entity_fields.OneToManyField(HostCollection), - 'installed_products': entity_fields.ListField(), - 'last_checkin': entity_fields.DateTimeField(), - 'location': entity_fields.StringField(), - 'name': entity_fields.StringField( - required=True, str_type='alpha', length=(6, 12), unique=True - ), - 'organization': entity_fields.OneToOneField( - Organization, - required=True, - ), - 'release_ver': entity_fields.StringField(), - 'service_level': entity_fields.StringField(), - 'uuid': entity_fields.StringField(), - # The type() builtin is still available within instance methods, - # class methods, static methods, inner classes, and so on. However, - # type() is *not* available at the current level of lexical scoping - # after this point. - 'type': entity_fields.StringField(default='system', required=True), - } - self._meta = { - 'api_path': 'katello/api/v2/systems', - 'server_modes': ('sat', 'sam'), - } - super().__init__(server_config, **kwargs) - - def path(self, which=None): - """Extend ``nailgun.entity_mixins.Entity.path``. - - This method contains a workaround for `Bugzilla #1202917`_. - - Most entities are uniquely identified by an ID. ``System`` is a bit - different: it has both an ID and a UUID, and the UUID is used to - uniquely identify a ``System``. - - Return a path in the format ``katello/api/v2/systems/`` if a UUID - is available and: - - * ``which is None``, or - * ``which == 'this'``. - - .. _Bugzilla #1202917: - https://bugzilla.redhat.com/show_bug.cgi?id=1202917 - - Finally, return a path in the form - ``katello/api/v2/systems//subscriptions`` if ``'subscriptions'`` - is passed in. - - """ - if which == "subscriptions": - return f'{super().path("base")}/{self.uuid}/{which}' - if hasattr(self, "uuid") and (which is None or which == "self"): - return f'{super().path(which="base")}/{self.uuid}' - return super().path(which) - - def read(self, entity=None, attrs=None, ignore=None, params=None): - """Fetch as many attributes as possible for this entity. - - Do not read the ``facts``, ``organization`` or ``type`` attributes. - For more information, see `Bugzilla #1202917 - `_. - - """ - if attrs is None: - attrs = self.read_json() - attrs['last_checkin'] = attrs.pop('checkin_time') - attrs['host_collections'] = attrs.pop('hostCollections') - attrs['installed_products'] = attrs.pop('installedProducts') - if ignore is None: - ignore = set() - ignore.update(['facts', 'organization', 'type']) - return super().read(entity, attrs, ignore, params) - - class TailoringFile( Entity, EntityCreateMixin, @@ -7732,7 +7500,7 @@ def __init__(self, server_config=None, **kwargs): if 'scap_file' in kwargs: with open(kwargs['scap_file']) as input_file: kwargs['scap_file'] = input_file.read() - self._meta = {'api_path': 'api/v2/compliance/tailoring_files', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/compliance/tailoring_files'} super().__init__(server_config, **kwargs) def create(self, create_missing=None): @@ -7775,7 +7543,6 @@ class Template(Entity): def __init__(self, server_config=None, **kwargs): self._meta = { 'api_path': 'api/v2/templates', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -7845,7 +7612,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/template_combinations', - 'server_modes': 'sat', } super().__init__(server_config, **kwargs) @@ -7864,7 +7630,6 @@ def __init__(self, server_config=None, **kwargs): self._meta = { 'api_path': 'api/v2/template_kinds', 'num_created_by_default': 8, - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) @@ -7889,7 +7654,7 @@ def __init__(self, server_config=None, **kwargs): 'user': entity_fields.OneToManyField(User), 'usergroup': entity_fields.OneToManyField(UserGroup), } - self._meta = {'api_path': 'api/v2/usergroups', 'server_modes': ('sat')} + self._meta = {'api_path': 'api/v2/usergroups'} super().__init__(server_config, **kwargs) def create_payload(self): @@ -7988,7 +7753,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'api/v2/users', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -8066,7 +7830,6 @@ def __init__(self, server_config=None, **kwargs): } self._meta = { 'api_path': 'foreman_virt_who_configure/api/v2/configs', - 'server_modes': ('sat', 'sam'), } super().__init__(server_config, **kwargs) @@ -8185,7 +7948,6 @@ def __init__(self, server_config=None, **kwargs): kwargs['scap_file'] = input_file.read() self._meta = { 'api_path': 'api/compliance/scap_contents', - 'server_modes': ('sat'), } super().__init__(server_config, **kwargs) diff --git a/nailgun/entity_mixins.py b/nailgun/entity_mixins.py index 232756b4..0b1452e0 100644 --- a/nailgun/entity_mixins.py +++ b/nailgun/entity_mixins.py @@ -378,7 +378,8 @@ def __init__(self, server_config=None, **kwargs): # Check that a valid set of field values has been passed in. if not set(kwargs.keys()).issubset(self._fields.keys()): raise NoSuchFieldError( - f'Valid fields are {self._fields.keys()}, but received {kwargs.keys()} instead.' + f'Valid fields are {list(self._fields.keys())}, invalid field(s) passed ' + f'to entity: {set(kwargs.keys()).difference(set(self._fields.keys()))}' ) # Iterate through the values passed in and assign them as instance diff --git a/tests/test_entities.py b/tests/test_entities.py index 732885e1..288a9a58 100644 --- a/tests/test_entities.py +++ b/tests/test_entities.py @@ -9,6 +9,7 @@ from unittest import mock from unittest import TestCase +from fauxfactory import gen_alpha from fauxfactory import gen_integer from fauxfactory import gen_string @@ -77,7 +78,6 @@ class InitTestCase(TestCase): def setUpClass(cls): """Set a server configuration at ``cls.cfg``.""" cls.cfg = config.ServerConfig('http://example.com') - cls.cfg_610 = config.ServerConfig('http://example.com', version='6.1.0') def test_init_succeeds(self): """Instantiate every entity. @@ -174,8 +174,6 @@ def test_init_succeeds(self): entities.Status, entities.Subnet, entities.Subscription, - # entities.System, # see below - # entities.SystemPackage, # see below entities.TailoringFile, entities.TemplateCombination, entities.Template, @@ -222,17 +220,6 @@ def test_init_succeeds(self): for entity, params in entities_: with self.subTest(entity): self.assertIsInstance(entity(self.cfg, **params), entity) - # Deprecated entities - deprecated_entities = [ - (entity, {}) - for entity in ( - entities.System, - entities.SystemPackage, - ) - ] - for entity, params in deprecated_entities: - with self.subTest(entity): - self.assertIsInstance(entity(self.cfg_610, **params), entity) def test_required_params(self): """Instantiate entities that require extra parameters. @@ -269,7 +256,6 @@ class PathTestCase(TestCase): def setUp(self): """Set ``self.cfg`` and ``self.id_``.""" self.cfg = config.ServerConfig('http://example.com') - self.cfg_610 = config.ServerConfig('http://example.com', version='6.1.0') self.id_ = gen_integer(min_value=1) def test_nowhich(self): @@ -304,11 +290,6 @@ def test_nowhich(self): with self.subTest((entity, path)): self.assertIn(path, entity(self.cfg).path()) self.assertIn(f'{path}/{self.id_}', entity(self.cfg, id=self.id_).path()) - # Deprecated entities - for entity, path in ((entities.System, '/systems'),): - with self.subTest((entity, path)): - self.assertIn(path, entity(self.cfg_610).path()) - self.assertIn(f'{path}/{self.id_}', entity(self.cfg_610, id=self.id_).path()) def test_id_and_which(self): """Execute ``entity(id=…).path(which=…)``.""" @@ -439,11 +420,6 @@ def test_no_such_path_error(self): with self.subTest((entity, which)): with self.assertRaises(NoSuchPathError): entity(self.cfg).path(which=which) - # Deprecated entities - for entity, which in ((entities.System, 'self'),): - with self.subTest((entity, which)): - with self.assertRaises(NoSuchPathError): - entity(self.cfg_610).path(which=which) def test_arfreport(self): """Test :meth:`nailgun.entities.ArfReport.path`. @@ -562,32 +538,6 @@ def test_sync_plan(self): self.assertIn(f'organizations/1/sync_plans/2/{which}', path) self.assertRegex(path, fr'{which}$') - def test_system(self): - """Test :meth:`nailgun.entities.System.path`. - - Assert that the following return appropriate paths: - - * ``System().path()`` - * ``System().path('base')`` - * ``System(uuid=…).path()`` - * ``System(uuid=…).path('self')`` - * ``System(uuid=…).path('subscriptions')`` - - """ - system = entities.System(self.cfg_610) - for path in (system.path(), system.path('base')): - self.assertIn('/systems', path) - self.assertRegex(path, r'systems$') - - system = entities.System(self.cfg_610, uuid=self.id_) - for path in (system.path(), system.path('self')): - self.assertIn(f'/systems/{self.id_}', path) - self.assertRegex(path, fr'{self.id_}$') - - path = system.path('subscriptions') - self.assertIn(f'/systems/{self.id_}/subscriptions', path) - self.assertRegex(path, r'subscriptions$') - def test_subscription(self): """Test :meth:`nailgun.entities.Subscription.path`. @@ -698,7 +648,6 @@ class CreatePayloadTestCase(TestCase): def setUpClass(cls): """Set a server configuration at ``cls.cfg``.""" cls.cfg = config.ServerConfig('http://example.com') - cls.cfg_610 = config.ServerConfig('http://example.com', version='6.1.0') def test_no_attributes(self): """Instantiate an entity and call ``create_payload`` on it.""" @@ -767,12 +716,23 @@ def test_sync_plan(self): def test_host_collection(self): """Create a :class:`nailgun.entities.HostCollection`.""" - payload = entities.HostCollection( - self.cfg_610, - system=[1], - ).create_payload() - self.assertNotIn('system_ids', payload) - self.assertIn('system_uuids', payload) + HOST_ID = 1 + ORG_ID = 1 + entity_kwargs = { + 'name': gen_alpha(), + 'description': gen_alpha(), + 'max_hosts': gen_integer(min_value=1, max_value=10), + 'unlimited_hosts': False, + 'organization': entities.Organization(self.cfg, id=ORG_ID), + 'host': [entities.Host(self.cfg, id=HOST_ID)], + } + host_collection = entities.HostCollection(self.cfg, **entity_kwargs) + payload = host_collection.create_payload() + # host and organization are translated for payload + entity_kwargs.pop('organization') + entity_kwargs.pop('host') + entity_kwargs.update({'organization_id': ORG_ID, 'host_ids': [HOST_ID]}) + self.assertDictEqual(entity_kwargs, payload) def test_content_view_filter_rule(self): """Create a :class:`nailgun.entities.ContentViewFilterRule`.""" @@ -1178,7 +1138,6 @@ class ReadTestCase(TestCase): def setUp(self): """Set a server configuration at ``self.cfg``.""" self.cfg = config.ServerConfig('http://example.com') - self.cfg_610 = config.ServerConfig('http://example.com', version='6.1.0') def test_entity_arg(self): """Call ``read`` on entities that require parameters for instantiation. @@ -1250,14 +1209,6 @@ def test_attrs_arg_v1(self): entity(self.cfg).read() self.assertEqual(read_json.call_count, 1) self.assertEqual(read.call_count, 1) - # Deprecated entities - for entity in (entities.System,): - with mock.patch.object(EntityReadMixin, 'read_json') as read_json: - with mock.patch.object(EntityReadMixin, 'read') as read: - with self.subTest(): - entity(self.cfg_610).read() - self.assertEqual(read_json.call_count, 1) - self.assertEqual(read.call_count, 1) def test_attrs_arg_v2(self): """Ensure ``read``, ``read_json`` and ``client.put`` are called once. @@ -1301,19 +1252,6 @@ def test_entity_ids(self): {'parameters': None}, {'host_parameters_attributes': None}, ), - ( - entities.System(self.cfg_610), - { - 'checkin_time': None, - 'hostCollections': None, - 'installedProducts': None, - }, - { - 'last_checkin': None, - 'host_collections': None, - 'installed_products': None, - }, - ), ( entities.Filter(self.cfg), {'override?': None, 'unlimited?': None}, @@ -1936,7 +1874,6 @@ class UpdatePayloadTestCase(TestCase): def setUpClass(cls): """Set a server configuration at ``cls.cfg``.""" cls.cfg = config.ServerConfig('http://example.com') - cls.cfg_610 = config.ServerConfig('http://example.com', version='6.1.0') def test_generic(self): """Instantiate a variety of entities and call ``update_payload``.""" @@ -2895,87 +2832,37 @@ def setUp(self): self.entity = entities.HostGroup(config.ServerConfig('some url')) self.read_json_pacther = mock.patch.object(self.entity, 'read_json') self.read_pacther = mock.patch.object(EntityReadMixin, 'read') - self.update_json_patcher = mock.patch.object(entities.HostGroup, 'update_json') - def test_read_sat61z(self): + def test_read(self): """Ensure ``read``, ``read_json`` and ``update_json`` are called once. This test is only appropriate for entities that override the ``read`` method in order to fiddle with the ``attrs`` argument. """ - for version in ('6.1', '6.1.0', '6.1.8'): - read_json = self.read_json_pacther.start() - read = self.read_pacther.start() - update_json = self.update_json_patcher.start() - with self.subTest(version=version): - self.entity._server_config.version = entities.Version(version) - read_json.return_value = { - 'ancestry': None, - 'id': 641212, # random - 'parameters': None, - } - update_json.return_value = { - 'content_source_id': None, - 'content_view_id': None, - 'lifecycle_environment_id': None, - } - self.entity.read() - for meth in (read_json, update_json, read): - self.assertEqual(meth.call_count, 1) - self.assertEqual( - read.call_args[0][1], - { - 'content_source_id': None, - 'content_view_id': None, - 'id': 641212, - 'lifecycle_environment_id': None, - 'group_parameters_attributes': None, - 'parent_id': None, - }, - ) - self.read_json_pacther.stop() - self.read_pacther.stop() - self.update_json_patcher.stop() - - def test_read_sat62z(self): - """Ensure ``read`` and ``read_json`` are called once. And - ``update_json`` are not called. - - This test is only appropriate for entities that override the ``read`` - method in order to fiddle with the ``attrs`` argument. - """ - for version in ('6.2', '6.2.0', '6.2.8'): - read_json = self.read_json_pacther.start() - read = self.read_pacther.start() - update_json = self.update_json_patcher.start() - read_json.return_value = { - 'ancestry': None, - 'id': 641212, # random - 'content_source_id': None, - 'content_view_id': None, - 'lifecycle_environment_id': None, - 'parameters': None, - } - with self.subTest(version=version): - self.entity._server_config.version = entities.Version(version) - self.entity.read() - for meth in (read_json, read): - self.assertEqual(meth.call_count, 1) - self.assertEqual(update_json.call_count, 0) - self.assertEqual( - read.call_args[0][1], - { - 'content_source_id': None, - 'content_view_id': None, - 'id': 641212, - 'lifecycle_environment_id': None, - 'parent_id': None, - 'group_parameters_attributes': None, - }, - ) - self.read_json_pacther.stop() - self.read_pacther.stop() - self.update_json_patcher.stop() + read_json = self.read_json_pacther.start() + read = self.read_pacther.start() + read_json.return_value = { + 'ancestry': None, + 'id': 641212, # random + 'parameters': None, + } + self.entity.read() + self.assertEqual(read.call_count, 1) + self.assertEqual(read_json.call_count, 1) + self.assertDictEqual( + read.call_args[0][1], # attrs for EntityReadMixin.read call + { + 'id': 641212, + 'group_parameters_attributes': None, + 'parent_id': None, + }, + ) + self.assertSetEqual( + read.call_args[0][2], # ignore for EntityReadMixin.read call + {'compute_resource', 'kickstart_repository', 'root_pass'}, + ) + self.read_json_pacther.stop() + self.read_pacther.stop() def test_delete_puppetclass(self): """Check that helper method is sane. @@ -3657,9 +3544,7 @@ class VersionTestCase(TestCase): def setUpClass(cls): """Create several server configs with different versions.""" super().setUpClass() - cls.cfg_608 = config.ServerConfig('bogus url', version='6.0.8') - cls.cfg_610 = config.ServerConfig('bogus url', version='6.1.0') - cls.cfg_620 = config.ServerConfig('bogus url', version='6.2.0') + cls.cfg = config.ServerConfig('bogus url') def test_missing_org_id(self): """Test methods for which no organization ID is returned. @@ -3674,101 +3559,17 @@ def test_missing_org_id(self): """ for entity in (entities.ContentView, entities.Product): - # Version 6.0.8 - label = gen_integer() # unrealistic value - with mock.patch.object(EntityReadMixin, 'read_json') as read_json: - read_json.return_value = {'organization': {'label': label}} - with mock.patch.object(entities, '_get_org') as helper: + with self.subTest(entity): + label = gen_alpha() + with mock.patch.object(EntityReadMixin, 'read_json') as read_json: + read_json.return_value = {'organization': {'label': label}} with mock.patch.object(EntityReadMixin, 'read') as read: - entity(self.cfg_608).read() - self.assertEqual(read_json.call_count, 1) - self.assertEqual(helper.call_count, 1) - self.assertEqual(read.call_count, 1) - self.assertEqual(helper.call_args[0], (self.cfg_608, label)) - - # Version 6.1.0 - with mock.patch.object(EntityReadMixin, 'read_json'): - with mock.patch.object(EntityReadMixin, 'read') as read: - entity(self.cfg_610).read() - self.assertTrue( - read.call_args[0][2] is None or 'organization' not in read.call_args[0][2] - ) - - def test_lifecycle_environment(self): - """Create a :class:`nailgun.entities.LifecycleEnvironment`. - - Assert that - :meth:`nailgun.entities.LifecycleEnvironment.create_payload` returns a - dict having a ``prior`` key in Satellite 6.0.8 and ``prior_id`` in - Satellite 6.1.0. - - """ - payload = entities.LifecycleEnvironment( - self.cfg_608, - prior=1, - ).create_payload() - self.assertNotIn('prior_id', payload) - self.assertIn('prior', payload) - - payload = entities.LifecycleEnvironment( - self.cfg_610, - prior=1, - ).create_payload() - self.assertNotIn('prior', payload) - self.assertIn('prior_id', payload) - - def test_repository_fields(self): - """Check :class:`nailgun.entities.Repository`'s fields. - - Assert that ``Repository`` has fields named "docker_upstream_name" and - "checksum_type", and that "docker" is a choice for the "content_type" - field starting with version 6.1. - - """ - repo_608 = entities.Repository(self.cfg_608) - repo_610 = entities.Repository(self.cfg_610) - for field_name in ('docker_upstream_name', 'checksum_type'): - self.assertNotIn(field_name, repo_608.get_fields()) - self.assertIn(field_name, repo_610.get_fields()) - self.assertNotIn('docker', repo_608.get_fields()['content_type'].choices) - self.assertIn('docker', repo_610.get_fields()['content_type'].choices) - - def test_hostpackage(self): - """Attempt to create a :class:`nailgun.entities.HostPackage` for the - Satellite 6.1. - - Assert that ``HostPackage`` raises ``NotImplementedError`` exception. - """ - with self.assertRaises(NotImplementedError): - entities.HostPackage(self.cfg_610, host=1) - - def test_hostsubscription(self): - """Attempt to create a :class:`nailgun.entities.HostSubscription` for - the Satellite 6.1. - - Assert that ``HostSubscription`` raises ``NotImplementedError`` - exception. - """ - with self.assertRaises(NotImplementedError): - entities.HostSubscription(self.cfg_610, host=1) - - def test_system(self): - """Attempt to create a :class:`nailgun.entities.System` for the - Satellite 6.2. - - Assert that ``System`` raises ``DeprecationWarning`` exception. - """ - with self.assertRaises(DeprecationWarning): - entities.System(self.cfg_620) - - def test_systempackage(self): - """Attempt to create a :class:`nailgun.entities.SystemPackage` for the - Satellite 6.1. - - Assert that ``SystemPackage`` raises ``DeprecationWarning`` exception. - """ - with self.assertRaises(DeprecationWarning): - entities.SystemPackage(self.cfg_620) + entity(self.cfg).read() + self.assertEqual(read_json.call_count, 1) + self.assertEqual(read.call_count, 1) + self.assertTrue( + read.call_args[0][2] is None or 'organization' not in read.call_args[0][2] + ) class JsonSerializableTestCase(TestCase):