diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index f00c019f..9a722ed3 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 diff --git a/doc/services/compute/v2/servers.rst b/doc/services/compute/v2/servers.rst index 4865771d..31343244 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.php b/samples/Compute/v2/servers/resume.php new file mode 100644 index 00000000..e3347623 --- /dev/null +++ b/samples/Compute/v2/servers/resume.php @@ -0,0 +1,17 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}', + ], +]); + +$service = $openstack->computeV2(); +$server = $service->getServer(['id' => '{serverId}']); + +$server->resume(); diff --git a/samples/Compute/v2/servers/suspend.php b/samples/Compute/v2/servers/suspend.php new file mode 100644 index 00000000..d53e1f1c --- /dev/null +++ b/samples/Compute/v2/servers/suspend.php @@ -0,0 +1,17 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}', + ], +]); + +$service = $openstack->computeV2(); +$server = $service->getServer(['id' => '{serverId}']); + +$server->suspend(); diff --git a/src/Compute/v2/Api.php b/src/Compute/v2/Api.php index 2a8dde1a..ee4adfa0 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 a9e25cbd..bb7e73ae 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(): void + { + $this->execute($this->api->resumeServer(), [ + 'id' => $this->id, + 'resume' => null, + ]); + } + + /** + * Suspends server. + */ + public function suspend(): void + { + $this->execute($this->api->suspendServer(), [ + 'id' => $this->id, + 'suspend' => null, + ]); + } + /** * Rebuilds the server. * diff --git a/tests/sample/Compute/v2/ServerTest.php b/tests/sample/Compute/v2/ServerTest.php index 0d3b5495..18c8f5a3 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); @@ -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]); @@ -361,4 +364,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', 300); + $this->assertEquals('ACTIVE', $server->status); + + $this->deleteServer($server); + } } \ No newline at end of file diff --git a/tests/sample/Compute/v2/VolumeAttachmentTest.php b/tests/sample/Compute/v2/VolumeAttachmentTest.php index e1eb73dc..5236a647 100644 --- a/tests/sample/Compute/v2/VolumeAttachmentTest.php +++ b/tests/sample/Compute/v2/VolumeAttachmentTest.php @@ -11,6 +11,11 @@ public function testAttach(): VolumeAttachment { $server = $this->createServer(); + // 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( [ 'name' => $this->randomStr(), diff --git a/tests/unit/Compute/v2/Models/ServerTest.php b/tests/unit/Compute/v2/Models/ServerTest.php index 5b637e12..a5e48e3d 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']];