# Copyright 2024 Acme Gating, LLC # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import testtools from kazoo.exceptions import NoNodeError from zuul import model from zuul.launcher.client import LauncherClient from tests.base import ( ZuulTestCase, iterate_timeout, ) class BaseCloudDriverTest(ZuulTestCase): cloud_test_connection_type = 'ssh' cloud_test_image_format = '' cloud_test_provider_name = '' def _getEndpoint(self): # Use the launcher provider so that we're using the same ttl # method caches. for provider in self.launcher.tenant_providers['tenant-one']: if provider.name == self.cloud_test_provider_name: return provider.getEndpoint() def _assertProviderNodeAttributes(self, pnode): self.assertEqual(pnode.connection_type, self.cloud_test_connection_type) self.assertIsNotNone(pnode.interface_ip) def _test_node_lifecycle(self, label): # Call this in a test to run a node lifecycle for _ in iterate_timeout( 30, "scheduler and launcher to have the same layout"): if (self.scheds.first.sched.local_layout_state.get("tenant-one") == self.launcher.local_layout_state.get("tenant-one")): break endpoint = self._getEndpoint() nodeset = model.NodeSet() nodeset.addNode(model.Node("node", label)) ctx = self.createZKContext(None) request = self.requestNodes([n.label for n in nodeset.getNodes()]) client = LauncherClient(self.zk_client, None) request = client.getRequest(request.uuid) self.assertEqual(request.state, model.NodesetRequest.State.FULFILLED) self.assertEqual(len(request.nodes), 1) client.acceptNodeset(request, nodeset) self.waitUntilSettled() with testtools.ExpectedException(NoNodeError): # Request should be gone request.refresh(ctx) for node in nodeset.getNodes(): pnode = node._provider_node self.assertIsNotNone(pnode) self.assertTrue(pnode.hasLock()) self._assertProviderNodeAttributes(pnode) self.assertGreater(len(list(endpoint.listInstances())), 0) client.useNodeset(nodeset) self.waitUntilSettled() for node in nodeset.getNodes(): pnode = node._provider_node self.assertTrue(pnode.hasLock()) self.assertTrue(pnode.state, pnode.State.IN_USE) client.returnNodeset(nodeset) self.waitUntilSettled() for node in nodeset.getNodes(): pnode = node._provider_node self.assertFalse(pnode.hasLock()) self.assertTrue(pnode.state, pnode.State.USED) for _ in iterate_timeout(60, "node to be deleted"): try: pnode.refresh(ctx) except NoNodeError: break # Iterate here because the aws driver (at least) performs # delayed async deletes. for _ in iterate_timeout(60, "instances to be deleted"): if len(list(endpoint.listInstances())) == 0: break def _test_diskimage(self): self.waitUntilSettled() self.assertHistory([ dict(name='build-debian-local-image', result='SUCCESS'), ], ordered=False) name = 'review.example.com%2Forg%2Fcommon-config/debian-local' artifacts = self.launcher.image_build_registry.\ getArtifactsForImage(name) self.assertEqual(1, len(artifacts)) self.assertEqual(self.cloud_test_image_format, artifacts[0].format) self.assertTrue(artifacts[0].validated) uploads = self.launcher.image_upload_registry.getUploadsForImage( name) self.assertEqual(1, len(uploads)) self.assertEqual(artifacts[0].uuid, uploads[0].artifact_uuid) self.assertIsNotNone(uploads[0].external_id) self.assertTrue(uploads[0].validated)