Merge "Microversion 2.35 adds keypairs pagination support"
This commit is contained in:
commit
29f82ad191
api-ref/source
doc/api_samples
keypairs/v2.35
keypairs-list-resp.jsonkeypairs-list-user1-resp.jsonkeypairs-list-user2-resp.jsonkeypairs-post-req.jsonkeypairs-post-resp.json
versions
nova
api/openstack
compute
tests
functional/api_sample_tests
api_samples/keypairs/v2.35
keypairs-list-resp.json.tplkeypairs-list-user1-resp.json.tplkeypairs-list-user2-resp.json.tplkeypairs-post-req.json.tplkeypairs-post-resp.json.tpl
test_keypairs.pyunit/api/openstack/compute
releasenotes/notes
@ -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."""
|
||||
|
18
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-list-resp.json.tpl
Normal file
18
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-list-resp.json.tpl
Normal file
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
12
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-list-user1-resp.json.tpl
Normal file
12
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-list-user1-resp.json.tpl
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"public_key": "%(public_key)s"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
18
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-list-user2-resp.json.tpl
Normal file
18
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-list-user2-resp.json.tpl
Normal file
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
7
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-post-req.json.tpl
Normal file
7
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-post-req.json.tpl
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"keypair": {
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"user_id": "%(user_id)s"
|
||||
}
|
||||
}
|
10
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-post-resp.json.tpl
Normal file
10
nova/tests/functional/api_sample_tests/api_samples/keypairs/v2.35/keypairs-post-resp.json.tpl
Normal file
@ -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…
x
Reference in New Issue
Block a user