Microversion 2.35 adds keypairs pagination support
After this microversion Nova API allows to get several keypairs with the help of new optional parameters 'limit' and 'marker' which were added to GET /os-keypairs request. Partial-Bug: #1599904 Implements blueprint: keypairs-pagination Change-Id: Idd3757f5be90ec4af1bd1a7ca3f9c20319dbfd33
This commit is contained in:
parent
777386b4bf
commit
47358449d3
@ -23,6 +23,8 @@ Request
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- user_id: keypair_user
|
||||
- limit: keypair_limit
|
||||
- marker: keypair_marker
|
||||
|
||||
Response
|
||||
--------
|
||||
|
@ -477,6 +477,25 @@ ip_query:
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
keypair_limit:
|
||||
description: |
|
||||
Requests a page size of items. Returns a number of items up to a limit value.
|
||||
Use the ``limit`` parameter to make an initial limited request and use the
|
||||
last-seen item from the response as the ``marker`` parameter value in a
|
||||
subsequent limited request.
|
||||
in: query
|
||||
required: false
|
||||
type: integer
|
||||
min_version: 2.35
|
||||
keypair_marker:
|
||||
description: |
|
||||
The last-seen item. Use the ``limit`` parameter to make an initial limited
|
||||
request and use the last-seen item from the response as the ``marker``
|
||||
parameter value in a subsequent limited request.
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
min_version: 2.35
|
||||
keypair_type_in:
|
||||
in: query
|
||||
required: false
|
||||
|
18
doc/api_samples/keypairs/v2.35/keypairs-list-resp.json
Normal file
18
doc/api_samples/keypairs/v2.35/keypairs-list-resp.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "7e:eb:ab:24:ba:d1:e1:88:ae:9a:fb:66:53:df:d3:bd",
|
||||
"name": "keypair-5d935425-31d5-48a7-a0f1-e76e9813f2c3",
|
||||
"type": "ssh",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkF3MX59OrlBs3dH5CU7lNmvpbrgZxSpyGjlnE8Flkirnc/Up22lpjznoxqeoTAwTW034k7Dz6aYIrZGmQwe2TkE084yqvlj45Dkyoj95fW/sZacm0cZNuL69EObEGHdprfGJQajrpz22NQoCD8TFB8Wv+8om9NH9Le6s+WPe98WC77KLw8qgfQsbIey+JawPWl4O67ZdL5xrypuRjfIPWjgy/VH85IXg/Z/GONZ2nxHgSShMkwqSFECAC5L3PHB+0+/12M/iikdatFSVGjpuHvkLOs3oe7m6HlOfluSJ85BzLWBbvva93qkGmLg4ZAc8rPh2O+YIsBUHNLLMM/oQp Generated-by-Nova\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"keypairs_links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/keypairs?limit=1&marker=keypair-5d935425-31d5-48a7-a0f1-e76e9813f2c3",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
12
doc/api_samples/keypairs/v2.35/keypairs-list-user1-resp.json
Normal file
12
doc/api_samples/keypairs/v2.35/keypairs-list-user1-resp.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "7e:eb:ab:24:ba:d1:e1:88:ae:9a:fb:66:53:df:d3:bd",
|
||||
"name": "keypair-5d935425-31d5-48a7-a0f1-e76e9813f2c3",
|
||||
"type": "ssh",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkF3MX59OrlBs3dH5CU7lNmvpbrgZxSpyGjlnE8Flkirnc/Up22lpjznoxqeoTAwTW034k7Dz6aYIrZGmQwe2TkE084yqvlj45Dkyoj95fW/sZacm0cZNuL69EObEGHdprfGJQajrpz22NQoCD8TFB8Wv+8om9NH9Le6s+WPe98WC77KLw8qgfQsbIey+JawPWl4O67ZdL5xrypuRjfIPWjgy/VH85IXg/Z/GONZ2nxHgSShMkwqSFECAC5L3PHB+0+/12M/iikdatFSVGjpuHvkLOs3oe7m6HlOfluSJ85BzLWBbvva93qkGmLg4ZAc8rPh2O+YIsBUHNLLMM/oQp Generated-by-Nova\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
18
doc/api_samples/keypairs/v2.35/keypairs-list-user2-resp.json
Normal file
18
doc/api_samples/keypairs/v2.35/keypairs-list-user2-resp.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "7e:eb:ab:24:ba:d1:e1:88:ae:9a:fb:66:53:df:d3:bd",
|
||||
"name": "keypair-5d935425-31d5-48a7-a0f1-e76e9813f2c3",
|
||||
"type": "ssh",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkF3MX59OrlBs3dH5CU7lNmvpbrgZxSpyGjlnE8Flkirnc/Up22lpjznoxqeoTAwTW034k7Dz6aYIrZGmQwe2TkE084yqvlj45Dkyoj95fW/sZacm0cZNuL69EObEGHdprfGJQajrpz22NQoCD8TFB8Wv+8om9NH9Le6s+WPe98WC77KLw8qgfQsbIey+JawPWl4O67ZdL5xrypuRjfIPWjgy/VH85IXg/Z/GONZ2nxHgSShMkwqSFECAC5L3PHB+0+/12M/iikdatFSVGjpuHvkLOs3oe7m6HlOfluSJ85BzLWBbvva93qkGmLg4ZAc8rPh2O+YIsBUHNLLMM/oQp Generated-by-Nova\n"
|
||||
}
|
||||
}
|
||||
],
|
||||
"keypairs_links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/keypairs?user_id=user2&limit=1&marker=keypair-5d935425-31d5-48a7-a0f1-e76e9813f2c3",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
7
doc/api_samples/keypairs/v2.35/keypairs-post-req.json
Normal file
7
doc/api_samples/keypairs/v2.35/keypairs-post-req.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"keypair": {
|
||||
"name": "keypair-ab9ff2e6-a6d7-4915-a241-044c369c07f9",
|
||||
"type": "ssh",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
10
doc/api_samples/keypairs/v2.35/keypairs-post-resp.json
Normal file
10
doc/api_samples/keypairs/v2.35/keypairs-post-resp.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "7e:eb:ab:24:ba:d1:e1:88:ae:9a:fb:66:53:df:d3:bd",
|
||||
"name": "keypair-ab9ff2e6-a6d7-4915-a241-044c369c07f9",
|
||||
"type": "ssh",
|
||||
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEApBdzF+fTq5QbN3R+QlO5TZr6W64GcUqcho5ZxPBZZIq53P1K\ndtpaY856ManqEwME1tN+JOw8+mmCK2RpkMHtk5BNPOMqr5Y+OQ5MqI/eX1v7GWnJ\ntHGTbi+vRDmxBh3aa3xiUGo66c9tjUKAg/ExQfFr/vKJvTR/S3urPlj3vfFgu+yi\n8PKoH0LGyHsviWsD1peDuu2XS+ca8qbkY3yD1o4Mv1R/OSF4P2fxjjWdp8R4EkoT\nJMKkhRAgAuS9zxwftPv9djP4opHWrRUlRo6bh75CzrN6Hu5uh5Tn5bkifOQcy1gW\n772vd6pBpi4OGQHPKz4djvmCLAVBzSyzDP6EKQIDAQABAoIBAQCB+tU/ZXKlIe+h\nMNTmoz1QfOe+AY625Rwx9cakGqMk4kKyC62VkgcxshfXCToSjzyhEuyEQOFYloT2\n7FY2xXb0gcS861Efv0pQlcQhbbz/GnQ/wC13ktPu3zTdPTm9l54xsFiMTGmYVaf4\n0mnMmhyjmKIsVGDJEDGZUD/oZj7wJGOFha5M4FZrZlJIrEZC0rGGlcC0kGF2no6B\nj1Mu7HjyK3pTKf4dlp+jeRikUF5Pct+qT+rcv2rZ3fl3inxtlLEwZeFPbp/njf/U\nIGxFzZsuLmiFlsJar6M5nEckTB3p25maWWaR8/0jvJRgsPnuoUrUoGDq87DMKCdk\nlw6by9fRAoGBANhnS9ko7Of+ntqIFR7xOG9p/oPATztgHkFxe4GbQ0leaDRTx3vE\ndQmUCnn24xtyVECaI9a4IV+LP1npw8niWUJ4pjgdAlkF4cCTu9sN+cBO15SfdACI\nzD1DaaHmpFCAWlpTo68VWlvWll6i2ncCkRJR1+q/C/yQz7asvl4AakElAoGBAMId\nxqMT2Sy9xLuHsrAoMUvBOkwaMYZH+IAb4DvUDjVIiKWjmonrmopS5Lpb+ALBKqZe\neVfD6HwWQqGwCFItToaEkZvrNfTapoNCHWWg001D49765UV5lMrArDbM1vXtFfM4\nDRYM6+Y6o/6QH8EBgXtyBxcYthIDBM3wBJa67xG1AoGAKTm8fFlMkIG0N4N3Kpbf\nnnH915GaRoBwIx2AXtd6QQ7oIRfYx95MQY/fUw7SgxcLr+btbulTCkWXwwRClUI2\nqPAdElGMcfMp56r9PaTy8EzUyu55heSJrB4ckIhEw0VAcTa/1wnlVduSd+LkZYmq\no2fOD11n5iycNXvBJF1F4LUCgYAMaRbwCi7SW3eefbiA5rDwJPRzNSGBckyC9EVL\nzezynyaNYH5a3wNMYKxa9dJPasYtSND9OXs9o7ay26xMhLUGiKc+jrUuaGRI9Asp\nGjUoNXT2JphN7s4CgHsCLep4YqYKnMTJah4S5CDj/5boIg6DM/EcGupZEHRYLkY8\n1MrAGQKBgQCi9yeC39ctLUNn+Ix604gttWWChdt3ozufTZ7HybJOSRA9Gh3iD5gm\nzlz0xqpGShKpOY2k+ftvja0poMdGeJLt84P3r2q01IgI7w0LmOj5m0W10dHysH27\nBWpCnHdBJMxnBsMRPoM4MKkmKWD9l5PSTCTWtkIpsyuDCko6D9UwZA==\n-----END RSA PRIVATE KEY-----\n",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkF3MX59OrlBs3dH5CU7lNmvpbrgZxSpyGjlnE8Flkirnc/Up22lpjznoxqeoTAwTW034k7Dz6aYIrZGmQwe2TkE084yqvlj45Dkyoj95fW/sZacm0cZNuL69EObEGHdprfGJQajrpz22NQoCD8TFB8Wv+8om9NH9Le6s+WPe98WC77KLw8qgfQsbIey+JawPWl4O67ZdL5xrypuRjfIPWjgy/VH85IXg/Z/GONZ2nxHgSShMkwqSFECAC5L3PHB+0+/12M/iikdatFSVGjpuHvkLOs3oe7m6HlOfluSJ85BzLWBbvva93qkGmLg4ZAc8rPh2O+YIsBUHNLLMM/oQp Generated-by-Nova\n",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.34",
|
||||
"version": "2.35",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.34",
|
||||
"version": "2.35",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
os-Migratelive Action does not throw badRequest in case of
|
||||
pre-checks failure. Verification result is available over
|
||||
instance-actions.
|
||||
* 2.35 - Adds keypairs pagination support.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
@ -95,7 +96,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
# Note(cyeoh): This only applies for the v2.1 API once microversions
|
||||
# support is fully merged. It does not affect the V2 API.
|
||||
_MIN_API_VERSION = "2.1"
|
||||
_MAX_API_VERSION = "2.34"
|
||||
_MAX_API_VERSION = "2.35"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
@ -18,8 +18,10 @@
|
||||
import webob
|
||||
import webob.exc
|
||||
|
||||
from nova.api.openstack import api_version_request
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute.schemas import keypairs
|
||||
from nova.api.openstack.compute.views import keypairs as keypairs_view
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
@ -36,8 +38,12 @@ ALIAS = 'os-keypairs'
|
||||
class KeypairController(wsgi.Controller):
|
||||
|
||||
"""Keypair API controller for the OpenStack API."""
|
||||
|
||||
_view_builder_class = keypairs_view.ViewBuilder
|
||||
|
||||
def __init__(self):
|
||||
self.api = compute_api.KeypairAPI()
|
||||
super(KeypairController, self).__init__()
|
||||
|
||||
def _filter_keypair(self, keypair, **attrs):
|
||||
# TODO(claudiub): After v2 and v2.1 is no longer supported,
|
||||
@ -221,7 +227,13 @@ class KeypairController(wsgi.Controller):
|
||||
# behaviors in this keypair resource.
|
||||
return {'keypair': keypair}
|
||||
|
||||
@wsgi.Controller.api_version("2.10")
|
||||
@wsgi.Controller.api_version("2.35")
|
||||
@extensions.expected_errors(400)
|
||||
def index(self, req):
|
||||
user_id = self._get_user_id(req)
|
||||
return self._index(req, links=True, type=True, user_id=user_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.10", "2.34") # noqa
|
||||
@extensions.expected_errors(())
|
||||
def index(self, req):
|
||||
# handle optional user-id for admin only
|
||||
@ -238,20 +250,38 @@ class KeypairController(wsgi.Controller):
|
||||
def index(self, req):
|
||||
return self._index(req)
|
||||
|
||||
def _index(self, req, user_id=None, **keypair_filters):
|
||||
def _index(self, req, user_id=None, links=False, **keypair_filters):
|
||||
"""List of keypairs for a user."""
|
||||
context = req.environ['nova.context']
|
||||
user_id = user_id or context.user_id
|
||||
context.can(kp_policies.POLICY_ROOT % 'index',
|
||||
target={'user_id': user_id,
|
||||
'project_id': context.project_id})
|
||||
key_pairs = self.api.get_key_pairs(context, user_id)
|
||||
rval = []
|
||||
for key_pair in key_pairs:
|
||||
rval.append({'keypair': self._filter_keypair(key_pair,
|
||||
**keypair_filters)})
|
||||
|
||||
return {'keypairs': rval}
|
||||
if api_version_request.is_supported(req, min_version='2.35'):
|
||||
limit, marker = common.get_limit_and_marker(req)
|
||||
else:
|
||||
limit = marker = None
|
||||
|
||||
try:
|
||||
key_pairs = self.api.get_key_pairs(
|
||||
context, user_id, limit=limit, marker=marker)
|
||||
except exception.MarkerNotFound as e:
|
||||
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
||||
key_pairs = [self._filter_keypair(key_pair, **keypair_filters)
|
||||
for key_pair in key_pairs]
|
||||
|
||||
keypairs_list = [{'keypair': key_pair} for key_pair in key_pairs]
|
||||
keypairs_dict = {'keypairs': keypairs_list}
|
||||
|
||||
if links:
|
||||
keypairs_links = self._view_builder.get_links(req, key_pairs)
|
||||
|
||||
if keypairs_links:
|
||||
keypairs_dict['keypairs_links'] = keypairs_links
|
||||
|
||||
return keypairs_dict
|
||||
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
|
25
nova/api/openstack/compute/views/keypairs.py
Normal file
25
nova/api/openstack/compute/views/keypairs.py
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright 2016 Mirantis Inc
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nova.api.openstack import common
|
||||
|
||||
|
||||
class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
_collection_name = "keypairs"
|
||||
|
||||
def get_links(self, request, keypairs):
|
||||
return self._get_collection_links(request, keypairs,
|
||||
self._collection_name, 'name')
|
@ -350,3 +350,14 @@ user documentation.
|
||||
Checks in ``os-migrateLive`` before live-migration actually starts are now
|
||||
made in background. ``os-migrateLive`` is not throwing `400 Bad Request` if
|
||||
pre-live-migration checks fail.
|
||||
|
||||
2.35
|
||||
----
|
||||
|
||||
Added pagination support for keypairs.
|
||||
|
||||
Optional parameters 'limit' and 'marker' were added to GET /os-keypairs
|
||||
request, the default sort_key was changed to 'name' field as ASC order,
|
||||
the generic request format is::
|
||||
|
||||
GET /os-keypairs?limit={limit}&marker={kp_name}
|
||||
|
@ -3981,9 +3981,10 @@ class KeypairAPI(base.Base):
|
||||
objects.KeyPair.destroy_by_name(context, user_id, key_name)
|
||||
self._notify(context, 'delete.end', key_name)
|
||||
|
||||
def get_key_pairs(self, context, user_id):
|
||||
def get_key_pairs(self, context, user_id, limit=None, marker=None):
|
||||
"""List key pairs."""
|
||||
return objects.KeyPairList.get_by_user(context, user_id)
|
||||
return objects.KeyPairList.get_by_user(
|
||||
context, user_id, limit=limit, marker=marker)
|
||||
|
||||
def get_key_pair(self, context, user_id, key_name):
|
||||
"""Get a keypair by name."""
|
||||
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"public_key": "%(public_key)s"
|
||||
}
|
||||
}
|
||||
],
|
||||
"keypairs_links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/keypairs?limit=1&marker=%(keypair_name)s",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"public_key": "%(public_key)s"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"public_key": "%(public_key)s"
|
||||
}
|
||||
}
|
||||
],
|
||||
"keypairs_links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/keypairs?user_id=user2&limit=1&marker=%(keypair_name)s",
|
||||
"rel": "next"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"keypair": {
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"user_id": "%(user_id)s"
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"private_key": "%(private_key)s",
|
||||
"public_key": "%(public_key)s",
|
||||
"user_id": "%(user_id)s"
|
||||
}
|
||||
}
|
@ -210,3 +210,76 @@ class KeyPairsV210SampleJsonTestNotAdmin(KeyPairsV210SampleJsonTest):
|
||||
response = self._do_post('os-keypairs', 'keypairs-post-req', subs)
|
||||
|
||||
self.assertEqual(403, response.status_code)
|
||||
|
||||
|
||||
class KeyPairsV235SampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
||||
ADMIN_API = True
|
||||
sample_dir = "keypairs"
|
||||
microversion = '2.35'
|
||||
expected_post_status_code = 201
|
||||
scenarios = [('v2_35', {'api_major_version': 'v2.1'})]
|
||||
|
||||
def setUp(self):
|
||||
super(KeyPairsV235SampleJsonTest, self).setUp()
|
||||
self.api.microversion = self.microversion
|
||||
|
||||
# TODO(pkholkin): this is only needed because we randomly choose the
|
||||
# uuid each time.
|
||||
def generalize_subs(self, subs, vanilla_regexes):
|
||||
subs['keypair_name'] = 'keypair-[0-9a-f-]+'
|
||||
return subs
|
||||
|
||||
def test_keypairs_post(self, user="admin", kp_name=None):
|
||||
return self._check_keypairs_post(
|
||||
keypair_type=keypair_obj.KEYPAIR_TYPE_SSH,
|
||||
user_id=user, kp_name=kp_name)
|
||||
|
||||
def _check_keypairs_post(self, **kwargs):
|
||||
"""Get api sample of key pairs post request."""
|
||||
key_name = kwargs.pop('kp_name')
|
||||
if not key_name:
|
||||
key_name = 'keypair-' + str(uuid.uuid4())
|
||||
|
||||
subs = dict(keypair_name=key_name, **kwargs)
|
||||
response = self._do_post('os-keypairs', 'keypairs-post-req', subs)
|
||||
subs = {'keypair_name': key_name}
|
||||
|
||||
self._verify_response('keypairs-post-resp', subs, response,
|
||||
self.expected_post_status_code)
|
||||
return key_name
|
||||
|
||||
def test_keypairs_list(self):
|
||||
# Get api sample of key pairs list request.
|
||||
|
||||
# sort key_pairs by name before paging
|
||||
keypairs = sorted([self.test_keypairs_post() for i in range(3)])
|
||||
|
||||
response = self._do_get('os-keypairs?marker=%s&limit=1' % keypairs[1])
|
||||
subs = {'keypair_name': keypairs[2]}
|
||||
self._verify_response('keypairs-list-resp', subs, response, 200)
|
||||
|
||||
def test_keypairs_list_for_different_users(self):
|
||||
# Get api sample of key pairs list request.
|
||||
|
||||
# create common kp_names for two users
|
||||
kp_names = ['keypair-' + str(uuid.uuid4()) for i in range(3)]
|
||||
|
||||
# sort key_pairs by name before paging
|
||||
keypairs_user1 = sorted([self.test_keypairs_post(
|
||||
user="user1", kp_name=kp_name) for kp_name in kp_names])
|
||||
keypairs_user2 = sorted([self.test_keypairs_post(
|
||||
user="user2", kp_name=kp_name) for kp_name in kp_names])
|
||||
|
||||
# get all keypairs after the second for user1
|
||||
response = self._do_get('os-keypairs?user_id=user1&marker=%s'
|
||||
% keypairs_user1[1])
|
||||
subs = {'keypair_name': keypairs_user1[2]}
|
||||
self._verify_response(
|
||||
'keypairs-list-user1-resp', subs, response, 200)
|
||||
|
||||
# get only one keypair after the second for user2
|
||||
response = self._do_get('os-keypairs?user_id=user2&marker=%s&limit=1'
|
||||
% keypairs_user2[1])
|
||||
subs = {'keypair_name': keypairs_user2[2]}
|
||||
self._verify_response(
|
||||
'keypairs-list-user2-resp', subs, response, 200)
|
||||
|
@ -562,3 +562,43 @@ class KeypairsTestV210(KeypairsTestV22):
|
||||
self.assertRaises(exception.PolicyNotAuthorized,
|
||||
self.controller.create,
|
||||
req, body=body)
|
||||
|
||||
|
||||
class KeypairsTestV235(test.TestCase):
|
||||
base_url = '/v2/fake'
|
||||
wsgi_api_version = '2.35'
|
||||
|
||||
def _setup_app_and_controller(self):
|
||||
self.app_server = fakes.wsgi_app_v21(init_only=('os-keypairs'))
|
||||
self.controller = keypairs_v21.KeypairController()
|
||||
|
||||
def setUp(self):
|
||||
super(KeypairsTestV235, self).setUp()
|
||||
self._setup_app_and_controller()
|
||||
|
||||
@mock.patch("nova.db.key_pair_get_all_by_user")
|
||||
def test_keypair_list_limit_and_marker(self, mock_kp_get):
|
||||
mock_kp_get.side_effect = db_key_pair_get_all_by_user
|
||||
|
||||
req = fakes.HTTPRequest.blank(
|
||||
self.base_url + '/os-keypairs?limit=3&marker=fake_marker',
|
||||
version=self.wsgi_api_version, use_admin_context=True)
|
||||
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
mock_kp_get.assert_called_once_with(
|
||||
req.environ['nova.context'], 'fake_user',
|
||||
limit=3, marker='fake_marker')
|
||||
response = {'keypairs': [{'keypair': dict(keypair_data, name='FAKE',
|
||||
type='ssh')}]}
|
||||
self.assertEqual(res_dict, response)
|
||||
|
||||
@mock.patch('nova.compute.api.KeypairAPI.get_key_pairs')
|
||||
def test_keypair_list_limit_and_marker_invalid_marker(self, mock_kp_get):
|
||||
mock_kp_get.side_effect = exception.MarkerNotFound(marker='unknown_kp')
|
||||
|
||||
req = fakes.HTTPRequest.blank(
|
||||
self.base_url + '/os-keypairs?limit=3&marker=unknown_kp',
|
||||
version=self.wsgi_api_version, use_admin_context=True)
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req)
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- Added microversion v2.35 that adds pagination support for keypairs with
|
||||
the help of new optional parameters 'limit' and 'marker' which were added
|
||||
to GET /os-keypairs request.
|
Loading…
Reference in New Issue
Block a user