From c49a28ea9fbb9a671261301543e8b16759968e80 Mon Sep 17 00:00:00 2001 From: Jamie Hannaford Date: Mon, 28 Mar 2016 18:00:00 +0200 Subject: [PATCH 1/4] Add better integration tests --- samples/networking/v2/floatingIPs/create.php | 21 +++++++++++++++ samples/networking/v2/floatingIPs/delete.php | 17 ++++++++++++ samples/networking/v2/floatingIPs/get.php | 17 ++++++++++++ samples/networking/v2/floatingIPs/list.php | 20 ++++++++++++++ samples/networking/v2/floatingIPs/update.php | 19 ++++++++++++++ .../v2/securityGroupRules/create.php | 26 +++++++++++++++++++ .../v2/securityGroupRules/delete.php | 19 ++++++++++++++ .../networking/v2/securityGroupRules/get.php | 17 ++++++++++++ .../networking/v2/securityGroupRules/list.php | 20 ++++++++++++++ .../networking/v2/securityGroups/create.php | 21 +++++++++++++++ .../networking/v2/securityGroups/delete.php | 19 ++++++++++++++ samples/networking/v2/securityGroups/get.php | 19 ++++++++++++++ samples/networking/v2/securityGroups/list.php | 21 +++++++++++++++ samples/networking/v2/subnets/create.php | 6 +---- 14 files changed, 257 insertions(+), 5 deletions(-) create mode 100644 samples/networking/v2/floatingIPs/create.php create mode 100644 samples/networking/v2/floatingIPs/delete.php create mode 100644 samples/networking/v2/floatingIPs/get.php create mode 100644 samples/networking/v2/floatingIPs/list.php create mode 100644 samples/networking/v2/floatingIPs/update.php create mode 100644 samples/networking/v2/securityGroupRules/create.php create mode 100644 samples/networking/v2/securityGroupRules/delete.php create mode 100644 samples/networking/v2/securityGroupRules/get.php create mode 100644 samples/networking/v2/securityGroupRules/list.php create mode 100644 samples/networking/v2/securityGroups/create.php create mode 100644 samples/networking/v2/securityGroups/delete.php create mode 100644 samples/networking/v2/securityGroups/get.php create mode 100644 samples/networking/v2/securityGroups/list.php diff --git a/samples/networking/v2/floatingIPs/create.php b/samples/networking/v2/floatingIPs/create.php new file mode 100644 index 00000000..96062541 --- /dev/null +++ b/samples/networking/v2/floatingIPs/create.php @@ -0,0 +1,21 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$networking = $openstack->networkingV2ExtLayer3(); + +/** @var \OpenStack\Networking\v2\Extensions\Layer3\Models\FloatingIp $ip */ +$ip = $networking->createFloatingIp([ + "floatingNetworkId" => "{networkId}", + "portId" => "{portId}", +]); \ No newline at end of file diff --git a/samples/networking/v2/floatingIPs/delete.php b/samples/networking/v2/floatingIPs/delete.php new file mode 100644 index 00000000..05ef3236 --- /dev/null +++ b/samples/networking/v2/floatingIPs/delete.php @@ -0,0 +1,17 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$openstack->networkingV2ExtLayer3() + ->getFloatingIp('{id}') + ->delete(); \ No newline at end of file diff --git a/samples/networking/v2/floatingIPs/get.php b/samples/networking/v2/floatingIPs/get.php new file mode 100644 index 00000000..46d755b3 --- /dev/null +++ b/samples/networking/v2/floatingIPs/get.php @@ -0,0 +1,17 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +/** @var \OpenStack\Networking\v2\Extensions\Layer3\Models\FloatingIp $ip */ +$ip = $openstack->networkingV2ExtLayer3() + ->getFloatingIp('{id}'); \ No newline at end of file diff --git a/samples/networking/v2/floatingIPs/list.php b/samples/networking/v2/floatingIPs/list.php new file mode 100644 index 00000000..6eb788c7 --- /dev/null +++ b/samples/networking/v2/floatingIPs/list.php @@ -0,0 +1,20 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$floatingIps = $openstack->networkingV2ExtLayer3() + ->listFloatingIps(); + +foreach ($floatingIps as $floatingIp) { + /** @var \OpenStack\Networking\v2\Extensions\Layer3\Models\FloatingIp $floatingIp */ +} \ No newline at end of file diff --git a/samples/networking/v2/floatingIPs/update.php b/samples/networking/v2/floatingIPs/update.php new file mode 100644 index 00000000..3342b06a --- /dev/null +++ b/samples/networking/v2/floatingIPs/update.php @@ -0,0 +1,19 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$floatingIp = $openstack->networkingV2ExtLayer3() + ->getFloatingIp('{id}'); + +$floatingIp->portId = '{newPortId}'; +$floatingIp->update(); \ No newline at end of file diff --git a/samples/networking/v2/securityGroupRules/create.php b/samples/networking/v2/securityGroupRules/create.php new file mode 100644 index 00000000..08c3981a --- /dev/null +++ b/samples/networking/v2/securityGroupRules/create.php @@ -0,0 +1,26 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$networking = $openstack->networkingV2ExtSecGroups(); + +/** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroupRule $rule */ +$rule = $networking->createSecurityGroupRule([ + "direction" => "ingress", + "ethertype" => "IPv4", + "portRangeMin" => "80", + "portRangeMax" => "80", + "protocol" => "tcp", + "remoteGroupId" => "{groupId}", + "securityGroupId" => "{secGroupId}", +]); \ No newline at end of file diff --git a/samples/networking/v2/securityGroupRules/delete.php b/samples/networking/v2/securityGroupRules/delete.php new file mode 100644 index 00000000..ce200948 --- /dev/null +++ b/samples/networking/v2/securityGroupRules/delete.php @@ -0,0 +1,19 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +/** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroupRule $rule */ +$rule = $openstack->networkingV2ExtSecGroups() + ->getSecurityGroupRule('{id}'); + +$rule->delete(); \ No newline at end of file diff --git a/samples/networking/v2/securityGroupRules/get.php b/samples/networking/v2/securityGroupRules/get.php new file mode 100644 index 00000000..670e8ada --- /dev/null +++ b/samples/networking/v2/securityGroupRules/get.php @@ -0,0 +1,17 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +/** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroupRule $rule */ +$rule = $openstack->networkingV2ExtSecGroups() + ->getSecurityGroupRule('{id}'); \ No newline at end of file diff --git a/samples/networking/v2/securityGroupRules/list.php b/samples/networking/v2/securityGroupRules/list.php new file mode 100644 index 00000000..06aa0612 --- /dev/null +++ b/samples/networking/v2/securityGroupRules/list.php @@ -0,0 +1,20 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$rules = $openstack->networkingV2ExtSecGroups() + ->listSecurityGroupRules(); + +foreach ($rules as $rule) { + /** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroupRule $rule */ +} \ No newline at end of file diff --git a/samples/networking/v2/securityGroups/create.php b/samples/networking/v2/securityGroups/create.php new file mode 100644 index 00000000..e42cb6fe --- /dev/null +++ b/samples/networking/v2/securityGroups/create.php @@ -0,0 +1,21 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$networking = $openstack->networkingV2ExtSecGroups(); + +/** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroup $secGroup */ +$secGroup = $networking->createSecurityGroup([ + 'name' => 'new-webservers', + 'description' => 'security group for webservers', +]); \ No newline at end of file diff --git a/samples/networking/v2/securityGroups/delete.php b/samples/networking/v2/securityGroups/delete.php new file mode 100644 index 00000000..f0e805ac --- /dev/null +++ b/samples/networking/v2/securityGroups/delete.php @@ -0,0 +1,19 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$networking = $openstack->networkingV2ExtSecGroups(); + +/** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroup $secGroup */ +$secGroup = $networking->getSecurityGroup('{id}'); +$secGroup->delete(); \ No newline at end of file diff --git a/samples/networking/v2/securityGroups/get.php b/samples/networking/v2/securityGroups/get.php new file mode 100644 index 00000000..138d6acd --- /dev/null +++ b/samples/networking/v2/securityGroups/get.php @@ -0,0 +1,19 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$networking = $openstack->networkingV2ExtSecGroups(); + +/** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroup $secGroup */ +$secGroup = $networking->getSecurityGroup('{id}'); +$secGroup->retrieve(); \ No newline at end of file diff --git a/samples/networking/v2/securityGroups/list.php b/samples/networking/v2/securityGroups/list.php new file mode 100644 index 00000000..ab0c90e6 --- /dev/null +++ b/samples/networking/v2/securityGroups/list.php @@ -0,0 +1,21 @@ + '{authUrl}', + 'region' => '{region}', + 'user' => [ + 'id' => '{userId}', + 'password' => '{password}' + ], + 'scope' => ['project' => ['id' => '{projectId}']] +]); + +$networking = $openstack->networkingV2ExtSecGroups(); + +$secGroups = $networking->listSecurityGroups(); + +foreach ($secGroups as $secGroup) { + /** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroup $secGroup */ +} \ No newline at end of file diff --git a/samples/networking/v2/subnets/create.php b/samples/networking/v2/subnets/create.php index 4f741e4d..07287476 100644 --- a/samples/networking/v2/subnets/create.php +++ b/samples/networking/v2/subnets/create.php @@ -9,11 +9,7 @@ 'id' => '{userId}', 'password' => '{password}' ], - 'scope' => [ - 'project' => [ - 'id' => '{projectId}' - ] - ] + 'scope' => ['project' => ['id' => '{projectId}']] ]); $networking = $openstack->networkingV2(); From 5d19aaf71a34544afb6a9e61721f5b7e84b33f03 Mon Sep 17 00:00:00 2001 From: Jamie Hannaford Date: Sun, 1 May 2016 18:00:00 +0200 Subject: [PATCH 2/4] Add networking classes --- src/Networking/v2/Api.php | 10 +- src/Networking/v2/Extensions/Layer3/Api.php | 168 +++++++++ .../v2/Extensions/Layer3/Models/FixedIp.php | 18 + .../Extensions/Layer3/Models/FloatingIp.php | 75 ++++ .../Extensions/Layer3/Models/GatewayInfo.php | 23 ++ .../v2/Extensions/Layer3/Models/Router.php | 83 +++++ .../v2/Extensions/Layer3/Params.php | 116 +++++++ .../v2/Extensions/Layer3/Service.php | 75 ++++ .../v2/Extensions/SecurityGroups/Api.php | 152 +++++++++ .../SecurityGroups/Models/SecurityGroup.php | 76 +++++ .../Models/SecurityGroupRule.php | 106 ++++++ .../v2/Extensions/SecurityGroups/Params.php | 92 +++++ .../v2/Extensions/SecurityGroups/Service.php | 79 +++++ src/Networking/v2/Models/Network.php | 13 +- src/Networking/v2/Models/Port.php | 28 +- src/Networking/v2/Models/Subnet.php | 4 +- src/Networking/v2/Params.php | 38 ++- tests/integration/Networking/v2/CoreTest.php | 320 ++++++++++++++++++ .../integration/Networking/v2/Layer3Test.php | 109 ++++++ .../Networking/v2/SecGroupTest.php | 11 + .../Layer3/Models/FloatingIpTest.php | 52 +++ .../Extensions/Layer3/Models/RouterTest.php | 91 +++++ .../v2/Extensions/Layer3/ServiceTest.php | 127 +++++++ .../Models/SecurityGroupRuleTest.php | 38 +++ .../Models/SecurityGroupTest.php | 38 +++ .../Extensions/SecurityGroups/ServiceTest.php | 115 +++++++ tests/unit/Networking/v2/Models/PortTest.php | 7 + 27 files changed, 2051 insertions(+), 13 deletions(-) create mode 100644 src/Networking/v2/Extensions/Layer3/Api.php create mode 100644 src/Networking/v2/Extensions/Layer3/Models/FixedIp.php create mode 100644 src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php create mode 100644 src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php create mode 100644 src/Networking/v2/Extensions/Layer3/Models/Router.php create mode 100644 src/Networking/v2/Extensions/Layer3/Params.php create mode 100644 src/Networking/v2/Extensions/Layer3/Service.php create mode 100644 src/Networking/v2/Extensions/SecurityGroups/Api.php create mode 100644 src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroup.php create mode 100644 src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRule.php create mode 100644 src/Networking/v2/Extensions/SecurityGroups/Params.php create mode 100644 src/Networking/v2/Extensions/SecurityGroups/Service.php create mode 100644 tests/integration/Networking/v2/CoreTest.php create mode 100644 tests/integration/Networking/v2/Layer3Test.php create mode 100644 tests/integration/Networking/v2/SecGroupTest.php create mode 100644 tests/unit/Networking/v2/Extensions/Layer3/Models/FloatingIpTest.php create mode 100644 tests/unit/Networking/v2/Extensions/Layer3/Models/RouterTest.php create mode 100644 tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php create mode 100644 tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRuleTest.php create mode 100644 tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupTest.php create mode 100644 tests/unit/Networking/v2/Extensions/SecurityGroups/ServiceTest.php diff --git a/src/Networking/v2/Api.php b/src/Networking/v2/Api.php index 6aafbb13..17651727 100644 --- a/src/Networking/v2/Api.php +++ b/src/Networking/v2/Api.php @@ -1,4 +1,4 @@ - 'POST', 'jsonKey' => 'network', 'params' => [ - 'name' => $this->params->name('network'), - 'shared' => $this->params->shared(), - 'adminStateUp' => $this->params->adminStateUp(), + 'name' => $this->params->name('network'), + 'shared' => $this->params->shared(), + 'adminStateUp' => $this->params->adminStateUp(), + 'routerAccessible' => $this->params->routerAccessibleJson(), + 'tenantId' => $this->params->tenantId(), ], ]; } diff --git a/src/Networking/v2/Extensions/Layer3/Api.php b/src/Networking/v2/Extensions/Layer3/Api.php new file mode 100644 index 00000000..5537c2f4 --- /dev/null +++ b/src/Networking/v2/Extensions/Layer3/Api.php @@ -0,0 +1,168 @@ +params = new Params(); + } + + public function postFloatingIps(): array + { + return [ + 'method' => 'POST', + 'path' => $this->pathPrefix . '/floatingips', + 'jsonKey' => 'floatingip', + 'params' => [ + 'tenantId' => $this->params->tenantIdJson(), + 'floatingNetworkId' => $this->params->floatingNetworkIdJson(), + 'fixedIpAddress' => $this->params->fixedIpAddressJson(), + 'floatingIpAddress' => $this->params->floatingIpAddressJson(), + 'portId' => $this->params->portIdJson(), + ], + ]; + } + + public function getFloatingIps(): array + { + return [ + 'method' => 'GET', + 'path' => $this->pathPrefix . '/floatingips', + 'params' => [], + ]; + } + + public function putFloatingIp(): array + { + return [ + 'method' => 'PUT', + 'path' => $this->pathPrefix . '/floatingips/{id}', + 'jsonKey' => 'floatingip', + 'params' => [ + 'id' => $this->params->idPath(), + 'floatingNetworkId' => $this->params->floatingNetworkIdJson(), + 'fixedIpAddress' => $this->params->fixedIpAddressJson(), + 'floatingIpAddress' => $this->params->floatingIpAddressJson(), + 'portId' => $this->params->portIdJson(), + ], + ]; + } + + public function getFloatingIp(): array + { + return [ + 'method' => 'GET', + 'path' => $this->pathPrefix . '/floatingips/{id}', + 'params' => [ + 'id' => $this->params->idPath(), + 'portId' => $this->params->portIdJson(), + ], + ]; + } + + public function deleteFloatingIp(): array + { + return [ + 'method' => 'DELETE', + 'path' => $this->pathPrefix . '/floatingips/{id}', + 'params' => [ + 'id' => $this->params->idPath(), + ], + ]; + } + + public function postRouters(): array + { + return [ + 'method' => 'POST', + 'path' => $this->pathPrefix . '/routers', + 'jsonKey' => 'router', + 'params' => [ + 'name' => $this->params->nameJson(), + 'externalGatewayInfo' => $this->params->externalGatewayInfo(), + 'adminStateUp' => $this->params->adminStateUp(), + 'tenantId' => $this->params->tenantId(), + 'distributed' => $this->params->distributedJson(), + 'ha' => $this->params->haJson(), + ], + ]; + } + + public function getRouters(): array + { + return [ + 'method' => 'GET', + 'path' => $this->pathPrefix . '/routers', + 'params' => [], + ]; + } + + public function putRouter(): array + { + return [ + 'method' => 'PUT', + 'path' => $this->pathPrefix . '/routers/{id}', + 'jsonKey' => 'router', + 'params' => [ + 'id' => $this->params->idPath(), + 'name' => $this->params->nameJson(), + 'externalGatewayInfo' => $this->params->externalGatewayInfo(), + 'adminStateUp' => $this->params->adminStateUp(), + ], + ]; + } + + public function getRouter(): array + { + return [ + 'method' => 'GET', + 'path' => $this->pathPrefix . '/routers/{id}', + 'params' => [ + 'id' => $this->params->idPath(), + ], + ]; + } + + public function deleteRouter(): array + { + return [ + 'method' => 'DELETE', + 'path' => $this->pathPrefix . '/routers/{id}', + 'params' => [ + 'id' => $this->params->idPath(), + ], + ]; + } + + public function putAddInterface() + { + return [ + 'method' => 'PUT', + 'path' => $this->pathPrefix . '/routers/{id}/add_router_interface', + 'params' => [ + 'id' => $this->params->idPath(), + 'subnetId' => $this->params->subnetId(), + 'portId' => $this->params->portIdJson(), + ], + ]; + } + + public function putRemoveInterface() + { + return [ + 'method' => 'PUT', + 'path' => $this->pathPrefix . '/routers/{id}/remove_router_interface', + 'params' => [ + 'id' => $this->params->idPath(), + 'subnetId' => $this->params->subnetId(), + 'portId' => $this->params->portIdJson(), + ], + ]; + } +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/Layer3/Models/FixedIp.php b/src/Networking/v2/Extensions/Layer3/Models/FixedIp.php new file mode 100644 index 00000000..7786df6f --- /dev/null +++ b/src/Networking/v2/Extensions/Layer3/Models/FixedIp.php @@ -0,0 +1,18 @@ + 'subnetId' + ]; +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php b/src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php new file mode 100644 index 00000000..a4f7dfd7 --- /dev/null +++ b/src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php @@ -0,0 +1,75 @@ + 'floatingNetworkId', + "router_id" => 'routerId', + "fixed_ip_address" => 'fixedIpAddress', + "floating_ip_address" => 'floatingIpAddress', + "tenant_id" => 'tenantId', + "port_id" => 'portId', + ]; + + protected $resourceKey = 'floatingip'; + protected $resourcesKey = 'floatingips'; + + public function create(array $userOptions): Creatable + { + $response = $this->execute($this->api->postFloatingIps(), $userOptions); + return $this->populateFromResponse($response); + } + + public function update() + { + $response = $this->executeWithState($this->api->putFloatingIp()); + $this->populateFromResponse($response); + } + + public function delete() + { + $this->executeWithState($this->api->deleteFloatingIp()); + } + + public function retrieve() + { + $this->executeWithState($this->api->getFloatingIp()); + } +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php b/src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php new file mode 100644 index 00000000..c72d3199 --- /dev/null +++ b/src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php @@ -0,0 +1,23 @@ + 'networkId', + 'enable_snat' => 'enableSnat', + 'fixed_ips' => 'fixedIps', + ]; +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/Layer3/Models/Router.php b/src/Networking/v2/Extensions/Layer3/Models/Router.php new file mode 100644 index 00000000..b2f23409 --- /dev/null +++ b/src/Networking/v2/Extensions/Layer3/Models/Router.php @@ -0,0 +1,83 @@ + 'externalGatewayInfo', + 'admin_state_up' => 'adminStateUp', + 'tenant_id' => 'tenantId', + ]; + + public function create(array $userOptions): Creatable + { + $response = $this->execute($this->api->postRouters(), $userOptions); + return $this->populateFromResponse($response); + } + + public function update() + { + $this->executeWithState($this->api->putRouter()); + } + + public function retrieve() + { + $this->executeWithState($this->api->getRouter()); + } + + public function delete() + { + $this->executeWithState($this->api->deleteRouter()); + } + + /** + * @param array $userOptions {@see \OpenStack\Networking\v2\Extensions\Layer3\Api::putAddInterface} + */ + public function addInterface(array $userOptions) + { + $userOptions['id'] = $this->id; + $this->execute($this->api->putAddInterface(), $userOptions); + } + + /** + * @param array $userOptions {@see \OpenStack\Networking\v2\Extensions\Layer3\Api::putRemoveInterface} + */ + public function removeInterface(array $userOptions) + { + $userOptions['id'] = $this->id; + $this->execute($this->api->putRemoveInterface(), $userOptions); + } +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/Layer3/Params.php b/src/Networking/v2/Extensions/Layer3/Params.php new file mode 100644 index 00000000..5ceef5cb --- /dev/null +++ b/src/Networking/v2/Extensions/Layer3/Params.php @@ -0,0 +1,116 @@ + self::STRING_TYPE, + 'description' => 'The UUID of the tenant. Only administrative users can specify a tenant UUID other than their own.', + 'sentAs' => 'tenant_id', + ]; + } + + public function floatingNetworkIdJson() + { + return [ + 'type' => self::STRING_TYPE, + 'description' => 'The UUID of the network associated with the floating IP.', + 'sentAs' => 'floating_network_id', + 'required' => true, + ]; + } + + public function fixedIpAddressJson() + { + return [ + 'type' => self::STRING_TYPE, + 'description' => 'The fixed IP address that is associated with the floating IP. To associate the floating IP with a fixed IP at creation time, you must specify the identifier of the internal port. If an internal port has multiple associated IP addresses, the service chooses the first IP address unless you explicitly define a fixed IP address in the fixed_ip_address parameter.', + 'sentAs' => 'fixed_ip_address', + ]; + } + + public function floatingIpAddressJson() + { + return [ + 'type' => self::STRING_TYPE, + 'description' => 'The floating IP address.', + 'sentAs' => 'fixed_ip_address', + ]; + } + + public function portIdJson() + { + return [ + 'type' => self::STRING_TYPE, + 'description' => 'The UUID of the port.', + 'sentAs' => 'port_id', + ]; + } + + public function enableSnatJson(): array + { + return [ + 'type' => self::BOOL_TYPE, + 'description' => 'Enable Source NAT (SNAT) attribute, a part of ext-gw-mode extension. When a gateway is attached to a router using an L3 extension, Network Address Translation (NAT) is enabled for traffic generated by subnets attached to the router.', + 'location' => self::JSON, + 'sentAs' => 'enable_snat', + ]; + } + + public function ipJson(): array + { + return [ + 'type' => self::STRING_TYPE, + ]; + } + + public function externalFixedIpsJson(): array + { + return [ + 'type' => self::ARRAY_TYPE, + 'location' => self::JSON, + 'sentAs' => 'external_fixed_ips', + 'items' => [ + 'type' => self::OBJECT_TYPE, + 'properties' => [ + 'subnetId' => $this->subnetId(), + 'ip' => $this->ipJson(), + ], + ], + ]; + } + + public function externalGatewayInfo(): array + { + return [ + 'type' => self::OBJECT_TYPE, + 'sentAs' => 'external_gateway_info', + 'properties' => [ + 'networkId' => $this->networkId(), + 'enableSnat' => $this->enableSnatJson(), + 'fixedIps' => $this->externalFixedIpsJson(), + ], + ]; + } + + public function distributedJson(): array + { + return [ + 'type' => self::BOOL_TYPE, + 'location' => self::JSON, + 'description' => 'If true, indicates a distributed router.', + ]; + } + + public function haJson(): array + { + return [ + 'type' => self::BOOL_TYPE, + 'location' => self::JSON, + 'description' => 'If true, indicates a highly-available router.', + ]; + } +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/Layer3/Service.php b/src/Networking/v2/Extensions/Layer3/Service.php new file mode 100644 index 00000000..8e8c9941 --- /dev/null +++ b/src/Networking/v2/Extensions/Layer3/Service.php @@ -0,0 +1,75 @@ +model(FloatingIp::class, $info); + } + + private function router(array $info = []): Router + { + return $this->model(Router::class, $info); + } + + /** + * @param array $options + * + * @return FloatingIp + */ + public function createFloatingIp(array $options): FloatingIp + { + return $this->floatingIp()->create($options); + } + + /** + * @return FloatingIp + */ + public function getFloatingIp($id): FloatingIp + { + return $this->floatingIp(['id' => $id]); + } + + /** + * @return \Generator + */ + public function listFloatingIps(): \Generator + { + return $this->floatingIp()->enumerate($this->api->getFloatingIps()); + } + + /** + * @param array $options + * + * @return Router + */ + public function createRouter(array $options): Router + { + return $this->router()->create($options); + } + + /** + * @return Router + */ + public function getRouter($id): Router + { + return $this->router(['id' => $id]); + } + + /** + * @return \Generator + */ + public function listRouters(): \Generator + { + return $this->router()->enumerate($this->api->getRouters()); + } +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/SecurityGroups/Api.php b/src/Networking/v2/Extensions/SecurityGroups/Api.php new file mode 100644 index 00000000..14112c30 --- /dev/null +++ b/src/Networking/v2/Extensions/SecurityGroups/Api.php @@ -0,0 +1,152 @@ +params = new Params(); + } + + /** + * Returns information about GET security-groups/{security_group_id} HTTP + * operation + * + * @return array + */ + public function getSecurityGroups() + { + return [ + 'method' => 'GET', + 'path' => 'security-groups', + 'params' => [], + ]; + } + + /** + * Returns information about POST security-groups HTTP operation + * + * @return array + */ + public function postSecurityGroups() + { + return [ + 'method' => 'POST', + 'path' => 'security-groups', + 'jsonKey' => 'security_group', + 'params' => [ + 'description' => $this->params->descriptionJson(), + 'name' => $this->params->nameJson(), + ], + ]; + } + + /** + * Returns information about GET security-groups/{security_group_id} HTTP + * operation + * + * @return array + */ + public function getSecurityGroup() + { + return [ + 'method' => 'GET', + 'path' => 'security-groups/{id}', + 'params' => [ + 'id' => $this->params->idPath(), + ], + ]; + } + + /** + * Returns information about DELETE security-groups/{security_group_id} HTTP + * operation + * + * @return array + */ + public function deleteSecurityGroup() + { + return [ + 'method' => 'DELETE', + 'path' => 'security-groups/{id}', + 'params' => [ + 'id' => $this->params->idPath(), + ], + ]; + } + + /** + * Returns information about GET security-group-rules HTTP operation + * + * @return array + */ + public function getSecurityRules() + { + return [ + 'method' => 'GET', + 'path' => 'security-group-rules', + 'params' => [], + ]; + } + + /** + * Returns information about POST security-group-rules HTTP operation + * + * @return array + */ + public function postSecurityRules() + { + return [ + 'method' => 'POST', + 'path' => 'security-group-rules', + 'jsonKey' => 'security_group_rule', + 'params' => [ + 'direction' => $this->params->directionJson(), + 'ethertype' => $this->params->ethertypeJson(), + 'securityGroupId' => $this->params->securityGroupIdJson(), + 'portRangeMin' => $this->params->portRangeMinJson(), + 'portRangeMax' => $this->params->portRangeMaxJson(), + 'protocol' => $this->params->protocolJson(), + 'remoteGroupId' => $this->params->remoteGroupIdJson(), + 'remoteIpPrefix' => $this->params->remoteIpPrefixJson(), + ], + ]; + } + + /** + * Returns information about DELETE + * security-group-rules/{rules-security-groups-id} HTTP operation + * + * @return array + */ + public function deleteSecurityRule() + { + return [ + 'method' => 'DELETE', + 'path' => 'security-group-rules/{id}', + 'params' => [ + 'id' => $this->params->idPath(), + ], + ]; + } + + /** + * Returns information about GET + * security-group-rules/{rules-security-groups-id} HTTP operation + * + * @return array + */ + public function getSecurityRule() + { + return [ + 'method' => 'GET', + 'path' => 'security-group-rules/{id}', + 'params' => [ + 'id' => $this->params->idPath(), + ], + ]; + } +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroup.php b/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroup.php new file mode 100644 index 00000000..724bf307 --- /dev/null +++ b/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroup.php @@ -0,0 +1,76 @@ + 'securityGroupRules', + 'tenant_id' => 'tenantId', + ]; + + protected $resourceKey = 'security_group'; + protected $resourcesKey = 'security_groups'; + + /** + * {@inheritDoc} + */ + public function create(array $userOptions): Creatable + { + $response = $this->execute($this->api->postSecurityGroups(), $userOptions); + return $this->populateFromResponse($response); + } + + /** + * {@inheritDoc} + */ + public function delete() + { + $this->executeWithState($this->api->deleteSecurityGroup()); + } + + /** + * {@inheritDoc} + */ + public function retrieve() + { + $response = $this->executeWithState($this->api->getSecurityGroup()); + $this->populateFromResponse($response); + } +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRule.php b/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRule.php new file mode 100644 index 00000000..75350dba --- /dev/null +++ b/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRule.php @@ -0,0 +1,106 @@ + 'portRangeMax', + 'port_range_min' => 'portRangeMin', + 'remote_group_id' => 'remoteGroupId', + 'remote_ip_prefix' => 'remoteIpPrefix', + 'security_group_id' => 'securityGroupId', + 'tenant_id' => 'tenantId', + ]; + + protected $resourceKey = 'security_group_rule'; + + protected $resourcesKey = 'security_group_rules'; + + /** + * {@inheritDoc} + */ + public function create(array $userOptions): Creatable + { + $response = $this->execute($this->api->postSecurityRules(), $userOptions); + return $this->populateFromResponse($response); + } + + /** + * {@inheritDoc} + */ + public function delete() + { + $this->executeWithState($this->api->deleteSecurityRule()); + } + + /** + * {@inheritDoc} + */ + public function retrieve() + { + $response = $this->executeWithState($this->api->getSecurityRule()); + $this->populateFromResponse($response); + } +} diff --git a/src/Networking/v2/Extensions/SecurityGroups/Params.php b/src/Networking/v2/Extensions/SecurityGroups/Params.php new file mode 100644 index 00000000..e4dfd3b3 --- /dev/null +++ b/src/Networking/v2/Extensions/SecurityGroups/Params.php @@ -0,0 +1,92 @@ + self::STRING_TYPE, + 'description' => "Ingress or egress: the direction in which the security group rule is applied. For a compute instance, an ingress security group rule is applied to incoming (ingress) traffic for that instance. An egress rule is applied to traffic leaving the instance.", + ]; + } + + public function ethertypeJson() + { + return [ + 'type' => self::STRING_TYPE, + 'description' => "Must be IPv4 or IPv6, and addresses represented in CIDR must match the ingress or egress rules.", + ]; + } + + public function idJson() + { + return [ + 'type' => self::STRING_TYPE, + 'description' => "The UUID of the security group rule.", + ]; + } + + public function portRangeMaxJson() + { + return [ + 'type' => self::STRING_TYPE, + 'sentAs' => 'port_range_max', + 'description' => "The maximum port number in the range that is matched by the security group rule. The port_range_min attribute constrains the port_range_max attribute. If the protocol is ICMP, this value must be an ICMP type.", + ]; + } + + public function portRangeMinJson() + { + return [ + 'sentAs' => 'port_range_min', + 'type' => self::STRING_TYPE, + 'description' => "The minimum port number in the range that is matched by the security group rule. If the protocol is TCP or UDP, this value must be less than or equal to the port_range_max attribute value. If the protocol is ICMP, this value must be an ICMP type.", + ]; + } + + public function protocolJson() + { + return [ + 'type' => self::STRING_TYPE, + 'description' => "The protocol that is matched by the security group rule. Value is null, icmp, icmpv6, tcp, or udp.", + ]; + } + + public function remoteGroupIdJson() + { + return [ + 'sentAs' => 'remote_group_id', + 'type' => self::STRING_TYPE, + 'description' => "The remote group UUID to associate with this security group rule. You can specify either the remote_group_id or remote_ip_prefix attribute in the request body.", + ]; + } + + public function remoteIpPrefixJson() + { + return [ + 'sentAs' => 'remote_ip_prefix', + 'type' => self::STRING_TYPE, + 'description' => "The remote IP prefix to associate with this security group rule. You can specify either the remote_group_id or remote_ip_prefix attribute in the request body. This attribute value matches the IP prefix as the source IP address of the IP packet.", + ]; + } + + public function securityGroupIdJson() + { + return [ + 'sentAs' => 'security_group_id', + 'type' => self::STRING_TYPE, + 'description' => "The UUID of the security group.", + ]; + } + + public function tenantIdJson() + { + return [ + 'sentAs' => 'tenant_id', + 'type' => self::STRING_TYPE, + 'description' => "The UUID of the tenant who owns the security group rule. Only administrative users can specify a tenant UUID other than their own.", + ]; + } +} \ No newline at end of file diff --git a/src/Networking/v2/Extensions/SecurityGroups/Service.php b/src/Networking/v2/Extensions/SecurityGroups/Service.php new file mode 100644 index 00000000..9e3fb9b0 --- /dev/null +++ b/src/Networking/v2/Extensions/SecurityGroups/Service.php @@ -0,0 +1,79 @@ +model(SecurityGroup::class, $info); + } + + private function securityGroupRule(array $info = []): SecurityGroupRule + { + return $this->model(SecurityGroupRule::class, $info); + } + + /** + * @return \Generator + */ + public function listSecurityGroups(): \Generator + { + return $this->securityGroup()->enumerate($this->api->getSecurityGroups()); + } + + /** + * @param array $options + * + * @return SecurityGroup + */ + public function createSecurityGroup(array $options): SecurityGroup + { + return $this->securityGroup()->create($options); + } + + /** + * @param string $id + * + * @return SecurityGroup + */ + public function getSecurityGroup(string $id): SecurityGroup + { + return $this->securityGroup(['id' => $id]); + } + + /** + * @return \Generator + */ + public function listSecurityGroupRules(): \Generator + { + return $this->securityGroupRule()->enumerate($this->api->getSecurityRules()); + } + + /** + * @param array $options + * + * @return SecurityGroupRule + */ + public function createSecurityGroupRule(array $options): SecurityGroupRule + { + return $this->securityGroupRule()->create($options); + } + + /** + * @param string $id + * + * @return SecurityGroupRule + */ + public function getSecurityGroupRule(string $id): SecurityGroupRule + { + return $this->securityGroupRule(['id' => $id]); + } +} \ No newline at end of file diff --git a/src/Networking/v2/Models/Network.php b/src/Networking/v2/Models/Network.php index 78b22efa..89c0b9a4 100644 --- a/src/Networking/v2/Models/Network.php +++ b/src/Networking/v2/Models/Network.php @@ -1,8 +1,9 @@ - 'adminStateUp', + 'tenant_id' => 'tenantId', ]; protected $resourceKey = 'network'; diff --git a/src/Networking/v2/Models/Port.php b/src/Networking/v2/Models/Port.php index 8e9fc4f5..303fed81 100644 --- a/src/Networking/v2/Models/Port.php +++ b/src/Networking/v2/Models/Port.php @@ -1,18 +1,22 @@ - 'adminStateUp', + 'display_name' => 'displayName', + 'network_id' => 'networkId', + 'tenant_id' => 'tenantId', + 'device_owner' => 'deviceOwner', + 'mac_address' => 'macAddress', + 'port_id' => 'portId', + 'security_groups' => 'securityGroups', + 'device_id' => 'deviceId', + 'fixed_ips' => 'fixedIps', + ]; + protected $resourceKey = 'port'; /** @@ -129,6 +146,11 @@ public function bulkCreate(array $userOptions): array return $this->extractMultipleInstances($response); } + public function retrieve() + { + $this->executeWithState($this->api->getPort()); + } + public function update() { $this->executeWithState($this->api->putPort()); diff --git a/src/Networking/v2/Models/Subnet.php b/src/Networking/v2/Models/Subnet.php index 2bfe5654..6380ee08 100644 --- a/src/Networking/v2/Models/Subnet.php +++ b/src/Networking/v2/Models/Subnet.php @@ -2,7 +2,7 @@ namespace OpenStack\Networking\v2\Models; -use OpenCloud\Common\Resource\AbstractResource; +use OpenCloud\Common\Resource\OperatorResource; use OpenCloud\Common\Resource\Listable; use OpenCloud\Common\Resource\Creatable; use OpenCloud\Common\Resource\Deletable; @@ -13,7 +13,7 @@ * * @property \OpenStack\Networking\v2\Api $api */ -class Subnet extends AbstractResource implements Listable, Retrievable, Creatable, Deletable +class Subnet extends OperatorResource implements Listable, Retrievable, Creatable, Deletable { /** @var string */ public $id; diff --git a/src/Networking/v2/Params.php b/src/Networking/v2/Params.php index c3972c0f..31eec5be 100644 --- a/src/Networking/v2/Params.php +++ b/src/Networking/v2/Params.php @@ -1,4 +1,4 @@ - self::STRING_TYPE, + 'location' => self::JSON, + ]; + } + + /** + * Returns information about name parameter + * + * @return array + */ + public function nameJson(): array + { + return [ + 'type' => self::STRING_TYPE, + 'location' => self::JSON, + ]; + } + public function urlId($type): array { return array_merge(parent::id($type), [ @@ -366,4 +392,14 @@ private function queryFilter($field): array Filters are applicable to all list requests.', ]; } + + public function routerAccessibleJson(): array + { + return [ + 'type' => self::BOOL_TYPE, + 'location' => self::JSON, + 'sentAs' => 'router:external', + 'description' => 'Indicates whether this network is externally accessible.', + ]; + } } diff --git a/tests/integration/Networking/v2/CoreTest.php b/tests/integration/Networking/v2/CoreTest.php new file mode 100644 index 00000000..f3eb3244 --- /dev/null +++ b/tests/integration/Networking/v2/CoreTest.php @@ -0,0 +1,320 @@ +startTimer(); + + $this->networks(); + $this->subnets(); + $this->ports(); + + $this->outputTimeTaken(); + } + + public function subnets() + { + $this->createSubnetsAndDelete(); + $this->createSubnetWithHostRoutes(); + + list($subnetId, $networkId) = $this->createSubnet(); + + $this->updateSubnet($subnetId); + $this->retrieveSubnet($subnetId); + $this->deleteSubnet($subnetId); + $this->deleteNetwork($networkId); + } + + public function networks() + { + $this->createNetworksAndDelete(); + + $networkId = $this->createNetwork(); + $this->updateNetwork($networkId); + $this->retrieveNetwork($networkId); + $this->deleteNetwork($networkId); + } + + private function createNetworksAndDelete() + { + $replacements = [ + '{networkName1}' => $this->randomStr(), + '{networkName2}' => $this->randomStr() + ]; + + /** @var $networks array */ + $path = $this->sampleFile($replacements, 'networks/create_batch.php'); + require_once $path; + + foreach ($networks as $network) { + $this->assertInstanceOf(Network::class, $network); + $this->assertNotEmpty($network->id); + + $this->networkId = $network->id; + $this->logStep('Created network {id}', ['{id}' => $this->networkId]); + + $this->deleteNetwork($network->id); + } + } + + private function createNetwork() + { + $replacements = [ + '{networkName}' => $this->randomStr(), + ]; + + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile($replacements, 'networks/create.php'); + require_once $path; + + $this->assertInstanceOf(Network::class, $network); + $this->assertNotEmpty($network->id); + + $this->logStep('Created network {id}', ['{id}' => $this->networkId]); + + return $network->id; + } + + private function updateNetwork($networkId) + { + $name = $this->randomStr(); + + $replacements = [ + '{networkId}' => $networkId, + '{newName}' => $name, + ]; + + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile($replacements, 'networks/update.php'); + require_once $path; + + $this->assertInstanceOf(Network::class, $network); + $this->assertEquals($name, $network->name); + + $this->logStep('Updated network ID to use this name: NAME', ['ID' => $networkId, 'NAME' => $name]); + } + + private function retrieveNetwork($networkId) + { + $replacements = ['{networkId}' => $networkId]; + + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile($replacements, 'networks/get.php'); + require_once $path; + + $this->assertInstanceOf(Network::class, $network); + + $this->logStep('Retrieved the details of network ID', ['ID' => $networkId]); + } + + private function deleteNetwork($networkId) + { + $replacements = ['{networkId}' => $networkId]; + + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile($replacements, 'networks/delete.php'); + require_once $path; + + $this->logStep('Deleted network ID', ['ID' => $networkId]); + } + + private function createSubnetsAndDelete() + { + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile(['{newName}' => $this->randomStr()], 'networks/create.php'); + require_once $path; + + $replacements = [ + '{subnetName1}' => $this->randomStr(), + '{subnetName2}' => $this->randomStr(), + '{networkId1}' => $network->id, + '{networkId2}' => $network->id, + ]; + + /** @var $subnets array */ + $path = $this->sampleFile($replacements, 'subnets/create_batch.php'); + require_once $path; + + foreach ($subnets as $subnet) { + $this->assertInstanceOf(Subnet::class, $subnet); + $this->assertNotEmpty($subnet->id); + + $this->logStep('Created subnet {id}', ['{id}' => $subnet->id]); + + $this->deleteSubnet($subnet->id); + } + + $path = $this->sampleFile(['{networkId}' => $network->id], 'networks/delete.php'); + require_once $path; + } + + private function createSubnet() + { + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile(['{newName}' => $this->randomStr()], 'networks/create.php'); + require_once $path; + + $replacements = [ + '{subnetName}' => $this->randomStr(), + '{networkId}' => $network->id, + ]; + + /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ + $path = $this->sampleFile($replacements, 'subnets/create.php'); + require_once $path; + + $this->assertInstanceOf(Subnet::class, $subnet); + $this->assertNotEmpty($subnet->id); + + $this->logStep('Created subnet {id}', ['{id}' => $subnet->id]); + + return [$subnet->id, $network->id]; + } + + private function createSubnetWithGatewayIp() + { + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile(['{newName}' => $this->randomStr()], 'networks/create.php'); + require_once $path; + + $replacements = [ + '{networkId}' => $network->id, + ]; + + /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ + $path = $this->sampleFile($replacements, 'subnets/create_with_gateway_ip.php'); + require_once $path; + + $this->assertInstanceOf(Subnet::class, $subnet); + $this->assertNotEmpty($subnet->id); + + $this->subnetId = $subnet->id; + + $this->logStep('Created subnet {id} with gateway ip', ['{id}' => $this->subnetId]); + + $path = $this->sampleFile($replacements, 'networks/delete.php'); + require_once $path; + } + + private function createSubnetWithHostRoutes() + { + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile(['{newName}' => $this->randomStr()], 'networks/create.php'); + require_once $path; + + $replacements = [ + '{networkId}' => $network->id, + ]; + + /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ + $path = $this->sampleFile($replacements, 'subnets/create_with_host_routes.php'); + require_once $path; + + $this->assertInstanceOf(Subnet::class, $subnet); + $this->assertNotEmpty($subnet->id); + + $this->logStep('Created subnet {id} with host routes', ['{id}' => $subnet->id]); + + $path = $this->sampleFile($replacements, 'networks/delete.php'); + require_once $path; + } + + private function updateSubnet($subnetId) + { + $name = $this->randomStr(); + + $replacements = [ + '{subnetId}' => $subnetId, + '{newName}' => $name, + ]; + + /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ + $path = $this->sampleFile($replacements, 'subnets/update.php'); + require_once $path; + + $this->assertInstanceOf(Subnet::class, $subnet); + $this->assertEquals($name, $subnet->name); + + $this->logStep('Updated subnet ID to use this name: NAME', ['ID' => $subnetId, 'NAME' => $name]); + } + + + private function retrieveSubnet($subnetId) + { + $replacements = ['{subnetId}' => $subnetId]; + + /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ + $path = $this->sampleFile($replacements, 'subnets/get.php'); + require_once $path; + + $this->assertInstanceOf(Subnet::class, $subnet); + + $this->logStep('Retrieved the details of subnet ID', ['ID' => $subnetId]); + } + + private function deleteSubnet($subnetId) + { + $replacements = ['{subnetId}' => $subnetId]; + + /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ + $path = $this->sampleFile($replacements, 'subnets/delete.php'); + require_once $path; + + $this->logStep('Deleted subnet ID', ['ID' => $subnetId]); + } + + public function ports() + { + $replacements = ['{newName}' => $this->randomStr()]; + + /** @var $network \OpenStack\Networking\v2\Models\Network */ + $path = $this->sampleFile($replacements, 'networks/create.php'); + require_once $path; + + $replacements = ['{networkId}' => $network->id]; + + /** @var $port \OpenStack\Networking\v2\Models\Port */ + $path = $this->sampleFile($replacements, 'ports/create.php'); + require_once $path; + $this->assertInstanceOf(Port::class, $port); + + $replacements['{portId}'] = $port->id; + $port->networkId = $network->id; + + /** @var $ports array */ + $path = $this->sampleFile($replacements, 'ports/create_batch.php'); + require_once $path; + foreach ($ports as $port) { + $this->assertInstanceOf(Port::class, $port); + $port->delete(); + } + + /** @var $port \OpenStack\Networking\v2\Models\Port */ + $path = $this->sampleFile($replacements, 'ports/list.php'); + require_once $path; + + /** @var $port \OpenStack\Networking\v2\Models\Port */ + $path = $this->sampleFile($replacements, 'ports/get.php'); + require_once $path; + $this->assertInstanceOf(Port::class, $port); + + /** @var $port \OpenStack\Networking\v2\Models\Port */ + $path = $this->sampleFile($replacements, 'ports/update.php'); + require_once $path; + $this->assertInstanceOf(Port::class, $port); + + $path = $this->sampleFile($replacements, 'ports/delete.php'); + require_once $path; + + $path = $this->sampleFile($replacements, 'networks/delete.php'); + require_once $path; + } +} diff --git a/tests/integration/Networking/v2/Layer3Test.php b/tests/integration/Networking/v2/Layer3Test.php new file mode 100644 index 00000000..1d58bd75 --- /dev/null +++ b/tests/integration/Networking/v2/Layer3Test.php @@ -0,0 +1,109 @@ +getBaseClient()->networkingV2ExtLayer3(); + } + + private function getV2Service(): \OpenStack\Networking\v2\Service + { + return $this->getBaseClient()->networkingV2(); + } + + public function runTests() + { + $this->startTimer(); + $this->floatingIps(); + $this->outputTimeTaken(); + } + + public function teardown() + { + parent::teardown(); + + $this->deleteItems($this->getV2Service()->listPorts()); + $this->deleteItems($this->getV2Service()->listNetworks()); + $this->deleteItems($this->getService()->listFloatingIps()); + } + + private function createNetwork(): Network + { + $network = $this->getV2Service()->createNetwork(['name' => $this->randomStr(), 'routerAccessible' => true]); + $network->waitUntilActive(); + return $network; + } + + private function createSubnet(Network $network): Subnet + { + return $this->getV2Service()->createSubnet([ + 'networkId' => $network->id, + 'name' => $this->randomStr(), + 'ipVersion' => 4, + 'cidr' => '192.168.199.0/24', + ]); + } + + private function createPort(Network $network): Port + { + return $this->getV2Service()->createPort(['networkId' => $network->id, 'name' => $this->randomStr()]); + } + + public function floatingIps() + { + $this->logStep('Creating network'); + $network = $this->createNetwork(); + + $this->logStep('Creating subnet for network %id%', ['%id%' => $network->id]); + $this->createSubnet($network); + + $this->logStep('Creating port for network %id%', ['%id%' => $network->id]); + $port1 = $this->createPort($network); + + $replacements = [ + '{networkId}' => $network->id, + '{portId}' => $port1->id, + ]; + + $this->logStep('Create floating IP'); + /** @var FloatingIp $ip */ + $path = $this->sampleFile($replacements, 'floatingIPs/create.php'); + require_once $path; + $this->assertInstanceOf(FloatingIp::class, $ip); + $this->assertEquals($network->id, $ip->floatingNetworkId); + $this->assertEquals($port1->id, $ip->portId); + + $this->logStep('List floating IPs'); + $path = $this->sampleFile($replacements, 'floatingIPs/list.php'); + require_once $path; + + $this->logStep('Get floating IP'); + $replacements['{id}'] = $ip->id; + $path = $this->sampleFile($replacements, 'floatingIPs/get.php'); + require_once $path; + $this->assertInstanceOf(FloatingIp::class, $ip); + + $this->logStep('Update floating IP'); + $port2 = $this->createPort($network); + $replacements['{newPortId}'] = $port2->id; + $path = $this->sampleFile($replacements, 'floatingIPs/update.php'); + require_once $path; + + $this->logStep('Delete floating IP'); + $path = $this->sampleFile($replacements, 'floatingIPs/update.php'); + require_once $path; + + $port1->delete(); + $port2->delete(); + $network->delete(); + } +} \ No newline at end of file diff --git a/tests/integration/Networking/v2/SecGroupTest.php b/tests/integration/Networking/v2/SecGroupTest.php new file mode 100644 index 00000000..f2e72232 --- /dev/null +++ b/tests/integration/Networking/v2/SecGroupTest.php @@ -0,0 +1,11 @@ +rootFixturesDir = dirname(__DIR__); + + $this->floatingIp = new FloatingIp($this->client->reveal(), new Api()); + $this->floatingIp->id = 'id'; + } + + public function test_it_updates() + { + $expectedJson = ['floatingip' => [ + "floating_network_id" => "376da547-b977-4cfe-9cba-275c80debf57", + "port_id" => "ce705c24-c1ef-408a-bda3-7bbd946164ab", + ]]; + + $this->setupMock('PUT', 'v2.0/floatingips/id', $expectedJson, [], new Response(202)); + + $this->floatingIp->floatingNetworkId = "376da547-b977-4cfe-9cba-275c80debf57"; + $this->floatingIp->portId = "ce705c24-c1ef-408a-bda3-7bbd946164ab"; + $this->floatingIp->update(); + } + + public function test_it_deletes() + { + $this->setupMock('DELETE', 'v2.0/floatingips/id', null, [], new Response(202)); + + $this->floatingIp->delete(); + } + + public function test_it_retrieves() + { + $this->setupMock('GET', 'v2.0/floatingips/id', null, [], 'FloatingIp'); + + $this->floatingIp->retrieve(); + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/Layer3/Models/RouterTest.php b/tests/unit/Networking/v2/Extensions/Layer3/Models/RouterTest.php new file mode 100644 index 00000000..ca733b12 --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/Layer3/Models/RouterTest.php @@ -0,0 +1,91 @@ +rootFixturesDir = dirname(__DIR__); + + $this->router = new Router($this->client->reveal(), new Api()); + $this->router->id = 'id'; + } + + public function test_it_deletes() + { + $this->setupMock('DELETE', 'v2.0/routers/id', null, [], new Response(202)); + + $this->router->delete(); + } + + public function test_it_updates() + { + $expectedJson = ['router' => [ + 'name' => 'new', + 'external_gateway_info' => [ + "network_id" => "8ca37218-28ff-41cb-9b10-039601ea7e6b", + "enable_snat" => true, + "external_fixed_ips" => [ + [ + "subnet_id" => "255.255.255.0", + "ip" => "192.168.10.1", + ], + ], + ], + ]]; + + $this->setupMock('PUT', 'v2.0/routers/id', $expectedJson, [], new Response(201)); + + $gatewayInfo = new GatewayInfo(); + $gatewayInfo->networkId = '8ca37218-28ff-41cb-9b10-039601ea7e6b'; + $gatewayInfo->enableSnat = true; + + $fixedIp = new FixedIp(); + $fixedIp->subnetId = '255.255.255.0'; + $fixedIp->ip = '192.168.10.1'; + $gatewayInfo->fixedIps = [$fixedIp]; + + $this->router->externalGatewayInfo = $gatewayInfo; + $this->router->name = 'new'; + + $this->router->update(); + } + + public function test_it_retrieves() + { + $this->setupMock('GET', 'v2.0/routers/id', null, [], 'Router'); + + $this->router->retrieve(); + } + + public function test_it_adds_interface() + { + $expectedJson = ['subnet_id' => 'a2f1f29d-571b-4533-907f-5803ab96ead1']; + + $this->setupMock('PUT', 'v2.0/routers/id/add_router_interface', $expectedJson, [], new Response(201)); + + $this->router->addInterface(['subnetId' => 'a2f1f29d-571b-4533-907f-5803ab96ead1']); + } + + public function test_it_remove_interface() + { + $expectedJson = ['subnet_id' => 'a2f1f29d-571b-4533-907f-5803ab96ead1']; + + $this->setupMock('PUT', 'v2.0/routers/id/remove_router_interface', $expectedJson, [], new Response(201)); + + $this->router->removeInterface(['subnetId' => 'a2f1f29d-571b-4533-907f-5803ab96ead1']); + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php b/tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php new file mode 100644 index 00000000..93aa750f --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php @@ -0,0 +1,127 @@ +rootFixturesDir = __DIR__; + + $this->service = new Service($this->client->reveal(), new Api()); + } + + public function test_it_lists_floating_ips() + { + $this->client + ->request('GET', 'v2.0/floatingips', ['headers' => []]) + ->shouldBeCalled() + ->willReturn($this->getFixture('FloatingIps')); + + foreach ($this->service->listFloatingIps() as $ip) { + /** @var $ip FloatingIp */ + $this->assertInstanceOf(FloatingIp::class, $ip); + + $this->assertNotNull($ip->tenantId); + $this->assertNotNull($ip->floatingNetworkId); + $this->assertNotNull($ip->floatingIpAddress); + $this->assertNotNull($ip->id); + $this->assertNotNull($ip->status); + } + } + + public function test_it_gets_floating_ip() + { + $this->assertInstanceOf(FloatingIp::class, $this->service->getFloatingIp('id')); + } + + public function test_it_creates_floatingIp() + { + $expectedJson = ["floatingip" => [ + "floating_network_id" => "376da547-b977-4cfe-9cba-275c80debf57", + "port_id" => "ce705c24-c1ef-408a-bda3-7bbd946164ab", + ]]; + + $this->setupMock('POST', 'v2.0/floatingips', $expectedJson, [], new Response(201)); + + $ip = $this->service->createFloatingIp([ + "floatingNetworkId" => "376da547-b977-4cfe-9cba-275c80debf57", + "portId" => "ce705c24-c1ef-408a-bda3-7bbd946164ab", + ]); + + $this->assertInstanceOf(FloatingIp::class, $ip); + } + + public function test_it_lists_routers() + { + $this->client + ->request('GET', 'v2.0/routers', ['headers' => []]) + ->shouldBeCalled() + ->willReturn($this->getFixture('Routers')); + + foreach ($this->service->listRouters() as $r) { + /** @var $r Router */ + $this->assertInstanceOf(Router::class, $r); + + $this->assertNotNull($r->status); + $this->assertNotNull($r->name); + $this->assertNotNull($r->adminStateUp); + $this->assertNotNull($r->tenantId); + $this->assertNotNull($r->id); + } + } + + public function test_it_gets_router() + { + $this->assertInstanceOf(Router::class, $this->service->getRouter('id')); + } + + public function test_it_creates_router() + { + $expectedJson = ["router" => [ + "name" => "test_router", + "external_gateway_info" => [ + "network_id" => "8ca37218-28ff-41cb-9b10-039601ea7e6b", + "enable_snat" => true, + "external_fixed_ips" => [ + [ + "subnet_id" => "255.255.255.0", + "ip" => "192.168.10.1", + ], + ], + ], + "admin_state_up" => true, + ]]; + + $this->setupMock('POST', 'v2.0/routers', $expectedJson, [], new Response(201)); + + $r = $this->service->createRouter([ + 'name' => 'test_router', + 'adminStateUp' => true, + 'externalGatewayInfo' => [ + 'networkId' => '8ca37218-28ff-41cb-9b10-039601ea7e6b', + 'enableSnat' => true, + 'fixedIps' => [ + [ + 'subnetId' => '255.255.255.0', + 'ip' => '192.168.10.1', + ], + ], + ], + ]); + + $this->assertInstanceOf(Router::class, $r); + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRuleTest.php b/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRuleTest.php new file mode 100644 index 00000000..24b0688a --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRuleTest.php @@ -0,0 +1,38 @@ +rootFixturesDir = dirname(__DIR__); + + $this->securityGroupRule = new SecurityGroupRule($this->client->reveal(), new Api()); + $this->securityGroupRule->id = 'id'; + } + + public function test_it_deletes() + { + $this->setupMock('DELETE', 'security-group-rules/id', null, [], new Response(202)); + + $this->securityGroupRule->delete(); + } + + public function test_it_retrieves() + { + $this->setupMock('GET', 'security-group-rules/id', null, [], 'SecurityGroupRule'); + + $this->securityGroupRule->retrieve(); + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupTest.php b/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupTest.php new file mode 100644 index 00000000..86527e47 --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupTest.php @@ -0,0 +1,38 @@ +rootFixturesDir = dirname(__DIR__); + + $this->securityGroup = new SecurityGroup($this->client->reveal(), new Api()); + $this->securityGroup->id = 'id'; + } + + public function test_it_deletes() + { + $this->setupMock('DELETE', 'security-groups/id', null, [], new Response(202)); + + $this->securityGroup->delete(); + } + + public function test_it_retrieves() + { + $this->setupMock('GET', 'security-groups/id', null, [], 'SecurityGroup'); + + $this->securityGroup->retrieve(); + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/ServiceTest.php b/tests/unit/Networking/v2/Extensions/SecurityGroups/ServiceTest.php new file mode 100644 index 00000000..451b689e --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/ServiceTest.php @@ -0,0 +1,115 @@ +rootFixturesDir = __DIR__; + + $this->service = new Service($this->client->reveal(), new Api()); + } + + public function test_it_lists_secgroups() + { + $this->client + ->request('GET', 'security-groups', ['headers' => []]) + ->shouldBeCalled() + ->willReturn($this->getFixture('SecurityGroups')); + + foreach ($this->service->listSecurityGroups() as $sg) { + /** @var $sg SecurityGroup */ + $this->assertInstanceOf(SecurityGroup::class, $sg); + + $this->assertEquals('default', $sg->name); + $this->assertEquals('default', $sg->description); + $this->assertEquals('85cc3048-abc3-43cc-89b3-377341426ac5', $sg->id); + $this->assertCount(2, $sg->securityGroupRules); + } + } + + public function test_it_creates_secgroup() + { + $options = [ + 'name' => 'new-webservers', + 'description' => 'security group for webservers', + ]; + + $expectedJson = ['security_group' => $options]; + + $this->setupMock('POST', 'security-groups', $expectedJson, [], new Response(201)); + + $n = $this->service->createSecurityGroup($options); + $this->assertInstanceOf(SecurityGroup::class, $n); + } + + public function test_it_gets_secgroup() + { + $this->assertInstanceOf(SecurityGroup::class, $this->service->getSecurityGroup('id')); + } + + public function test_it_lists_secgrouprules() + { + $this->client + ->request('GET', 'security-group-rules', ['headers' => []]) + ->shouldBeCalled() + ->willReturn($this->getFixture('SecurityGroupRules')); + + foreach ($this->service->listSecurityGroupRules() as $sgr) { + /** @var $sgr SecurityGroupRule */ + $this->assertInstanceOf(SecurityGroupRule::class, $sgr); + + $this->assertNotNull($sgr->direction); + $this->assertNotNull($sgr->ethertype); + $this->assertNotNull($sgr->id); + $this->assertNotNull($sgr->securityGroupId); + $this->assertNotNull($sgr->tenantId); + } + } + + public function test_it_creates_secgrouprule() + { + $options = [ + "direction" => "ingress", + "portRangeMin" => "80", + "ethertype" => "IPv4", + "portRangeMax" => "80", + "protocol" => "tcp", + "remoteGroupId" => "85cc3048-abc3-43cc-89b3-377341426ac5", + "securityGroupId" => "a7734e61-b545-452d-a3cd-0189cbd9747a", + ]; + + $expectedJson = ['security_group_rule' => [ + "direction" => "ingress", + "port_range_min" => "80", + "ethertype" => "IPv4", + "port_range_max" => "80", + "protocol" => "tcp", + "remote_group_id" => "85cc3048-abc3-43cc-89b3-377341426ac5", + "security_group_id" => "a7734e61-b545-452d-a3cd-0189cbd9747a", + ]]; + + $this->setupMock('POST', 'security-group-rules', $expectedJson, [], new Response(201)); + + $n = $this->service->createSecurityGroupRule($options); + $this->assertInstanceOf(SecurityGroupRule::class, $n); + } + + public function test_it_gets_secgrouprule() + { + $this->assertInstanceOf(SecurityGroupRule::class, $this->service->getSecurityGroupRule('id')); + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Models/PortTest.php b/tests/unit/Networking/v2/Models/PortTest.php index 4082c830..65939991 100644 --- a/tests/unit/Networking/v2/Models/PortTest.php +++ b/tests/unit/Networking/v2/Models/PortTest.php @@ -47,6 +47,13 @@ public function test_it_updates() $this->port->update(); } + public function test_it_retrieves() + { + $this->setupMock('GET', 'v2.0/ports/' . self::PORT_ID, null, [], new Response(204)); + + $this->port->retrieve(); + } + public function test_it_deletes() { $this->setupMock('DELETE', 'v2.0/ports/' . self::PORT_ID, null, [], new Response(204)); From fd7d2a62557f6ee7ec604d8f915fd13b06ba13b4 Mon Sep 17 00:00:00 2001 From: Jamie Hannaford Date: Sun, 1 May 2016 18:00:00 +0200 Subject: [PATCH 3/4] Refactor --- src/BlockStorage/v2/Models/Snapshot.php | 4 +- src/BlockStorage/v2/Models/Volume.php | 4 +- src/BlockStorage/v2/Models/VolumeType.php | 4 +- src/Compute/v2/Models/Flavor.php | 4 +- src/Compute/v2/Models/Image.php | 4 +- src/Compute/v2/Models/Server.php | 4 +- src/Identity/v2/Models/Catalog.php | 4 +- src/Identity/v2/Models/Endpoint.php | 4 +- src/Identity/v2/Models/Entry.php | 4 +- src/Identity/v2/Models/Tenant.php | 4 +- src/Identity/v2/Models/Token.php | 4 +- src/Identity/v3/Models/Assignment.php | 4 +- src/Identity/v3/Models/Catalog.php | 4 +- src/Identity/v3/Models/Credential.php | 4 +- src/Identity/v3/Models/Domain.php | 4 +- src/Identity/v3/Models/Endpoint.php | 4 +- src/Identity/v3/Models/Group.php | 4 +- src/Identity/v3/Models/Policy.php | 4 +- src/Identity/v3/Models/Project.php | 4 +- src/Identity/v3/Models/Role.php | 4 +- src/Identity/v3/Models/Service.php | 4 +- src/Identity/v3/Models/Token.php | 4 +- src/Identity/v3/Models/User.php | 4 +- src/Images/v2/Models/Image.php | 4 +- src/Images/v2/Models/Member.php | 4 +- src/ObjectStore/v1/Models/Account.php | 4 +- src/ObjectStore/v1/Models/Container.php | 4 +- src/ObjectStore/v1/Models/Object.php | 4 +- src/OpenStack.php | 40 ++- .../{V2Test.php => v2/CoreTest.php} | 9 +- .../Compute/{V2Test.php => v2/CoreTest.php} | 9 +- tests/integration/Identity/V2Test.php | 16 - tests/integration/Identity/v2/CoreTest.php | 12 + .../Identity/{V3Test.php => v3/CoreTest.php} | 10 +- .../Images/{V2Test.php => v2/CoreTest.php} | 24 +- tests/integration/Networking/V2Test.php | 338 ------------------ .../{V1Test.php => v1/CoreTest.php} | 9 +- tests/integration/SampleManager.php | 5 + tests/integration/run.php | 4 +- .../Layer3/Fixtures/FloatingIp.resp | 15 + .../Layer3/Fixtures/FloatingIps.resp | 27 ++ .../v2/Extensions/Layer3/Fixtures/Router.resp | 23 ++ .../Extensions/Layer3/Fixtures/Routers.resp | 34 ++ .../Fixtures/SecurityGroup.resp | 37 ++ .../Fixtures/SecurityGroupRule.resp | 17 + .../Fixtures/SecurityGroupRules.resp | 31 ++ .../Fixtures/SecurityGroups.resp | 39 ++ tests/unit/OpenStackTest.php | 14 +- 48 files changed, 348 insertions(+), 477 deletions(-) rename tests/integration/BlockStorage/{V2Test.php => v2/CoreTest.php} (97%) rename tests/integration/Compute/{V2Test.php => v2/CoreTest.php} (98%) delete mode 100644 tests/integration/Identity/V2Test.php create mode 100644 tests/integration/Identity/v2/CoreTest.php rename tests/integration/Identity/{V3Test.php => v3/CoreTest.php} (98%) rename tests/integration/Images/{V2Test.php => v2/CoreTest.php} (86%) delete mode 100644 tests/integration/Networking/V2Test.php rename tests/integration/ObjectStore/{V1Test.php => v1/CoreTest.php} (97%) create mode 100644 tests/unit/Networking/v2/Extensions/Layer3/Fixtures/FloatingIp.resp create mode 100644 tests/unit/Networking/v2/Extensions/Layer3/Fixtures/FloatingIps.resp create mode 100644 tests/unit/Networking/v2/Extensions/Layer3/Fixtures/Router.resp create mode 100644 tests/unit/Networking/v2/Extensions/Layer3/Fixtures/Routers.resp create mode 100644 tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroup.resp create mode 100644 tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroupRule.resp create mode 100644 tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroupRules.resp create mode 100644 tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroups.resp diff --git a/src/BlockStorage/v2/Models/Snapshot.php b/src/BlockStorage/v2/Models/Snapshot.php index 072d8415..aead6c9c 100644 --- a/src/BlockStorage/v2/Models/Snapshot.php +++ b/src/BlockStorage/v2/Models/Snapshot.php @@ -2,7 +2,7 @@ namespace OpenStack\BlockStorage\v2\Models; -use OpenCloud\Common\Resource\AbstractResource; +use OpenCloud\Common\Resource\OperatorResource; use OpenCloud\Common\Resource\Creatable; use OpenCloud\Common\Resource\Deletable; use OpenCloud\Common\Resource\HasMetadata; @@ -16,7 +16,7 @@ /** * @property \OpenStack\BlockStorage\v2\Api $api */ -class Snapshot extends AbstractResource implements Listable, Creatable, Updateable, Deletable, Retrievable, HasMetadata +class Snapshot extends OperatorResource implements Listable, Creatable, Updateable, Deletable, Retrievable, HasMetadata { use HasWaiterTrait; diff --git a/src/BlockStorage/v2/Models/Volume.php b/src/BlockStorage/v2/Models/Volume.php index 50be8759..4cdd60f2 100644 --- a/src/BlockStorage/v2/Models/Volume.php +++ b/src/BlockStorage/v2/Models/Volume.php @@ -1,7 +1,7 @@ 'nova', 'catalogType' => 'compute']; - return $this->builder->createService('Compute', 2, array_merge($defaults, $options)); + return $this->builder->createService('Compute\\v2', array_merge($defaults, $options)); } /** @@ -80,7 +80,33 @@ public function computeV2(array $options = []): \OpenStack\Compute\v2\Service public function networkingV2(array $options = []): \OpenStack\Networking\v2\Service { $defaults = ['catalogName' => 'neutron', 'catalogType' => 'network']; - return $this->builder->createService('Networking', 2, array_merge($defaults, $options)); + return $this->builder->createService('Networking\\v2', array_merge($defaults, $options)); + } + + /** + * Creates a new Networking v2 Layer 3 service. + * + * @param array $options Options that will be used in configuring the service. + * + * @return \OpenStack\Networking\v2\Extensions\Layer3\Service + */ + public function networkingV2ExtLayer3(array $options = []): \OpenStack\Networking\v2\Extensions\Layer3\Service + { + $defaults = ['catalogName' => 'neutron', 'catalogType' => 'network']; + return $this->builder->createService('Networking\\v2\\Extensions\\Layer3', array_merge($defaults, $options)); + } + + /** + * Creates a new Networking v2 Layer 3 service. + * + * @param array $options Options that will be used in configuring the service. + * + * @return \OpenStack\Networking\v2\Extensions\SecurityGroups\Service + */ + public function networkingV2ExtSecGroups(array $options = []): \OpenStack\Networking\v2\Extensions\SecurityGroups\Service + { + $defaults = ['catalogName' => 'neutron', 'catalogType' => 'network']; + return $this->builder->createService('Networking\\v2\\Extensions\\SecurityGroups', array_merge($defaults, $options)); } /** @@ -93,7 +119,7 @@ public function networkingV2(array $options = []): \OpenStack\Networking\v2\Serv public function identityV2(array $options = []): \OpenStack\Identity\v2\Service { $defaults = ['catalogName' => false, 'catalogType' => false]; - return $this->builder->createService('Identity', 2, array_merge($defaults, $options)); + return $this->builder->createService('Identity\\v2', array_merge($defaults, $options)); } /** @@ -106,7 +132,7 @@ public function identityV2(array $options = []): \OpenStack\Identity\v2\Service public function identityV3(array $options = []): \OpenStack\Identity\v3\Service { $defaults = ['catalogName' => false, 'catalogType' => false]; - return $this->builder->createService('Identity', 3, array_merge($defaults, $options)); + return $this->builder->createService('Identity\\v3', array_merge($defaults, $options)); } /** @@ -119,7 +145,7 @@ public function identityV3(array $options = []): \OpenStack\Identity\v3\Service public function objectStoreV1(array $options = []): \OpenStack\ObjectStore\v1\Service { $defaults = ['catalogName' => 'swift', 'catalogType' => 'object-store']; - return $this->builder->createService('ObjectStore', 1, array_merge($defaults, $options)); + return $this->builder->createService('ObjectStore\\v1', array_merge($defaults, $options)); } /** @@ -132,7 +158,7 @@ public function objectStoreV1(array $options = []): \OpenStack\ObjectStore\v1\Se public function blockStorageV2(array $options = []): \OpenStack\BlockStorage\v2\Service { $defaults = ['catalogName' => 'cinderv2', 'catalogType' => 'volumev2']; - return $this->builder->createService('BlockStorage', 2, array_merge($defaults, $options)); + return $this->builder->createService('BlockStorage\\v2', array_merge($defaults, $options)); } /** @@ -145,6 +171,6 @@ public function blockStorageV2(array $options = []): \OpenStack\BlockStorage\v2\ public function imagesV2(array $options = []): \OpenStack\Images\v2\Service { $defaults = ['catalogName' => 'glance', 'catalogType' => 'image']; - return $this->builder->createService('Images', 2, array_merge($defaults, $options)); + return $this->builder->createService('Images\\v2', array_merge($defaults, $options)); } } diff --git a/tests/integration/BlockStorage/V2Test.php b/tests/integration/BlockStorage/v2/CoreTest.php similarity index 97% rename from tests/integration/BlockStorage/V2Test.php rename to tests/integration/BlockStorage/v2/CoreTest.php index 77a7d641..fdf761eb 100644 --- a/tests/integration/BlockStorage/V2Test.php +++ b/tests/integration/BlockStorage/v2/CoreTest.php @@ -1,6 +1,6 @@ service; } - protected function getBasePath() - { - return __DIR__ . '/../../../samples/block_storage/v2/'; - } - public function runTests() { $this->startTimer(); diff --git a/tests/integration/Compute/V2Test.php b/tests/integration/Compute/v2/CoreTest.php similarity index 98% rename from tests/integration/Compute/V2Test.php rename to tests/integration/Compute/v2/CoreTest.php index b92314c2..3583bf02 100644 --- a/tests/integration/Compute/V2Test.php +++ b/tests/integration/Compute/v2/CoreTest.php @@ -1,6 +1,6 @@ service; } - protected function getBasePath() - { - return __DIR__ . '/../../../samples/compute/v2/'; - } - private function searchImages($name) { foreach ($this->getService()->listImages() as $image) { diff --git a/tests/integration/Identity/V2Test.php b/tests/integration/Identity/V2Test.php deleted file mode 100644 index 7d7624fc..00000000 --- a/tests/integration/Identity/V2Test.php +++ /dev/null @@ -1,16 +0,0 @@ -service; } - protected function getBasePath() - { - return __DIR__ . '/../../../samples/identity/v3/'; - } - public function runTests() { $this->defaultLogging = true; diff --git a/tests/integration/Images/V2Test.php b/tests/integration/Images/v2/CoreTest.php similarity index 86% rename from tests/integration/Images/V2Test.php rename to tests/integration/Images/v2/CoreTest.php index bd3eb4de..4cd10fe0 100644 --- a/tests/integration/Images/V2Test.php +++ b/tests/integration/Images/v2/CoreTest.php @@ -1,33 +1,13 @@ service) { - $this->service = Utils::getOpenStack()->imagesV2(); - } - - return $this->service; - } - - protected function getBasePath() - { - return __DIR__ . '/../../../samples/images/v2/'; - } - public function runTests() { $this->startTimer(); diff --git a/tests/integration/Networking/V2Test.php b/tests/integration/Networking/V2Test.php deleted file mode 100644 index 7d5f500d..00000000 --- a/tests/integration/Networking/V2Test.php +++ /dev/null @@ -1,338 +0,0 @@ -service) { - $this->service = Utils::getOpenStack()->networkingV2(); - } - - return $this->service; - } - - protected function getBasePath() - { - return __DIR__ . '/../../../samples/networking/v2/'; - } - - public function runTests() - { - $this->startTimer(); - - $this->networks(); - $this->subnets(); - $this->ports(); - - $this->outputTimeTaken(); - } - - public function subnets() - { - $this->createSubnetsAndDelete(); - //$this->createSubnetWithGatewayIp(); - $this->createSubnetWithHostRoutes(); - - list($subnetId, $networkId) = $this->createSubnet(); - - $this->updateSubnet($subnetId); - $this->retrieveSubnet($subnetId); - $this->deleteSubnet($subnetId); - $this->deleteNetwork($networkId); - } - - public function networks() - { - $this->createNetworksAndDelete(); - - $networkId = $this->createNetwork(); - $this->updateNetwork($networkId); - $this->retrieveNetwork($networkId); - $this->deleteNetwork($networkId); - } - - private function createNetworksAndDelete() - { - $replacements = [ - '{networkName1}' => $this->randomStr(), - '{networkName2}' => $this->randomStr() - ]; - - /** @var $networks array */ - $path = $this->sampleFile($replacements, 'networks/create_batch.php'); - require_once $path; - - foreach ($networks as $network) { - $this->assertInstanceOf(Network::class, $network); - $this->assertNotEmpty($network->id); - - $this->networkId = $network->id; - $this->logStep('Created network {id}', ['{id}' => $this->networkId]); - - $this->deleteNetwork($network->id); - } - } - - private function createNetwork() - { - $replacements = [ - '{networkName}' => $this->randomStr(), - ]; - - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile($replacements, 'networks/create.php'); - require_once $path; - - $this->assertInstanceOf(Network::class, $network); - $this->assertNotEmpty($network->id); - - $this->logStep('Created network {id}', ['{id}' => $this->networkId]); - - return $network->id; - } - - private function updateNetwork($networkId) - { - $name = $this->randomStr(); - - $replacements = [ - '{networkId}' => $networkId, - '{newName}' => $name, - ]; - - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile($replacements, 'networks/update.php'); - require_once $path; - - $this->assertInstanceOf(Network::class, $network); - $this->assertEquals($name, $network->name); - - $this->logStep('Updated network ID to use this name: NAME', ['ID' => $networkId, 'NAME' => $name]); - } - - private function retrieveNetwork($networkId) - { - $replacements = ['{networkId}' => $networkId]; - - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile($replacements, 'networks/get.php'); - require_once $path; - - $this->assertInstanceOf(Network::class, $network); - - $this->logStep('Retrieved the details of network ID', ['ID' => $networkId]); - } - - private function deleteNetwork($networkId) - { - $replacements = ['{networkId}' => $networkId]; - - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile($replacements, 'networks/delete.php'); - require_once $path; - - $this->logStep('Deleted network ID', ['ID' => $networkId]); - } - - private function createSubnetsAndDelete() - { - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile(['{newName}' => $this->randomStr()], 'networks/create.php'); - require_once $path; - - $replacements = [ - '{subnetName1}' => $this->randomStr(), - '{subnetName2}' => $this->randomStr(), - '{networkId1}' => $network->id, - '{networkId2}' => $network->id, - ]; - - /** @var $subnets array */ - $path = $this->sampleFile($replacements, 'subnets/create_batch.php'); - require_once $path; - - foreach ($subnets as $subnet) { - $this->assertInstanceOf(Subnet::class, $subnet); - $this->assertNotEmpty($subnet->id); - - $this->logStep('Created subnet {id}', ['{id}' => $subnet->id]); - - $this->deleteSubnet($subnet->id); - } - - $path = $this->sampleFile(['{networkId}' => $network->id], 'networks/delete.php'); - require_once $path; - } - - private function createSubnet() - { - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile(['{newName}' => $this->randomStr()], 'networks/create.php'); - require_once $path; - - $replacements = [ - '{subnetName}' => $this->randomStr(), - '{networkId}' => $network->id, - ]; - - /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ - $path = $this->sampleFile($replacements, 'subnets/create.php'); - require_once $path; - - $this->assertInstanceOf(Subnet::class, $subnet); - $this->assertNotEmpty($subnet->id); - - $this->logStep('Created subnet {id}', ['{id}' => $subnet->id]); - - return [$subnet->id, $network->id]; - } - - private function createSubnetWithGatewayIp() - { - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile(['{newName}' => $this->randomStr()], 'networks/create.php'); - require_once $path; - - $replacements = [ - '{networkId}' => $network->id, - ]; - - /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ - $path = $this->sampleFile($replacements, 'subnets/create_with_gateway_ip.php'); - require_once $path; - - $this->assertInstanceOf(Subnet::class, $subnet); - $this->assertNotEmpty($subnet->id); - - $this->subnetId = $subnet->id; - - $this->logStep('Created subnet {id} with gateway ip', ['{id}' => $this->subnetId]); - - $path = $this->sampleFile($replacements, 'networks/delete.php'); - require_once $path; - } - - private function createSubnetWithHostRoutes() - { - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile(['{newName}' => $this->randomStr()], 'networks/create.php'); - require_once $path; - - $replacements = [ - '{networkId}' => $network->id, - ]; - - /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ - $path = $this->sampleFile($replacements, 'subnets/create_with_host_routes.php'); - require_once $path; - - $this->assertInstanceOf(Subnet::class, $subnet); - $this->assertNotEmpty($subnet->id); - - $this->logStep('Created subnet {id} with host routes', ['{id}' => $subnet->id]); - - $path = $this->sampleFile($replacements, 'networks/delete.php'); - require_once $path; - } - - private function updateSubnet($subnetId) - { - $name = $this->randomStr(); - - $replacements = [ - '{subnetId}' => $subnetId, - '{newName}' => $name, - ]; - - /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ - $path = $this->sampleFile($replacements, 'subnets/update.php'); - require_once $path; - - $this->assertInstanceOf(Subnet::class, $subnet); - $this->assertEquals($name, $subnet->name); - - $this->logStep('Updated subnet ID to use this name: NAME', ['ID' => $subnetId, 'NAME' => $name]); - } - - - private function retrieveSubnet($subnetId) - { - $replacements = ['{subnetId}' => $subnetId]; - - /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ - $path = $this->sampleFile($replacements, 'subnets/get.php'); - require_once $path; - - $this->assertInstanceOf(Subnet::class, $subnet); - - $this->logStep('Retrieved the details of subnet ID', ['ID' => $subnetId]); - } - - private function deleteSubnet($subnetId) - { - $replacements = ['{subnetId}' => $subnetId]; - - /** @var $subnet \OpenStack\Networking\v2\Models\Subnet */ - $path = $this->sampleFile($replacements, 'subnets/delete.php'); - require_once $path; - - $this->logStep('Deleted subnet ID', ['ID' => $subnetId]); - } - - public function ports() - { - $replacements = ['{newName}' => $this->randomStr()]; - - /** @var $network \OpenStack\Networking\v2\Models\Network */ - $path = $this->sampleFile($replacements, 'networks/create.php'); - require_once $path; - - $replacements = ['{networkId}' => $network->id]; - - /** @var $port \OpenStack\Networking\v2\Models\Port */ - $path = $this->sampleFile($replacements, 'ports/create.php'); - require_once $path; - $this->assertInstanceOf(Port::class, $port); - - $replacements['{portId}'] = $port->id; - $port->networkId = $network->id; - - /** @var $ports array */ - $path = $this->sampleFile($replacements, 'ports/create_batch.php'); - require_once $path; - foreach ($ports as $port) { - $this->assertInstanceOf(Port::class, $port); - $port->delete(); - } - - /** @var $port \OpenStack\Networking\v2\Models\Port */ - $path = $this->sampleFile($replacements, 'ports/list.php'); - require_once $path; - - /** @var $port \OpenStack\Networking\v2\Models\Port */ - $path = $this->sampleFile($replacements, 'ports/get.php'); - require_once $path; - $this->assertInstanceOf(Port::class, $port); - - /** @var $port \OpenStack\Networking\v2\Models\Port */ - $path = $this->sampleFile($replacements, 'ports/update.php'); - require_once $path; - $this->assertInstanceOf(Port::class, $port); - - $path = $this->sampleFile($replacements, 'ports/delete.php'); - require_once $path; - - $path = $this->sampleFile($replacements, 'networks/delete.php'); - require_once $path; - } -} diff --git a/tests/integration/ObjectStore/V1Test.php b/tests/integration/ObjectStore/v1/CoreTest.php similarity index 97% rename from tests/integration/ObjectStore/V1Test.php rename to tests/integration/ObjectStore/v1/CoreTest.php index 07df7739..d94550b7 100644 --- a/tests/integration/ObjectStore/V1Test.php +++ b/tests/integration/ObjectStore/v1/CoreTest.php @@ -1,12 +1,12 @@ service; } - protected function getBasePath() - { - return __DIR__ . '/../../../samples/object_store/v1/'; - } - public function runTests() { $this->startTimer(); diff --git a/tests/integration/SampleManager.php b/tests/integration/SampleManager.php index 0d84bca1..7a020551 100644 --- a/tests/integration/SampleManager.php +++ b/tests/integration/SampleManager.php @@ -40,6 +40,11 @@ protected function getGlobalReplacements() ]; } + public function getConnectionStr() + { + return str_replace('$openstack =', 'return', $this->getConnectionTemplate()); + } + protected function getConnectionTemplate() { if ($this->verbosity === 1) { diff --git a/tests/integration/run.php b/tests/integration/run.php index 94dbee2d..0ff606cb 100644 --- a/tests/integration/run.php +++ b/tests/integration/run.php @@ -4,7 +4,7 @@ require_once $rootDir . '/vendor/autoload.php'; -$basePath = $rootDir . '/samples'; +$sampleDir = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'samples'; -$runner = new \OpenCloud\Integration\Runner($basePath, 'OpenStack\\Integration'); +$runner = new \OpenCloud\Integration\Runner($sampleDir, __DIR__, 'OpenStack\\Integration'); $runner->runServices(); diff --git a/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/FloatingIp.resp b/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/FloatingIp.resp new file mode 100644 index 00000000..d4f9fbd5 --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/FloatingIp.resp @@ -0,0 +1,15 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "floatingip": { + "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57", + "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f", + "fixed_ip_address": "10.0.0.3", + "floating_ip_address": "172.24.4.228", + "tenant_id": "4969c491a3c74ee4af974e6d800c62de", + "status": "ACTIVE", + "port_id": "ce705c24-c1ef-408a-bda3-7bbd946164ab", + "id": "2f245a7b-796b-4f26-9cf9-9e82d248fda7" + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/FloatingIps.resp b/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/FloatingIps.resp new file mode 100644 index 00000000..66046e79 --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/FloatingIps.resp @@ -0,0 +1,27 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "floatingips": [ + { + "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f", + "tenant_id": "4969c491a3c74ee4af974e6d800c62de", + "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57", + "fixed_ip_address": "10.0.0.3", + "floating_ip_address": "172.24.4.228", + "port_id": "ce705c24-c1ef-408a-bda3-7bbd946164ab", + "id": "2f245a7b-796b-4f26-9cf9-9e82d248fda7", + "status": "ACTIVE" + }, + { + "router_id": null, + "tenant_id": "4969c491a3c74ee4af974e6d800c62de", + "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57", + "fixed_ip_address": null, + "floating_ip_address": "172.24.4.227", + "port_id": null, + "id": "61cea855-49cb-4846-997d-801b70c71bdd", + "status": "DOWN" + } + ] +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/Router.resp b/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/Router.resp new file mode 100644 index 00000000..79fed195 --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/Router.resp @@ -0,0 +1,23 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "router": { + "status": "ACTIVE", + "external_gateway_info": { + "network_id": "85d76829-6415-48ff-9c63-5c5ca8c61ac6", + "enable_snat": true, + "external_fixed_ips": [ + { + "subnet_id": "255.255.255.0", + "ip": "192.168.10.2" + } + ] + }, + "name": "router1", + "admin_state_up": true, + "tenant_id": "d6554fe62e2f41efbb6e026fad5c1542", + "routes": [], + "id": "a07eea83-7710-4860-931b-5fe220fae533" + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/Routers.resp b/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/Routers.resp new file mode 100644 index 00000000..76cf5cbf --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/Layer3/Fixtures/Routers.resp @@ -0,0 +1,34 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "routers": [ + { + "status": "ACTIVE", + "external_gateway_info": null, + "name": "second_routers", + "admin_state_up": true, + "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3", + "routes": [], + "id": "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b" + }, + { + "status": "ACTIVE", + "external_gateway_info": { + "network_id": "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8", + "enable_snat": true, + "external_fixed_ips": [ + { + "subnet_id": "255.255.255.0", + "ip": "192.168.10.2" + } + ] + }, + "name": "router1", + "admin_state_up": true, + "tenant_id": "33a40233088643acb66ff6eb0ebea679", + "routes": [], + "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d" + } + ] +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroup.resp b/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroup.resp new file mode 100644 index 00000000..d7000122 --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroup.resp @@ -0,0 +1,37 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "security_group":{ + "description":"default", + "id":"85cc3048-abc3-43cc-89b3-377341426ac5", + "name":"default", + "security_group_rules":[ + { + "direction":"ingress", + "ethertype":"IPv6", + "id":"c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max":22, + "port_range_min":22, + "protocol":"TCP", + "remote_group_id":null, + "remote_ip_prefix":null, + "security_group_id":"85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id":"5831008" + }, + { + "direction":"ingress", + "ethertype":"IPv4", + "id":"f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max":22, + "port_range_min":22, + "protocol":"TCP", + "remote_group_id":null, + "remote_ip_prefix":null, + "security_group_id":"85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id":"5831008" + } + ], + "tenant_id":"5831008" + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroupRule.resp b/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroupRule.resp new file mode 100644 index 00000000..36ab1466 --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroupRule.resp @@ -0,0 +1,17 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "security_group_rule":{ + "direction":"ingress", + "ethertype":"IPv6", + "id":"c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max":22, + "port_range_min":22, + "protocol":"TCP", + "remote_group_id":null, + "remote_ip_prefix":null, + "security_group_id":"85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id":"5831008" + } +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroupRules.resp b/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroupRules.resp new file mode 100644 index 00000000..e5ce88fa --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroupRules.resp @@ -0,0 +1,31 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "security_group_rules":[ + { + "direction":"ingress", + "ethertype":"IPv6", + "id":"c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max":22, + "port_range_min":22, + "protocol":"TCP", + "remote_group_id":null, + "remote_ip_prefix":null, + "security_group_id":"85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id":"5831008" + }, + { + "direction":"ingress", + "ethertype":"IPv4", + "id":"f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max":22, + "port_range_min":22, + "protocol":"TCP", + "remote_group_id":null, + "remote_ip_prefix":null, + "security_group_id":"85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id":"5831008" + } + ] +} \ No newline at end of file diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroups.resp b/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroups.resp new file mode 100644 index 00000000..34d040a8 --- /dev/null +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/Fixtures/SecurityGroups.resp @@ -0,0 +1,39 @@ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "security_groups": [ + { + "description": "default", + "id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "name": "default", + "security_group_rules": [ + { + "direction": "ingress", + "ethertype": "IPv6", + "id": "c0b09f00-1d49-4e64-a0a7-8a186d928138", + "port_range_max": 22, + "port_range_min": 22, + "protocol": "TCP", + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "5831008" + }, + { + "direction": "ingress", + "ethertype": "IPv4", + "id": "f7d45c89-008e-4bab-88ad-d6811724c51c", + "port_range_max": 22, + "port_range_min": 22, + "protocol": "TCP", + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "tenant_id": "5831008" + } + ], + "tenant_id": "5831008" + } + ] +} \ No newline at end of file diff --git a/tests/unit/OpenStackTest.php b/tests/unit/OpenStackTest.php index 2ecf5a97..a145def0 100644 --- a/tests/unit/OpenStackTest.php +++ b/tests/unit/OpenStackTest.php @@ -22,7 +22,7 @@ public function setUp() public function test_it_supports_compute_v2() { $this->builder - ->createService('Compute', 2, ['catalogName' => 'nova', 'catalogType' => 'compute']) + ->createService('Compute\\v2', ['catalogName' => 'nova', 'catalogType' => 'compute']) ->shouldBeCalled() ->willReturn($this->service('Compute', 2)); @@ -32,7 +32,7 @@ public function test_it_supports_compute_v2() public function test_it_supports_identity_v2() { $this->builder - ->createService('Identity', 2, ['catalogName' => false, 'catalogType' => false]) + ->createService('Identity\\v2', ['catalogName' => false, 'catalogType' => false]) ->shouldBeCalled() ->willReturn($this->service('Identity', 2)); @@ -42,7 +42,7 @@ public function test_it_supports_identity_v2() public function test_it_supports_identity_v3() { $this->builder - ->createService('Identity', 3, ['catalogName' => false, 'catalogType' => false]) + ->createService('Identity\\v3', ['catalogName' => false, 'catalogType' => false]) ->shouldBeCalled() ->willReturn($this->service('Identity', 3)); @@ -52,7 +52,7 @@ public function test_it_supports_identity_v3() public function test_it_supports_networking_v2() { $this->builder - ->createService('Networking', 2, ['catalogName' => 'neutron', 'catalogType' => 'network']) + ->createService('Networking\\v2', ['catalogName' => 'neutron', 'catalogType' => 'network']) ->shouldBeCalled() ->willReturn($this->service('Networking', 2)); @@ -62,7 +62,7 @@ public function test_it_supports_networking_v2() public function test_it_supports_object_store_v1() { $this->builder - ->createService('ObjectStore', 1, ['catalogName' => 'swift', 'catalogType' => 'object-store']) + ->createService('ObjectStore\\v1', ['catalogName' => 'swift', 'catalogType' => 'object-store']) ->shouldBeCalled() ->willReturn($this->service('ObjectStore', 1)); @@ -72,7 +72,7 @@ public function test_it_supports_object_store_v1() public function test_it_supports_block_storage_v2() { $this->builder - ->createService('BlockStorage', 2, ['catalogName' => 'cinderv2', 'catalogType' => 'volumev2']) + ->createService('BlockStorage\\v2', ['catalogName' => 'cinderv2', 'catalogType' => 'volumev2']) ->shouldBeCalled() ->willReturn($this->service('BlockStorage', 2)); @@ -82,7 +82,7 @@ public function test_it_supports_block_storage_v2() public function test_it_supports_images_v2() { $this->builder - ->createService('Images', 2, ['catalogName' => 'glance', 'catalogType' => 'image']) + ->createService('Images\\v2', ['catalogName' => 'glance', 'catalogType' => 'image']) ->shouldBeCalled() ->willReturn($this->service('Images', 2)); From 94d784a274b651caf80b825db258ac2cd1cde985 Mon Sep 17 00:00:00 2001 From: Jamie Hannaford Date: Mon, 11 Apr 2016 12:07:17 +0200 Subject: [PATCH 4/4] fix styling --- samples/networking/v2/floatingIPs/create.php | 2 +- samples/networking/v2/floatingIPs/delete.php | 2 +- samples/networking/v2/floatingIPs/get.php | 2 +- samples/networking/v2/floatingIPs/list.php | 2 +- samples/networking/v2/floatingIPs/update.php | 2 +- samples/networking/v2/securityGroupRules/create.php | 2 +- samples/networking/v2/securityGroupRules/delete.php | 2 +- samples/networking/v2/securityGroupRules/get.php | 2 +- samples/networking/v2/securityGroupRules/list.php | 2 +- samples/networking/v2/securityGroups/create.php | 2 +- samples/networking/v2/securityGroups/delete.php | 2 +- samples/networking/v2/securityGroups/get.php | 2 +- samples/networking/v2/securityGroups/list.php | 2 +- src/Networking/v2/Extensions/Layer3/Api.php | 2 +- src/Networking/v2/Extensions/Layer3/Models/FixedIp.php | 2 +- src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php | 2 +- src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php | 2 +- src/Networking/v2/Extensions/Layer3/Models/Router.php | 2 +- src/Networking/v2/Extensions/Layer3/Params.php | 2 +- src/Networking/v2/Extensions/Layer3/Service.php | 2 +- src/Networking/v2/Extensions/SecurityGroups/Api.php | 2 +- .../v2/Extensions/SecurityGroups/Models/SecurityGroup.php | 4 ++-- .../Extensions/SecurityGroups/Models/SecurityGroupRule.php | 2 +- src/Networking/v2/Extensions/SecurityGroups/Params.php | 2 +- src/Networking/v2/Extensions/SecurityGroups/Service.php | 2 +- tests/integration/Networking/v2/Layer3Test.php | 2 +- tests/integration/Networking/v2/SecGroupTest.php | 5 +++-- .../v2/Extensions/Layer3/Models/FloatingIpTest.php | 2 +- .../Networking/v2/Extensions/Layer3/Models/RouterTest.php | 2 +- tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php | 2 +- .../SecurityGroups/Models/SecurityGroupRuleTest.php | 4 ++-- .../Extensions/SecurityGroups/Models/SecurityGroupTest.php | 4 ++-- .../Networking/v2/Extensions/SecurityGroups/ServiceTest.php | 2 +- 33 files changed, 38 insertions(+), 37 deletions(-) diff --git a/samples/networking/v2/floatingIPs/create.php b/samples/networking/v2/floatingIPs/create.php index 96062541..96c1cb27 100644 --- a/samples/networking/v2/floatingIPs/create.php +++ b/samples/networking/v2/floatingIPs/create.php @@ -18,4 +18,4 @@ $ip = $networking->createFloatingIp([ "floatingNetworkId" => "{networkId}", "portId" => "{portId}", -]); \ No newline at end of file +]); diff --git a/samples/networking/v2/floatingIPs/delete.php b/samples/networking/v2/floatingIPs/delete.php index 05ef3236..6accb015 100644 --- a/samples/networking/v2/floatingIPs/delete.php +++ b/samples/networking/v2/floatingIPs/delete.php @@ -14,4 +14,4 @@ $openstack->networkingV2ExtLayer3() ->getFloatingIp('{id}') - ->delete(); \ No newline at end of file + ->delete(); diff --git a/samples/networking/v2/floatingIPs/get.php b/samples/networking/v2/floatingIPs/get.php index 46d755b3..54ff62ca 100644 --- a/samples/networking/v2/floatingIPs/get.php +++ b/samples/networking/v2/floatingIPs/get.php @@ -14,4 +14,4 @@ /** @var \OpenStack\Networking\v2\Extensions\Layer3\Models\FloatingIp $ip */ $ip = $openstack->networkingV2ExtLayer3() - ->getFloatingIp('{id}'); \ No newline at end of file + ->getFloatingIp('{id}'); diff --git a/samples/networking/v2/floatingIPs/list.php b/samples/networking/v2/floatingIPs/list.php index 6eb788c7..da87c819 100644 --- a/samples/networking/v2/floatingIPs/list.php +++ b/samples/networking/v2/floatingIPs/list.php @@ -17,4 +17,4 @@ foreach ($floatingIps as $floatingIp) { /** @var \OpenStack\Networking\v2\Extensions\Layer3\Models\FloatingIp $floatingIp */ -} \ No newline at end of file +} diff --git a/samples/networking/v2/floatingIPs/update.php b/samples/networking/v2/floatingIPs/update.php index 3342b06a..9698d30d 100644 --- a/samples/networking/v2/floatingIPs/update.php +++ b/samples/networking/v2/floatingIPs/update.php @@ -16,4 +16,4 @@ ->getFloatingIp('{id}'); $floatingIp->portId = '{newPortId}'; -$floatingIp->update(); \ No newline at end of file +$floatingIp->update(); diff --git a/samples/networking/v2/securityGroupRules/create.php b/samples/networking/v2/securityGroupRules/create.php index 08c3981a..70ac6094 100644 --- a/samples/networking/v2/securityGroupRules/create.php +++ b/samples/networking/v2/securityGroupRules/create.php @@ -23,4 +23,4 @@ "protocol" => "tcp", "remoteGroupId" => "{groupId}", "securityGroupId" => "{secGroupId}", -]); \ No newline at end of file +]); diff --git a/samples/networking/v2/securityGroupRules/delete.php b/samples/networking/v2/securityGroupRules/delete.php index ce200948..52b56e5f 100644 --- a/samples/networking/v2/securityGroupRules/delete.php +++ b/samples/networking/v2/securityGroupRules/delete.php @@ -16,4 +16,4 @@ $rule = $openstack->networkingV2ExtSecGroups() ->getSecurityGroupRule('{id}'); -$rule->delete(); \ No newline at end of file +$rule->delete(); diff --git a/samples/networking/v2/securityGroupRules/get.php b/samples/networking/v2/securityGroupRules/get.php index 670e8ada..085e5acf 100644 --- a/samples/networking/v2/securityGroupRules/get.php +++ b/samples/networking/v2/securityGroupRules/get.php @@ -14,4 +14,4 @@ /** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroupRule $rule */ $rule = $openstack->networkingV2ExtSecGroups() - ->getSecurityGroupRule('{id}'); \ No newline at end of file + ->getSecurityGroupRule('{id}'); diff --git a/samples/networking/v2/securityGroupRules/list.php b/samples/networking/v2/securityGroupRules/list.php index 06aa0612..de1e9701 100644 --- a/samples/networking/v2/securityGroupRules/list.php +++ b/samples/networking/v2/securityGroupRules/list.php @@ -17,4 +17,4 @@ foreach ($rules as $rule) { /** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroupRule $rule */ -} \ No newline at end of file +} diff --git a/samples/networking/v2/securityGroups/create.php b/samples/networking/v2/securityGroups/create.php index e42cb6fe..32ddb0f7 100644 --- a/samples/networking/v2/securityGroups/create.php +++ b/samples/networking/v2/securityGroups/create.php @@ -18,4 +18,4 @@ $secGroup = $networking->createSecurityGroup([ 'name' => 'new-webservers', 'description' => 'security group for webservers', -]); \ No newline at end of file +]); diff --git a/samples/networking/v2/securityGroups/delete.php b/samples/networking/v2/securityGroups/delete.php index f0e805ac..69bb2ba7 100644 --- a/samples/networking/v2/securityGroups/delete.php +++ b/samples/networking/v2/securityGroups/delete.php @@ -16,4 +16,4 @@ /** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroup $secGroup */ $secGroup = $networking->getSecurityGroup('{id}'); -$secGroup->delete(); \ No newline at end of file +$secGroup->delete(); diff --git a/samples/networking/v2/securityGroups/get.php b/samples/networking/v2/securityGroups/get.php index 138d6acd..26f46278 100644 --- a/samples/networking/v2/securityGroups/get.php +++ b/samples/networking/v2/securityGroups/get.php @@ -16,4 +16,4 @@ /** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroup $secGroup */ $secGroup = $networking->getSecurityGroup('{id}'); -$secGroup->retrieve(); \ No newline at end of file +$secGroup->retrieve(); diff --git a/samples/networking/v2/securityGroups/list.php b/samples/networking/v2/securityGroups/list.php index ab0c90e6..2a423f36 100644 --- a/samples/networking/v2/securityGroups/list.php +++ b/samples/networking/v2/securityGroups/list.php @@ -18,4 +18,4 @@ foreach ($secGroups as $secGroup) { /** @var \OpenStack\Networking\v2\Extensions\SecurityGroups\Models\SecurityGroup $secGroup */ -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/Layer3/Api.php b/src/Networking/v2/Extensions/Layer3/Api.php index 5537c2f4..002d2a43 100644 --- a/src/Networking/v2/Extensions/Layer3/Api.php +++ b/src/Networking/v2/Extensions/Layer3/Api.php @@ -165,4 +165,4 @@ public function putRemoveInterface() ], ]; } -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/Layer3/Models/FixedIp.php b/src/Networking/v2/Extensions/Layer3/Models/FixedIp.php index 7786df6f..f328dbef 100644 --- a/src/Networking/v2/Extensions/Layer3/Models/FixedIp.php +++ b/src/Networking/v2/Extensions/Layer3/Models/FixedIp.php @@ -15,4 +15,4 @@ class FixedIp extends AbstractResource protected $aliases = [ 'subnet_id' => 'subnetId' ]; -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php b/src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php index a4f7dfd7..2798648c 100644 --- a/src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php +++ b/src/Networking/v2/Extensions/Layer3/Models/FloatingIp.php @@ -72,4 +72,4 @@ public function retrieve() { $this->executeWithState($this->api->getFloatingIp()); } -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php b/src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php index c72d3199..58364995 100644 --- a/src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php +++ b/src/Networking/v2/Extensions/Layer3/Models/GatewayInfo.php @@ -20,4 +20,4 @@ class GatewayInfo extends AbstractResource 'enable_snat' => 'enableSnat', 'fixed_ips' => 'fixedIps', ]; -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/Layer3/Models/Router.php b/src/Networking/v2/Extensions/Layer3/Models/Router.php index b2f23409..f33c3db6 100644 --- a/src/Networking/v2/Extensions/Layer3/Models/Router.php +++ b/src/Networking/v2/Extensions/Layer3/Models/Router.php @@ -80,4 +80,4 @@ public function removeInterface(array $userOptions) $userOptions['id'] = $this->id; $this->execute($this->api->putRemoveInterface(), $userOptions); } -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/Layer3/Params.php b/src/Networking/v2/Extensions/Layer3/Params.php index 5ceef5cb..57856cb5 100644 --- a/src/Networking/v2/Extensions/Layer3/Params.php +++ b/src/Networking/v2/Extensions/Layer3/Params.php @@ -113,4 +113,4 @@ public function haJson(): array 'description' => 'If true, indicates a highly-available router.', ]; } -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/Layer3/Service.php b/src/Networking/v2/Extensions/Layer3/Service.php index 8e8c9941..a510c258 100644 --- a/src/Networking/v2/Extensions/Layer3/Service.php +++ b/src/Networking/v2/Extensions/Layer3/Service.php @@ -72,4 +72,4 @@ public function listRouters(): \Generator { return $this->router()->enumerate($this->api->getRouters()); } -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/SecurityGroups/Api.php b/src/Networking/v2/Extensions/SecurityGroups/Api.php index 14112c30..0f2c1680 100644 --- a/src/Networking/v2/Extensions/SecurityGroups/Api.php +++ b/src/Networking/v2/Extensions/SecurityGroups/Api.php @@ -149,4 +149,4 @@ public function getSecurityRule() ], ]; } -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroup.php b/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroup.php index 724bf307..1ac12d54 100644 --- a/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroup.php +++ b/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroup.php @@ -1,4 +1,4 @@ -executeWithState($this->api->getSecurityGroup()); $this->populateFromResponse($response); } -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRule.php b/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRule.php index 75350dba..cb1148a0 100644 --- a/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRule.php +++ b/src/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRule.php @@ -1,4 +1,4 @@ - "The UUID of the tenant who owns the security group rule. Only administrative users can specify a tenant UUID other than their own.", ]; } -} \ No newline at end of file +} diff --git a/src/Networking/v2/Extensions/SecurityGroups/Service.php b/src/Networking/v2/Extensions/SecurityGroups/Service.php index 9e3fb9b0..17972d73 100644 --- a/src/Networking/v2/Extensions/SecurityGroups/Service.php +++ b/src/Networking/v2/Extensions/SecurityGroups/Service.php @@ -76,4 +76,4 @@ public function getSecurityGroupRule(string $id): SecurityGroupRule { return $this->securityGroupRule(['id' => $id]); } -} \ No newline at end of file +} diff --git a/tests/integration/Networking/v2/Layer3Test.php b/tests/integration/Networking/v2/Layer3Test.php index 1d58bd75..556530d4 100644 --- a/tests/integration/Networking/v2/Layer3Test.php +++ b/tests/integration/Networking/v2/Layer3Test.php @@ -106,4 +106,4 @@ public function floatingIps() $port2->delete(); $network->delete(); } -} \ No newline at end of file +} diff --git a/tests/integration/Networking/v2/SecGroupTest.php b/tests/integration/Networking/v2/SecGroupTest.php index f2e72232..e4e510a9 100644 --- a/tests/integration/Networking/v2/SecGroupTest.php +++ b/tests/integration/Networking/v2/SecGroupTest.php @@ -7,5 +7,6 @@ class SecGroupTest extends TestCase { public function runTests() - {} -} \ No newline at end of file + { + } +} diff --git a/tests/unit/Networking/v2/Extensions/Layer3/Models/FloatingIpTest.php b/tests/unit/Networking/v2/Extensions/Layer3/Models/FloatingIpTest.php index a718fa8b..62915f42 100644 --- a/tests/unit/Networking/v2/Extensions/Layer3/Models/FloatingIpTest.php +++ b/tests/unit/Networking/v2/Extensions/Layer3/Models/FloatingIpTest.php @@ -49,4 +49,4 @@ public function test_it_retrieves() $this->floatingIp->retrieve(); } -} \ No newline at end of file +} diff --git a/tests/unit/Networking/v2/Extensions/Layer3/Models/RouterTest.php b/tests/unit/Networking/v2/Extensions/Layer3/Models/RouterTest.php index ca733b12..1f1b013a 100644 --- a/tests/unit/Networking/v2/Extensions/Layer3/Models/RouterTest.php +++ b/tests/unit/Networking/v2/Extensions/Layer3/Models/RouterTest.php @@ -88,4 +88,4 @@ public function test_it_remove_interface() $this->router->removeInterface(['subnetId' => 'a2f1f29d-571b-4533-907f-5803ab96ead1']); } -} \ No newline at end of file +} diff --git a/tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php b/tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php index 93aa750f..afe2eff0 100644 --- a/tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php +++ b/tests/unit/Networking/v2/Extensions/Layer3/ServiceTest.php @@ -124,4 +124,4 @@ public function test_it_creates_router() $this->assertInstanceOf(Router::class, $r); } -} \ No newline at end of file +} diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRuleTest.php b/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRuleTest.php index 24b0688a..ba69b0c8 100644 --- a/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRuleTest.php +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupRuleTest.php @@ -1,4 +1,4 @@ -securityGroupRule->retrieve(); } -} \ No newline at end of file +} diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupTest.php b/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupTest.php index 86527e47..76eb42c3 100644 --- a/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupTest.php +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/Models/SecurityGroupTest.php @@ -1,4 +1,4 @@ -securityGroup->retrieve(); } -} \ No newline at end of file +} diff --git a/tests/unit/Networking/v2/Extensions/SecurityGroups/ServiceTest.php b/tests/unit/Networking/v2/Extensions/SecurityGroups/ServiceTest.php index 451b689e..039e7737 100644 --- a/tests/unit/Networking/v2/Extensions/SecurityGroups/ServiceTest.php +++ b/tests/unit/Networking/v2/Extensions/SecurityGroups/ServiceTest.php @@ -112,4 +112,4 @@ public function test_it_gets_secgrouprule() { $this->assertInstanceOf(SecurityGroupRule::class, $this->service->getSecurityGroupRule('id')); } -} \ No newline at end of file +}