Skip to content

Commit 63d8c75

Browse files
committed
Add scheduler hint sample
1 parent 22c3c9a commit 63d8c75

File tree

8 files changed

+143
-16
lines changed

8 files changed

+143
-16
lines changed

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ All code snippets used in the docs must live in `samples/` rather than being mai
107107

108108
Sample tests typically create a temporary PHP file from a template and `require_once` it, so keep samples self-contained and readable.
109109

110+
When adding sample tests, prefer reusing resources created earlier in the same test file instead of provisioning duplicate ones. In practice, `testCreate` should return the created resource, dependent tests should consume it via `@depends`, and cleanup should happen in the final `testDelete`.
111+
110112
## Documentation
111113

112114
User docs live in `doc/` and use Sphinx plus reStructuredText. If a change affects public behavior, examples, or supported options, update docs as needed.

doc/services/compute/v2/server-groups.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ optional ``rules`` object instead:
4444
When Nova responds with the newer singular ``policy`` field, the SDK also exposes that value as the first item in
4545
``policies`` for compatibility with the older response shape.
4646

47+
Create A Server In A Group
48+
--------------------------
49+
50+
To place a server into an existing server group, pass the server group UUID through ``schedulerHints.group`` when you
51+
create the server:
52+
53+
.. sample:: Compute/v2/server_groups/create_server.php
54+
4755
Read
4856
----
4957

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
require 'vendor/autoload.php';
4+
5+
$openstack = new OpenStack\OpenStack([
6+
'authUrl' => '{authUrl}',
7+
'region' => '{region}',
8+
'user' => [
9+
'id' => '{userId}',
10+
'password' => '{password}',
11+
],
12+
'scope' => ['project' => ['id' => '{projectId}']],
13+
]);
14+
15+
$compute = $openstack->computeV2(['region' => '{region}']);
16+
17+
$server = $compute->createServer([
18+
'name' => '{serverName}',
19+
'imageId' => '{imageId}',
20+
'flavorId' => '{flavorId}',
21+
'networks' => [
22+
['uuid' => '{networkId}'],
23+
],
24+
'schedulerHints' => [
25+
'group' => '{serverGroupId}',
26+
],
27+
]);

src/Compute/v2/Api.php

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public function __construct()
1818
$this->params = new Params();
1919
}
2020

21+
private function serverParam(array $param): array
22+
{
23+
return array_merge($param, ['path' => 'server']);
24+
}
25+
2126
public function getLimits(): array
2227
{
2328
return [
@@ -189,21 +194,21 @@ public function deleteImageMetadataKey(): array
189194
public function postServer(): array
190195
{
191196
return [
192-
'path' => 'servers',
193-
'method' => 'POST',
194-
'jsonKey' => 'server',
195-
'params' => [
196-
'imageId' => $this->notRequired($this->params->imageId()),
197-
'flavorId' => $this->params->flavorId(),
198-
'personality' => $this->params->personality(),
199-
'metadata' => $this->notRequired($this->params->metadata()),
200-
'name' => $this->isRequired($this->params->name('server')),
201-
'securityGroups' => $this->params->securityGroups(),
202-
'userData' => $this->params->userData(),
203-
'availabilityZone' => $this->params->availabilityZone(),
204-
'networks' => $this->params->networks(),
205-
'blockDeviceMapping' => $this->params->blockDeviceMapping(),
206-
'keyName' => $this->params->keyName(),
197+
'path' => 'servers',
198+
'method' => 'POST',
199+
'params' => [
200+
'imageId' => $this->serverParam($this->notRequired($this->params->imageId())),
201+
'flavorId' => $this->serverParam($this->params->flavorId()),
202+
'personality' => $this->serverParam($this->params->personality()),
203+
'metadata' => $this->serverParam($this->notRequired($this->params->metadata())),
204+
'name' => $this->serverParam($this->isRequired($this->params->name('server'))),
205+
'securityGroups' => $this->serverParam($this->params->securityGroups()),
206+
'userData' => $this->serverParam($this->params->userData()),
207+
'availabilityZone' => $this->serverParam($this->params->availabilityZone()),
208+
'networks' => $this->serverParam($this->params->networks()),
209+
'blockDeviceMapping' => $this->serverParam($this->params->blockDeviceMapping()),
210+
'keyName' => $this->serverParam($this->params->keyName()),
211+
'schedulerHints' => $this->params->schedulerHints(),
207212
],
208213
];
209214
}

src/Compute/v2/Params.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,16 @@ public function blockDeviceMapping(): array
366366
];
367367
}
368368

369+
public function schedulerHints(): array
370+
{
371+
return [
372+
'type' => self::OBJECT_TYPE,
373+
'location' => self::JSON,
374+
'sentAs' => 'os:scheduler_hints',
375+
'description' => 'Scheduler hints to pass alongside the server create request, for example ["group" => "{serverGroupId}"].',
376+
];
377+
}
378+
369379
public function filterHost(): array
370380
{
371381
return [

tests/sample/Compute/v2/ServerGroupTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace OpenStack\Sample\Compute\v2;
44

55
use OpenStack\Common\Error\BadResponseError;
6+
use OpenStack\Compute\v2\Models\Server;
67
use OpenStack\Compute\v2\Models\ServerGroup;
8+
use RuntimeException;
79

810
class ServerGroupTest extends TestCase
911
{
@@ -47,6 +49,49 @@ public function testCreate(): ServerGroup
4749
return $serverGroup;
4850
}
4951

52+
/**
53+
* @depends testCreate
54+
*/
55+
public function testCreateServerInGroup(ServerGroup $createdServerGroup)
56+
{
57+
$flavorId = getenv('OS_FLAVOR');
58+
59+
if (!$flavorId) {
60+
throw new RuntimeException('OS_FLAVOR env var must be set');
61+
}
62+
63+
$network = $this->getNetworkService()->createNetwork(['name' => $this->randomStr()]);
64+
$this->getNetworkService()->createSubnet(
65+
[
66+
'name' => $this->randomStr(),
67+
'networkId' => $network->id,
68+
'ipVersion' => 4,
69+
'cidr' => '10.20.30.0/24',
70+
]
71+
);
72+
73+
/** @var Server $server */
74+
require_once $this->sampleFile(
75+
'server_groups/create_server.php',
76+
[
77+
'{serverName}' => $this->randomStr(),
78+
'{imageId}' => $this->searchImageId(),
79+
'{flavorId}' => $flavorId,
80+
'{networkId}' => $network->id,
81+
'{serverGroupId}' => $createdServerGroup->id,
82+
]
83+
);
84+
85+
$this->assertInstanceOf(Server::class, $server);
86+
87+
$server->waitUntilActive(300);
88+
$createdServerGroup->retrieve();
89+
90+
$this->assertContains($server->id, $createdServerGroup->members);
91+
92+
$this->deleteServer($server);
93+
}
94+
5095
/**
5196
* @depends testCreate
5297
*/

tests/sample/Compute/v2/TestCase.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,13 @@ protected function createServer(): Server
7979
*/
8080
protected function deleteServer(Server $server): void
8181
{
82+
$server->retrieve();
83+
$networks = array_keys($server->addresses);
84+
8285
$server->delete();
8386
$server->waitUntilDeleted();
8487

85-
foreach (array_keys($server->addresses) as $networkName) {
88+
foreach ($networks as $networkName) {
8689
$network = $this->getNetworkService()->listNetworks(['name' => $networkName])->current();
8790
$this->deleteNetwork($network);
8891
}

tests/unit/Compute/v2/ServiceTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,33 @@ public function test_it_creates_servers()
4848
self::assertInstanceOf(Server::class, $this->service->createServer($opts));
4949
}
5050

51+
public function test_it_creates_servers_with_scheduler_hints()
52+
{
53+
$opts = [
54+
'name' => 'foo',
55+
'imageId' => '',
56+
'flavorId' => '',
57+
'schedulerHints' => [
58+
'group' => 'server-group-id',
59+
],
60+
];
61+
62+
$expectedJson = [
63+
'server' => [
64+
'name' => $opts['name'],
65+
'imageRef' => $opts['imageId'],
66+
'flavorRef' => $opts['flavorId'],
67+
],
68+
'os:scheduler_hints' => [
69+
'group' => 'server-group-id',
70+
],
71+
];
72+
73+
$this->mockRequest('POST', 'servers', 'server-post', $expectedJson, []);
74+
75+
self::assertInstanceOf(Server::class, $this->service->createServer($opts));
76+
}
77+
5178
public function test_it_lists_servers()
5279
{
5380
$this->mockRequest('GET', ['path' => 'servers', 'query' => ['limit' => 5]], 'servers-get');

0 commit comments

Comments
 (0)