From da261687db8cb01ca5a44edbe49da9880deb8255 Mon Sep 17 00:00:00 2001 From: Martin Zurowietz Date: Tue, 18 Dec 2018 09:28:33 +0100 Subject: [PATCH 1/7] Implement resuming and suspending of servers --- samples/compute/v2/servers/resume_server.php | 21 + samples/compute/v2/servers/suspend_server.php | 21 + src/Compute/v2/Api.php | 24 + src/Compute/v2/Models/Server.php | 22 + tests/integration/Compute/v2/CoreTest.php | 763 ++++++++++++++++++ tests/unit/Compute/v2/Models/ServerTest.php | 18 + 6 files changed, 869 insertions(+) create mode 100644 samples/compute/v2/servers/resume_server.php create mode 100644 samples/compute/v2/servers/suspend_server.php create mode 100644 tests/integration/Compute/v2/CoreTest.php diff --git a/samples/compute/v2/servers/resume_server.php b/samples/compute/v2/servers/resume_server.php new file mode 100644 index 000000000..e155f86aa --- /dev/null +++ b/samples/compute/v2/servers/resume_server.php @@ -0,0 +1,21 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$compute = $openstack->computeV2(['region' => '{region}']); + +$server = $compute->getServer([ + 'id' => '{serverId}', +]); + +$server->resume(); diff --git a/samples/compute/v2/servers/suspend_server.php b/samples/compute/v2/servers/suspend_server.php new file mode 100644 index 000000000..42b80016c --- /dev/null +++ b/samples/compute/v2/servers/suspend_server.php @@ -0,0 +1,21 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$compute = $openstack->computeV2(['region' => '{region}']); + +$server = $compute->getServer([ + 'id' => '{serverId}', +]); + +$server->suspend(); diff --git a/src/Compute/v2/Api.php b/src/Compute/v2/Api.php index 2a8dde1a9..ee4adfa00 100644 --- a/src/Compute/v2/Api.php +++ b/src/Compute/v2/Api.php @@ -332,6 +332,30 @@ public function stopServer(): array ]; } + public function resumeServer(): array + { + return [ + 'method' => 'POST', + 'path' => 'servers/{id}/action', + 'params' => [ + 'id' => $this->params->urlId('server'), + 'resume' => $this->params->nullAction(), + ], + ]; + } + + public function suspendServer(): array + { + return [ + 'method' => 'POST', + 'path' => 'servers/{id}/action', + 'params' => [ + 'id' => $this->params->urlId('server'), + 'suspend' => $this->params->nullAction(), + ], + ]; + } + public function rebuildServer(): array { return [ diff --git a/src/Compute/v2/Models/Server.php b/src/Compute/v2/Models/Server.php index a9e25cbd9..741db5267 100644 --- a/src/Compute/v2/Models/Server.php +++ b/src/Compute/v2/Models/Server.php @@ -217,6 +217,28 @@ public function stop() ]); } + /** + * Resumes server. + */ + public function resume() + { + $this->execute($this->api->resumeServer(), [ + 'id' => $this->id, + 'resume' => null, + ]); + } + + /** + * Suspends server. + */ + public function suspend() + { + $this->execute($this->api->suspendServer(), [ + 'id' => $this->id, + 'suspend' => null, + ]); + } + /** * Rebuilds the server. * diff --git a/tests/integration/Compute/v2/CoreTest.php b/tests/integration/Compute/v2/CoreTest.php new file mode 100644 index 000000000..b3db5a8fc --- /dev/null +++ b/tests/integration/Compute/v2/CoreTest.php @@ -0,0 +1,763 @@ +service) { + $this->service = Utils::getOpenStack()->computeV2(); + } + + return $this->service; + } + + private function getNetworkService() + { + if (!$this->networkService) { + $this->networkService = Utils::getOpenStack()->networkingV2(); + } + + return $this->networkService; + } + + private function getBlockStorageService() + { + if (!$this->blockStorageService) { + $this->blockStorageService = Utils::getOpenStack()->blockStorageV2(); + } + + return $this->blockStorageService; + } + + private function searchImages($name) + { + foreach ($this->getService()->listImages() as $image) { + if (strpos($image->name, $name) !== false) { + $this->imageId = $image->id; + break; + } + } + + if (!$this->imageId) { + throw new \RuntimeException(sprintf('Unable to find image "%s". Make sure this image is available for integration test.', $name)); + } + } + + protected function setUp() + { + $this->network = $this->getNetworkService()->createNetwork( + [ + 'name' => self::NETWORK, + 'adminStateUp' => true, + ] + ); + + $this->logStep('Created network {name} with id {id}', ['name' => $this->network->name, 'id' => $this->network->id]); + + $this->subnet = $this->getNetworkService()->createSubnet( + [ + 'name' => self::SUBNET, + 'networkId' => $this->network->id, + 'ipVersion' => 4, + 'cidr' => '10.20.30.0/24', + ] + ); + + $this->logStep('Created subnet {name} with id {id}', ['name' => $this->subnet->name, 'id' => $this->subnet->id]); + + $this->volume = $this->getBlockStorageService()->createVolume( + [ + 'name' => self::VOLUME, + 'description' => '', + 'size' => 1 + ] + ); + + $this->logStep('Created volume {name} with id {id}', ['name' => $this->volume->name, 'id' => $this->volume->id]); + } + + public function runTests() + { + $this->startTimer(); + + // Manually trigger setUp + $this->setUp(); + + $this->searchImages(self::IMAGE); + + // Servers + $this->createServer(); + + try { + $this->updateServer(); + $this->retrieveServer(); + $this->serverMetadata(); + + // Server actions + //$this->changeServerPassword(); + $this->stopServer(); + $this->startServer(); + $this->resizeServer(); + $this->confirmServerResize(); + $this->rebuildServer(); + $this->rescueServer(); + $this->createServerImage(); + $this->rebootServer(); + + // Security groups + $this->addSecurityGroupToServer(); + $this->listServerSecurityGroups(); + $this->removeServerSecurityGroup(); + + // Volume attachments + $this->attachVolumeToServer(); + $this->listVolumeAttachmentsForServer(); + $this->detachVolumeFromServer(); + + // Flavors + $this->createFlavor(); + $this->listFlavors(); + $this->getFlavor(); + + // Images + $this->listImages(); + $this->getImage(); + $this->imageMetadata(); + $this->deleteServerImage(); + + // Keypairs + $this->listKeypairs(); + $this->createKeypair(); + $this->getKeypair(); + $this->deleteKeypair(); + + // Limits + $this->getLimits(); + + // Hypervisors + $this->listHypervisors(); + $this->getHypervisorsStatistics(); + $this->getHypervisor(); + + // Console + $this->getVncConsole(); + + // Interface attachments + $this->createInterfaceAttachment(); + } finally { + // Teardown + $this->deleteServer(); + $this->deleteFlavor(); + $this->subnet->delete(); + $this->network->delete(); + $this->volume->delete(); + } + + $this->outputTimeTaken(); + } + + private function createServer() + { + $flavorId = getenv('OS_FLAVOR'); + + if (!$flavorId) { + throw new \RuntimeException('OS_FLAVOR env var must be set'); + } + + $replacements = [ + '{serverName}' => $this->randomStr(), + '{imageId}' => $this->imageId, + '{flavorId}' => $flavorId, + '{networkId}' => $this->network->id + ]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + $path = $this->sampleFile($replacements, 'servers/create_server.php'); + require_once $path; + + $server->waitUntilActive(false); + + $this->assertInstanceOf('OpenStack\Compute\v2\Models\Server', $server); + $this->assertNotEmpty($server->id); + $this->assertNotEmpty($server->adminPass); + + $this->serverId = $server->id; + $this->adminPass = $server->adminPass; + + $this->logStep('Created server {id}', ['{id}' => $server->id]); + } + + private function updateServer() + { + $name = $this->randomStr(); + + $replacements = [ + '{serverId}' => $this->serverId, + '{newName}' => $name, + ]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + $path = $this->sampleFile($replacements, 'servers/update_server.php'); + require_once $path; + + $this->assertInstanceOf('OpenStack\Compute\v2\Models\Server', $server); + $this->assertEquals($name, $server->name); + + $server->waitUntilActive(false); + + $this->logStep('Updated server ID to use this name: NAME', ['ID' => $this->serverId, 'NAME' => $name]); + } + + private function deleteServer() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + $path = $this->sampleFile($replacements, 'servers/delete_server.php'); + require_once $path; + + // Needed so that subnet and network can be removed + $server->waitUntilDeleted(); + $this->logStep('Deleted server ID', ['ID' => $this->serverId]); + } + + private function retrieveServer() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + $path = $this->sampleFile($replacements, 'servers/get_server.php'); + require_once $path; + + $this->assertInstanceOf('OpenStack\Compute\v2\Models\Server', $server); + $this->assertEquals($this->serverId, $server->id); + $this->assertNotNull($server->created); + $this->assertNotNull($server->updated); + $this->assertNotNull($server->name); + $this->assertNotNull($server->ipv4); + $this->assertNotNull($server->status); + $this->assertInstanceOf(Image::class, $server->image); + $this->assertInstanceOf(Flavor::class, $server->flavor); + + $this->logStep('Retrieved the details of server ID', ['ID' => $this->serverId]); + } + + private function serverMetadata() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/reset_server_metadata.php'); + $this->logStep('Reset metadata of server {serverId}', $replacements); + + require_once $this->sampleFile($replacements, 'servers/get_server_metadata.php'); + $this->logStep('Retrieved metadata of server {serverId}', $replacements); + + require_once $this->sampleFile($replacements, 'servers/delete_server_metadata_item.php'); + $this->logStep('Deleted metadata key of server {serverId}', $replacements); + } + + private function changeServerPassword() + { + $this->adminPass = $this->randomStr(); + + $replacements = [ + '{serverId}' => $this->serverId, + '{newPassword}' => $this->adminPass, + ]; + + require_once $this->sampleFile($replacements, 'servers/change_server_password.php'); + + $this->logStep('Changed root password of server {serverId} to {newPassword}', $replacements); + } + + private function resizeServer() + { + $resizeFlavorId = getenv('OS_RESIZE_FLAVOR'); + if (!$resizeFlavorId) { + throw new \RuntimeException('OS_RESIZE_FLAVOR env var must be set'); + } + + $replacements = [ + '{serverId}' => $this->serverId, + '{flavorId}' => $resizeFlavorId, + ]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/resize_server.php'); + + $server->waitUntil('VERIFY_RESIZE'); + + $this->logStep('Resized server {serverId} to flavor {flavorId}', $replacements); + } + + private function confirmServerResize() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/confirm_server_resize.php'); + + $server->waitUntilActive(); + + $this->logStep('Confirmed resize of server {serverId}', $replacements); + } + + private function rebuildServer() + { + $replacements = [ + '{serverId}' => $this->serverId, + '{imageId}' => $this->imageId, + '{adminPass}' => $this->adminPass, + ]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/rebuild_server.php'); + + $server->waitUntilActive(); + + $this->logStep('Rebuilt server {serverId}', $replacements); + } + + private function rescueServer() + { + $replacements = [ + '{serverId}' => $this->serverId, + '{imageId}' => $this->imageId, + '{adminPass}' => $this->adminPass, + ]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/rescue_server.php'); + + $server->waitUntil('RESCUE'); + + require_once $this->sampleFile($replacements, 'servers/unrescue_server.php'); + + $server->waitUntilActive(); + + $this->logStep('Rescued server {serverId}', $replacements); + } + + private function rebootServer() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/reboot_server.php'); + + $server->waitUntilActive(false); + + $this->logStep('Rebooted server {serverId}', $replacements); + } + + private function stopServer() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/stop_server.php'); + + $server->waitUntil('SHUTOFF', false); + + $this->logStep('Stopped server {serverId}', $replacements); + } + + private function startServer() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/start_server.php'); + + $server->waitUntilActive(false); + + $this->logStep('Started server {serverId}', $replacements); + } + + private function suspendServer() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/suspend_server.php'); + + $server->waitUntil('SUSPENDED', false); + + $this->logStep('Suspended server {serverId}', $replacements); + } + + private function resumeServer() + { + $replacements = ['{serverId}' => $this->serverId]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'servers/resume_server.php'); + + $server->waitUntilActive(false); + + $this->logStep('Resumed server {serverId}', $replacements); + } + + private function createFlavor() + { + $replacements = [ + '{flavorName}' => $this->randomStr() + ]; + + /** @var $flavor \OpenStack\Compute\v2\Models\Flavor */ + $path = $this->sampleFile($replacements, 'flavors/create_flavor.php'); + require_once $path; + + $this->assertInstanceOf('\OpenStack\Compute\v2\Models\Flavor', $flavor); + + $this->flavorId = $flavor->id; + $this->logStep('Created flavor {id}', ['{id}' => $flavor->id]); + } + + private function deleteFlavor() + { + $replacements = ['{flavorId}' => $this->flavorId]; + + $path = $this->sampleFile($replacements, 'flavors/delete_flavor.php'); + require_once $path; + + $this->logStep('Deleted flavor ID', ['ID' => $this->flavorId]); + } + + private function listFlavors() + { + require_once $this->sampleFile([], 'flavors/list_flavors.php'); + + $this->logStep('Listed all available flavors'); + } + + private function getFlavor() + { + $replacements = ['{flavorId}' => 1]; + + require_once $this->sampleFile($replacements, 'flavors/get_flavor.php'); + + $this->logStep('Retrieved details for flavor {flavorId}', $replacements); + } + + private function createServerImage() + { + $name = $this->randomStr(); + + $replacements = [ + '{serverId}' => $this->serverId, + '{imageName}' => $name, + ]; + + /** @var $server \OpenStack\Compute\v2\Models\Server */ + require_once $this->sampleFile($replacements, 'images/create_server_image.php'); + + $server->waitWithCallback(function (Server $server) { + return !$server->taskState; + }, false); + + $this->searchImages($name); + + $this->logStep('Created an image for server {serverId} with name {imageName}', $replacements); + } + + private function listImages() + { + require_once $this->sampleFile([], 'images/list_images.php'); + + $this->logStep('Listed all available images'); + } + + private function getImage() + { + $replacements = ['{imageId}' => $this->imageId]; + + require_once $this->sampleFile($replacements, 'images/get_image.php'); + + $this->logStep('Retrieved details for image {imageId}', $replacements); + } + + private function imageMetadata() + { + $replacements = ['{imageId}' => $this->imageId]; + + /** @var $image \OpenStack\Compute\v2\Models\Image */ + require_once $this->sampleFile($replacements, 'images/reset_image_metadata.php'); + $this->logStep('Reset metadata of image {imageId}', $replacements); + + require_once $this->sampleFile($replacements, 'images/retrieve_image_metadata.php'); + $this->logStep('Retrieved metadata of image {imageId}', $replacements); + + require_once $this->sampleFile($replacements + ['{metadataKey}'], 'images/delete_image_metadata_item.php'); + $this->logStep('Deleted metadata key of image {imageId}', $replacements); + } + + private function deleteServerImage() + { + $replacements = ['{imageId}' => $this->imageId]; + require_once $this->sampleFile($replacements, 'images/delete_image.php'); + $this->logStep('Deleted image {imageId}', $replacements); + } + + private function listKeypairs() + { + /** @var $keypairs \Generator */ + require_once $this->sampleFile([], 'keypairs/list_keypairs.php'); + + $this->assertInstanceOf(\Generator::class, $keypairs); + + $this->logStep('Listed all keypairs'); + } + + private function createKeypair() + { + $replacements = [ + '{name}' => $this->randomStr(), + '{publicKey}' => 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCp4H/vDGnLi0QgWgMsQkv//FEz0xgv/mujVX+XCh6fHXxc/PbaASY+MsoI2Xr238cG9eaeAAUvbpJuEuHQ0M9WX97bvsWaWzLQ9F6hzLAwUBGxcG8cSh1nB3Ah7alR2nbIZ1N94yE72hXLb1AGogJ97NBVIph438BCXUNejqoOBsXL8UBP3RGdPnTHJ/6XSMaNTQAJruQMoQwecyGFQmuS2IEy2mBOmSldD6JZirHpj7PTCKJY4CS89QChGpKIeOymKn4tEQQVVtNFUyULEMdin88H1yMftPfq7QqH+ULFT2X2XvP3CI+sESq84lrIcVu7LjJCRIwlKsnMu2ESYCdz foo@bar.com' + ]; + + require_once $this->sampleFile($replacements, 'keypairs/create_keypair.php'); + /**@var Keypair $keypair */ + + $this->assertInstanceOf(Keypair::class, $keypair); + $this->assertEquals($replacements['{name}'], $keypair->name); + $this->assertEquals($replacements['{publicKey}'], $keypair->publicKey); + + $this->keypairName = $keypair->name; + $this->logStep('Created keypair name {name}', ['{name}' => $keypair->name]); + } + + private function getKeypair() + { + $replacements = [ + '{name}' => $this->keypairName, + ]; + + require_once $this->sampleFile($replacements, 'keypairs/get_keypair.php'); + + /**@var Keypair $keypair */ + $this->assertInstanceOf(Keypair::class, $keypair); + + $this->assertEquals($replacements['{name}'], $keypair->name); + + $this->logStep('Retrieved details for keypair {name}', $replacements); + } + + private function deleteKeypair() + { + $replacements = [ + '{name}' => $this->keypairName, + ]; + + require_once $this->sampleFile($replacements, 'keypairs/delete_keypair.php'); + $this->logStep('Deleted keypair name {name}', ['{name}' => $this->keypairName]); + } + + private function listHypervisors() + { + require_once $this->sampleFile([], 'hypervisors/list_hypervisors.php'); + + $this->logStep('Listed all available hypervisors'); + } + + private function getHypervisor() + { + $replacements = [ + '{hypervisorId}' => '1', + ]; + + require_once $this->sampleFile($replacements, 'hypervisors/get_hypervisor.php'); + + /**@var Hypervisor $hypervisor */ + $this->assertInstanceOf(Hypervisor::class, $hypervisor); + $this->assertEquals($replacements['{hypervisorId}'], $hypervisor->id); + + $this->logStep('Retrieved details for hypervisor id {hypervisorId}', $replacements); + } + + private function getHypervisorsStatistics() + { + require_once $this->sampleFile([], 'hypervisors/get_hypervisors_statistics.php'); + + /**@var HypervisorStatistic $hypervisorStatistics */ + $this->assertInstanceOf(HypervisorStatistic::class, $hypervisorStatistics); + + $this->logStep('Retrieved hypervisors statistics'); + } + + private function getLimits() + { + require_once $this->sampleFile([], 'limits/get_limits.php'); + + /**@var Limit $limit */ + $this->assertInstanceOf(Limit::class, $limit); + + $this->logStep('Retrieved tenant limit'); + } + + private function addSecurityGroupToServer() + { + $replacements = [ + '{serverId}' => $this->serverId, + '{secGroupName}' => 'default' + ]; + + require_once $this->sampleFile($replacements, 'servers/add_security_group.php'); + + /**@var Server $server*/ + $this->logStep('Added security group {secGroupName} to server {serverId}', $replacements); + } + + private function listServerSecurityGroups() + { + $replacements = [ + '{serverId}' => $this->serverId + ]; + + require_once $this->sampleFile($replacements, 'servers/list_security_groups.php'); + + /**@var \Generator $securityGroups */ + $this->assertInstanceOf(\Generator::class, $securityGroups); + + $this->logStep('Listed all security groups attached to server {serverId}', $replacements); + } + + private function removeServerSecurityGroup() + { + $replacements = [ + '{serverId}' => $this->serverId, + '{secGroupName}' => 'default' + ]; + + require_once $this->sampleFile($replacements, 'servers/remove_security_group.php'); + + $this->logStep('Delete security group {secGroupName} from server {serverId}', $replacements); + } + + private function attachVolumeToServer() + { + $replacements = [ + '{serverId}' => $this->serverId, + '{volumeId}' => $this->volume->id + ]; + + require_once $this->sampleFile($replacements, 'servers/attach_volume_attachment.php'); + /**@var VolumeAttachment $volumeAttachment */ + $this->volumeAttachmentId = $volumeAttachment->id; + + $this->volume->waitUntil('in-use'); + + $this->logStep( + 'Attached volume {volumeId} to server {serverId} with volume attachment id {volumeAttachmentId}', + array_merge($replacements, ['{volumeAttachmentId}' => $volumeAttachment->id]) + ); + } + + private function listVolumeAttachmentsForServer() + { + $replacements = [ + '{serverId}' => $this->serverId + ]; + + require_once $this->sampleFile($replacements, 'servers/list_volume_attachments.php'); + + $this->logStep('Retrieved volume attachments for server {serverId}', $replacements); + } + + private function detachVolumeFromServer() + { + $replacements = [ + '{serverId}' => $this->serverId, + '{volumeAttachmentId}' => $this->volumeAttachmentId, + ]; + + require_once $this->sampleFile($replacements, 'servers/detach_volume_attachment.php'); + + $this->volume->waitUntil('available'); + + $this->logStep('Detached volume attachments for server {serverId}', $replacements); + } + + private function getVncConsole() + { + $replacements = [ + '{serverId}' => $this->serverId + ]; + + require_once $this->sampleFile($replacements, 'servers/get_server_vnc_console.php'); + + $this->logStep('Get VNC console for server {serverId}', $replacements); + } + + private function createInterfaceAttachment() + { + $replacements = [ + '{serverId}' => $this->serverId, + '{networkId}' => $this->network->id + ]; + + require_once $this->sampleFile($replacements, 'servers/create_interface_attachment.php'); + + $this->logStep('Create interface attachment for server {serverId}', $replacements); + } + + private function getConsoleOutput() + { + $replacements = [ + '{serverId}' => $this->serverId + ]; + + require_once $this->sampleFile($replacements, 'servers/get_server_console_output.php'); + + $this->logStep('Get console output for server {serverId}', $replacements); + } +} diff --git a/tests/unit/Compute/v2/Models/ServerTest.php b/tests/unit/Compute/v2/Models/ServerTest.php index 5b637e12a..a5e48e3d3 100644 --- a/tests/unit/Compute/v2/Models/ServerTest.php +++ b/tests/unit/Compute/v2/Models/ServerTest.php @@ -211,6 +211,24 @@ public function test_it_stops() self::assertNull($this->server->stop()); } + public function test_it_resumes() + { + $expectedJson = ['resume' => null]; + + $this->setupMock('POST', 'servers/serverId/action', $expectedJson, [], new Response(202)); + + $this->assertNull($this->server->resume()); + } + + public function test_it_suspends() + { + $expectedJson = ['suspend' => null]; + + $this->setupMock('POST', 'servers/serverId/action', $expectedJson, [], new Response(202)); + + $this->assertNull($this->server->suspend()); + } + public function test_it_resizes() { $expectedJson = ['resize' => ['flavorRef' => 'flavorId']]; From e3feec6a449cacc7cb199464fda3facf93d67b22 Mon Sep 17 00:00:00 2001 From: Martin Zurowietz Date: Tue, 18 Dec 2018 09:35:46 +0100 Subject: [PATCH 2/7] Add missing call to integration tests for resume/suspend server --- tests/integration/Compute/v2/CoreTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration/Compute/v2/CoreTest.php b/tests/integration/Compute/v2/CoreTest.php index b3db5a8fc..c5fc36fcd 100644 --- a/tests/integration/Compute/v2/CoreTest.php +++ b/tests/integration/Compute/v2/CoreTest.php @@ -145,6 +145,8 @@ public function runTests() //$this->changeServerPassword(); $this->stopServer(); $this->startServer(); + $this->suspendServer(); + $this->resumeServer(); $this->resizeServer(); $this->confirmServerResize(); $this->rebuildServer(); From a7adbb6dbe00b14a15f14dac2ae42e807bea8ad0 Mon Sep 17 00:00:00 2001 From: Konstantin Babushkin Date: Tue, 30 Jan 2024 14:24:24 +0100 Subject: [PATCH 3/7] fix tests --- doc/services/compute/v2/servers.rst | 11 + .../v2/servers/resume.php} | 10 +- .../v2/servers/suspend.php} | 10 +- src/Compute/v2/Models/Server.php | 4 +- tests/integration/Compute/v2/CoreTest.php | 765 ------------------ tests/sample/Compute/v2/ServerTest.php | 29 +- 6 files changed, 47 insertions(+), 782 deletions(-) rename samples/{compute/v2/servers/resume_server.php => Compute/v2/servers/resume.php} (50%) rename samples/{compute/v2/servers/suspend_server.php => Compute/v2/servers/suspend.php} (51%) delete mode 100644 tests/integration/Compute/v2/CoreTest.php diff --git a/doc/services/compute/v2/servers.rst b/doc/services/compute/v2/servers.rst index 4865771da..313432448 100644 --- a/doc/services/compute/v2/servers.rst +++ b/doc/services/compute/v2/servers.rst @@ -280,3 +280,14 @@ You can also refine by network label: $ipAddresses = $server->listAddresses([ 'networkLabel' => '{networkLabel}', ]); + +Suspend +------- + +.. sample:: Compute/v2/images/suspend.php + +Resume +------ + +.. sample:: Compute/v2/images/resume.php + diff --git a/samples/compute/v2/servers/resume_server.php b/samples/Compute/v2/servers/resume.php similarity index 50% rename from samples/compute/v2/servers/resume_server.php rename to samples/Compute/v2/servers/resume.php index e155f86aa..e3347623a 100644 --- a/samples/compute/v2/servers/resume_server.php +++ b/samples/Compute/v2/servers/resume.php @@ -7,15 +7,11 @@ 'region' => '{region}', 'user' => [ 'id' => '{userId}', - 'password' => '{password}' + 'password' => '{password}', ], - 'scope' => ['project' => ['id' => '{projectId}']] ]); -$compute = $openstack->computeV2(['region' => '{region}']); - -$server = $compute->getServer([ - 'id' => '{serverId}', -]); +$service = $openstack->computeV2(); +$server = $service->getServer(['id' => '{serverId}']); $server->resume(); diff --git a/samples/compute/v2/servers/suspend_server.php b/samples/Compute/v2/servers/suspend.php similarity index 51% rename from samples/compute/v2/servers/suspend_server.php rename to samples/Compute/v2/servers/suspend.php index 42b80016c..d53e1f1c6 100644 --- a/samples/compute/v2/servers/suspend_server.php +++ b/samples/Compute/v2/servers/suspend.php @@ -7,15 +7,11 @@ 'region' => '{region}', 'user' => [ 'id' => '{userId}', - 'password' => '{password}' + 'password' => '{password}', ], - 'scope' => ['project' => ['id' => '{projectId}']] ]); -$compute = $openstack->computeV2(['region' => '{region}']); - -$server = $compute->getServer([ - 'id' => '{serverId}', -]); +$service = $openstack->computeV2(); +$server = $service->getServer(['id' => '{serverId}']); $server->suspend(); diff --git a/src/Compute/v2/Models/Server.php b/src/Compute/v2/Models/Server.php index 741db5267..bb7e73ae8 100644 --- a/src/Compute/v2/Models/Server.php +++ b/src/Compute/v2/Models/Server.php @@ -220,7 +220,7 @@ public function stop() /** * Resumes server. */ - public function resume() + public function resume(): void { $this->execute($this->api->resumeServer(), [ 'id' => $this->id, @@ -231,7 +231,7 @@ public function resume() /** * Suspends server. */ - public function suspend() + public function suspend(): void { $this->execute($this->api->suspendServer(), [ 'id' => $this->id, diff --git a/tests/integration/Compute/v2/CoreTest.php b/tests/integration/Compute/v2/CoreTest.php deleted file mode 100644 index c5fc36fcd..000000000 --- a/tests/integration/Compute/v2/CoreTest.php +++ /dev/null @@ -1,765 +0,0 @@ -service) { - $this->service = Utils::getOpenStack()->computeV2(); - } - - return $this->service; - } - - private function getNetworkService() - { - if (!$this->networkService) { - $this->networkService = Utils::getOpenStack()->networkingV2(); - } - - return $this->networkService; - } - - private function getBlockStorageService() - { - if (!$this->blockStorageService) { - $this->blockStorageService = Utils::getOpenStack()->blockStorageV2(); - } - - return $this->blockStorageService; - } - - private function searchImages($name) - { - foreach ($this->getService()->listImages() as $image) { - if (strpos($image->name, $name) !== false) { - $this->imageId = $image->id; - break; - } - } - - if (!$this->imageId) { - throw new \RuntimeException(sprintf('Unable to find image "%s". Make sure this image is available for integration test.', $name)); - } - } - - protected function setUp() - { - $this->network = $this->getNetworkService()->createNetwork( - [ - 'name' => self::NETWORK, - 'adminStateUp' => true, - ] - ); - - $this->logStep('Created network {name} with id {id}', ['name' => $this->network->name, 'id' => $this->network->id]); - - $this->subnet = $this->getNetworkService()->createSubnet( - [ - 'name' => self::SUBNET, - 'networkId' => $this->network->id, - 'ipVersion' => 4, - 'cidr' => '10.20.30.0/24', - ] - ); - - $this->logStep('Created subnet {name} with id {id}', ['name' => $this->subnet->name, 'id' => $this->subnet->id]); - - $this->volume = $this->getBlockStorageService()->createVolume( - [ - 'name' => self::VOLUME, - 'description' => '', - 'size' => 1 - ] - ); - - $this->logStep('Created volume {name} with id {id}', ['name' => $this->volume->name, 'id' => $this->volume->id]); - } - - public function runTests() - { - $this->startTimer(); - - // Manually trigger setUp - $this->setUp(); - - $this->searchImages(self::IMAGE); - - // Servers - $this->createServer(); - - try { - $this->updateServer(); - $this->retrieveServer(); - $this->serverMetadata(); - - // Server actions - //$this->changeServerPassword(); - $this->stopServer(); - $this->startServer(); - $this->suspendServer(); - $this->resumeServer(); - $this->resizeServer(); - $this->confirmServerResize(); - $this->rebuildServer(); - $this->rescueServer(); - $this->createServerImage(); - $this->rebootServer(); - - // Security groups - $this->addSecurityGroupToServer(); - $this->listServerSecurityGroups(); - $this->removeServerSecurityGroup(); - - // Volume attachments - $this->attachVolumeToServer(); - $this->listVolumeAttachmentsForServer(); - $this->detachVolumeFromServer(); - - // Flavors - $this->createFlavor(); - $this->listFlavors(); - $this->getFlavor(); - - // Images - $this->listImages(); - $this->getImage(); - $this->imageMetadata(); - $this->deleteServerImage(); - - // Keypairs - $this->listKeypairs(); - $this->createKeypair(); - $this->getKeypair(); - $this->deleteKeypair(); - - // Limits - $this->getLimits(); - - // Hypervisors - $this->listHypervisors(); - $this->getHypervisorsStatistics(); - $this->getHypervisor(); - - // Console - $this->getVncConsole(); - - // Interface attachments - $this->createInterfaceAttachment(); - } finally { - // Teardown - $this->deleteServer(); - $this->deleteFlavor(); - $this->subnet->delete(); - $this->network->delete(); - $this->volume->delete(); - } - - $this->outputTimeTaken(); - } - - private function createServer() - { - $flavorId = getenv('OS_FLAVOR'); - - if (!$flavorId) { - throw new \RuntimeException('OS_FLAVOR env var must be set'); - } - - $replacements = [ - '{serverName}' => $this->randomStr(), - '{imageId}' => $this->imageId, - '{flavorId}' => $flavorId, - '{networkId}' => $this->network->id - ]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - $path = $this->sampleFile($replacements, 'servers/create_server.php'); - require_once $path; - - $server->waitUntilActive(false); - - $this->assertInstanceOf('OpenStack\Compute\v2\Models\Server', $server); - $this->assertNotEmpty($server->id); - $this->assertNotEmpty($server->adminPass); - - $this->serverId = $server->id; - $this->adminPass = $server->adminPass; - - $this->logStep('Created server {id}', ['{id}' => $server->id]); - } - - private function updateServer() - { - $name = $this->randomStr(); - - $replacements = [ - '{serverId}' => $this->serverId, - '{newName}' => $name, - ]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - $path = $this->sampleFile($replacements, 'servers/update_server.php'); - require_once $path; - - $this->assertInstanceOf('OpenStack\Compute\v2\Models\Server', $server); - $this->assertEquals($name, $server->name); - - $server->waitUntilActive(false); - - $this->logStep('Updated server ID to use this name: NAME', ['ID' => $this->serverId, 'NAME' => $name]); - } - - private function deleteServer() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - $path = $this->sampleFile($replacements, 'servers/delete_server.php'); - require_once $path; - - // Needed so that subnet and network can be removed - $server->waitUntilDeleted(); - $this->logStep('Deleted server ID', ['ID' => $this->serverId]); - } - - private function retrieveServer() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - $path = $this->sampleFile($replacements, 'servers/get_server.php'); - require_once $path; - - $this->assertInstanceOf('OpenStack\Compute\v2\Models\Server', $server); - $this->assertEquals($this->serverId, $server->id); - $this->assertNotNull($server->created); - $this->assertNotNull($server->updated); - $this->assertNotNull($server->name); - $this->assertNotNull($server->ipv4); - $this->assertNotNull($server->status); - $this->assertInstanceOf(Image::class, $server->image); - $this->assertInstanceOf(Flavor::class, $server->flavor); - - $this->logStep('Retrieved the details of server ID', ['ID' => $this->serverId]); - } - - private function serverMetadata() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/reset_server_metadata.php'); - $this->logStep('Reset metadata of server {serverId}', $replacements); - - require_once $this->sampleFile($replacements, 'servers/get_server_metadata.php'); - $this->logStep('Retrieved metadata of server {serverId}', $replacements); - - require_once $this->sampleFile($replacements, 'servers/delete_server_metadata_item.php'); - $this->logStep('Deleted metadata key of server {serverId}', $replacements); - } - - private function changeServerPassword() - { - $this->adminPass = $this->randomStr(); - - $replacements = [ - '{serverId}' => $this->serverId, - '{newPassword}' => $this->adminPass, - ]; - - require_once $this->sampleFile($replacements, 'servers/change_server_password.php'); - - $this->logStep('Changed root password of server {serverId} to {newPassword}', $replacements); - } - - private function resizeServer() - { - $resizeFlavorId = getenv('OS_RESIZE_FLAVOR'); - if (!$resizeFlavorId) { - throw new \RuntimeException('OS_RESIZE_FLAVOR env var must be set'); - } - - $replacements = [ - '{serverId}' => $this->serverId, - '{flavorId}' => $resizeFlavorId, - ]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/resize_server.php'); - - $server->waitUntil('VERIFY_RESIZE'); - - $this->logStep('Resized server {serverId} to flavor {flavorId}', $replacements); - } - - private function confirmServerResize() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/confirm_server_resize.php'); - - $server->waitUntilActive(); - - $this->logStep('Confirmed resize of server {serverId}', $replacements); - } - - private function rebuildServer() - { - $replacements = [ - '{serverId}' => $this->serverId, - '{imageId}' => $this->imageId, - '{adminPass}' => $this->adminPass, - ]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/rebuild_server.php'); - - $server->waitUntilActive(); - - $this->logStep('Rebuilt server {serverId}', $replacements); - } - - private function rescueServer() - { - $replacements = [ - '{serverId}' => $this->serverId, - '{imageId}' => $this->imageId, - '{adminPass}' => $this->adminPass, - ]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/rescue_server.php'); - - $server->waitUntil('RESCUE'); - - require_once $this->sampleFile($replacements, 'servers/unrescue_server.php'); - - $server->waitUntilActive(); - - $this->logStep('Rescued server {serverId}', $replacements); - } - - private function rebootServer() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/reboot_server.php'); - - $server->waitUntilActive(false); - - $this->logStep('Rebooted server {serverId}', $replacements); - } - - private function stopServer() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/stop_server.php'); - - $server->waitUntil('SHUTOFF', false); - - $this->logStep('Stopped server {serverId}', $replacements); - } - - private function startServer() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/start_server.php'); - - $server->waitUntilActive(false); - - $this->logStep('Started server {serverId}', $replacements); - } - - private function suspendServer() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/suspend_server.php'); - - $server->waitUntil('SUSPENDED', false); - - $this->logStep('Suspended server {serverId}', $replacements); - } - - private function resumeServer() - { - $replacements = ['{serverId}' => $this->serverId]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'servers/resume_server.php'); - - $server->waitUntilActive(false); - - $this->logStep('Resumed server {serverId}', $replacements); - } - - private function createFlavor() - { - $replacements = [ - '{flavorName}' => $this->randomStr() - ]; - - /** @var $flavor \OpenStack\Compute\v2\Models\Flavor */ - $path = $this->sampleFile($replacements, 'flavors/create_flavor.php'); - require_once $path; - - $this->assertInstanceOf('\OpenStack\Compute\v2\Models\Flavor', $flavor); - - $this->flavorId = $flavor->id; - $this->logStep('Created flavor {id}', ['{id}' => $flavor->id]); - } - - private function deleteFlavor() - { - $replacements = ['{flavorId}' => $this->flavorId]; - - $path = $this->sampleFile($replacements, 'flavors/delete_flavor.php'); - require_once $path; - - $this->logStep('Deleted flavor ID', ['ID' => $this->flavorId]); - } - - private function listFlavors() - { - require_once $this->sampleFile([], 'flavors/list_flavors.php'); - - $this->logStep('Listed all available flavors'); - } - - private function getFlavor() - { - $replacements = ['{flavorId}' => 1]; - - require_once $this->sampleFile($replacements, 'flavors/get_flavor.php'); - - $this->logStep('Retrieved details for flavor {flavorId}', $replacements); - } - - private function createServerImage() - { - $name = $this->randomStr(); - - $replacements = [ - '{serverId}' => $this->serverId, - '{imageName}' => $name, - ]; - - /** @var $server \OpenStack\Compute\v2\Models\Server */ - require_once $this->sampleFile($replacements, 'images/create_server_image.php'); - - $server->waitWithCallback(function (Server $server) { - return !$server->taskState; - }, false); - - $this->searchImages($name); - - $this->logStep('Created an image for server {serverId} with name {imageName}', $replacements); - } - - private function listImages() - { - require_once $this->sampleFile([], 'images/list_images.php'); - - $this->logStep('Listed all available images'); - } - - private function getImage() - { - $replacements = ['{imageId}' => $this->imageId]; - - require_once $this->sampleFile($replacements, 'images/get_image.php'); - - $this->logStep('Retrieved details for image {imageId}', $replacements); - } - - private function imageMetadata() - { - $replacements = ['{imageId}' => $this->imageId]; - - /** @var $image \OpenStack\Compute\v2\Models\Image */ - require_once $this->sampleFile($replacements, 'images/reset_image_metadata.php'); - $this->logStep('Reset metadata of image {imageId}', $replacements); - - require_once $this->sampleFile($replacements, 'images/retrieve_image_metadata.php'); - $this->logStep('Retrieved metadata of image {imageId}', $replacements); - - require_once $this->sampleFile($replacements + ['{metadataKey}'], 'images/delete_image_metadata_item.php'); - $this->logStep('Deleted metadata key of image {imageId}', $replacements); - } - - private function deleteServerImage() - { - $replacements = ['{imageId}' => $this->imageId]; - require_once $this->sampleFile($replacements, 'images/delete_image.php'); - $this->logStep('Deleted image {imageId}', $replacements); - } - - private function listKeypairs() - { - /** @var $keypairs \Generator */ - require_once $this->sampleFile([], 'keypairs/list_keypairs.php'); - - $this->assertInstanceOf(\Generator::class, $keypairs); - - $this->logStep('Listed all keypairs'); - } - - private function createKeypair() - { - $replacements = [ - '{name}' => $this->randomStr(), - '{publicKey}' => 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCp4H/vDGnLi0QgWgMsQkv//FEz0xgv/mujVX+XCh6fHXxc/PbaASY+MsoI2Xr238cG9eaeAAUvbpJuEuHQ0M9WX97bvsWaWzLQ9F6hzLAwUBGxcG8cSh1nB3Ah7alR2nbIZ1N94yE72hXLb1AGogJ97NBVIph438BCXUNejqoOBsXL8UBP3RGdPnTHJ/6XSMaNTQAJruQMoQwecyGFQmuS2IEy2mBOmSldD6JZirHpj7PTCKJY4CS89QChGpKIeOymKn4tEQQVVtNFUyULEMdin88H1yMftPfq7QqH+ULFT2X2XvP3CI+sESq84lrIcVu7LjJCRIwlKsnMu2ESYCdz foo@bar.com' - ]; - - require_once $this->sampleFile($replacements, 'keypairs/create_keypair.php'); - /**@var Keypair $keypair */ - - $this->assertInstanceOf(Keypair::class, $keypair); - $this->assertEquals($replacements['{name}'], $keypair->name); - $this->assertEquals($replacements['{publicKey}'], $keypair->publicKey); - - $this->keypairName = $keypair->name; - $this->logStep('Created keypair name {name}', ['{name}' => $keypair->name]); - } - - private function getKeypair() - { - $replacements = [ - '{name}' => $this->keypairName, - ]; - - require_once $this->sampleFile($replacements, 'keypairs/get_keypair.php'); - - /**@var Keypair $keypair */ - $this->assertInstanceOf(Keypair::class, $keypair); - - $this->assertEquals($replacements['{name}'], $keypair->name); - - $this->logStep('Retrieved details for keypair {name}', $replacements); - } - - private function deleteKeypair() - { - $replacements = [ - '{name}' => $this->keypairName, - ]; - - require_once $this->sampleFile($replacements, 'keypairs/delete_keypair.php'); - $this->logStep('Deleted keypair name {name}', ['{name}' => $this->keypairName]); - } - - private function listHypervisors() - { - require_once $this->sampleFile([], 'hypervisors/list_hypervisors.php'); - - $this->logStep('Listed all available hypervisors'); - } - - private function getHypervisor() - { - $replacements = [ - '{hypervisorId}' => '1', - ]; - - require_once $this->sampleFile($replacements, 'hypervisors/get_hypervisor.php'); - - /**@var Hypervisor $hypervisor */ - $this->assertInstanceOf(Hypervisor::class, $hypervisor); - $this->assertEquals($replacements['{hypervisorId}'], $hypervisor->id); - - $this->logStep('Retrieved details for hypervisor id {hypervisorId}', $replacements); - } - - private function getHypervisorsStatistics() - { - require_once $this->sampleFile([], 'hypervisors/get_hypervisors_statistics.php'); - - /**@var HypervisorStatistic $hypervisorStatistics */ - $this->assertInstanceOf(HypervisorStatistic::class, $hypervisorStatistics); - - $this->logStep('Retrieved hypervisors statistics'); - } - - private function getLimits() - { - require_once $this->sampleFile([], 'limits/get_limits.php'); - - /**@var Limit $limit */ - $this->assertInstanceOf(Limit::class, $limit); - - $this->logStep('Retrieved tenant limit'); - } - - private function addSecurityGroupToServer() - { - $replacements = [ - '{serverId}' => $this->serverId, - '{secGroupName}' => 'default' - ]; - - require_once $this->sampleFile($replacements, 'servers/add_security_group.php'); - - /**@var Server $server*/ - $this->logStep('Added security group {secGroupName} to server {serverId}', $replacements); - } - - private function listServerSecurityGroups() - { - $replacements = [ - '{serverId}' => $this->serverId - ]; - - require_once $this->sampleFile($replacements, 'servers/list_security_groups.php'); - - /**@var \Generator $securityGroups */ - $this->assertInstanceOf(\Generator::class, $securityGroups); - - $this->logStep('Listed all security groups attached to server {serverId}', $replacements); - } - - private function removeServerSecurityGroup() - { - $replacements = [ - '{serverId}' => $this->serverId, - '{secGroupName}' => 'default' - ]; - - require_once $this->sampleFile($replacements, 'servers/remove_security_group.php'); - - $this->logStep('Delete security group {secGroupName} from server {serverId}', $replacements); - } - - private function attachVolumeToServer() - { - $replacements = [ - '{serverId}' => $this->serverId, - '{volumeId}' => $this->volume->id - ]; - - require_once $this->sampleFile($replacements, 'servers/attach_volume_attachment.php'); - /**@var VolumeAttachment $volumeAttachment */ - $this->volumeAttachmentId = $volumeAttachment->id; - - $this->volume->waitUntil('in-use'); - - $this->logStep( - 'Attached volume {volumeId} to server {serverId} with volume attachment id {volumeAttachmentId}', - array_merge($replacements, ['{volumeAttachmentId}' => $volumeAttachment->id]) - ); - } - - private function listVolumeAttachmentsForServer() - { - $replacements = [ - '{serverId}' => $this->serverId - ]; - - require_once $this->sampleFile($replacements, 'servers/list_volume_attachments.php'); - - $this->logStep('Retrieved volume attachments for server {serverId}', $replacements); - } - - private function detachVolumeFromServer() - { - $replacements = [ - '{serverId}' => $this->serverId, - '{volumeAttachmentId}' => $this->volumeAttachmentId, - ]; - - require_once $this->sampleFile($replacements, 'servers/detach_volume_attachment.php'); - - $this->volume->waitUntil('available'); - - $this->logStep('Detached volume attachments for server {serverId}', $replacements); - } - - private function getVncConsole() - { - $replacements = [ - '{serverId}' => $this->serverId - ]; - - require_once $this->sampleFile($replacements, 'servers/get_server_vnc_console.php'); - - $this->logStep('Get VNC console for server {serverId}', $replacements); - } - - private function createInterfaceAttachment() - { - $replacements = [ - '{serverId}' => $this->serverId, - '{networkId}' => $this->network->id - ]; - - require_once $this->sampleFile($replacements, 'servers/create_interface_attachment.php'); - - $this->logStep('Create interface attachment for server {serverId}', $replacements); - } - - private function getConsoleOutput() - { - $replacements = [ - '{serverId}' => $this->serverId - ]; - - require_once $this->sampleFile($replacements, 'servers/get_server_console_output.php'); - - $this->logStep('Get console output for server {serverId}', $replacements); - } -} diff --git a/tests/sample/Compute/v2/ServerTest.php b/tests/sample/Compute/v2/ServerTest.php index 0d3b54956..02e687721 100644 --- a/tests/sample/Compute/v2/ServerTest.php +++ b/tests/sample/Compute/v2/ServerTest.php @@ -318,7 +318,7 @@ public function testGetVncConsole(Server $createdServer) { /** @var array $console */ require_once $this->sampleFile('servers/get_server_vnc_console.php', [ - '{serverId}' => $createdServer->id + '{serverId}' => $createdServer->id, ]); $this->assertIsArray($console); @@ -361,4 +361,31 @@ public function testDelete(Server $createdServer) $this->expectException(BadResponseError::class); $createdServer->retrieve(); } + + public function testSuspend() + { + $server = $this->createServer(); + + require_once $this->sampleFile('servers/suspend.php', ['{serverId}' => $server->id]); + + $server->waitUntil('SUSPENDED'); + $this->assertEquals('SUSPENDED', $server->status); + + return $server; + } + + /** + * @depends testSuspend + */ + public function testResume(Server $server) + { + $this->assertEquals('SUSPENDED', $server->status); + + require_once $this->sampleFile('servers/resume.php', ['{serverId}' => $server->id]); + + $server->waitUntil('ACTIVE'); + $this->assertEquals('ACTIVE', $server->status); + + $this->deleteServer($server); + } } \ No newline at end of file From 7a102d34d6822530c7f435e82a86fb9088b2642e Mon Sep 17 00:00:00 2001 From: Konstantin Babushkin Date: Tue, 30 Jan 2024 15:14:13 +0100 Subject: [PATCH 4/7] add failure logs artifact --- .github/workflows/integration_tests.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index f00c019f8..9a722ed39 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -42,10 +42,12 @@ jobs: name: Deploy OpenStack ${{ matrix.name }} and run integration tests with php ${{matrix.php_version}} steps: - uses: actions/checkout@v2 + - name: get cache directory id: composer-cache run: | echo "::set-output name=dir::$(composer config cache-files-dir)" + - uses: actions/cache@v3 with: path: | @@ -54,13 +56,16 @@ jobs: key: ${{ runner.os }}-composer-${{ matrix.php_version }}-${{ hashFiles('**.composer.lock') }} restore-keys: | ${{ runner.os }}-composer-${{ matrix.php_version }}- + - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php_version }} extensions: curl tools: composer:v2 coverage: none + - run: composer install --prefer-dist --no-interaction --no-progress + - name: Restore devstack cache uses: actions/cache@v3 with: @@ -69,6 +74,7 @@ jobs: !/opt/stack/data ~/devstack/ key: ${{ runner.os }}-openstack-${{ matrix.openstack_version }}-${{ github.workflow }} + - name: Deploy devstack uses: EmilienM/devstack-action@v0.11 with: @@ -81,6 +87,7 @@ jobs: [filter:versioned_writes] allow_object_versioning = true enabled_services: 's-account,s-container,s-object,s-proxy,s-bak' + - name: Set env variables run: | { @@ -96,9 +103,23 @@ jobs: echo OS_FLAVOR=1 echo OS_DOMAIN_ID=default } >> "$GITHUB_ENV" + - name: Check if Block Storage API v2 must be tested if: matrix.block_storage_v2 == true run: echo "OS_BLOCK_STORAGE_V2=1" >> "$GITHUB_ENV" + - name: Execute Integration tests via PhpUnit run: vendor/bin/phpunit --configuration ./phpunit.sample.xml.dist + - name: Collect logs + if: ${{ failure() }} + run: | + set -x + journalctl >failure-logs + + - name: Save logs + if: ${{ failure() }} + uses: actions/upload-artifact@v3 + with: + name: failure-logs + path: failure-logs From 3994c4ed201e9e3e2e2d8c9f2454d5bde600346f Mon Sep 17 00:00:00 2001 From: Konstantin Babushkin Date: Tue, 30 Jan 2024 16:37:01 +0100 Subject: [PATCH 5/7] wait after volume attachment --- tests/sample/Compute/v2/VolumeAttachmentTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/sample/Compute/v2/VolumeAttachmentTest.php b/tests/sample/Compute/v2/VolumeAttachmentTest.php index e1eb73dc3..fb29b4add 100644 --- a/tests/sample/Compute/v2/VolumeAttachmentTest.php +++ b/tests/sample/Compute/v2/VolumeAttachmentTest.php @@ -11,6 +11,9 @@ public function testAttach(): VolumeAttachment { $server = $this->createServer(); + // let's wait for the server to be completely up - https://bugs.launchpad.net/nova/+bug/1998148 + sleep(10); + $volume = $this->getCachedService(Service::class)->createVolume( [ 'name' => $this->randomStr(), From 099097be11cd1e34317bb41575136ab5d07a0036 Mon Sep 17 00:00:00 2001 From: Konstantin Babushkin Date: Tue, 30 Jan 2024 17:26:22 +0100 Subject: [PATCH 6/7] increase wait timeout for server resume --- tests/sample/Compute/v2/ServerTest.php | 2 +- tests/sample/Compute/v2/VolumeAttachmentTest.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/sample/Compute/v2/ServerTest.php b/tests/sample/Compute/v2/ServerTest.php index 02e687721..b4abd48cf 100644 --- a/tests/sample/Compute/v2/ServerTest.php +++ b/tests/sample/Compute/v2/ServerTest.php @@ -383,7 +383,7 @@ public function testResume(Server $server) require_once $this->sampleFile('servers/resume.php', ['{serverId}' => $server->id]); - $server->waitUntil('ACTIVE'); + $server->waitUntil('ACTIVE', 300); $this->assertEquals('ACTIVE', $server->status); $this->deleteServer($server); diff --git a/tests/sample/Compute/v2/VolumeAttachmentTest.php b/tests/sample/Compute/v2/VolumeAttachmentTest.php index fb29b4add..5236a647c 100644 --- a/tests/sample/Compute/v2/VolumeAttachmentTest.php +++ b/tests/sample/Compute/v2/VolumeAttachmentTest.php @@ -11,7 +11,9 @@ public function testAttach(): VolumeAttachment { $server = $this->createServer(); - // let's wait for the server to be completely up - https://bugs.launchpad.net/nova/+bug/1998148 + // let's wait for the server to be completely up + // https://bugs.launchpad.net/nova/+bug/1998148 + // https://bugs.launchpad.net/nova/+bug/1960346 sleep(10); $volume = $this->getCachedService(Service::class)->createVolume( From 0a7b081079f11de9d62a5d2d84e378054bc9bb54 Mon Sep 17 00:00:00 2001 From: Konstantin Babushkin Date: Tue, 30 Jan 2024 17:54:17 +0100 Subject: [PATCH 7/7] increase time for get console output --- tests/sample/Compute/v2/ServerTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/sample/Compute/v2/ServerTest.php b/tests/sample/Compute/v2/ServerTest.php index b4abd48cf..18c8f5a3c 100644 --- a/tests/sample/Compute/v2/ServerTest.php +++ b/tests/sample/Compute/v2/ServerTest.php @@ -331,6 +331,9 @@ public function testGetVncConsole(Server $createdServer) */ public function testGetConsoleOutput(Server $createdServer) { + // wait for the server to be ready + sleep(5); + /** @var string $consoleOutput */ require_once $this->sampleFile('servers/get_server_console_output.php', ['{serverId}' => $createdServer->id]);