Fix H405 (multi line docstring) warnings (openstack_dashboard)
H405: multi line docstring summary not separated with an empty line Closes-Bug: #1696996 Change-Id: Id895695663b19522d9cdc22f8b012e49680d708b
This commit is contained in:
parent
95629a337e
commit
b9d0243c33
@ -199,8 +199,10 @@ class Quota(object):
|
|||||||
|
|
||||||
|
|
||||||
class QuotaSet(Sequence):
|
class QuotaSet(Sequence):
|
||||||
"""Wrapper for client QuotaSet objects which turns the individual quotas
|
"""Wrapper for client QuotaSet objects.
|
||||||
into Quota objects for easier handling/iteration.
|
|
||||||
|
This turns the individual quotas into Quota objects
|
||||||
|
for easier handling/iteration.
|
||||||
|
|
||||||
`QuotaSet` objects support a mix of `list` and `dict` methods; you can use
|
`QuotaSet` objects support a mix of `list` and `dict` methods; you can use
|
||||||
the bracket notation (`qs["my_quota"] = 0`) to add new quota values, and
|
the bracket notation (`qs["my_quota"] = 0`) to add new quota values, and
|
||||||
@ -229,8 +231,9 @@ class QuotaSet(Sequence):
|
|||||||
return self.items[index]
|
return self.items[index]
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
"""Merge another QuotaSet into this one. Existing quotas are
|
"""Merge another QuotaSet into this one.
|
||||||
not overridden.
|
|
||||||
|
Existing quotas are not overridden.
|
||||||
"""
|
"""
|
||||||
if not isinstance(other, QuotaSet):
|
if not isinstance(other, QuotaSet):
|
||||||
msg = "Can only add QuotaSet to QuotaSet, " \
|
msg = "Can only add QuotaSet to QuotaSet, " \
|
||||||
|
@ -253,7 +253,9 @@ def update_pagination(entities, page_size, marker, sort_dir):
|
|||||||
@profiler.trace
|
@profiler.trace
|
||||||
def volume_list_paged(request, search_opts=None, marker=None, paginate=False,
|
def volume_list_paged(request, search_opts=None, marker=None, paginate=False,
|
||||||
sort_dir="desc"):
|
sort_dir="desc"):
|
||||||
"""To see all volumes in the cloud as an admin you can pass in a special
|
"""List volumes with pagination.
|
||||||
|
|
||||||
|
To see all volumes in the cloud as an admin you can pass in a special
|
||||||
search option: {'all_tenants': 1}
|
search option: {'all_tenants': 1}
|
||||||
"""
|
"""
|
||||||
has_more_data = False
|
has_more_data = False
|
||||||
@ -611,8 +613,7 @@ def volume_cg_snapshot_delete(request, cg_snapshot_id):
|
|||||||
|
|
||||||
@memoized
|
@memoized
|
||||||
def volume_backup_supported(request):
|
def volume_backup_supported(request):
|
||||||
"""This method will determine if cinder supports backup.
|
"""This method will determine if cinder supports backup."""
|
||||||
"""
|
|
||||||
# TODO(lcheng) Cinder does not expose the information if cinder
|
# TODO(lcheng) Cinder does not expose the information if cinder
|
||||||
# backup is configured yet. This is a workaround until that
|
# backup is configured yet. This is a workaround until that
|
||||||
# capability is available.
|
# capability is available.
|
||||||
@ -970,8 +971,7 @@ def list_extensions(cinder_api):
|
|||||||
|
|
||||||
@memoized_with_request(list_extensions)
|
@memoized_with_request(list_extensions)
|
||||||
def extension_supported(extensions, extension_name):
|
def extension_supported(extensions, extension_name):
|
||||||
"""This method will determine if Cinder supports a given extension name.
|
"""This method will determine if Cinder supports a given extension name."""
|
||||||
"""
|
|
||||||
for extension in extensions:
|
for extension in extensions:
|
||||||
if extension.name == extension_name:
|
if extension.name == extension_name:
|
||||||
return True
|
return True
|
||||||
@ -980,7 +980,9 @@ def extension_supported(extensions, extension_name):
|
|||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
def transfer_list(request, detailed=True, search_opts=None):
|
def transfer_list(request, detailed=True, search_opts=None):
|
||||||
"""To see all volumes transfers as an admin pass in a special
|
"""List volume transfers.
|
||||||
|
|
||||||
|
To see all volumes transfers as an admin pass in a special
|
||||||
search option: {'all_tenants': 1}
|
search option: {'all_tenants': 1}
|
||||||
"""
|
"""
|
||||||
c_client = cinderclient(request)
|
c_client = cinderclient(request)
|
||||||
|
@ -239,9 +239,7 @@ def image_delete(request, image_id):
|
|||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
def image_get(request, image_id):
|
def image_get(request, image_id):
|
||||||
"""Returns an Image object populated with metadata for image
|
"""Returns an Image object populated with metadata for a given image."""
|
||||||
with supplied identifier.
|
|
||||||
"""
|
|
||||||
image = glanceclient(request).images.get(image_id)
|
image = glanceclient(request).images.get(image_id)
|
||||||
return Image(image)
|
return Image(image)
|
||||||
|
|
||||||
@ -525,8 +523,9 @@ class Namespace(BaseGlanceMetadefAPIResourceWrapper):
|
|||||||
def filter_properties_target(namespaces_iter,
|
def filter_properties_target(namespaces_iter,
|
||||||
resource_types,
|
resource_types,
|
||||||
properties_target):
|
properties_target):
|
||||||
"""Filter metadata namespaces based on the given resource types and
|
"""Filter metadata namespaces.
|
||||||
properties target.
|
|
||||||
|
Filtering is done based ongiven resource types and a properties target.
|
||||||
|
|
||||||
:param namespaces_iter: Metadata namespaces iterable.
|
:param namespaces_iter: Metadata namespaces iterable.
|
||||||
:param resource_types: List of resource type names.
|
:param resource_types: List of resource type names.
|
||||||
|
@ -311,8 +311,9 @@ def get_default_domain(request, get_name=True):
|
|||||||
|
|
||||||
|
|
||||||
def get_effective_domain_id(request):
|
def get_effective_domain_id(request):
|
||||||
"""Gets the id of the default domain to use when creating Identity
|
"""Gets the id of the default domain.
|
||||||
objects. If the requests default domain is the same as DEFAULT_DOMAIN,
|
|
||||||
|
If the requests default domain is the same as DEFAULT_DOMAIN,
|
||||||
return None.
|
return None.
|
||||||
"""
|
"""
|
||||||
default_domain = get_default_domain(request)
|
default_domain = get_default_domain(request)
|
||||||
|
@ -225,8 +225,9 @@ class FlavorExtraSpec(object):
|
|||||||
|
|
||||||
|
|
||||||
def get_auth_params_from_request(request):
|
def get_auth_params_from_request(request):
|
||||||
"""Extracts the properties from the request object needed by the novaclient
|
"""Extracts properties needed by novaclient call from the request object.
|
||||||
call below. These will be used to memoize the calls to novaclient
|
|
||||||
|
These will be used to memoize the calls to novaclient.
|
||||||
"""
|
"""
|
||||||
return (
|
return (
|
||||||
request.user.username,
|
request.user.username,
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""API over the cinder service.
|
"""API over the cinder service."""
|
||||||
"""
|
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
@ -28,14 +27,12 @@ CLIENT_KEYWORDS = {'marker', 'sort_dir', 'paginate'}
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Volumes(generic.View):
|
class Volumes(generic.View):
|
||||||
"""API for cinder volumes.
|
"""API for cinder volumes."""
|
||||||
"""
|
|
||||||
url_regex = r'cinder/volumes/$'
|
url_regex = r'cinder/volumes/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a detailed list of volumes associated with the current user's
|
"""Get a detailed list of volumes associated with the current project.
|
||||||
project.
|
|
||||||
|
|
||||||
Example GET:
|
Example GET:
|
||||||
http://localhost/api/cinder/volumes?paginate=true&sort_dir=asc
|
http://localhost/api/cinder/volumes?paginate=true&sort_dir=asc
|
||||||
@ -99,8 +96,7 @@ class Volumes(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Volume(generic.View):
|
class Volume(generic.View):
|
||||||
"""API for cinder volume.
|
"""API for cinder volume."""
|
||||||
"""
|
|
||||||
url_regex = r'cinder/volumes/(?P<volume_id>[^/]+)/$'
|
url_regex = r'cinder/volumes/(?P<volume_id>[^/]+)/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -118,8 +114,7 @@ class Volume(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class VolumeTypes(generic.View):
|
class VolumeTypes(generic.View):
|
||||||
"""API for volume types.
|
"""API for volume types."""
|
||||||
"""
|
|
||||||
url_regex = r'cinder/volumetypes/$'
|
url_regex = r'cinder/volumetypes/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -162,8 +157,7 @@ class VolumeMetadata(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class VolumeType(generic.View):
|
class VolumeType(generic.View):
|
||||||
"""API for getting a volume type.
|
"""API for getting a volume type."""
|
||||||
"""
|
|
||||||
url_regex = r'cinder/volumetypes/(?P<volumetype_id>[^/]+)/$'
|
url_regex = r'cinder/volumetypes/(?P<volumetype_id>[^/]+)/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -189,14 +183,12 @@ class VolumeType(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class VolumeSnapshots(generic.View):
|
class VolumeSnapshots(generic.View):
|
||||||
"""API for cinder volume snapshots.
|
"""API for cinder volume snapshots."""
|
||||||
"""
|
|
||||||
url_regex = r'cinder/volumesnapshots/$'
|
url_regex = r'cinder/volumesnapshots/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a detailed list of volume snapshots associated with the current
|
"""Get a list of volume snapshots associated with the current project.
|
||||||
user's project.
|
|
||||||
|
|
||||||
The listing result is an object with property "items".
|
The listing result is an object with property "items".
|
||||||
"""
|
"""
|
||||||
@ -277,8 +269,7 @@ class VolumeTypeMetadata(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Extensions(generic.View):
|
class Extensions(generic.View):
|
||||||
"""API for cinder extensions.
|
# API for cinder extensions.
|
||||||
"""
|
|
||||||
url_regex = r'cinder/extensions/$'
|
url_regex = r'cinder/extensions/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -324,13 +315,13 @@ class TenantAbsoluteLimits(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Services(generic.View):
|
class Services(generic.View):
|
||||||
"""API for cinder services.
|
"""API for cinder services."""
|
||||||
"""
|
|
||||||
url_regex = r'cinder/services/$'
|
url_regex = r'cinder/services/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a list of cinder services.
|
"""Get a list of cinder services.
|
||||||
|
|
||||||
Will return HTTP 501 status code if the service_list extension is
|
Will return HTTP 501 status code if the service_list extension is
|
||||||
not supported.
|
not supported.
|
||||||
"""
|
"""
|
||||||
@ -352,8 +343,7 @@ class Services(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class DefaultQuotaSets(generic.View):
|
class DefaultQuotaSets(generic.View):
|
||||||
"""API for getting default quotas for cinder
|
"""API for getting default quotas for cinder"""
|
||||||
"""
|
|
||||||
url_regex = r'cinder/quota-sets/defaults/$'
|
url_regex = r'cinder/quota-sets/defaults/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -400,8 +390,7 @@ class DefaultQuotaSets(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class QuotaSets(generic.View):
|
class QuotaSets(generic.View):
|
||||||
"""API for setting quotas for a given project.
|
"""API for setting quotas for a given project."""
|
||||||
"""
|
|
||||||
url_regex = r'cinder/quota-sets/(?P<project_id>[0-9a-f]+)$'
|
url_regex = r'cinder/quota-sets/(?P<project_id>[0-9a-f]+)$'
|
||||||
|
|
||||||
@rest_utils.ajax(data_required=True)
|
@rest_utils.ajax(data_required=True)
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""API for the glance service.
|
"""API for the glance service."""
|
||||||
"""
|
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
@ -29,21 +28,18 @@ CLIENT_KEYWORDS = {'resource_type', 'marker',
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Version(generic.View):
|
class Version(generic.View):
|
||||||
"""API for active glance version.
|
"""API for active glance version."""
|
||||||
"""
|
|
||||||
url_regex = r'glance/version/$'
|
url_regex = r'glance/version/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get active glance version.
|
"""Get active glance version."""
|
||||||
"""
|
|
||||||
return {'version': str(api.glance.get_version())}
|
return {'version': str(api.glance.get_version())}
|
||||||
|
|
||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Image(generic.View):
|
class Image(generic.View):
|
||||||
"""API for retrieving a single image
|
"""API for retrieving a single image"""
|
||||||
"""
|
|
||||||
url_regex = r'glance/images/(?P<image_id>[^/]+|default)/$'
|
url_regex = r'glance/images/(?P<image_id>[^/]+|default)/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -95,14 +91,12 @@ class Image(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class ImageProperties(generic.View):
|
class ImageProperties(generic.View):
|
||||||
"""API for retrieving only a custom properties of single image.
|
"""API for retrieving only a custom properties of single image."""
|
||||||
"""
|
|
||||||
url_regex = r'glance/images/(?P<image_id>[^/]+)/properties/'
|
url_regex = r'glance/images/(?P<image_id>[^/]+)/properties/'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request, image_id):
|
def get(self, request, image_id):
|
||||||
"""Get custom properties of specific image.
|
"""Get custom properties of specific image."""
|
||||||
"""
|
|
||||||
return api.glance.image_get(request, image_id).properties
|
return api.glance.image_get(request, image_id).properties
|
||||||
|
|
||||||
@rest_utils.ajax(data_required=True)
|
@rest_utils.ajax(data_required=True)
|
||||||
@ -123,8 +117,7 @@ class UploadObjectForm(forms.Form):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Images(generic.View):
|
class Images(generic.View):
|
||||||
"""API for Glance images.
|
"""API for Glance images."""
|
||||||
"""
|
|
||||||
url_regex = r'glance/images/$'
|
url_regex = r'glance/images/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""API for the heat service.
|
"""API for the heat service."""
|
||||||
"""
|
|
||||||
|
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
|
||||||
@ -21,8 +20,7 @@ from openstack_dashboard.api.rest import utils as rest_utils
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Validate(generic.View):
|
class Validate(generic.View):
|
||||||
"""API for validating a template
|
"""API for validating a template"""
|
||||||
"""
|
|
||||||
url_regex = r'heat/validate/$'
|
url_regex = r'heat/validate/$'
|
||||||
|
|
||||||
@rest_utils.ajax(data_required=True)
|
@rest_utils.ajax(data_required=True)
|
||||||
@ -40,14 +38,12 @@ class Validate(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Services(generic.View):
|
class Services(generic.View):
|
||||||
"""API for heat services.
|
"""API for heat services."""
|
||||||
"""
|
|
||||||
url_regex = r'heat/services/$'
|
url_regex = r'heat/services/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a list of heat services.
|
"""Get a list of heat services."""
|
||||||
"""
|
|
||||||
if api.base.is_service_enabled(request, 'orchestration'):
|
if api.base.is_service_enabled(request, 'orchestration'):
|
||||||
result = api.heat.service_list(request)
|
result = api.heat.service_list(request)
|
||||||
return {'items': [u.to_dict() for u in result]}
|
return {'items': [u.to_dict() for u in result]}
|
||||||
|
@ -25,7 +25,9 @@ class NaNJSONEncoder(json.JSONEncoder):
|
|||||||
super(NaNJSONEncoder, self).__init__(**kwargs)
|
super(NaNJSONEncoder, self).__init__(**kwargs)
|
||||||
|
|
||||||
def iterencode(self, o, _one_shot=False):
|
def iterencode(self, o, _one_shot=False):
|
||||||
"""The sole purpose of defining a custom JSONEncoder class is to
|
"""JSON encoder with NaN and float inf support.
|
||||||
|
|
||||||
|
The sole purpose of defining a custom JSONEncoder class is to
|
||||||
override floatstr() inner function, or more specifically the
|
override floatstr() inner function, or more specifically the
|
||||||
representation of NaN and +/-float('inf') values in a JSON. Although
|
representation of NaN and +/-float('inf') values in a JSON. Although
|
||||||
Infinity values are not supported by JSON standard, we still can
|
Infinity values are not supported by JSON standard, we still can
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""API over the keystone service.
|
"""API over the keystone service."""
|
||||||
"""
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import django.http
|
import django.http
|
||||||
@ -25,21 +24,18 @@ from openstack_dashboard.api.rest import utils as rest_utils
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Version(generic.View):
|
class Version(generic.View):
|
||||||
"""API for active keystone version.
|
"""API for active keystone version."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/version/$'
|
url_regex = r'keystone/version/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get active keystone version.
|
"""Get active keystone version."""
|
||||||
"""
|
|
||||||
return {'version': str(api.keystone.get_version())}
|
return {'version': str(api.keystone.get_version())}
|
||||||
|
|
||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Users(generic.View):
|
class Users(generic.View):
|
||||||
"""API for keystone users.
|
"""API for keystone users."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/users/$'
|
url_regex = r'keystone/users/$'
|
||||||
client_keywords = {'project_id', 'domain_id', 'group_id'}
|
client_keywords = {'project_id', 'domain_id', 'group_id'}
|
||||||
|
|
||||||
@ -113,8 +109,7 @@ class Users(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class User(generic.View):
|
class User(generic.View):
|
||||||
"""API for a single keystone user.
|
"""API for a single keystone user."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/users/(?P<id>[0-9a-f]+|current)$'
|
url_regex = r'keystone/users/(?P<id>[0-9a-f]+|current)$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -172,8 +167,7 @@ class User(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Roles(generic.View):
|
class Roles(generic.View):
|
||||||
"""API over all roles.
|
"""API over all roles."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/roles/$'
|
url_regex = r'keystone/roles/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -230,8 +224,7 @@ class Roles(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Role(generic.View):
|
class Role(generic.View):
|
||||||
"""API for a single role.
|
"""API for a single role."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/roles/(?P<id>[0-9a-f]+|default)$'
|
url_regex = r'keystone/roles/(?P<id>[0-9a-f]+|default)$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -269,8 +262,7 @@ class Role(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Domains(generic.View):
|
class Domains(generic.View):
|
||||||
"""API over all domains.
|
"""API over all domains."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/domains/$'
|
url_regex = r'keystone/domains/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -321,8 +313,7 @@ class Domains(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Domain(generic.View):
|
class Domain(generic.View):
|
||||||
"""API over a single domains.
|
"""API over a single domains."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/domains/(?P<id>[0-9a-f]+|default)$'
|
url_regex = r'keystone/domains/(?P<id>[0-9a-f]+|default)$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -477,8 +468,7 @@ class Project(generic.View):
|
|||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request, id):
|
def get(self, request, id):
|
||||||
"""Get a specific project by id.
|
"""Get a specific project by id."""
|
||||||
"""
|
|
||||||
return api.keystone.tenant_get(request, id).to_dict()
|
return api.keystone.tenant_get(request, id).to_dict()
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -532,16 +522,13 @@ class ServiceCatalog(generic.View):
|
|||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Return the Keystone service catalog associated with the current
|
"""Return the service catalog associated with the current user."""
|
||||||
user.
|
|
||||||
"""
|
|
||||||
return request.user.service_catalog
|
return request.user.service_catalog
|
||||||
|
|
||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class UserSession(generic.View):
|
class UserSession(generic.View):
|
||||||
"""API for a single keystone user.
|
"""API for a single keystone user."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/user-session/$'
|
url_regex = r'keystone/user-session/$'
|
||||||
allowed_fields = {
|
allowed_fields = {
|
||||||
'available_services_regions',
|
'available_services_regions',
|
||||||
@ -561,8 +548,7 @@ class UserSession(generic.View):
|
|||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get the current user session.
|
"""Get the current user session."""
|
||||||
"""
|
|
||||||
res = {k: getattr(request.user, k, None) for k in self.allowed_fields}
|
res = {k: getattr(request.user, k, None) for k in self.allowed_fields}
|
||||||
if getattr(settings, 'ENABLE_CLIENT_TOKEN', True):
|
if getattr(settings, 'ENABLE_CLIENT_TOKEN', True):
|
||||||
res['token'] = request.user.token.id
|
res['token'] = request.user.token.id
|
||||||
@ -571,14 +557,12 @@ class UserSession(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Services(generic.View):
|
class Services(generic.View):
|
||||||
"""API for keystone services.
|
"""API for keystone services."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/services/$'
|
url_regex = r'keystone/services/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a list of keystone services.
|
"""Get a list of keystone services."""
|
||||||
"""
|
|
||||||
region = request.user.services_region
|
region = request.user.services_region
|
||||||
services = []
|
services = []
|
||||||
for i, service in enumerate(request.user.service_catalog):
|
for i, service in enumerate(request.user.service_catalog):
|
||||||
@ -591,13 +575,13 @@ class Services(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Groups(generic.View):
|
class Groups(generic.View):
|
||||||
"""API over all groups.
|
"""API over all groups."""
|
||||||
"""
|
|
||||||
url_regex = r'keystone/groups/$'
|
url_regex = r'keystone/groups/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a list of groups.
|
"""Get a list of groups.
|
||||||
|
|
||||||
The listing result is an object with property "items".
|
The listing result is an object with property "items".
|
||||||
"""
|
"""
|
||||||
domain_context = request.session.get('domain_context')
|
domain_context = request.session.get('domain_context')
|
||||||
|
@ -13,8 +13,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""API for the network abstraction APIs.
|
"""API for the network abstraction APIs."""
|
||||||
"""
|
|
||||||
|
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
|
||||||
@ -49,8 +48,7 @@ class SecurityGroups(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class FloatingIP(generic.View):
|
class FloatingIP(generic.View):
|
||||||
"""API for a single floating IP address.
|
"""API for a single floating IP address."""
|
||||||
"""
|
|
||||||
url_regex = r'network/floatingip/$'
|
url_regex = r'network/floatingip/$'
|
||||||
|
|
||||||
@rest_utils.ajax(data_required=True)
|
@rest_utils.ajax(data_required=True)
|
||||||
@ -84,8 +82,7 @@ class FloatingIP(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class FloatingIPs(generic.View):
|
class FloatingIPs(generic.View):
|
||||||
"""API for floating IP addresses.
|
"""API for floating IP addresses."""
|
||||||
"""
|
|
||||||
url_regex = r'network/floatingips/$'
|
url_regex = r'network/floatingips/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -104,8 +101,7 @@ class FloatingIPs(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class FloatingIPPools(generic.View):
|
class FloatingIPPools(generic.View):
|
||||||
"""API for floating IP pools.
|
"""API for floating IP pools."""
|
||||||
"""
|
|
||||||
url_regex = r'network/floatingippools/$'
|
url_regex = r'network/floatingippools/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""API over the neutron service.
|
"""API over the neutron service."""
|
||||||
"""
|
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
@ -72,7 +71,8 @@ class Networks(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Subnets(generic.View):
|
class Subnets(generic.View):
|
||||||
"""API for Neutron SubNets
|
"""API for Neutron Subnets
|
||||||
|
|
||||||
http://developer.openstack.org/api-ref-networking-v2.html#subnets
|
http://developer.openstack.org/api-ref-networking-v2.html#subnets
|
||||||
"""
|
"""
|
||||||
url_regex = r'neutron/subnets/$'
|
url_regex = r'neutron/subnets/$'
|
||||||
@ -119,6 +119,7 @@ class Subnets(generic.View):
|
|||||||
@urls.register
|
@urls.register
|
||||||
class Ports(generic.View):
|
class Ports(generic.View):
|
||||||
"""API for Neutron Ports
|
"""API for Neutron Ports
|
||||||
|
|
||||||
http://developer.openstack.org/api-ref-networking-v2.html#ports
|
http://developer.openstack.org/api-ref-networking-v2.html#ports
|
||||||
"""
|
"""
|
||||||
url_regex = r'neutron/ports/$'
|
url_regex = r'neutron/ports/$'
|
||||||
@ -138,8 +139,7 @@ class Ports(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Trunks(generic.View):
|
class Trunks(generic.View):
|
||||||
"""API for neutron Trunks
|
"""API for neutron Trunks"""
|
||||||
"""
|
|
||||||
url_regex = r'neutron/trunks/$'
|
url_regex = r'neutron/trunks/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -155,14 +155,12 @@ class Trunks(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Services(generic.View):
|
class Services(generic.View):
|
||||||
"""API for Neutron agents
|
"""API for Neutron agents"""
|
||||||
"""
|
|
||||||
url_regex = r'neutron/agents/$'
|
url_regex = r'neutron/agents/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a list of agents
|
"""Get a list of agents"""
|
||||||
"""
|
|
||||||
if api.base.is_service_enabled(request, 'network') and \
|
if api.base.is_service_enabled(request, 'network') and \
|
||||||
api.neutron.is_extension_supported(request, 'agent'):
|
api.neutron.is_extension_supported(request, 'agent'):
|
||||||
result = api.neutron.agent_list(request, **request.GET)
|
result = api.neutron.agent_list(request, **request.GET)
|
||||||
@ -173,8 +171,7 @@ class Services(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Extensions(generic.View):
|
class Extensions(generic.View):
|
||||||
"""API for neutron extensions.
|
"""API for neutron extensions."""
|
||||||
"""
|
|
||||||
url_regex = r'neutron/extensions/$'
|
url_regex = r'neutron/extensions/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -192,8 +189,7 @@ class Extensions(generic.View):
|
|||||||
|
|
||||||
|
|
||||||
class DefaultQuotaSets(generic.View):
|
class DefaultQuotaSets(generic.View):
|
||||||
"""API for getting default quotas for neutron
|
"""API for getting default quotas for neutron"""
|
||||||
"""
|
|
||||||
url_regex = r'neutron/quota-sets/defaults/$'
|
url_regex = r'neutron/quota-sets/defaults/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -218,8 +214,7 @@ class DefaultQuotaSets(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class QuotasSets(generic.View):
|
class QuotasSets(generic.View):
|
||||||
"""API for setting quotas of a given project.
|
"""API for setting quotas of a given project."""
|
||||||
"""
|
|
||||||
url_regex = r'neutron/quotas-sets/(?P<project_id>[0-9a-f]+)$'
|
url_regex = r'neutron/quotas-sets/(?P<project_id>[0-9a-f]+)$'
|
||||||
|
|
||||||
@rest_utils.ajax(data_required=True)
|
@rest_utils.ajax(data_required=True)
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""API over the nova service.
|
"""API over the nova service."""
|
||||||
"""
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
@ -34,8 +33,7 @@ from openstack_dashboard.usage import quotas
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Snapshots(generic.View):
|
class Snapshots(generic.View):
|
||||||
"""API for nova snapshots.
|
"""API for nova snapshots."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/snapshots/$'
|
url_regex = r'nova/snapshots/$'
|
||||||
|
|
||||||
@rest_utils.ajax(data_required=True)
|
@rest_utils.ajax(data_required=True)
|
||||||
@ -50,14 +48,12 @@ class Snapshots(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Keypairs(generic.View):
|
class Keypairs(generic.View):
|
||||||
"""API for nova keypairs.
|
"""API for nova keypairs."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/keypairs/$'
|
url_regex = r'nova/keypairs/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a list of keypairs associated with the current logged-in
|
"""Get a list of keypairs associated with the current logged-in user.
|
||||||
account.
|
|
||||||
|
|
||||||
The listing result is an object with property "items".
|
The listing result is an object with property "items".
|
||||||
"""
|
"""
|
||||||
@ -130,13 +126,13 @@ class Keypair(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Services(generic.View):
|
class Services(generic.View):
|
||||||
"""API for nova services.
|
"""API for nova services."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/services/$'
|
url_regex = r'nova/services/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get a list of nova services.
|
"""Get a list of nova services.
|
||||||
|
|
||||||
Will return HTTP 501 status code if the service_list extension is
|
Will return HTTP 501 status code if the service_list extension is
|
||||||
not supported.
|
not supported.
|
||||||
"""
|
"""
|
||||||
@ -150,8 +146,7 @@ class Services(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class AvailabilityZones(generic.View):
|
class AvailabilityZones(generic.View):
|
||||||
"""API for nova availability zones.
|
"""API for nova availability zones."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/availzones/$'
|
url_regex = r'nova/availzones/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -173,8 +168,7 @@ class AvailabilityZones(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Limits(generic.View):
|
class Limits(generic.View):
|
||||||
"""API for nova limits.
|
"""API for nova limits."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/limits/$'
|
url_regex = r'nova/limits/$'
|
||||||
|
|
||||||
@rest_utils.ajax(json_encoder=json_encoder.NaNJSONEncoder)
|
@rest_utils.ajax(json_encoder=json_encoder.NaNJSONEncoder)
|
||||||
@ -199,8 +193,7 @@ class Limits(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class ServerActions(generic.View):
|
class ServerActions(generic.View):
|
||||||
"""API over all server actions.
|
"""API over all server actions."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/actions/$'
|
url_regex = r'nova/servers/(?P<server_id>[^/]+)/actions/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -219,8 +212,7 @@ class ServerActions(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class SecurityGroups(generic.View):
|
class SecurityGroups(generic.View):
|
||||||
"""API over all server security groups.
|
"""API over all server security groups."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/security-groups/$'
|
url_regex = r'nova/servers/(?P<server_id>[^/]+)/security-groups/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -239,8 +231,7 @@ class SecurityGroups(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Volumes(generic.View):
|
class Volumes(generic.View):
|
||||||
"""API over all server volumes.
|
"""API over all server volumes."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/volumes/$'
|
url_regex = r'nova/servers/(?P<server_id>[^/]+)/volumes/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -259,14 +250,12 @@ class Volumes(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class RemoteConsoleInfo(generic.View):
|
class RemoteConsoleInfo(generic.View):
|
||||||
"""API for remote console information.
|
"""API for remote console information."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-info/$'
|
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-info/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def post(self, request, server_id):
|
def post(self, request, server_id):
|
||||||
"""Gets information about an available remote console for the given
|
"""Gets information of a remote console for the given server.
|
||||||
server.
|
|
||||||
|
|
||||||
Example POST:
|
Example POST:
|
||||||
http://localhost/api/nova/servers/abcd/console-info/
|
http://localhost/api/nova/servers/abcd/console-info/
|
||||||
@ -317,8 +306,7 @@ class RemoteConsoleInfo(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class ConsoleOutput(generic.View):
|
class ConsoleOutput(generic.View):
|
||||||
"""API for console output.
|
"""API for console output."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-output/$'
|
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-output/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -339,8 +327,7 @@ class ConsoleOutput(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Servers(generic.View):
|
class Servers(generic.View):
|
||||||
"""API over all servers.
|
"""API over all servers."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servers/$'
|
url_regex = r'nova/servers/$'
|
||||||
|
|
||||||
_optional_create = [
|
_optional_create = [
|
||||||
@ -415,8 +402,7 @@ class Servers(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Server(generic.View):
|
class Server(generic.View):
|
||||||
"""API for retrieving a single server
|
"""API for retrieving a single server"""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servers/(?P<server_id>[^/]+|default)$'
|
url_regex = r'nova/servers/(?P<server_id>[^/]+|default)$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -429,8 +415,7 @@ class Server(generic.View):
|
|||||||
|
|
||||||
@rest_utils.ajax(data_required=True)
|
@rest_utils.ajax(data_required=True)
|
||||||
def post(self, request, server_id):
|
def post(self, request, server_id):
|
||||||
"""Perform a change to a server
|
"""Perform a change to a server"""
|
||||||
"""
|
|
||||||
operation = request.DATA.get('operation', 'none')
|
operation = request.DATA.get('operation', 'none')
|
||||||
operations = {
|
operations = {
|
||||||
'stop': api.nova.server_stop,
|
'stop': api.nova.server_stop,
|
||||||
@ -451,8 +436,7 @@ class Server(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class ServerGroups(generic.View):
|
class ServerGroups(generic.View):
|
||||||
"""API for nova server groups.
|
"""API for nova server groups."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servergroups/$'
|
url_regex = r'nova/servergroups/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -467,8 +451,7 @@ class ServerGroups(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class ServerMetadata(generic.View):
|
class ServerMetadata(generic.View):
|
||||||
"""API for server metadata.
|
"""API for server metadata."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/servers/(?P<server_id>[^/]+|default)/metadata$'
|
url_regex = r'nova/servers/(?P<server_id>[^/]+|default)/metadata$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -496,8 +479,7 @@ class ServerMetadata(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Extensions(generic.View):
|
class Extensions(generic.View):
|
||||||
"""API for nova extensions.
|
"""API for nova extensions."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/extensions/$'
|
url_regex = r'nova/extensions/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -516,8 +498,7 @@ class Extensions(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Flavors(generic.View):
|
class Flavors(generic.View):
|
||||||
"""API for nova flavors.
|
"""API for nova flavors."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/flavors/$'
|
url_regex = r'nova/flavors/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -580,8 +561,7 @@ class Flavors(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Flavor(generic.View):
|
class Flavor(generic.View):
|
||||||
"""API for retrieving a single flavor
|
"""API for retrieving a single flavor"""
|
||||||
"""
|
|
||||||
url_regex = r'nova/flavors/(?P<flavor_id>[^/]+)/$'
|
url_regex = r'nova/flavors/(?P<flavor_id>[^/]+)/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -654,8 +634,7 @@ class Flavor(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class FlavorExtraSpecs(generic.View):
|
class FlavorExtraSpecs(generic.View):
|
||||||
"""API for managing flavor extra specs
|
"""API for managing flavor extra specs"""
|
||||||
"""
|
|
||||||
url_regex = r'nova/flavors/(?P<flavor_id>[^/]+)/extra-specs/$'
|
url_regex = r'nova/flavors/(?P<flavor_id>[^/]+)/extra-specs/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -684,8 +663,7 @@ class FlavorExtraSpecs(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class AggregateExtraSpecs(generic.View):
|
class AggregateExtraSpecs(generic.View):
|
||||||
"""API for managing aggregate extra specs
|
"""API for managing aggregate extra specs"""
|
||||||
"""
|
|
||||||
url_regex = r'nova/aggregates/(?P<aggregate_id>[^/]+)/extra-specs/$'
|
url_regex = r'nova/aggregates/(?P<aggregate_id>[^/]+)/extra-specs/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -712,8 +690,7 @@ class AggregateExtraSpecs(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class DefaultQuotaSets(generic.View):
|
class DefaultQuotaSets(generic.View):
|
||||||
"""API for getting default quotas for nova
|
"""API for getting default quotas for nova"""
|
||||||
"""
|
|
||||||
url_regex = r'nova/quota-sets/defaults/$'
|
url_regex = r'nova/quota-sets/defaults/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -771,8 +748,7 @@ class DefaultQuotaSets(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class EditableQuotaSets(generic.View):
|
class EditableQuotaSets(generic.View):
|
||||||
"""API for editable quotas.
|
"""API for editable quotas."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/quota-sets/editable/$'
|
url_regex = r'nova/quota-sets/editable/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -791,8 +767,7 @@ class EditableQuotaSets(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class QuotaSets(generic.View):
|
class QuotaSets(generic.View):
|
||||||
"""API for setting quotas for a given project.
|
"""API for setting quotas for a given project."""
|
||||||
"""
|
|
||||||
url_regex = r'nova/quota-sets/(?P<project_id>[0-9a-f]+)$'
|
url_regex = r'nova/quota-sets/(?P<project_id>[0-9a-f]+)$'
|
||||||
|
|
||||||
@rest_utils.ajax(data_required=True)
|
@rest_utils.ajax(data_required=True)
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
"""API for the swift service.
|
"""API for the swift service."""
|
||||||
"""
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
@ -31,22 +31,19 @@ from openstack_dashboard.api import swift
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Info(generic.View):
|
class Info(generic.View):
|
||||||
"""API for information about the Swift installation.
|
"""API for information about the Swift installation."""
|
||||||
"""
|
|
||||||
url_regex = r'swift/info/$'
|
url_regex = r'swift/info/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get information about the Swift installation.
|
"""Get information about the Swift installation."""
|
||||||
"""
|
|
||||||
capabilities = api.swift.swift_get_capabilities(request)
|
capabilities = api.swift.swift_get_capabilities(request)
|
||||||
return {'info': capabilities}
|
return {'info': capabilities}
|
||||||
|
|
||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Containers(generic.View):
|
class Containers(generic.View):
|
||||||
"""API for swift container listing for an account
|
"""API for swift container listing for an account"""
|
||||||
"""
|
|
||||||
url_regex = r'swift/containers/$'
|
url_regex = r'swift/containers/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -71,15 +68,13 @@ class Containers(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Container(generic.View):
|
class Container(generic.View):
|
||||||
"""API for swift container level information
|
"""API for swift container level information"""
|
||||||
"""
|
|
||||||
|
|
||||||
url_regex = r'swift/containers/(?P<container>[^/]+)/metadata/$'
|
url_regex = r'swift/containers/(?P<container>[^/]+)/metadata/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
def get(self, request, container):
|
def get(self, request, container):
|
||||||
"""Get the container details
|
"""Get the container details"""
|
||||||
"""
|
|
||||||
return api.swift.swift_get_container(request, container).to_dict()
|
return api.swift.swift_get_container(request, container).to_dict()
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -117,8 +112,7 @@ class Container(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Objects(generic.View):
|
class Objects(generic.View):
|
||||||
"""API for a list of swift objects
|
"""API for a list of swift objects"""
|
||||||
"""
|
|
||||||
url_regex = r'swift/containers/(?P<container>[^/]+)/objects/$'
|
url_regex = r'swift/containers/(?P<container>[^/]+)/objects/$'
|
||||||
|
|
||||||
@rest_utils.ajax()
|
@rest_utils.ajax()
|
||||||
@ -158,8 +152,7 @@ class UploadObjectForm(forms.Form):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class Object(generic.View):
|
class Object(generic.View):
|
||||||
"""API for a single swift object or pseudo-folder
|
"""API for a single swift object or pseudo-folder"""
|
||||||
"""
|
|
||||||
url_regex = r'swift/containers/(?P<container>[^/]+)/object/' \
|
url_regex = r'swift/containers/(?P<container>[^/]+)/object/' \
|
||||||
'(?P<object_name>.+)$'
|
'(?P<object_name>.+)$'
|
||||||
|
|
||||||
@ -219,8 +212,7 @@ class Object(generic.View):
|
|||||||
api.swift.swift_delete_object(request, container, object_name)
|
api.swift.swift_delete_object(request, container, object_name)
|
||||||
|
|
||||||
def get(self, request, container, object_name):
|
def get(self, request, container, object_name):
|
||||||
"""Get the object contents.
|
"""Get the object contents."""
|
||||||
"""
|
|
||||||
obj = api.swift.swift_get_object(
|
obj = api.swift.swift_get_object(
|
||||||
request,
|
request,
|
||||||
container,
|
container,
|
||||||
@ -245,8 +237,7 @@ class Object(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class ObjectMetadata(generic.View):
|
class ObjectMetadata(generic.View):
|
||||||
"""API for a single swift object
|
"""API for a single swift object"""
|
||||||
"""
|
|
||||||
url_regex = r'swift/containers/(?P<container>[^/]+)/metadata/' \
|
url_regex = r'swift/containers/(?P<container>[^/]+)/metadata/' \
|
||||||
'(?P<object_name>.+)$'
|
'(?P<object_name>.+)$'
|
||||||
|
|
||||||
@ -262,8 +253,7 @@ class ObjectMetadata(generic.View):
|
|||||||
|
|
||||||
@urls.register
|
@urls.register
|
||||||
class ObjectCopy(generic.View):
|
class ObjectCopy(generic.View):
|
||||||
"""API to copy a swift object
|
"""API to copy a swift object"""
|
||||||
"""
|
|
||||||
url_regex = r'swift/containers/(?P<container>[^/]+)/copy/' \
|
url_regex = r'swift/containers/(?P<container>[^/]+)/copy/' \
|
||||||
'(?P<object_name>.+)$'
|
'(?P<object_name>.+)$'
|
||||||
|
|
||||||
|
@ -20,13 +20,13 @@ urlpatterns = []
|
|||||||
# @register below, and the import the endpoint module in the
|
# @register below, and the import the endpoint module in the
|
||||||
# rest_api/__init__.py module
|
# rest_api/__init__.py module
|
||||||
def register(view):
|
def register(view):
|
||||||
'''Register API views to respond to a regex pattern (url_regex on the
|
"""Register API views to respond to a regex pattern.
|
||||||
view class).
|
|
||||||
|
|
||||||
|
``url_regex`` on a wrapped view class is used as the regex pattern.
|
||||||
The view should be a standard Django class-based view implementing an
|
The view should be a standard Django class-based view implementing an
|
||||||
as_view() method. The url_regex attribute of the view should be a standard
|
as_view() method. The url_regex attribute of the view should be a standard
|
||||||
Django URL regex pattern.
|
Django URL regex pattern.
|
||||||
'''
|
"""
|
||||||
p = urls.url(view.url_regex, view.as_view())
|
p = urls.url(view.url_regex, view.as_view())
|
||||||
urlpatterns.append(p)
|
urlpatterns.append(p)
|
||||||
return view
|
return view
|
||||||
|
@ -75,7 +75,9 @@ class JSONResponse(_RestResponse):
|
|||||||
|
|
||||||
def ajax(authenticated=True, data_required=False,
|
def ajax(authenticated=True, data_required=False,
|
||||||
json_encoder=json.JSONEncoder):
|
json_encoder=json.JSONEncoder):
|
||||||
'''Provide a decorator to wrap a view method so that it may exist in an
|
"""Decorator to allow the wrappered view to exist in an AJAX environment.
|
||||||
|
|
||||||
|
Provide a decorator to wrap a view method so that it may exist in an
|
||||||
entirely AJAX environment:
|
entirely AJAX environment:
|
||||||
|
|
||||||
- data decoded from JSON as input and data coded as JSON as output
|
- data decoded from JSON as input and data coded as JSON as output
|
||||||
@ -98,7 +100,7 @@ def ajax(authenticated=True, data_required=False,
|
|||||||
|
|
||||||
Methods returning nothing (or None explicitly) will result in a 204 "NO
|
Methods returning nothing (or None explicitly) will result in a 204 "NO
|
||||||
CONTENT" being returned to the caller.
|
CONTENT" being returned to the caller.
|
||||||
'''
|
"""
|
||||||
def decorator(function, authenticated=authenticated,
|
def decorator(function, authenticated=authenticated,
|
||||||
data_required=data_required):
|
data_required=data_required):
|
||||||
@functools.wraps(function,
|
@functools.wraps(function,
|
||||||
@ -173,7 +175,9 @@ def parse_filters_kwargs(request, client_keywords=None):
|
|||||||
|
|
||||||
|
|
||||||
def post2data(func):
|
def post2data(func):
|
||||||
"""The sole purpose of this decorator is to restore original form values
|
"""Decorator to restore original form values along with their types.
|
||||||
|
|
||||||
|
The sole purpose of this decorator is to restore original form values
|
||||||
along with their types stored on client-side under key $$originalJSON.
|
along with their types stored on client-side under key $$originalJSON.
|
||||||
This in turn prevents the loss of field types when they are passed with
|
This in turn prevents the loss of field types when they are passed with
|
||||||
header 'Content-Type: multipart/form-data', which is needed to pass a
|
header 'Content-Type: multipart/form-data', which is needed to pass a
|
||||||
|
@ -71,9 +71,9 @@ class HypervisorViewTest(test.BaseAdminViewTests):
|
|||||||
'hypervisor_stats',
|
'hypervisor_stats',
|
||||||
'service_list')})
|
'service_list')})
|
||||||
def test_service_list_unavailable(self):
|
def test_service_list_unavailable(self):
|
||||||
"""test that error message should be returned when
|
# test that error message should be returned when
|
||||||
nova.service_list isn't available
|
# nova.service_list isn't available.
|
||||||
"""
|
|
||||||
hypervisors = self.hypervisors.list()
|
hypervisors = self.hypervisors.list()
|
||||||
stats = self.hypervisors.stats
|
stats = self.hypervisors.stats
|
||||||
api.nova.hypervisor_list(IsA(http.HttpRequest)).AndReturn(hypervisors)
|
api.nova.hypervisor_list(IsA(http.HttpRequest)).AndReturn(hypervisors)
|
||||||
|
@ -45,9 +45,8 @@ class ImageURLField(forms.URLField):
|
|||||||
|
|
||||||
|
|
||||||
def create_image_metadata(data):
|
def create_image_metadata(data):
|
||||||
"""Use the given dict of image form data to generate the metadata used for
|
"""Generate metadata dict for a new image from a given form data."""
|
||||||
creating the image in glance.
|
|
||||||
"""
|
|
||||||
# Glance does not really do anything with container_format at the
|
# Glance does not really do anything with container_format at the
|
||||||
# moment. It requires it is set to the same disk_format for the three
|
# moment. It requires it is set to the same disk_format for the three
|
||||||
# Amazon image types, otherwise it just treats them as 'bare.' As such
|
# Amazon image types, otherwise it just treats them as 'bare.' As such
|
||||||
|
@ -19,13 +19,12 @@ from openstack_dashboard.api import glance
|
|||||||
|
|
||||||
|
|
||||||
def get_available_images(request, project_id=None, images_cache=None):
|
def get_available_images(request, project_id=None, images_cache=None):
|
||||||
"""Returns a list of images that are public or owned by the given
|
"""Returns a list of images that are public or owned by the given project.
|
||||||
project_id. If project_id is not specified, only public images
|
|
||||||
are returned.
|
If project_id is not specified, only public images are returned.
|
||||||
|
|
||||||
:param images_cache: An optional dict-like object in which to
|
:param images_cache: An optional dict-like object in which to
|
||||||
cache public and per-project id image metadata.
|
cache public and per-project id image metadata.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if images_cache is None:
|
if images_cache is None:
|
||||||
images_cache = {}
|
images_cache = {}
|
||||||
|
@ -101,9 +101,6 @@ class DeleteInstance(policy.PolicyTargetMixin, tables.DeleteAction):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def allowed(self, request, instance=None):
|
def allowed(self, request, instance=None):
|
||||||
"""Allow delete action if instance is in error state or not currently
|
|
||||||
being deleted.
|
|
||||||
"""
|
|
||||||
error_state = False
|
error_state = False
|
||||||
if instance:
|
if instance:
|
||||||
error_state = (instance.status == 'ERROR')
|
error_state = (instance.status == 'ERROR')
|
||||||
|
@ -3920,9 +3920,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
|||||||
api.network: ('servers_update_addresses',),
|
api.network: ('servers_update_addresses',),
|
||||||
})
|
})
|
||||||
def test_index_form_action_with_pagination(self):
|
def test_index_form_action_with_pagination(self):
|
||||||
"""The form action on the next page should have marker
|
# The form action on the next page should have marker
|
||||||
object from the previous page last element.
|
# object from the previous page last element.
|
||||||
"""
|
|
||||||
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
|
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
|
||||||
servers = self.servers.list()[:3]
|
servers = self.servers.list()[:3]
|
||||||
|
|
||||||
@ -3984,9 +3984,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
|||||||
api.glance: ('image_list_detailed',),
|
api.glance: ('image_list_detailed',),
|
||||||
api.network: ('servers_update_addresses',)})
|
api.network: ('servers_update_addresses',)})
|
||||||
def test_delete_instance_with_pagination(self):
|
def test_delete_instance_with_pagination(self):
|
||||||
"""Instance should be deleted from
|
# Instance should be deleted from the next page.
|
||||||
the next page.
|
|
||||||
"""
|
|
||||||
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
|
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
|
||||||
servers = self.servers.list()[:3]
|
servers = self.servers.list()[:3]
|
||||||
server = servers[-1]
|
server = servers[-1]
|
||||||
|
@ -35,10 +35,10 @@ def flavor_list(request):
|
|||||||
|
|
||||||
def sort_flavor_list(request, flavors):
|
def sort_flavor_list(request, flavors):
|
||||||
"""Utility method to sort a list of flavors.
|
"""Utility method to sort a list of flavors.
|
||||||
By default, returns the available flavors, sorted by RAM
|
|
||||||
usage (ascending). Override these behaviours with a
|
By default, returns the available flavors, sorted by RAM usage (ascending).
|
||||||
CREATE_INSTANCE_FLAVOR_SORT dict
|
Override these behaviours with a ``CREATE_INSTANCE_FLAVOR_SORT`` dict
|
||||||
in local_settings.py.
|
in ``local_settings.py``.
|
||||||
"""
|
"""
|
||||||
def get_key(flavor, sort_key):
|
def get_key(flavor, sort_key):
|
||||||
try:
|
try:
|
||||||
|
@ -85,8 +85,10 @@ console_invalid_status = {
|
|||||||
|
|
||||||
|
|
||||||
class TranslationHelper(object):
|
class TranslationHelper(object):
|
||||||
"""Helper class to provide the translations of instances, networks,
|
"""Helper class to provide the translations.
|
||||||
routers and ports from other parts of the code to the network topology
|
|
||||||
|
This allows the network topology to access the translated strings
|
||||||
|
for various resources defined in other parts of the code.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# turn translation tuples into dicts for easy access
|
# turn translation tuples into dicts for easy access
|
||||||
|
@ -228,8 +228,7 @@ class SecurityGroupsViewTests(test.TestCase):
|
|||||||
self._create_security_group(sec_group)
|
self._create_security_group(sec_group)
|
||||||
|
|
||||||
def test_create_security_groups_special_chars(self):
|
def test_create_security_groups_special_chars(self):
|
||||||
"""Ensure that a group name is not restricted to alphanumeric
|
"""Ensure non-alphanumeric characters can be used as a group name.
|
||||||
characters.
|
|
||||||
|
|
||||||
bug #1233501 Security group names cannot contain at characters
|
bug #1233501 Security group names cannot contain at characters
|
||||||
bug #1224576 Security group names cannot contain spaces
|
bug #1224576 Security group names cannot contain spaces
|
||||||
|
@ -566,9 +566,6 @@ class DetachVolume(tables.BatchAction):
|
|||||||
|
|
||||||
|
|
||||||
class AttachedInstanceColumn(tables.WrappingColumn):
|
class AttachedInstanceColumn(tables.WrappingColumn):
|
||||||
"""Customized column class that does complex processing on the attachments
|
|
||||||
for a volume instance.
|
|
||||||
"""
|
|
||||||
def get_raw_data(self, attachment):
|
def get_raw_data(self, attachment):
|
||||||
request = self.table.request
|
request = self.table.request
|
||||||
return safestring.mark_safe(get_attachment_name(request, attachment))
|
return safestring.mark_safe(get_attachment_name(request, attachment))
|
||||||
|
@ -93,8 +93,9 @@ class BaseWebObject(unittest.TestCase):
|
|||||||
self.driver.implicitly_wait(self.conf.selenium.implicit_wait)
|
self.driver.implicitly_wait(self.conf.selenium.implicit_wait)
|
||||||
|
|
||||||
def _wait_until(self, predicate, timeout=None, poll_frequency=0.5):
|
def _wait_until(self, predicate, timeout=None, poll_frequency=0.5):
|
||||||
"""Wait until the value returned by predicate is not False or
|
"""Wait until the value returned by predicate is not False.
|
||||||
the timeout is elapsed.
|
|
||||||
|
It also returns when the timeout is elapsed.
|
||||||
'predicate' takes the driver as argument.
|
'predicate' takes the driver as argument.
|
||||||
"""
|
"""
|
||||||
if not timeout:
|
if not timeout:
|
||||||
@ -103,10 +104,12 @@ class BaseWebObject(unittest.TestCase):
|
|||||||
predicate)
|
predicate)
|
||||||
|
|
||||||
def _wait_till_text_present_in_element(self, element, texts, timeout=None):
|
def _wait_till_text_present_in_element(self, element, texts, timeout=None):
|
||||||
"""Waiting for a text to appear in a certain element very often is
|
"""Waiting for a text to appear in a certain element.
|
||||||
actually waiting for a _different_ element with a different text to
|
|
||||||
appear in place of an old element. So a way to avoid capturing stale
|
Most frequent usage is actually to wait for a _different_ element
|
||||||
element reference should be provided for this use case.
|
with a different text to appear in place of an old element.
|
||||||
|
So a way to avoid capturing stale element reference should be provided
|
||||||
|
for this use case.
|
||||||
|
|
||||||
Better to wrap getting entity status cell in a lambda
|
Better to wrap getting entity status cell in a lambda
|
||||||
to avoid problems with cell being replaced with totally different
|
to avoid problems with cell being replaced with totally different
|
||||||
|
@ -32,7 +32,9 @@ def _is_test_cls(cls):
|
|||||||
|
|
||||||
|
|
||||||
def _mark_method_skipped(meth, reason):
|
def _mark_method_skipped(meth, reason):
|
||||||
"""Mark method as skipped by replacing the actual method with wrapper
|
"""Decorate to mark method as skipped.
|
||||||
|
|
||||||
|
This marks method as skipped by replacing the actual method with wrapper
|
||||||
that raises the testtools.testcase.TestSkipped exception.
|
that raises the testtools.testcase.TestSkipped exception.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -71,8 +73,9 @@ def _get_skip_method(obj):
|
|||||||
|
|
||||||
|
|
||||||
def services_required(*req_services):
|
def services_required(*req_services):
|
||||||
"""Decorator for marking test's service requirements,
|
"""Decorator for marking test's service requirements.
|
||||||
if requirements are not met in the configuration file
|
|
||||||
|
If requirements are not met in the configuration file
|
||||||
test is marked as skipped.
|
test is marked as skipped.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@ -110,8 +113,9 @@ def services_required(*req_services):
|
|||||||
|
|
||||||
|
|
||||||
def _parse_compound_config_option_value(option_name):
|
def _parse_compound_config_option_value(option_name):
|
||||||
"""Parses the value of a given config option where option's section name is
|
"""Parses the value of a given config option.
|
||||||
separated from option name by '.'.
|
|
||||||
|
The section name of the option is separated from option name by '.'.
|
||||||
"""
|
"""
|
||||||
name_parts = option_name.split('.')
|
name_parts = option_name.split('.')
|
||||||
name_parts.reverse()
|
name_parts.reverse()
|
||||||
@ -163,8 +167,7 @@ def skip_because(**kwargs):
|
|||||||
|
|
||||||
|
|
||||||
def attach_video(func):
|
def attach_video(func):
|
||||||
"""Notify test runner to attach test video in any case
|
"""Notify test runner to attach test video in any case"""
|
||||||
"""
|
|
||||||
|
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def wrapper(self, *args, **kwgs):
|
def wrapper(self, *args, **kwgs):
|
||||||
|
@ -200,8 +200,9 @@ class BaseTestCase(testtools.TestCase):
|
|||||||
super(BaseTestCase, self).addOnException(wrapped_handler)
|
super(BaseTestCase, self).addOnException(wrapped_handler)
|
||||||
|
|
||||||
def _configure_log(self):
|
def _configure_log(self):
|
||||||
"""Configure log to capture test logs include selenium logs in order
|
"""Configure log to capture test logs include selenium logs.
|
||||||
to attach them if test will be broken.
|
|
||||||
|
This allows us to attach them if test will be broken.
|
||||||
"""
|
"""
|
||||||
# clear other handlers to set target handler
|
# clear other handlers to set target handler
|
||||||
ROOT_LOGGER.handlers[:] = []
|
ROOT_LOGGER.handlers[:] = []
|
||||||
@ -276,8 +277,10 @@ class BaseTestCase(testtools.TestCase):
|
|||||||
return rec(_log)
|
return rec(_log)
|
||||||
|
|
||||||
def zoom_out(self, times=3):
|
def zoom_out(self, times=3):
|
||||||
"""Zooming out prevents different elements being driven out of xvfb
|
"""Zooming out a specified element.
|
||||||
viewport (which in Selenium>=2.50.1 prevents interaction with them.
|
|
||||||
|
It prevents different elements being driven out of xvfb viewport
|
||||||
|
(which in Selenium>=2.50.1 prevents interaction with them).
|
||||||
"""
|
"""
|
||||||
html = self.driver.find_element(by.By.TAG_NAME, 'html')
|
html = self.driver.find_element(by.By.TAG_NAME, 'html')
|
||||||
html.send_keys(keys.Keys.NULL)
|
html.send_keys(keys.Keys.NULL)
|
||||||
|
@ -61,6 +61,7 @@ class MetadatadefinitionsPage(basepage.BaseNavigationPage):
|
|||||||
|
|
||||||
def json_load_template(self, namespace_template_name):
|
def json_load_template(self, namespace_template_name):
|
||||||
"""Read template for namespace creation
|
"""Read template for namespace creation
|
||||||
|
|
||||||
:param namespace_template_name: Path to template
|
:param namespace_template_name: Path to template
|
||||||
:return = json data container
|
:return = json data container
|
||||||
"""
|
"""
|
||||||
|
@ -56,6 +56,7 @@ class PageObject(basewebobject.BaseWebObject):
|
|||||||
|
|
||||||
def switch_window(self, window_name=None, window_index=None):
|
def switch_window(self, window_name=None, window_index=None):
|
||||||
"""Switches focus between the webdriver windows.
|
"""Switches focus between the webdriver windows.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
- window_name: The name of the window to switch to.
|
- window_name: The name of the window to switch to.
|
||||||
- window_index: The index of the window handle to switch to.
|
- window_index: The index of the window handle to switch to.
|
||||||
|
@ -42,15 +42,15 @@ class BaseRegion(basewebobject.BaseWebObject):
|
|||||||
self._dynamic_properties = {}
|
self._dynamic_properties = {}
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
"""It is not possible to create property bounded just to object
|
# It is not possible to create property bounded just to object
|
||||||
and not class at runtime, therefore it is necessary to
|
# and not class at runtime, therefore it is necessary to
|
||||||
override __getattr__ and make fake 'properties' by storing them in
|
# override __getattr__ and make fake 'properties' by storing them in
|
||||||
the protected attribute _dynamic_attributes and returning result
|
# the protected attribute _dynamic_attributes and returning result
|
||||||
of the method associated with the specified attribute.
|
# of the method associated with the specified attribute.
|
||||||
|
|
||||||
|
# This way the feeling of having regions accessed as 'properties'
|
||||||
|
# is created, which is one of the requirement of page object pattern.
|
||||||
|
|
||||||
This way the feeling of having regions accessed as 'properties'
|
|
||||||
is created, which is one of the requirement of page object pattern.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
return self._dynamic_properties[name]
|
return self._dynamic_properties[name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -287,9 +287,8 @@ class BaseFormRegion(baseregion.BaseRegion):
|
|||||||
_default_form_locator = (by.By.CSS_SELECTOR, 'div.modal-dialog')
|
_default_form_locator = (by.By.CSS_SELECTOR, 'div.modal-dialog')
|
||||||
|
|
||||||
def __init__(self, driver, conf, src_elem=None):
|
def __init__(self, driver, conf, src_elem=None):
|
||||||
"""In most cases forms can be located through _default_form_locator,
|
# In most cases forms can be located through _default_form_locator,
|
||||||
so specifying source element can be skipped.
|
# so specifying source element can be skipped.
|
||||||
"""
|
|
||||||
if src_elem is None:
|
if src_elem is None:
|
||||||
# fake self.src_elem must be set up in order self._get_element work
|
# fake self.src_elem must be set up in order self._get_element work
|
||||||
self.src_elem = driver
|
self.src_elem = driver
|
||||||
@ -449,9 +448,10 @@ class TabbedFormRegion(FormRegion):
|
|||||||
|
|
||||||
|
|
||||||
class DateFormRegion(BaseFormRegion):
|
class DateFormRegion(BaseFormRegion):
|
||||||
"""Form that queries data to table that is regularly below the form,
|
"""Form that queries data to table that is regularly below the form.
|
||||||
typical example is located on Project/Compute/Overview page.
|
|
||||||
"""
|
A typical example is located on Project/Compute/Overview page.
|
||||||
|
"""
|
||||||
|
|
||||||
_from_field_locator = (by.By.CSS_SELECTOR, 'input#id_start')
|
_from_field_locator = (by.By.CSS_SELECTOR, 'input#id_start')
|
||||||
_to_field_locator = (by.By.CSS_SELECTOR, 'input#id_end')
|
_to_field_locator = (by.By.CSS_SELECTOR, 'input#id_end')
|
||||||
|
@ -221,8 +221,9 @@ class DropDownMenuRegion(baseregion.BaseRegion):
|
|||||||
|
|
||||||
|
|
||||||
class UserDropDownMenuRegion(DropDownMenuRegion):
|
class UserDropDownMenuRegion(DropDownMenuRegion):
|
||||||
"""Drop down menu located in the right side of the topbar,
|
"""Drop down menu located in the right side of the topbar.
|
||||||
contains links to settings and help.
|
|
||||||
|
This menu contains links to settings and help.
|
||||||
"""
|
"""
|
||||||
_settings_link_locator = (by.By.CSS_SELECTOR,
|
_settings_link_locator = (by.By.CSS_SELECTOR,
|
||||||
'a[href*="/settings/"]')
|
'a[href*="/settings/"]')
|
||||||
|
@ -208,6 +208,7 @@ class TableRegion(baseregion.BaseRegion):
|
|||||||
|
|
||||||
def assert_definition(self, expected_table_definition, sorting=False):
|
def assert_definition(self, expected_table_definition, sorting=False):
|
||||||
"""Checks that actual table is expected one.
|
"""Checks that actual table is expected one.
|
||||||
|
|
||||||
Items to compare: 'next' and 'prev' links, count of rows and names of
|
Items to compare: 'next' and 'prev' links, count of rows and names of
|
||||||
elements in list
|
elements in list
|
||||||
:param expected_table_definition: expected values (dictionary)
|
:param expected_table_definition: expected values (dictionary)
|
||||||
@ -225,8 +226,7 @@ class TableRegion(baseregion.BaseRegion):
|
|||||||
|
|
||||||
|
|
||||||
def bind_table_action(action_name):
|
def bind_table_action(action_name):
|
||||||
"""A decorator to bind table region method to an actual table action
|
"""Decorator to bind table region method to an actual table action button.
|
||||||
button.
|
|
||||||
|
|
||||||
Many table actions when started (by clicking a corresponding button
|
Many table actions when started (by clicking a corresponding button
|
||||||
in UI) lead to some form showing up. To further interact with this form,
|
in UI) lead to some form showing up. To further interact with this form,
|
||||||
|
@ -43,6 +43,7 @@ class TestDownloadRCFile(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def test_download_rc_v2_file(self):
|
def test_download_rc_v2_file(self):
|
||||||
"""This is a basic scenario test:
|
"""This is a basic scenario test:
|
||||||
|
|
||||||
Steps:
|
Steps:
|
||||||
1) Login to Horizon Dashboard as admin user
|
1) Login to Horizon Dashboard as admin user
|
||||||
2) Navigate to Project > Compute > Access & Security > API Access tab
|
2) Navigate to Project > Compute > Access & Security > API Access tab
|
||||||
@ -62,6 +63,7 @@ class TestDownloadRCFile(helpers.AdminTestCase):
|
|||||||
@decorators.skip_because(bugs=['1584057'])
|
@decorators.skip_because(bugs=['1584057'])
|
||||||
def test_download_rc_v3_file(self):
|
def test_download_rc_v3_file(self):
|
||||||
"""This is a basic scenario test:
|
"""This is a basic scenario test:
|
||||||
|
|
||||||
Steps:
|
Steps:
|
||||||
1) Login to Horizon Dashboard as admin user
|
1) Login to Horizon Dashboard as admin user
|
||||||
2) Navigate to Project > Compute > Access & Security > API Access tab
|
2) Navigate to Project > Compute > Access & Security > API Access tab
|
||||||
|
@ -25,6 +25,7 @@ class TestDefaults(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def test_update_defaults(self):
|
def test_update_defaults(self):
|
||||||
"""Tests the Update Default Quotas functionality:
|
"""Tests the Update Default Quotas functionality:
|
||||||
|
|
||||||
1) Login as Admin and go to Admin > System > Defaults
|
1) Login as Admin and go to Admin > System > Defaults
|
||||||
2) Updates default Quotas by adding a random number between 1 and 10
|
2) Updates default Quotas by adding a random number between 1 and 10
|
||||||
3) Verifies that the updated values are present in the
|
3) Verifies that the updated values are present in the
|
||||||
|
@ -80,6 +80,7 @@ class TestFlavors(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def test_flavor_create(self):
|
def test_flavor_create(self):
|
||||||
"""tests the flavor creation and deletion functionalities:
|
"""tests the flavor creation and deletion functionalities:
|
||||||
|
|
||||||
* creates a new flavor
|
* creates a new flavor
|
||||||
* verifies the flavor appears in the flavors table
|
* verifies the flavor appears in the flavors table
|
||||||
* deletes the newly created flavor
|
* deletes the newly created flavor
|
||||||
@ -89,8 +90,7 @@ class TestFlavors(helpers.AdminTestCase):
|
|||||||
self._delete_flavor(self.FLAVOR_NAME)
|
self._delete_flavor(self.FLAVOR_NAME)
|
||||||
|
|
||||||
def test_flavor_update_info(self):
|
def test_flavor_update_info(self):
|
||||||
"""Tests the flavor Edit row action functionality:
|
"""Tests the flavor Edit row action functionality"""
|
||||||
"""
|
|
||||||
|
|
||||||
self._create_flavor(self.FLAVOR_NAME)
|
self._create_flavor(self.FLAVOR_NAME)
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ class TestHostAggregates(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def test_host_aggregate_create(self):
|
def test_host_aggregate_create(self):
|
||||||
"""tests the host aggregate creation and deletion functionalities:
|
"""tests the host aggregate creation and deletion functionalities:
|
||||||
|
|
||||||
* creates a new host aggregate
|
* creates a new host aggregate
|
||||||
* verifies the host aggregate appears in the host aggregates table
|
* verifies the host aggregate appears in the host aggregates table
|
||||||
* deletes the newly created host aggregate
|
* deletes the newly created host aggregate
|
||||||
|
@ -74,6 +74,7 @@ class TestImagesBasic(TestImagesLegacy):
|
|||||||
@decorators.skip_because(bugs=['1595335'])
|
@decorators.skip_because(bugs=['1595335'])
|
||||||
def test_image_create_delete(self):
|
def test_image_create_delete(self):
|
||||||
"""tests the image creation and deletion functionalities:
|
"""tests the image creation and deletion functionalities:
|
||||||
|
|
||||||
* creates a new image from horizon.conf http_image
|
* creates a new image from horizon.conf http_image
|
||||||
* verifies the image appears in the images table as active
|
* verifies the image appears in the images table as active
|
||||||
* deletes the newly created image
|
* deletes the newly created image
|
||||||
@ -84,6 +85,7 @@ class TestImagesBasic(TestImagesLegacy):
|
|||||||
|
|
||||||
def test_image_create_delete_from_local_file(self):
|
def test_image_create_delete_from_local_file(self):
|
||||||
"""tests the image creation and deletion functionalities:
|
"""tests the image creation and deletion functionalities:
|
||||||
|
|
||||||
* downloads image from horizon.conf stated in http_image
|
* downloads image from horizon.conf stated in http_image
|
||||||
* creates the image from the downloaded file
|
* creates the image from the downloaded file
|
||||||
* verifies the image appears in the images table as active
|
* verifies the image appears in the images table as active
|
||||||
@ -96,20 +98,21 @@ class TestImagesBasic(TestImagesLegacy):
|
|||||||
|
|
||||||
def test_images_pagination(self):
|
def test_images_pagination(self):
|
||||||
"""This test checks images pagination
|
"""This test checks images pagination
|
||||||
Steps:
|
|
||||||
1) Login to Horizon Dashboard as horizon user
|
Steps:
|
||||||
2) Navigate to user settings page
|
1) Login to Horizon Dashboard as horizon user
|
||||||
3) Change 'Items Per Page' value to 1
|
2) Navigate to user settings page
|
||||||
4) Go to Project -> Compute -> Images page
|
3) Change 'Items Per Page' value to 1
|
||||||
5) Check that only 'Next' link is available, only one image is
|
4) Go to Project -> Compute -> Images page
|
||||||
available (and it has correct name)
|
5) Check that only 'Next' link is available, only one image is
|
||||||
6) Click 'Next' and check that both 'Prev' and 'Next' links are
|
available (and it has correct name)
|
||||||
available, only one image is available (and it has correct name)
|
6) Click 'Next' and check that both 'Prev' and 'Next' links are
|
||||||
7) Click 'Next' and check that only 'Prev' link is available,
|
available, only one image is available (and it has correct name)
|
||||||
only one image is visible (and it has correct name)
|
7) Click 'Next' and check that only 'Prev' link is available,
|
||||||
8) Click 'Prev' and check results (should be the same as for step6)
|
only one image is visible (and it has correct name)
|
||||||
9) Click 'Prev' and check results (should be the same as for step5)
|
8) Click 'Prev' and check results (should be the same as for step6)
|
||||||
10) Go to user settings page and restore 'Items Per Page'
|
9) Click 'Prev' and check results (should be the same as for step5)
|
||||||
|
10) Go to user settings page and restore 'Items Per Page'
|
||||||
"""
|
"""
|
||||||
default_image_list = self.CONFIG.image.images_list
|
default_image_list = self.CONFIG.image.images_list
|
||||||
items_per_page = 1
|
items_per_page = 1
|
||||||
@ -148,6 +151,7 @@ class TestImagesBasic(TestImagesLegacy):
|
|||||||
|
|
||||||
def test_update_image_metadata(self):
|
def test_update_image_metadata(self):
|
||||||
"""Test update image metadata
|
"""Test update image metadata
|
||||||
|
|
||||||
* logs in as admin user
|
* logs in as admin user
|
||||||
* creates image from locally downloaded file
|
* creates image from locally downloaded file
|
||||||
* verifies the image appears in the images table as active
|
* verifies the image appears in the images table as active
|
||||||
@ -176,6 +180,7 @@ class TestImagesBasic(TestImagesLegacy):
|
|||||||
|
|
||||||
def test_remove_protected_image(self):
|
def test_remove_protected_image(self):
|
||||||
"""tests that protected image is not deletable
|
"""tests that protected image is not deletable
|
||||||
|
|
||||||
* logs in as admin user
|
* logs in as admin user
|
||||||
* creates image from locally downloaded file
|
* creates image from locally downloaded file
|
||||||
* verifies the image appears in the images table as active
|
* verifies the image appears in the images table as active
|
||||||
@ -215,6 +220,7 @@ class TestImagesBasic(TestImagesLegacy):
|
|||||||
|
|
||||||
def test_edit_image_description_and_name(self):
|
def test_edit_image_description_and_name(self):
|
||||||
"""tests that image description is editable
|
"""tests that image description is editable
|
||||||
|
|
||||||
* creates image from locally downloaded file
|
* creates image from locally downloaded file
|
||||||
* verifies the image appears in the images table as active
|
* verifies the image appears in the images table as active
|
||||||
* toggle edit action and adds some description
|
* toggle edit action and adds some description
|
||||||
@ -263,12 +269,13 @@ class TestImagesAdvanced(TestImagesLegacy):
|
|||||||
"""Login as demo user"""
|
"""Login as demo user"""
|
||||||
def test_create_volume_from_image(self):
|
def test_create_volume_from_image(self):
|
||||||
"""This test case checks create volume from image functionality:
|
"""This test case checks create volume from image functionality:
|
||||||
Steps:
|
|
||||||
1. Login to Horizon Dashboard as regular user
|
Steps:
|
||||||
2. Navigate to Project -> Compute -> Images
|
1. Login to Horizon Dashboard as regular user
|
||||||
3. Create new volume from image
|
2. Navigate to Project -> Compute -> Images
|
||||||
4. Check that volume is created with expected name
|
3. Create new volume from image
|
||||||
5. Check that volume status is Available
|
4. Check that volume is created with expected name
|
||||||
|
5. Check that volume status is Available
|
||||||
"""
|
"""
|
||||||
images_page = self.images_page
|
images_page = self.images_page
|
||||||
source_image = self.CONFIG.image.images_list[0]
|
source_image = self.CONFIG.image.images_list[0]
|
||||||
@ -290,13 +297,14 @@ class TestImagesAdvanced(TestImagesLegacy):
|
|||||||
|
|
||||||
def test_launch_instance_from_image(self):
|
def test_launch_instance_from_image(self):
|
||||||
"""This test case checks launch instance from image functionality:
|
"""This test case checks launch instance from image functionality:
|
||||||
Steps:
|
|
||||||
1. Login to Horizon Dashboard as regular user
|
Steps:
|
||||||
2. Navigate to Project -> Compute -> Images
|
1. Login to Horizon Dashboard as regular user
|
||||||
3. Launch new instance from image
|
2. Navigate to Project -> Compute -> Images
|
||||||
4. Check that instance is create
|
3. Launch new instance from image
|
||||||
5. Check that status of newly created instance is Active
|
4. Check that instance is create
|
||||||
6. Check that image_name in correct in instances table
|
5. Check that status of newly created instance is Active
|
||||||
|
6. Check that image_name in correct in instances table
|
||||||
"""
|
"""
|
||||||
images_page = self.images_page
|
images_page = self.images_page
|
||||||
source_image = self.CONFIG.image.images_list[0]
|
source_image = self.CONFIG.image.images_list[0]
|
||||||
@ -331,15 +339,16 @@ class TestImagesAdmin(helpers.AdminTestCase, TestImagesLegacy):
|
|||||||
|
|
||||||
def test_filter_images(self):
|
def test_filter_images(self):
|
||||||
"""This test checks filtering of images
|
"""This test checks filtering of images
|
||||||
Steps:
|
|
||||||
1) Login to Horizon dashboard as admin user
|
Steps:
|
||||||
2) Go to Admin -> System -> Images
|
1) Login to Horizon dashboard as admin user
|
||||||
3) Use filter by Image Name
|
2) Go to Admin -> System -> Images
|
||||||
4) Check that filtered table has one image only (which name is
|
3) Use filter by Image Name
|
||||||
equal to filter value)
|
4) Check that filtered table has one image only (which name is
|
||||||
5) Check that no other images in the table
|
equal to filter value)
|
||||||
6) Clear filter and set nonexistent image name. Check that 0 rows
|
5) Check that no other images in the table
|
||||||
are displayed
|
6) Clear filter and set nonexistent image name. Check that 0 rows
|
||||||
|
are displayed
|
||||||
"""
|
"""
|
||||||
images_list = self.CONFIG.image.images_list
|
images_list = self.CONFIG.image.images_list
|
||||||
images_page = self.images_page
|
images_page = self.images_page
|
||||||
|
@ -24,6 +24,7 @@ class TestInstances(helpers.TestCase):
|
|||||||
|
|
||||||
def test_create_delete_instance(self):
|
def test_create_delete_instance(self):
|
||||||
"""tests the instance creation and deletion functionality:
|
"""tests the instance creation and deletion functionality:
|
||||||
|
|
||||||
* creates a new instance in Project > Compute > Instances page
|
* creates a new instance in Project > Compute > Instances page
|
||||||
* verifies the instance appears in the instances table as active
|
* verifies the instance appears in the instances table as active
|
||||||
* deletes the newly created instance via proper page (depends on user)
|
* deletes the newly created instance via proper page (depends on user)
|
||||||
@ -49,6 +50,7 @@ class TestInstances(helpers.TestCase):
|
|||||||
@decorators.skip_because(bugs=['1584057'])
|
@decorators.skip_because(bugs=['1584057'])
|
||||||
def test_instances_pagination(self):
|
def test_instances_pagination(self):
|
||||||
"""This test checks instance pagination
|
"""This test checks instance pagination
|
||||||
|
|
||||||
Steps:
|
Steps:
|
||||||
1) Login to Horizon Dashboard as regular user
|
1) Login to Horizon Dashboard as regular user
|
||||||
2) Navigate to user settings page
|
2) Navigate to user settings page
|
||||||
@ -57,9 +59,9 @@ class TestInstances(helpers.TestCase):
|
|||||||
5) Create 2 instances
|
5) Create 2 instances
|
||||||
6) Go to appropriate page (depends on user)
|
6) Go to appropriate page (depends on user)
|
||||||
7) Check that only 'Next' link is available, only one instance is
|
7) Check that only 'Next' link is available, only one instance is
|
||||||
available (and it has correct name) on the first page
|
available (and it has correct name) on the first page
|
||||||
8) Click 'Next' and check that on the second page only one instance is
|
8) Click 'Next' and check that on the second page only one instance is
|
||||||
available (and it has correct name), there is no 'Next' link on page
|
available (and it has correct name), there is no 'Next' link on page
|
||||||
9) Go to user settings page and restore 'Items Per Page'
|
9) Go to user settings page and restore 'Items Per Page'
|
||||||
10) Delete created instances via proper page (depends on user)
|
10) Delete created instances via proper page (depends on user)
|
||||||
"""
|
"""
|
||||||
@ -110,6 +112,7 @@ class TestInstances(helpers.TestCase):
|
|||||||
|
|
||||||
def test_instances_pagination_and_filtration(self):
|
def test_instances_pagination_and_filtration(self):
|
||||||
"""This test checks instance pagination and filtration
|
"""This test checks instance pagination and filtration
|
||||||
|
|
||||||
Steps:
|
Steps:
|
||||||
1) Login to Horizon Dashboard as regular user
|
1) Login to Horizon Dashboard as regular user
|
||||||
2) Go to to user settings page
|
2) Go to to user settings page
|
||||||
@ -118,11 +121,11 @@ class TestInstances(helpers.TestCase):
|
|||||||
5) Create 2 instances
|
5) Create 2 instances
|
||||||
6) Go to appropriate page (depends on user)
|
6) Go to appropriate page (depends on user)
|
||||||
7) Check filter by Name of the first and the second instance in order
|
7) Check filter by Name of the first and the second instance in order
|
||||||
to have one instance in the list (and it should have correct name) and
|
to have one instance in the list (and it should have correct name)
|
||||||
no 'Next' link is available
|
and no 'Next' link is available
|
||||||
8) Check filter by common part of Name of in order to have one instance
|
8) Check filter by common part of Name of in order to have one instance
|
||||||
in the list (and it should have correct name) and 'Next' link is
|
in the list (and it should have correct name) and 'Next' link is
|
||||||
available on the first page and is not available on the second page
|
available on the first page and is not available on the second page
|
||||||
9) Go to user settings page and restore 'Items Per Page'
|
9) Go to user settings page and restore 'Items Per Page'
|
||||||
10) Delete created instances via proper page (depends on user)
|
10) Delete created instances via proper page (depends on user)
|
||||||
|
|
||||||
@ -181,6 +184,7 @@ class TestInstances(helpers.TestCase):
|
|||||||
|
|
||||||
def test_filter_instances(self):
|
def test_filter_instances(self):
|
||||||
"""This test checks filtering of instances by Instance Name
|
"""This test checks filtering of instances by Instance Name
|
||||||
|
|
||||||
Steps:
|
Steps:
|
||||||
1) Login to Horizon dashboard as regular user
|
1) Login to Horizon dashboard as regular user
|
||||||
2) Go to Project > Compute > Instances
|
2) Go to Project > Compute > Instances
|
||||||
@ -188,9 +192,9 @@ class TestInstances(helpers.TestCase):
|
|||||||
4) Go to appropriate page (depends on user)
|
4) Go to appropriate page (depends on user)
|
||||||
5) Use filter by Instance Name
|
5) Use filter by Instance Name
|
||||||
6) Check that filtered table has one instance only (which name is equal
|
6) Check that filtered table has one instance only (which name is equal
|
||||||
to filter value) and no other instances in the table
|
to filter value) and no other instances in the table
|
||||||
7) Check that filtered table has both instances (search by common part
|
7) Check that filtered table has both instances (search by common part
|
||||||
of instance names)
|
of instance names)
|
||||||
8) Set nonexistent instance name. Check that 0 rows are displayed
|
8) Set nonexistent instance name. Check that 0 rows are displayed
|
||||||
9) Clear filter and delete instances via proper page (depends on user)
|
9) Clear filter and delete instances via proper page (depends on user)
|
||||||
"""
|
"""
|
||||||
|
@ -16,6 +16,7 @@ from openstack_dashboard.test.integration_tests.pages import loginpage
|
|||||||
|
|
||||||
class TestLogin(helpers.BaseTestCase):
|
class TestLogin(helpers.BaseTestCase):
|
||||||
"""This is a basic scenario test:
|
"""This is a basic scenario test:
|
||||||
|
|
||||||
* checks that the login page is available
|
* checks that the login page is available
|
||||||
* logs in as a regular user
|
* logs in as a regular user
|
||||||
* checks that the user home page loads without error
|
* checks that the user home page loads without error
|
||||||
|
@ -31,6 +31,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
|
|||||||
is_public=True, is_protected=False, template_path=None,
|
is_public=True, is_protected=False, template_path=None,
|
||||||
checks=(PUBLIC, PROTECTED)):
|
checks=(PUBLIC, PROTECTED)):
|
||||||
"""Create NameSpace and run checks
|
"""Create NameSpace and run checks
|
||||||
|
|
||||||
:param namespace_name: Display name of namespace in template
|
:param namespace_name: Display name of namespace in template
|
||||||
:param page: Connection point
|
:param page: Connection point
|
||||||
:param template_json_container: JSON container with NameSpace content
|
:param template_json_container: JSON container with NameSpace content
|
||||||
@ -71,6 +72,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def namespace_delete_with_checks(self, namespace_name, page):
|
def namespace_delete_with_checks(self, namespace_name, page):
|
||||||
"""Delete NameSpace and run checks
|
"""Delete NameSpace and run checks
|
||||||
|
|
||||||
:param namespace_name: Display name of namespace in template
|
:param namespace_name: Display name of namespace in template
|
||||||
:param page: Connection point
|
:param page: Connection point
|
||||||
:return: Nothing
|
:return: Nothing
|
||||||
@ -83,6 +85,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def test_namespace_create_delete(self):
|
def test_namespace_create_delete(self):
|
||||||
"""Tests the NameSpace creation and deletion functionality:
|
"""Tests the NameSpace creation and deletion functionality:
|
||||||
|
|
||||||
* Actions:
|
* Actions:
|
||||||
* 1) Login to Horizon Dashboard as admin user.
|
* 1) Login to Horizon Dashboard as admin user.
|
||||||
* 2) Navigate to Admin -> System -> Metadata Definitions.
|
* 2) Navigate to Admin -> System -> Metadata Definitions.
|
||||||
|
@ -23,6 +23,7 @@ class TestNetworks(helpers.TestCase):
|
|||||||
|
|
||||||
def test_private_network_create(self):
|
def test_private_network_create(self):
|
||||||
"""tests the network creation and deletion functionalities:
|
"""tests the network creation and deletion functionalities:
|
||||||
|
|
||||||
* creates a new private network and a new subnet associated with it
|
* creates a new private network and a new subnet associated with it
|
||||||
* verifies the network appears in the networks table as active
|
* verifies the network appears in the networks table as active
|
||||||
* deletes the newly created network
|
* deletes the newly created network
|
||||||
|
@ -44,6 +44,7 @@ class TestRouters(helpers.TestCase):
|
|||||||
|
|
||||||
def test_router_create(self):
|
def test_router_create(self):
|
||||||
"""tests the router creation and deletion functionalities:
|
"""tests the router creation and deletion functionalities:
|
||||||
|
|
||||||
* creates a new router for public network
|
* creates a new router for public network
|
||||||
* verifies the router appears in the routers table as active
|
* verifies the router appears in the routers table as active
|
||||||
* deletes the newly created router
|
* deletes the newly created router
|
||||||
@ -73,6 +74,7 @@ class TestRouters(helpers.TestCase):
|
|||||||
|
|
||||||
def test_router_add_delete_interface(self):
|
def test_router_add_delete_interface(self):
|
||||||
"""Tests the router interface creation and deletion functionalities:
|
"""Tests the router interface creation and deletion functionalities:
|
||||||
|
|
||||||
* Follows the steps to create a new router
|
* Follows the steps to create a new router
|
||||||
* Clicks on the new router name from the routers table
|
* Clicks on the new router name from the routers table
|
||||||
* Moves to the Interfaces page/tab
|
* Moves to the Interfaces page/tab
|
||||||
@ -102,8 +104,8 @@ class TestRouters(helpers.TestCase):
|
|||||||
self._delete_router()
|
self._delete_router()
|
||||||
|
|
||||||
def test_router_delete_interface_by_row(self):
|
def test_router_delete_interface_by_row(self):
|
||||||
"""Tests the router interface creation and deletion by
|
"""Tests the router interface creation and deletion by row action:
|
||||||
row action functionalities:
|
|
||||||
* Follows the steps to create a new router
|
* Follows the steps to create a new router
|
||||||
* Clicks on the new router name from the routers table
|
* Clicks on the new router name from the routers table
|
||||||
* Moves to the Interfaces page/tab
|
* Moves to the Interfaces page/tab
|
||||||
@ -160,6 +162,7 @@ class TestAdminRouters(helpers.AdminTestCase):
|
|||||||
@decorators.services_required("neutron")
|
@decorators.services_required("neutron")
|
||||||
def test_router_create_admin(self):
|
def test_router_create_admin(self):
|
||||||
"""tests the router creation and deletion functionalities:
|
"""tests the router creation and deletion functionalities:
|
||||||
|
|
||||||
* creates a new router for public network
|
* creates a new router for public network
|
||||||
* verifies the router appears in the routers table as active
|
* verifies the router appears in the routers table as active
|
||||||
* edits router name
|
* edits router name
|
||||||
|
@ -20,25 +20,26 @@ class TestRouters(helpers.TestCase):
|
|||||||
|
|
||||||
@decorators.services_required("neutron")
|
@decorators.services_required("neutron")
|
||||||
def test_router_create(self):
|
def test_router_create(self):
|
||||||
"""This test case checks create, clear/set gateway,
|
"""Checks create, clear/set gateway, delete router functionality
|
||||||
delete router functionality
|
|
||||||
executed by non-admin user::
|
Executed by non-admin user.
|
||||||
Steps:
|
|
||||||
1. Login to Horizon Dashboard as horizon user
|
Steps:
|
||||||
2. Navigate to Project -> Network -> Routers page
|
1. Login to Horizon Dashboard as horizon user
|
||||||
3. Create new router
|
2. Navigate to Project -> Network -> Routers page
|
||||||
4. Check that the router appears in the routers table as active
|
3. Create new router
|
||||||
5. Check that no Error messages present
|
4. Check that the router appears in the routers table as active
|
||||||
6. Clear the gateway
|
5. Check that no Error messages present
|
||||||
7. Check that the router is still in the routers table
|
6. Clear the gateway
|
||||||
with no external network
|
7. Check that the router is still in the routers table
|
||||||
8. Check that no Error messages present
|
with no external network
|
||||||
9. Set the gateway to 'public' network
|
8. Check that no Error messages present
|
||||||
10. Check that no Error messages present
|
9. Set the gateway to 'public' network
|
||||||
11. Check that router's external network is set to 'public'
|
10. Check that no Error messages present
|
||||||
12. Delete the router
|
11. Check that router's external network is set to 'public'
|
||||||
13. Check that the router is absent in the routers table
|
12. Delete the router
|
||||||
14. Check that no Error messages present
|
13. Check that the router is absent in the routers table
|
||||||
|
14. Check that no Error messages present
|
||||||
"""
|
"""
|
||||||
|
|
||||||
routers_page = self.home_pg.go_to_network_routerspage()
|
routers_page = self.home_pg.go_to_network_routerspage()
|
||||||
|
@ -64,17 +64,19 @@ class TestSecuritygroup(helpers.TestCase):
|
|||||||
|
|
||||||
def test_securitygroup_create_delete(self):
|
def test_securitygroup_create_delete(self):
|
||||||
"""tests the security group creation and deletion functionalities:
|
"""tests the security group creation and deletion functionalities:
|
||||||
|
|
||||||
* creates a new security group
|
* creates a new security group
|
||||||
* verifies the security group appears in the security groups table
|
* verifies the security group appears in the security groups table
|
||||||
* deletes the newly created security group
|
* deletes the newly created security group
|
||||||
* verifies the security group does not appear in the table after
|
* verifies the security group does not appear in the table after
|
||||||
deletion
|
deletion
|
||||||
"""
|
"""
|
||||||
self._create_securitygroup()
|
self._create_securitygroup()
|
||||||
self._delete_securitygroup()
|
self._delete_securitygroup()
|
||||||
|
|
||||||
def test_managerules_create_delete_by_row(self):
|
def test_managerules_create_delete_by_row(self):
|
||||||
"""tests the manage rules creation and deletion functionalities:
|
"""tests the manage rules creation and deletion functionalities:
|
||||||
|
|
||||||
* create a new security group
|
* create a new security group
|
||||||
* verifies the security group appears in the security groups table
|
* verifies the security group appears in the security groups table
|
||||||
* creates a new rule
|
* creates a new rule
|
||||||
@ -83,7 +85,7 @@ class TestSecuritygroup(helpers.TestCase):
|
|||||||
* verifies the rule does not appear in the table after deletion
|
* verifies the rule does not appear in the table after deletion
|
||||||
* deletes the newly created security group
|
* deletes the newly created security group
|
||||||
* verifies the security group does not appear in the table after
|
* verifies the security group does not appear in the table after
|
||||||
deletion
|
deletion
|
||||||
"""
|
"""
|
||||||
self._create_securitygroup()
|
self._create_securitygroup()
|
||||||
self._add_rule()
|
self._add_rule()
|
||||||
@ -92,6 +94,7 @@ class TestSecuritygroup(helpers.TestCase):
|
|||||||
|
|
||||||
def test_managerules_create_delete_by_table(self):
|
def test_managerules_create_delete_by_table(self):
|
||||||
"""tests the manage rules creation and deletion functionalities:
|
"""tests the manage rules creation and deletion functionalities:
|
||||||
|
|
||||||
* create a new security group
|
* create a new security group
|
||||||
* verifies the security group appears in the security groups table
|
* verifies the security group appears in the security groups table
|
||||||
* creates a new rule
|
* creates a new rule
|
||||||
@ -100,7 +103,7 @@ class TestSecuritygroup(helpers.TestCase):
|
|||||||
* verifies the rule does not appear in the table after deletion
|
* verifies the rule does not appear in the table after deletion
|
||||||
* deletes the newly created security group
|
* deletes the newly created security group
|
||||||
* verifies the security group does not appear in the table after
|
* verifies the security group does not appear in the table after
|
||||||
deletion
|
deletion
|
||||||
"""
|
"""
|
||||||
self._create_securitygroup()
|
self._create_securitygroup()
|
||||||
self._add_rule()
|
self._add_rule()
|
||||||
|
@ -43,9 +43,10 @@ class TestStacks(helpers.AdminTestCase):
|
|||||||
@decorators.services_required("heat")
|
@decorators.services_required("heat")
|
||||||
def test_create_delete_stack(self):
|
def test_create_delete_stack(self):
|
||||||
"""tests the stack creation and deletion functionality
|
"""tests the stack creation and deletion functionality
|
||||||
|
|
||||||
* creates a new stack
|
* creates a new stack
|
||||||
* verifies the stack appears in the stacks table in Create Complete
|
* verifies the stack appears in the stacks table in Create Complete
|
||||||
state
|
state
|
||||||
* deletes the newly created stack
|
* deletes the newly created stack
|
||||||
* verifies the stack does not appear in the table after deletion
|
* verifies the stack does not appear in the table after deletion
|
||||||
"""
|
"""
|
||||||
|
@ -56,9 +56,8 @@ class TestPasswordChange(helpers.TestCase):
|
|||||||
"Failed to login with default password")
|
"Failed to login with default password")
|
||||||
|
|
||||||
def test_password_change(self):
|
def test_password_change(self):
|
||||||
"""Changes the password, verifies it was indeed changed and resets to
|
# Changes the password, verifies it was indeed changed and
|
||||||
default password.
|
# resets to default password.
|
||||||
"""
|
|
||||||
passwordchange_page = self.home_pg.go_to_settings_changepasswordpage()
|
passwordchange_page = self.home_pg.go_to_settings_changepasswordpage()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -74,9 +73,8 @@ class TestPasswordChange(helpers.TestCase):
|
|||||||
self._login()
|
self._login()
|
||||||
|
|
||||||
def test_show_message_after_logout(self):
|
def test_show_message_after_logout(self):
|
||||||
"""Ensure an informational message is shown on the login page after the
|
# Ensure an informational message is shown on the login page
|
||||||
user is logged out.
|
# after the user is logged out.
|
||||||
"""
|
|
||||||
passwordchange_page = self.home_pg.go_to_settings_changepasswordpage()
|
passwordchange_page = self.home_pg.go_to_settings_changepasswordpage()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -111,6 +109,7 @@ class TestUserSettings(helpers.TestCase):
|
|||||||
|
|
||||||
def test_user_settings_change(self):
|
def test_user_settings_change(self):
|
||||||
"""tests the user's settings options:
|
"""tests the user's settings options:
|
||||||
|
|
||||||
* changes the system's language
|
* changes the system's language
|
||||||
* changes the timezone
|
* changes the timezone
|
||||||
* changes the number of items per page (page size)
|
* changes the number of items per page (page size)
|
||||||
|
@ -45,16 +45,17 @@ class TestVolumeSnapshotsBasic(helpers.TestCase):
|
|||||||
|
|
||||||
def test_create_edit_delete_volume_snapshot(self):
|
def test_create_edit_delete_volume_snapshot(self):
|
||||||
"""Test checks create/delete volume snapshot action
|
"""Test checks create/delete volume snapshot action
|
||||||
Steps:
|
|
||||||
1. Login to Horizon Dashboard
|
Steps:
|
||||||
2. Navigate to Project -> Compute -> Volumes page
|
1. Login to Horizon Dashboard
|
||||||
3. Create snapshot for existed volume
|
2. Navigate to Project -> Compute -> Volumes page
|
||||||
4. Check that no ERROR appears
|
3. Create snapshot for existed volume
|
||||||
5. Check that snapshot is in the list
|
4. Check that no ERROR appears
|
||||||
6. Check that snapshot has reference to correct volume
|
5. Check that snapshot is in the list
|
||||||
7. Edit snapshot name and description
|
6. Check that snapshot has reference to correct volume
|
||||||
8. Delete volume snapshot from proper page
|
7. Edit snapshot name and description
|
||||||
9. Check that volume snapshot not in the list
|
8. Delete volume snapshot from proper page
|
||||||
|
9. Check that volume snapshot not in the list
|
||||||
"""
|
"""
|
||||||
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
||||||
volumes_snapshot_page = volumes_page.create_volume_snapshot(
|
volumes_snapshot_page = volumes_page.create_volume_snapshot(
|
||||||
@ -90,25 +91,26 @@ class TestVolumeSnapshotsBasic(helpers.TestCase):
|
|||||||
|
|
||||||
def test_volume_snapshots_pagination(self):
|
def test_volume_snapshots_pagination(self):
|
||||||
"""This test checks volumes snapshots pagination
|
"""This test checks volumes snapshots pagination
|
||||||
Steps:
|
|
||||||
1) Login to Horizon Dashboard
|
Steps:
|
||||||
2) Go to Project -> Compute -> Volumes -> Volumes tab, create
|
1) Login to Horizon Dashboard
|
||||||
volumes and 3 snapshots
|
2) Go to Project -> Compute -> Volumes -> Volumes tab, create
|
||||||
3) Navigate to user settings page
|
volumes and 3 snapshots
|
||||||
4) Change 'Items Per Page' value to 1
|
3) Navigate to user settings page
|
||||||
5) Go to Project -> Compute -> Volumes -> Volumes Snapshot tab
|
4) Change 'Items Per Page' value to 1
|
||||||
or Admin -> System -> Volumes -> Volumes Snapshot tab
|
5) Go to Project -> Compute -> Volumes -> Volumes Snapshot tab
|
||||||
(depends on user)
|
or Admin -> System -> Volumes -> Volumes Snapshot tab
|
||||||
6) Check that only 'Next' link is available, only one snapshot is
|
(depends on user)
|
||||||
available (and it has correct name)
|
6) Check that only 'Next' link is available, only one snapshot is
|
||||||
7) Click 'Next' and check that both 'Prev' and 'Next' links are
|
available (and it has correct name)
|
||||||
available, only one snapshot is available (and it has correct name)
|
7) Click 'Next' and check that both 'Prev' and 'Next' links are
|
||||||
8) Click 'Next' and check that only 'Prev' link is available,
|
available, only one snapshot is available (and it has correct name)
|
||||||
only one snapshot is visible (and it has correct name)
|
8) Click 'Next' and check that only 'Prev' link is available,
|
||||||
9) Click 'Prev' and check result (should be the same as for step7)
|
only one snapshot is visible (and it has correct name)
|
||||||
10) Click 'Prev' and check result (should be the same as for step6)
|
9) Click 'Prev' and check result (should be the same as for step7)
|
||||||
11) Go to user settings page and restore 'Items Per Page'
|
10) Click 'Prev' and check result (should be the same as for step6)
|
||||||
12) Delete created snapshots and volumes
|
11) Go to user settings page and restore 'Items Per Page'
|
||||||
|
12) Delete created snapshots and volumes
|
||||||
"""
|
"""
|
||||||
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
||||||
count = 3
|
count = 3
|
||||||
@ -223,14 +225,15 @@ class TestVolumeSnapshotsAdvanced(helpers.TestCase):
|
|||||||
|
|
||||||
def test_create_volume_from_snapshot(self):
|
def test_create_volume_from_snapshot(self):
|
||||||
"""Test checks possibility to create volume from snapshot
|
"""Test checks possibility to create volume from snapshot
|
||||||
Steps:
|
|
||||||
1. Login to Horizon Dashboard as regular user
|
Steps:
|
||||||
2. Navigate to Project -> Compute -> Volumes page
|
1. Login to Horizon Dashboard as regular user
|
||||||
3. Create snapshot for existed volume
|
2. Navigate to Project -> Compute -> Volumes page
|
||||||
4. Create new volume from snapshot
|
3. Create snapshot for existed volume
|
||||||
5. Check the volume is created and has 'Available' status
|
4. Create new volume from snapshot
|
||||||
6. Delete volume snapshot
|
5. Check the volume is created and has 'Available' status
|
||||||
7. Delete volume
|
6. Delete volume snapshot
|
||||||
|
7. Delete volume
|
||||||
"""
|
"""
|
||||||
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
||||||
volumes_snapshot_page = volumes_page.create_volume_snapshot(
|
volumes_snapshot_page = volumes_page.create_volume_snapshot(
|
||||||
|
@ -27,18 +27,19 @@ class TestVolumesBasic(helpers.TestCase):
|
|||||||
|
|
||||||
def test_volume_create_edit_delete(self):
|
def test_volume_create_edit_delete(self):
|
||||||
"""This test case checks create, edit, delete volume functionality:
|
"""This test case checks create, edit, delete volume functionality:
|
||||||
Steps:
|
|
||||||
1. Login to Horizon Dashboard
|
Steps:
|
||||||
2. Navigate to Project -> Compute -> Volumes page
|
1. Login to Horizon Dashboard
|
||||||
3. Create new volume
|
2. Navigate to Project -> Compute -> Volumes page
|
||||||
4. Check that the volume is in the list
|
3. Create new volume
|
||||||
5. Check that no Error messages present
|
4. Check that the volume is in the list
|
||||||
6. Edit the volume
|
5. Check that no Error messages present
|
||||||
7. Check that the volume is still in the list
|
6. Edit the volume
|
||||||
8. Check that no Error messages present
|
7. Check that the volume is still in the list
|
||||||
9. Delete the volume via proper page (depends on user)
|
8. Check that no Error messages present
|
||||||
10. Check that the volume is absent in the list
|
9. Delete the volume via proper page (depends on user)
|
||||||
11. Check that no Error messages present
|
10. Check that the volume is absent in the list
|
||||||
|
11. Check that no Error messages present
|
||||||
"""
|
"""
|
||||||
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
||||||
volumes_page.create_volume(self.VOLUME_NAME)
|
volumes_page.create_volume(self.VOLUME_NAME)
|
||||||
@ -78,24 +79,25 @@ class TestVolumesBasic(helpers.TestCase):
|
|||||||
|
|
||||||
def test_volumes_pagination(self):
|
def test_volumes_pagination(self):
|
||||||
"""This test checks volumes pagination
|
"""This test checks volumes pagination
|
||||||
Steps:
|
|
||||||
1) Login to Horizon Dashboard
|
Steps:
|
||||||
2) Go to Project -> Compute -> Volumes -> Volumes tab and create
|
1) Login to Horizon Dashboard
|
||||||
three volumes
|
2) Go to Project -> Compute -> Volumes -> Volumes tab and create
|
||||||
3) Navigate to user settings page
|
three volumes
|
||||||
4) Change 'Items Per Page' value to 1
|
3) Navigate to user settings page
|
||||||
5) Go to Project -> Compute -> Volumes -> Volumes tab or
|
4) Change 'Items Per Page' value to 1
|
||||||
Admin -> System -> Volumes -> Volumes tab (depends on user)
|
5) Go to Project -> Compute -> Volumes -> Volumes tab or
|
||||||
6) Check that only 'Next' link is available, only one volume is
|
Admin -> System -> Volumes -> Volumes tab (depends on user)
|
||||||
available (and it has correct name)
|
6) Check that only 'Next' link is available, only one volume is
|
||||||
7) Click 'Next' and check that both 'Prev' and 'Next' links are
|
available (and it has correct name)
|
||||||
available, only one volume is available (and it has correct name)
|
7) Click 'Next' and check that both 'Prev' and 'Next' links are
|
||||||
8) Click 'Next' and check that only 'Prev' link is available,
|
available, only one volume is available (and it has correct name)
|
||||||
only one volume is visible (and it has correct name)
|
8) Click 'Next' and check that only 'Prev' link is available,
|
||||||
9) Click 'Prev' and check result (should be the same as for step7)
|
only one volume is visible (and it has correct name)
|
||||||
10) Click 'Prev' and check result (should be the same as for step6)
|
9) Click 'Prev' and check result (should be the same as for step7)
|
||||||
11) Go to user settings page and restore 'Items Per Page'
|
10) Click 'Prev' and check result (should be the same as for step6)
|
||||||
12) Delete created volumes
|
11) Go to user settings page and restore 'Items Per Page'
|
||||||
|
12) Delete created volumes
|
||||||
"""
|
"""
|
||||||
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
||||||
count = 3
|
count = 3
|
||||||
@ -167,15 +169,16 @@ class TestVolumesAdvanced(helpers.TestCase):
|
|||||||
@decorators.skip_because(bugs=['1584057'])
|
@decorators.skip_because(bugs=['1584057'])
|
||||||
def test_manage_volume_attachments(self):
|
def test_manage_volume_attachments(self):
|
||||||
"""This test case checks attach/detach actions for volume
|
"""This test case checks attach/detach actions for volume
|
||||||
Steps:
|
|
||||||
1. Login to Horizon Dashboard as horizon user
|
Steps:
|
||||||
2. Navigate to Project -> Compute -> Instances, create instance
|
1. Login to Horizon Dashboard as horizon user
|
||||||
3. Navigate to Project -> Compute -> Volumes, create volume
|
2. Navigate to Project -> Compute -> Instances, create instance
|
||||||
4. Attach volume to instance from step2
|
3. Navigate to Project -> Compute -> Volumes, create volume
|
||||||
5. Check that volume status and link to instance
|
4. Attach volume to instance from step2
|
||||||
6. Detach volume from instance
|
5. Check that volume status and link to instance
|
||||||
7. Check volume status
|
6. Detach volume from instance
|
||||||
8. Delete volume and instance
|
7. Check volume status
|
||||||
|
8. Delete volume and instance
|
||||||
"""
|
"""
|
||||||
instance_name = helpers.gen_random_resource_name('instance')
|
instance_name = helpers.gen_random_resource_name('instance')
|
||||||
instances_page = self.home_pg.go_to_compute_instancespage()
|
instances_page = self.home_pg.go_to_compute_instancespage()
|
||||||
@ -251,12 +254,13 @@ class TestVolumesActions(helpers.TestCase):
|
|||||||
|
|
||||||
def test_volume_extend(self):
|
def test_volume_extend(self):
|
||||||
"""This test case checks extend volume functionality:
|
"""This test case checks extend volume functionality:
|
||||||
Steps:
|
|
||||||
1. Check current volume size
|
Steps:
|
||||||
2. Extend volume
|
1. Check current volume size
|
||||||
3. Check that no Error messages present
|
2. Extend volume
|
||||||
4. Check that the volume is still in the list
|
3. Check that no Error messages present
|
||||||
5. Check that the volume size is changed
|
4. Check that the volume is still in the list
|
||||||
|
5. Check that the volume size is changed
|
||||||
"""
|
"""
|
||||||
orig_size = self.volumes_page.get_size(self.VOLUME_NAME)
|
orig_size = self.volumes_page.get_size(self.VOLUME_NAME)
|
||||||
self.volumes_page.extend_volume(self.VOLUME_NAME, orig_size + 1)
|
self.volumes_page.extend_volume(self.VOLUME_NAME, orig_size + 1)
|
||||||
@ -272,12 +276,13 @@ class TestVolumesActions(helpers.TestCase):
|
|||||||
@decorators.skip_because(bugs=['1584057'])
|
@decorators.skip_because(bugs=['1584057'])
|
||||||
def test_volume_upload_to_image(self):
|
def test_volume_upload_to_image(self):
|
||||||
"""This test case checks upload volume to image functionality:
|
"""This test case checks upload volume to image functionality:
|
||||||
Steps:
|
|
||||||
1. Upload volume to image with some disk format
|
Steps:
|
||||||
2. Check that image is created
|
1. Upload volume to image with some disk format
|
||||||
3. Check that no Error messages present
|
2. Check that image is created
|
||||||
4. Delete the image
|
3. Check that no Error messages present
|
||||||
5. Repeat actions for all disk formats
|
4. Delete the image
|
||||||
|
5. Repeat actions for all disk formats
|
||||||
"""
|
"""
|
||||||
self.volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
self.volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
||||||
all_formats = {"qcow2": u'QCOW2', "raw": u'Raw', "vdi": u'VDI',
|
all_formats = {"qcow2": u'QCOW2', "raw": u'Raw', "vdi": u'VDI',
|
||||||
@ -306,13 +311,14 @@ class TestVolumesActions(helpers.TestCase):
|
|||||||
|
|
||||||
def test_volume_launch_as_instance(self):
|
def test_volume_launch_as_instance(self):
|
||||||
"""This test case checks launch volume as instance functionality:
|
"""This test case checks launch volume as instance functionality:
|
||||||
Steps:
|
|
||||||
1. Launch volume as instance
|
Steps:
|
||||||
2. Check that instance is created
|
1. Launch volume as instance
|
||||||
3. Check that no Error messages present
|
2. Check that instance is created
|
||||||
4. Check that instance status is 'active'
|
3. Check that no Error messages present
|
||||||
5. Check that volume status is 'in use'
|
4. Check that instance status is 'active'
|
||||||
6. Delete instance
|
5. Check that volume status is 'in use'
|
||||||
|
6. Delete instance
|
||||||
"""
|
"""
|
||||||
self.volumes_page.launch_instance(self.VOLUME_NAME, self.INSTANCE_NAME)
|
self.volumes_page.launch_instance(self.VOLUME_NAME, self.INSTANCE_NAME)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
|
@ -19,15 +19,16 @@ class TestAdminVolumeTypes(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def test_volume_type_create_delete(self):
|
def test_volume_type_create_delete(self):
|
||||||
"""This test case checks create, delete volume type:
|
"""This test case checks create, delete volume type:
|
||||||
Steps:
|
|
||||||
1. Login to Horizon Dashboard as admin user
|
Steps:
|
||||||
2. Navigate to Admin -> System -> Volumes -> Volume Types page
|
1. Login to Horizon Dashboard as admin user
|
||||||
3. Create new volume type
|
2. Navigate to Admin -> System -> Volumes -> Volume Types page
|
||||||
4. Check that the volume type is in the list
|
3. Create new volume type
|
||||||
5. Check that no Error messages present
|
4. Check that the volume type is in the list
|
||||||
6. Delete the volume type
|
5. Check that no Error messages present
|
||||||
7. Check that the volume type is absent in the list
|
6. Delete the volume type
|
||||||
8. Check that no Error messages present
|
7. Check that the volume type is absent in the list
|
||||||
|
8. Check that no Error messages present
|
||||||
"""
|
"""
|
||||||
volume_types_page = self.home_pg.go_to_system_volumes_volumetypespage()
|
volume_types_page = self.home_pg.go_to_system_volumes_volumetypespage()
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ class TestQoSSpec(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def test_qos_spec_create_delete(self):
|
def test_qos_spec_create_delete(self):
|
||||||
"""tests the QoS Spec creation and deletion functionality
|
"""tests the QoS Spec creation and deletion functionality
|
||||||
|
|
||||||
* creates a new QoS Spec
|
* creates a new QoS Spec
|
||||||
* verifies the QoS Spec appears in the QoS Specs table
|
* verifies the QoS Spec appears in the QoS Specs table
|
||||||
* deletes the newly created QoS Spec
|
* deletes the newly created QoS Spec
|
||||||
@ -78,10 +80,11 @@ class TestQoSSpec(helpers.AdminTestCase):
|
|||||||
|
|
||||||
def test_qos_spec_edit_consumer(self):
|
def test_qos_spec_edit_consumer(self):
|
||||||
"""tests Edit Consumer of QoS Spec functionality
|
"""tests Edit Consumer of QoS Spec functionality
|
||||||
|
|
||||||
* creates a new QoS Spec
|
* creates a new QoS Spec
|
||||||
* verifies the QoS Spec appears in the QoS Specs table
|
* verifies the QoS Spec appears in the QoS Specs table
|
||||||
* edit consumer of created QoS Spec (check all options - front-end,
|
* edit consumer of created QoS Spec (check all options - front-end,
|
||||||
both, back-end)
|
both, back-end)
|
||||||
* verifies current consumer of the QoS Spec in the QoS Specs table
|
* verifies current consumer of the QoS Spec in the QoS Specs table
|
||||||
* deletes the newly created QoS Spec
|
* deletes the newly created QoS Spec
|
||||||
* verifies the QoS Spec does not appear in the table after deletion
|
* verifies the QoS Spec does not appear in the table after deletion
|
||||||
|
@ -43,9 +43,11 @@ def load_test_data(load_onto=None):
|
|||||||
|
|
||||||
|
|
||||||
class TestData(object):
|
class TestData(object):
|
||||||
"""Holder object for test data. Any functions passed to the init method
|
"""Holder object for test data.
|
||||||
will be called with the ``TestData`` object as their only argument. They
|
|
||||||
can then load data onto the object as desired.
|
Any functions passed to the init method will be called with the
|
||||||
|
``TestData`` object as their only argument.
|
||||||
|
They can then load data onto the object as desired.
|
||||||
|
|
||||||
The idea is to use the instantiated object like this::
|
The idea is to use the instantiated object like this::
|
||||||
|
|
||||||
@ -93,9 +95,7 @@ class TestDataContainer(object):
|
|||||||
return self._objects
|
return self._objects
|
||||||
|
|
||||||
def filter(self, filtered=None, **kwargs):
|
def filter(self, filtered=None, **kwargs):
|
||||||
"""Returns objects in this container whose attributes match the given
|
"""Returns objects whose attributes match the given kwargs."""
|
||||||
keyword arguments.
|
|
||||||
"""
|
|
||||||
if filtered is None:
|
if filtered is None:
|
||||||
filtered = self._objects
|
filtered = self._objects
|
||||||
try:
|
try:
|
||||||
@ -111,8 +111,9 @@ class TestDataContainer(object):
|
|||||||
return self.filter(filtered=filtered, **kwargs)
|
return self.filter(filtered=filtered, **kwargs)
|
||||||
|
|
||||||
def get(self, **kwargs):
|
def get(self, **kwargs):
|
||||||
"""Returns the single object in this container whose attributes match
|
"""Returns a single object whose attributes match the given kwargs.
|
||||||
the given keyword arguments. An error will be raised if the arguments
|
|
||||||
|
An error will be raised if the arguments
|
||||||
provided don't return exactly one match.
|
provided don't return exactly one match.
|
||||||
"""
|
"""
|
||||||
matches = self.filter(**kwargs)
|
matches = self.filter(**kwargs)
|
||||||
|
@ -396,6 +396,7 @@ def _get_tenant_volume_usages(request, usages, disabled_quotas, tenant_id):
|
|||||||
@memoized
|
@memoized
|
||||||
def tenant_quota_usages(request, tenant_id=None):
|
def tenant_quota_usages(request, tenant_id=None):
|
||||||
"""Get our quotas and construct our usage object.
|
"""Get our quotas and construct our usage object.
|
||||||
|
|
||||||
If no tenant_id is provided, a the request.user.project_id
|
If no tenant_id is provided, a the request.user.project_id
|
||||||
is assumed to be used
|
is assumed to be used
|
||||||
"""
|
"""
|
||||||
|
@ -30,7 +30,9 @@ def get_int_or_uuid(value):
|
|||||||
|
|
||||||
|
|
||||||
def get_display_label(choices, status):
|
def get_display_label(choices, status):
|
||||||
"""This method is used in places where a resource's status or
|
"""Get a display label for resource status.
|
||||||
|
|
||||||
|
This method is used in places where a resource's status or
|
||||||
admin state labels need to assigned before they are sent to the
|
admin state labels need to assigned before they are sent to the
|
||||||
view template.
|
view template.
|
||||||
"""
|
"""
|
||||||
|
3
tox.ini
3
tox.ini
@ -117,8 +117,7 @@ commands =
|
|||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
exclude = .venv,.git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,node_modules
|
exclude = .venv,.git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,node_modules
|
||||||
# H405 multi line docstring summary not separated with an empty line
|
ignore =
|
||||||
ignore = H405
|
|
||||||
# Enable the following hacking rules which are disabled by default
|
# Enable the following hacking rules which are disabled by default
|
||||||
# H203 Use assertIs(Not)None to check for None
|
# H203 Use assertIs(Not)None to check for None
|
||||||
# H904 Delay string interpolations at logging calls
|
# H904 Delay string interpolations at logging calls
|
||||||
|
Loading…
Reference in New Issue
Block a user