Skip to content

Commit

Permalink
Merge pull request #3810 from allegro/optimize-hosts-endpoints
Browse files Browse the repository at this point in the history
Optimize hosts endpoints
  • Loading branch information
hipek8 authored Jun 11, 2024
2 parents 5440253 + b62440b commit 2931ba7
Show file tree
Hide file tree
Showing 15 changed files with 61 additions and 52 deletions.
15 changes: 6 additions & 9 deletions src/ralph/assets/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from ralph.licences.api import BaseObjectLicenceViewSet
from ralph.licences.models import BaseObjectLicence
from ralph.networks.models import IPAddress
from ralph.security.models import SecurityScan


class BusinessSegmentViewSet(RalphAPIViewSet):
Expand Down Expand Up @@ -98,6 +97,8 @@ class Meta(NetworkableObjectFilters.Meta):
Prefetch('licences', queryset=BaseObjectLicence.objects.select_related(
*BaseObjectLicenceViewSet.select_related
)),
'securityscan__tags',
'securityscan__vulnerabilities__tags',
'custom_fields',
'service_env__service__business_owners',
'service_env__service__technical_owners',
Expand Down Expand Up @@ -244,23 +245,19 @@ class DCHostViewSet(BaseObjectViewSetMixin, RalphAPIViewSet):
'content_type',
]
select_related = [
'service_env', 'service_env__service', 'service_env__environment',
'configuration_path', 'configuration_path__module',
'service_env__service', 'service_env__environment',
'configuration_path__module',
'parent__cloudproject',
]
prefetch_related = [
'tags',
'custom_fields',
'securityscan__vulnerabilities__tags',
'securityscan__tags',
Prefetch(
'ethernet_set',
queryset=models.Ethernet.objects.select_related('ipaddress')
),
Prefetch(
'securityscan',
queryset=SecurityScan.objects.prefetch_related(
'vulnerabilities', 'tags'
)
),
]
extended_filter_fields = {
'name': [
Expand Down
9 changes: 6 additions & 3 deletions src/ralph/assets/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -954,11 +954,14 @@ def setUp(self):
self.cloud_host.update_custom_field('test_cf', 'xyz')

def test_get_dc_hosts_list(self):
url = reverse('dchost-list')
with self.assertNumQueries(12):
dc_assets = DataCenterAssetFullFactory.create_batch(20)
VirtualServerFullFactory.create_batch(20, parent=dc_assets[0])
CloudHostFullFactory.create_batch(20, hypervisor=dc_assets[0])
url = reverse('dchost-list') + "?limit=100"
with self.assertNumQueries(15):
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 3)
self.assertEqual(response.data['count'], 63)

def test_filter_by_type_dc_asset(self):
url = '{}?{}'.format(
Expand Down
1 change: 1 addition & 0 deletions src/ralph/back_office/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class BackOfficeAssetViewSet(RalphAPIViewSet):
'service_env__service__business_owners',
'service_env__service__technical_owners',
'tags',
'content_type',
]
queryset = BackOfficeAsset.objects.all()
serializer_class = BackOfficeAssetSerializer
Expand Down
2 changes: 2 additions & 0 deletions src/ralph/back_office/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
OfficeInfrastructure,
Warehouse
)
from ralph.security.tests.factories import SecurityScanFactory

date_now = datetime.now().date()

Expand Down Expand Up @@ -57,6 +58,7 @@ class BackOfficeAssetFactory(DjangoModelFactory):
invoice_date = date_now - timedelta(days=15)
invoice_no = factory.Sequence(lambda n: 'Invoice number ' + str(n))
price = FuzzyDecimal(10, 300)
securityscan = factory.RelatedFactory(SecurityScanFactory, 'base_object')

class Meta:
model = BackOfficeAsset
Expand Down
6 changes: 4 additions & 2 deletions src/ralph/back_office/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ def setUp(self):
self.bo_asset.save()

def test_get_back_office_assets_list(self):
url = reverse('backofficeasset-list')
response = self.client.get(url, format='json')
BackOfficeAssetFactory.create_batch(100)
url = reverse('backofficeasset-list') + "?limit=100"
with self.assertNumQueries(14):
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data['count'], BackOfficeAsset.objects.count()
Expand Down
7 changes: 0 additions & 7 deletions src/ralph/data_center/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
ServerRoom,
VIP
)
from ralph.security.models import SecurityScan


class DataCenterAssetFilterSet(NetworkableObjectFilters):
Expand Down Expand Up @@ -64,12 +63,6 @@ class DataCenterAssetViewSet(BaseObjectViewSetMixin, RalphAPIViewSet):
'ethernet_set',
queryset=Ethernet.objects.select_related('ipaddress')
),
Prefetch(
'securityscan',
queryset=SecurityScan.objects.prefetch_related(
'vulnerabilities', 'tags'
)
),
'fibrechannelcard_set',
'processor_set',
'disk_set',
Expand Down
7 changes: 4 additions & 3 deletions src/ralph/data_center/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
VIP,
VIPProtocol
)
from ralph.security.tests.factories import SecurityScanFactory

date_now = datetime.now().date()

Expand Down Expand Up @@ -70,9 +71,7 @@ class Meta:

class ClusterFactory(DjangoModelFactory):

name = factory.Iterator(
['Databases', 'Applications', 'Switch', 'Load balancer']
)
name = factory.Sequence(lambda n: f"Cluster {n}")
type = factory.SubFactory(ClusterTypeFactory)
configuration_path = factory.SubFactory(ConfigurationClassFactory)
service_env = factory.SubFactory(ServiceEnvironmentFactory)
Expand Down Expand Up @@ -211,6 +210,8 @@ class DataCenterAssetFullFactory(DataCenterAssetFactory):
'base_object',
)

securityscan = factory.RelatedFactory(SecurityScanFactory, 'base_object')

@factory.post_generation
def post_tags(self, create, extracted, **kwargs):
self.tags.add('abc, cde', 'xyz')
Expand Down
14 changes: 8 additions & 6 deletions src/ralph/data_center/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ def setUp(self):
self.dc_asset_2 = DataCenterAssetFullFactory()

def test_get_data_center_assets_list(self):
url = reverse('datacenterasset-list')
with self.assertNumQueries(17):
DataCenterAssetFullFactory.create_batch(100)
url = reverse('datacenterasset-list') + "?limit=100"
with self.assertNumQueries(20):
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
Expand Down Expand Up @@ -551,18 +552,19 @@ def test_create_cluster_without_hostname_or_name(self):
})

def test_list_cluster(self):
url = reverse('cluster-list')
with self.assertNumQueries(12):
ClusterFactory.create_batch(20)
url = reverse('cluster-list') + "?limit=100"
with self.assertNumQueries(13):
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data['results']), 2)
self.assertEqual(len(response.data['results']), 22)
for item in response.data['results']:
if item['id'] == self.cluster_1.id:
self.assertEqual(len(item['base_objects']), 2)

def test_get_cluster_details(self):
url = reverse('cluster-detail', args=(self.cluster_1.id,))
with self.assertNumQueries(11):
with self.assertNumQueries(12):
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['name'], self.cluster_1.name)
Expand Down
4 changes: 4 additions & 0 deletions src/ralph/data_center/tests/test_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def setUp(self):
rack__name='Rack #1',
rack__server_room__name='SR1',
rack__server_room__data_center__name='DC1',
securityscan=None,
)

def test_listing_show_ok_when_scan_succeed_and_no_vulnerabilities(
Expand Down Expand Up @@ -219,6 +220,7 @@ def setUp(self):
rack__name='Rack #1',
rack__server_room__name='SR1',
rack__server_room__data_center__name='DC1',
securityscan=None,
)
self.scan_no_vuls = SecurityScanFactory(
base_object=self.asset_no_vuls.baseobject_ptr, vulnerabilities=[],
Expand All @@ -232,6 +234,7 @@ def setUp(self):
rack__name='Rack #1',
rack__server_room__name='SR1',
rack__server_room__data_center__name='DC1',
securityscan=None,
)
self.scan_with_vuls2 = SecurityScanFactory(
base_object=self.asset_with_today_vul.baseobject_ptr,
Expand All @@ -246,6 +249,7 @@ def setUp(self):
rack__name='Rack #1',
rack__server_room__name='SR1',
rack__server_room__data_center__name='DC1',
securityscan=None,
)
self.scan_with_vuls2 = SecurityScanFactory(
base_object=self.asset_vuls2.baseobject_ptr,
Expand Down
2 changes: 1 addition & 1 deletion src/ralph/security/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Meta:


class VulnerabilityViewSet(RalphAPIViewSet):
queryset = Vulnerability.objects.all()
queryset = Vulnerability.objects.all().prefetch_related('tags')
serializer_class = VulnerabilitySerializer
filter_fields = [
'external_vulnerability_id',
Expand Down
10 changes: 10 additions & 0 deletions src/ralph/security/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,16 @@ def test_get_vulnerability_list(self):
response.data['count'], Vulnerability.objects.count()
)

def test_get_vulnerability_list_query_count(self):
VulnerabilityFactory.create_batch(99)
url = reverse('vulnerability-list')
with self.assertNumQueries(5):
response = self.client.get(url + "?limit=100", format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
response.data['count'], Vulnerability.objects.count()
)

def test_get_vulnerability_details(self):
url = reverse('vulnerability-detail', args=(self.vulnerability.id,))
response = self.client.get(url, format='json')
Expand Down
13 changes: 0 additions & 13 deletions src/ralph/virtual/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
from ralph.data_center.models import DCHost
from ralph.lib.api.exceptions import Conflict
from ralph.security.api import SecurityScanSerializer
from ralph.security.models import SecurityScan
from ralph.virtual.admin import VirtualServerAdmin
from ralph.virtual.models import (
CloudFlavor,
Expand Down Expand Up @@ -247,12 +246,6 @@ class CloudHostViewSet(BaseObjectViewSetMixin, RalphAPIViewSet):
'ethernet_set',
queryset=Ethernet.objects.select_related('ipaddress')
),
Prefetch(
'securityscan',
queryset=SecurityScan.objects.prefetch_related(
'vulnerabilities', 'tags'
)
),
]

filter_fields = [
Expand Down Expand Up @@ -298,12 +291,6 @@ class VirtualServerViewSet(BaseObjectViewSetMixin, RalphAPIViewSet):
'ethernet_set',
queryset=Ethernet.objects.select_related('ipaddress')
),
Prefetch(
'securityscan',
queryset=SecurityScan.objects.prefetch_related(
'vulnerabilities', 'tags'
)
),
# TODO: clusters
]
filter_fields = [
Expand Down
6 changes: 5 additions & 1 deletion src/ralph/virtual/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ServiceEnvironmentFactory
)
from ralph.data_center.tests.factories import DataCenterAssetFactory
from ralph.security.tests.factories import SecurityScanFactory
from ralph.virtual.models import (
CloudFlavor,
CloudHost,
Expand Down Expand Up @@ -80,7 +81,7 @@ class CloudHostFactory(DjangoModelFactory):
CloudProviderFactory,
name='openstack',
)
host_id = factory.Iterator(['host_id1', 'host_id2', 'host_id3', 'host_id4'])
host_id = factory.Sequence(lambda n: f'host_id1{n}.local')
parent = factory.SubFactory(CloudProjectFactory)
configuration_path = factory.SubFactory(ConfigurationClassFactory)
service_env = factory.SubFactory(ServiceEnvironmentFactory)
Expand All @@ -92,6 +93,8 @@ class Meta:

class CloudHostFullFactory(CloudHostFactory):
hypervisor = factory.SubFactory(DataCenterAssetFactory)
securityscan = factory.RelatedFactory(SecurityScanFactory, 'base_object')


@factory.post_generation
def post_tags(self, create, extracted, **kwargs):
Expand Down Expand Up @@ -141,6 +144,7 @@ class VirtualServerFullFactory(VirtualServerFactory):
proc2 = factory.RelatedFactory(ProcessorFactory, 'base_object')
disk1 = factory.RelatedFactory(DiskFactory, 'base_object')
disk2 = factory.RelatedFactory(DiskFactory, 'base_object')
securityscan = factory.RelatedFactory(SecurityScanFactory, 'base_object')

@factory.post_generation
def post_tags(self, create, extracted, **kwargs):
Expand Down
15 changes: 9 additions & 6 deletions src/ralph/virtual/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from ralph.virtual.tests.factories import (
CloudFlavorFactory,
CloudHostFactory,
CloudHostFullFactory,
CloudProjectFactory,
CloudProviderFactory,
VirtualServerFullFactory
Expand Down Expand Up @@ -97,11 +98,12 @@ def test_get_list(self, field):
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_get_cloudhost_list(self):
url = reverse('cloudhost-list')
with self.assertNumQueries(12):
CloudHostFullFactory.create_batch(100)
url = reverse('cloudhost-list') + "?limit=100"
with self.assertNumQueries(15):
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 2)
self.assertEqual(response.data['count'], 102)

@unpack
@data(
Expand Down Expand Up @@ -450,11 +452,12 @@ def setUp(self):
)

def test_get_virtual_server_list(self):
url = reverse('virtualserver-list')
with self.assertNumQueries(13):
VirtualServerFullFactory.create_batch(20)
url = reverse('virtualserver-list') + "?limit=100"
with self.assertNumQueries(16):
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 2)
self.assertEqual(response.data['count'], 22)

def test_get_virtual_server_details(self):
url = reverse('virtualserver-detail', args=(self.virtual_server.id,))
Expand Down
2 changes: 1 addition & 1 deletion src/ralph/virtual/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ def test_cleanup_security_scan_transition(self):

class VirtualServerTestCase(RalphTestCase, NetworkableBaseObjectTestMixin):
def setUp(self):
self.vs = VirtualServerFullFactory()
self.vs = VirtualServerFullFactory(securityscan=None)
self.custom_field_str = CustomField.objects.create(
name='test str', type=CustomFieldTypes.STRING, default_value='xyz'
)
Expand Down

0 comments on commit 2931ba7

Please sign in to comment.