Merge "Merge feature/r1 branch into master"

This commit is contained in:
Zuul 2022-01-24 14:09:12 +00:00 committed by Gerrit Code Review
commit 12fa1370bc
341 changed files with 16287 additions and 11753 deletions

View File

@ -354,6 +354,76 @@
zuul_copy_output:
'{{ devstack_base_dir }}/masakari-logs': logs
- job:
name: openstacksdk-functional-devstack-manila
parent: openstacksdk-functional-devstack-minimum
description: |
Run openstacksdk functional tests against a master devstack with manila
required-projects:
- openstack/manila
- name: openstack/openstacksdk
override-branch: feature/r1
vars:
devstack_localrc:
# Set up manila with a fake driver - makes things super fast and should
# have no impact on the API
MANILA_INSTALL_TEMPEST_PLUGIN_SYSTEMWIDE: false
SHARE_DRIVER: manila.tests.share.drivers.dummy.DummyDriver
MANILA_CONFIGURE_GROUPS: alpha,beta,gamma,membernet
MANILA_CONFIGURE_DEFAULT_TYPES: true
MANILA_SERVICE_IMAGE_ENABLED: false
MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL: 1
MANILA_SERVER_MIGRATION_PERIOD_TASK_INTERVAL: 10
MANILA_REPLICA_STATE_UPDATE_INTERVAL: 10
MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS: 'snapshot_support=True create_share_from_snapshot_support=True revert_to_snapshot_support=True mount_snapshot_support=True'
MANILA_ENABLED_BACKENDS: alpha,beta,gamma
MANILA_OPTGROUP_alpha_driver_handles_share_servers: false
MANILA_OPTGROUP_alpha_replication_domain: DUMMY_DOMAIN
MANILA_OPTGROUP_alpha_share_backend_name: ALPHA
MANILA_OPTGROUP_alpha_share_driver: manila.tests.share.drivers.dummy.DummyDriver
MANILA_OPTGROUP_beta_driver_handles_share_servers: false
MANILA_OPTGROUP_beta_replication_domain: DUMMY_DOMAIN
MANILA_OPTGROUP_beta_share_backend_name: BETA
MANILA_OPTGROUP_beta_share_driver: manila.tests.share.drivers.dummy.DummyDriver
MANILA_OPTGROUP_gamma_driver_handles_share_servers: true
MANILA_OPTGROUP_gamma_network_config_group: membernet
MANILA_OPTGROUP_gamma_share_backend_name: GAMMA
MANILA_OPTGROUP_gamma_share_driver: manila.tests.share.drivers.dummy.DummyDriver
MANILA_OPTGROUP_gamma_admin_network_config_group: membernet
MANILA_OPTGROUP_membernet_network_api_class: manila.network.standalone_network_plugin.StandaloneNetworkPlugin
MANILA_OPTGROUP_membernet_network_plugin_ipv4_enabled: true
MANILA_OPTGROUP_membernet_standalone_network_plugin_allowed_ip_ranges: 10.0.0.10-10.0.0.209
MANILA_OPTGROUP_membernet_standalone_network_plugin_gateway: 10.0.0.1
MANILA_OPTGROUP_membernet_standalone_network_plugin_mask: 24
MANILA_OPTGROUP_membernet_standalone_network_plugin_network_type: vlan
MANILA_OPTGROUP_membernet_standalone_network_plugin_segmentation_id: 1010
devstack_plugins:
manila: https://opendev.org/openstack/manila
devstack_services:
c-api: false
c-bak: false
c-sch: false
c-vol: false
cinder: false
s-account: false
s-container: false
s-object: false
s-proxy: false
n-api: false
n-api-meta: false
n-cauth: false
n-cond: false
n-cpu: false
n-novnc: false
n-obj: false
n-sch: false
nova: false
placement-api: false
dstat: false
tox_environment:
OPENSTACKSDK_HAS_MANILA: 1
OPENSTACKSDK_TESTS_SUBDIR: shared_file_system
- job:
name: metalsmith-integration-openstacksdk-src
parent: metalsmith-integration-glance-netboot-cirros-direct
@ -395,6 +465,8 @@
- openstacksdk-functional-devstack-senlin
- openstacksdk-functional-devstack-magnum:
voting: false
- openstacksdk-functional-devstack-manila:
voting: false
- openstacksdk-functional-devstack-masakari:
voting: false
- openstacksdk-functional-devstack-ironic:

View File

@ -46,3 +46,10 @@ Stats Operations
.. autoclass:: openstack.block_storage.v2._proxy.Proxy
:noindex:
:members: backend_pools
QuotaSet Operations
^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.block_storage.v2._proxy.Proxy
:noindex:
:members: get_quota_set, get_quota_set_defaults,
revert_quota_set, update_quota_set

View File

@ -46,3 +46,10 @@ Stats Operations
.. autoclass:: openstack.block_storage.v3._proxy.Proxy
:noindex:
:members: backend_pools
QuotaSet Operations
^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.block_storage.v3._proxy.Proxy
:noindex:
:members: get_quota_set, get_quota_set_defaults,
revert_quota_set, update_quota_set

View File

@ -149,3 +149,26 @@ Extension Operations
.. autoclass:: openstack.compute.v2._proxy.Proxy
:noindex:
:members: find_extension, extensions
QuotaSet Operations
^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.compute.v2._proxy.Proxy
:noindex:
:members: get_quota_set, get_quota_set_defaults,
revert_quota_set, update_quota_set
Server Migration Operations
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.compute.v2._proxy.Proxy
:noindex:
:members: abort_server_migration, force_complete_server_migration,
get_server_migration, server_migrations
Migration Operations
^^^^^^^^^^^^^^^^^^^^
.. autoclass:: openstack.compute.v2._proxy.Proxy
:noindex:
:members: migrations

View File

@ -42,7 +42,8 @@ Group Operations
.. autoclass:: openstack.identity.v3._proxy.Proxy
:noindex:
:members: create_group, update_group, delete_group, get_group, find_group,
groups
groups, add_user_to_group, remove_user_from_group,
check_user_in_group
Policy Operations
^^^^^^^^^^^^^^^^^
@ -82,8 +83,11 @@ Role Assignment Operations
:noindex:
:members: role_assignments, role_assignments_filter,
assign_project_role_to_user, unassign_project_role_from_user,
validate_user_has_role, assign_project_role_to_group,
unassign_project_role_from_group, validate_group_has_role
validate_user_has_project_role, assign_project_role_to_group,
unassign_project_role_from_group, validate_group_has_project_role,
assign_domain_role_to_user, unassign_domain_role_from_user,
validate_user_has_domain_role, assign_domain_role_to_group,
unassign_domain_role_from_group, validate_group_has_domain_role
Service Operations
^^^^^^^^^^^^^^^^^^

View File

@ -119,6 +119,12 @@ QoS Operations
get_qos_minimum_bandwidth_rule,
find_qos_minimum_bandwidth_rule,
qos_minimum_bandwidth_rules,
create_qos_minimum_packet_rate_rule,
update_qos_minimum_packet_rate_rule,
delete_qos_minimum_packet_rate_rule,
get_qos_minimum_packet_rate_rule,
find_qos_minimum_packet_rate_rule,
qos_minimum_packet_rate_rules,
create_qos_bandwidth_limit_rule,
update_qos_bandwidth_limit_rule,
delete_qos_bandwidth_limit_rule,

View File

@ -22,3 +22,60 @@ service.
.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy
:noindex:
:members: availability_zones
Shared File System Shares
^^^^^^^^^^^^^^^^^^^^^^^^^
Interact with Shares supported by the Shared File Systems
service.
.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy
:noindex:
:members: shares, get_share, delete_share, update_share, create_share,
revert_share_to_snapshot
Shared File System Storage Pools
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Interact with the storage pool statistics exposed by the Shared File
Systems Service.
.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy
:noindex:
:members: storage_pools
Shared File System User Messages
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
View and manipulate asynchronous user messages emitted by the Shared
File Systems service.
.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy
:noindex:
:members: user_messages, get_user_message, delete_user_message
Shared File System Limits
^^^^^^^^^^^^^^^^^^^^^^^^^
Get absolute limits of resources supported by the Shared File Systems
service.
.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy
:noindex:
:members: limits
Shared File System Snapshots
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Interact with Share Snapshots supported by the Shared File Systems
service.
.. autoclass:: openstack.shared_file_system.v2._proxy.Proxy
:noindex:
:members: share_snapshots, get_share_snapshot, delete_share_snapshot,
update_share_snapshot, create_share_snapshot

View File

@ -5,11 +5,13 @@ Block Storage Resources
:maxdepth: 1
v2/backup
v2/quota_set
v2/snapshot
v2/type
v2/volume
v3/backup
v3/quota_set
v3/snapshot
v3/type
v3/volume

View File

@ -0,0 +1,12 @@
openstack.block_storage.v2.quota_set
====================================
.. automodule:: openstack.block_storage.v2.quota_set
The QuotaSet Class
------------------
The ``QuotaSet`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.block_storage.v2.quota_set.QuotaSet
:members:

View File

@ -0,0 +1,12 @@
openstack.block_storage.v3.quota_set
====================================
.. automodule:: openstack.block_storage.v3.quota_set
The QuotaSet Class
------------------
The ``QuotaSet`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.block_storage.v3.quota_set.QuotaSet
:members:

View File

@ -9,7 +9,10 @@ Compute Resources
v2/image
v2/keypair
v2/limits
v2/migration
v2/server
v2/server_interface
v2/server_migration
v2/server_ip
v2/hypervisor
v2/quota_set

View File

@ -0,0 +1,12 @@
openstack.compute.v2.migration
==============================
.. automodule:: openstack.compute.v2.migration
The Migration Class
-------------------
The ``Migration`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.compute.v2.migration.Migration
:members:

View File

@ -0,0 +1,12 @@
openstack.compute.v2.quota_set
==============================
.. automodule:: openstack.compute.v2.quota_set
The QuotaSet Class
------------------
The ``QuotaSet`` class inherits from :class:`~openstack.resource.Resource`.
.. autoclass:: openstack.compute.v2.quota_set.QuotaSet
:members:

View File

@ -0,0 +1,13 @@
openstack.compute.v2.server_migration
=====================================
.. automodule:: openstack.compute.v2.server_migration
The ServerMigration Class
-------------------------
The ``ServerMigration`` class inherits from
:class:`~openstack.resource.Resource`.
.. autoclass:: openstack.compute.v2.server_migration.ServerMigration
:members:

View File

@ -30,6 +30,7 @@ Network Resources
v2/qos_bandwidth_limit_rule
v2/qos_dscp_marking_rule
v2/qos_minimum_bandwidth_rule
v2/qos_minimum_packet_rate_rule
v2/qos_policy
v2/qos_rule_type
v2/quota

View File

@ -0,0 +1,13 @@
openstack.network.v2.qos_minimum_packet_rate_rule
=================================================
.. automodule:: openstack.network.v2.qos_minimum_packet_rate_rule
The QoSMinimumPacketRateRule Class
----------------------------------
The ``QoSMinimumPacketRateRule`` class inherits from
:class:`~openstack.resource.Resource`.
.. autoclass:: openstack.network.v2.qos_minimum_packet_rate_rule.QoSMinimumPacketRateRule
:members:

View File

@ -5,3 +5,8 @@ Shared File System service resources
:maxdepth: 1
v2/availability_zone
v2/storage_pool
v2/limit
v2/share
v2/user_message
v2/share_snapshot

View File

@ -0,0 +1,13 @@
openstack.shared_file_system.v2.limit
=====================================
.. automodule:: openstack.shared_file_system.v2.limit
The Limit Class
---------------
The ``Limit`` class inherits from
:class:`~openstack.resource.Resource`.
.. autoclass:: openstack.shared_file_system.v2.limit.Limit
:members:

View File

@ -0,0 +1,13 @@
openstack.shared_file_system.v2.share
=====================================
.. automodule:: openstack.shared_file_system.v2.share
The Share Class
---------------
The ``Share`` class inherits from
:class:`~openstack.resource.Resource`.
.. autoclass:: openstack.shared_file_system.v2.share.Share
:members:

View File

@ -0,0 +1,13 @@
openstack.shared_file_system.v2.share_snapshot
==============================================
.. automodule:: openstack.shared_file_system.v2.share_snapshot
The ShareSnapshot Class
-----------------------
The ``ShareSnapshot`` class inherits from
:class:`~openstack.resource.Resource`.
.. autoclass:: openstack.shared_file_system.v2.share_snapshot.ShareSnapshot
:members:

View File

@ -0,0 +1,13 @@
openstack.shared_file_system.v2.storage_pool
============================================
.. automodule:: openstack.shared_file_system.v2.storage_pool
The StoragePool Class
---------------------
The ``StoragePool`` class inherits from
:class:`~openstack.resource.Resource`.
.. autoclass:: openstack.shared_file_system.v2.storage_pool.StoragePool
:members:

View File

@ -0,0 +1,13 @@
openstack.shared_file_system.v2.user_message
============================================
.. automodule:: openstack.shared_file_system.v2.user_message
The UserMessage Class
---------------------
The ``UserMessage`` class inherits from
:class:`~openstack.resource.Resource`.
.. autoclass:: openstack.shared_file_system.v2.user_message.UserMessage
:members:

View File

@ -53,19 +53,20 @@ class Proxy(proxy.Proxy):
:param kwargs query: Optional query parameters to be sent to
restrict the devices to be returned. Available parameters include:
* hostname: The hostname of the device.
* type: The type of the device.
* vendor: The vendor ID of the device.
* sort: A list of sorting keys separated by commas. Each sorting
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
* limit: Requests a specified size of returned items from the
query. Returns a number of items up to the specified limit
value.
query. Returns a number of items up to the specified limit
value.
* marker: Specifies the ID of the last-seen item. Use the limit
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
:returns: A generator of device instances.
"""
return self._list(_device.Device, **query)
@ -97,11 +98,13 @@ class Proxy(proxy.Proxy):
"""
return self._create(_device_profile.DeviceProfile, **attrs)
def delete_device_profile(self, name_or_id, ignore_missing=True):
def delete_device_profile(self, device_profile, ignore_missing=True):
"""Delete a device profile
:param name_or_id: The value can be either the ID or name of
a device profile.
:param device_profile: The value can be either the ID of a device
profile or a
:class:`~openstack.accelerator.v2.device_profile.DeviceProfile`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the device profile does not exist.
@ -109,8 +112,10 @@ class Proxy(proxy.Proxy):
attempting to delete a nonexistent device profile.
:returns: ``None``
"""
return self._delete(_device_profile.DeviceProfile,
name_or_id, ignore_missing=ignore_missing)
return self._delete(
_device_profile.DeviceProfile,
device_profile,
ignore_missing=ignore_missing)
def get_device_profile(self, uuid, fields=None):
"""Get a single device profile.
@ -140,35 +145,44 @@ class Proxy(proxy.Proxy):
"""
return self._create(_arq.AcceleratorRequest, **attrs)
def delete_accelerator_request(self, name_or_id, ignore_missing=True):
def delete_accelerator_request(
self, accelerator_request, ignore_missing=True,
):
"""Delete a device profile
:param name_or_id: The value can be either the ID or name of
an accelerator request.
:param device_profile: The value can be either the ID of a device
profile or a
:class:`~openstack.accelerator.v2.device_profile.DeviceProfile`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the device profile does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent accelerator request.
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the device profile does not exist.
When set to ``True``, no exception will be set when attempting to
delete a nonexistent accelerator request.
:returns: ``None``
"""
return self._delete(_arq.AcceleratorRequest, name_or_id,
ignore_missing=ignore_missing)
return self._delete(
_arq.AcceleratorRequest,
accelerator_request,
ignore_missing=ignore_missing)
def get_accelerator_request(self, uuid, fields=None):
"""Get a single accelerator request.
:param uuid: The value can be the UUID of a accelerator request.
:returns: One :class:
`~openstack.accelerator.v2.accelerator_request.AcceleratorRequest`
`~openstack.accelerator.v2.accelerator_request.AcceleratorRequest`
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
accelerator request matching the criteria could be found.
accelerator request matching the criteria could be found.
"""
return self._get(_arq.AcceleratorRequest, uuid)
def update_accelerator_request(self, uuid, properties):
"""Bind/Unbind an accelerator to VM.
:param uuid: The uuid of the accelerator_request to be bound/unbound.
:param properties: The info of VM
that will bind/unbind the accelerator.
that will bind/unbind the accelerator.
:returns: True if bind/unbind succeeded, False otherwise.
"""
return self._get_resource(_arq.AcceleratorRequest,

View File

@ -52,11 +52,13 @@ class Deployable(resource.Resource):
# The baremetal proxy defaults to retrying on conflict, allow
# overriding it via an explicit retry_on_conflict=False.
kwargs['retriable_status_codes'] = retriable_status_codes - {409}
try:
call = getattr(session, method.lower())
except AttributeError:
raise exceptions.ResourceFailure(
msg="Invalid commit method: %s" % method)
"Invalid commit method: %s" % method)
request.url = request.url + "/program"
response = call(request.url, json=request.body,
headers=request.headers, microversion=microversion,

View File

@ -36,8 +36,8 @@ class Proxy(proxy.Proxy):
:param resource_type: The type of resource to get.
:type resource_type: :class:`~openstack.resource.Resource`
:param value: The value to get. Can be either the ID of a
resource or a :class:`~openstack.resource.Resource`
subclass.
resource or a :class:`~openstack.resource.Resource`
subclass.
:param fields: Limit the resource fields to fetch.
:returns: The result of the ``fetch``
@ -57,7 +57,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of chassis.
:param details: A boolean indicating whether the detailed information
for every chassis should be returned.
for every chassis should be returned.
:param dict query: Optional query parameters to be sent to
restrict the chassis to be returned. Available parameters include:
@ -92,7 +92,7 @@ class Proxy(proxy.Proxy):
"""Create a new chassis from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.baremetal.v1.chassis.Chassis`.
:class:`~openstack.baremetal.v1.chassis.Chassis`.
:returns: The results of chassis creation.
:rtype: :class:`~openstack.baremetal.v1.chassis.Chassis`.
@ -228,7 +228,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of nodes.
:param details: A boolean indicating whether the detailed information
for every node should be returned.
for every node should be returned.
:param dict query: Optional query parameters to be sent to restrict
the nodes returned. Available parameters include:
@ -277,7 +277,7 @@ class Proxy(proxy.Proxy):
"""Create a new node from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.baremetal.v1.node.Node`.
:class:`~openstack.baremetal.v1.node.Node`.
:returns: The results of node creation.
:rtype: :class:`~openstack.baremetal.v1.node.Node`.
@ -344,9 +344,9 @@ class Proxy(proxy.Proxy):
being locked. However, when setting ``instance_id``, this is
a normal code and should not be retried.
See `Update Node
<https://docs.openstack.org/api-ref/baremetal/?expanded=update-node-detail#update-node>`_
for details.
See `Update Node
<https://docs.openstack.org/api-ref/baremetal/?expanded=update-node-detail#update-node>`_
for details.
:returns: The updated node.
:rtype: :class:`~openstack.baremetal.v1.node.Node`
@ -617,7 +617,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of ports.
:param details: A boolean indicating whether the detailed information
for every port should be returned.
for every port should be returned.
:param dict query: Optional query parameters to be sent to restrict
the ports returned. Available parameters include:
@ -662,7 +662,7 @@ class Proxy(proxy.Proxy):
"""Create a new port from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.baremetal.v1.port.Port`.
:class:`~openstack.baremetal.v1.port.Port`.
:returns: The results of port creation.
:rtype: :class:`~openstack.baremetal.v1.port.Port`.
@ -741,7 +741,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of port groups.
:param details: A boolean indicating whether the detailed information
for every port group should be returned.
for every port group should be returned.
:param dict query: Optional query parameters to be sent to restrict
the port groups returned. Available parameters include:
@ -780,7 +780,7 @@ class Proxy(proxy.Proxy):
"""Create a new portgroup from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.baremetal.v1.port_group.PortGroup`.
:class:`~openstack.baremetal.v1.port_group.PortGroup`.
:returns: The results of portgroup creation.
:rtype: :class:`~openstack.baremetal.v1.port_group.PortGroup`.
@ -894,9 +894,9 @@ class Proxy(proxy.Proxy):
a :class:`~openstack.baremetal.v1.node.Node` instance.
:param string vif_id: Backend-specific VIF ID.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the VIF does not exist. Otherwise, ``False``
is returned.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the VIF does not exist. Otherwise, ``False``
is returned.
:return: ``True`` if the VIF was detached, otherwise ``False``.
:raises: :exc:`~openstack.exceptions.NotSupported` if the server
does not support the VIF API.
@ -957,7 +957,7 @@ class Proxy(proxy.Proxy):
"""Create a new allocation from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.baremetal.v1.allocation.Allocation`.
:class:`~openstack.baremetal.v1.allocation.Allocation`.
:returns: The results of allocation creation.
:rtype: :class:`~openstack.baremetal.v1.allocation.Allocation`.
@ -1106,7 +1106,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of volume_connector.
:param details: A boolean indicating whether the detailed information
for every volume_connector should be returned.
for every volume_connector should be returned.
:param dict query: Optional query parameters to be sent to restrict
the volume_connectors returned. Available parameters include:
@ -1145,12 +1145,11 @@ class Proxy(proxy.Proxy):
"""Create a new volume_connector from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
:returns: The results of volume_connector creation.
:rtype::class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
:rtype:
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
"""
return self._create(_volumeconnector.VolumeConnector, **attrs)
@ -1164,8 +1163,8 @@ class Proxy(proxy.Proxy):
when the volume connector does not exist. When set to `True``,
None will be returned when attempting to find a nonexistent
volume connector.
:returns: One :class:
`~openstack.baremetal.v1.volumeconnector.VolumeConnector`
:returns: One
:class:`~openstack.baremetal.v1.volumeconnector.VolumeConnector`
object or None.
"""
return self._find(_volumeconnector.VolumeConnector, vc_id,
@ -1175,14 +1174,13 @@ class Proxy(proxy.Proxy):
"""Get a specific volume_connector.
:param volume_connector: The value can be the ID of a
volume_connector or a :class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector
instance.`
volume_connector or a
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`
instance.
:param fields: Limit the resource fields to fetch.`
:returns: One
:class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`
:class: `~openstack.baremetal.v1.volume_connector.VolumeConnector`
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
volume_connector matching the name or ID could be found.`
"""
@ -1193,15 +1191,16 @@ class Proxy(proxy.Proxy):
def update_volume_connector(self, volume_connector, **attrs):
"""Update a volume_connector.
:param volume_connector:Either the ID of a volume_connector
or an instance of
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector.`
:param volume_connector: Either the ID of a volume_connector
or an instance of
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
:param dict attrs: The attributes to update on the
volume_connector represented by the ``volume_connector`` parameter.`
volume_connector represented by the ``volume_connector``
parameter.
:returns: The updated volume_connector.
:rtype::class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector.`
:rtype:
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`
"""
return self._update(_volumeconnector.VolumeConnector,
volume_connector, **attrs)
@ -1210,14 +1209,14 @@ class Proxy(proxy.Proxy):
"""Apply a JSON patch to the volume_connector.
:param volume_connector: The value can be the ID of a
volume_connector or a :class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`
volume_connector or a
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`
instance.
:param patch: JSON patch to apply.
:returns: The updated volume_connector.
:rtype::class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector.`
:rtype:
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector.`
"""
return self._get_resource(_volumeconnector.VolumeConnector,
volume_connector).patch(self, patch)
@ -1228,8 +1227,7 @@ class Proxy(proxy.Proxy):
:param volume_connector: The value can be either the ID of a
volume_connector.VolumeConnector or a
:class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`
instance.
:param bool ignore_missing: When set to ``False``, an exception
:class:`~openstack.exceptions.ResourceNotFound` will be raised
@ -1238,8 +1236,8 @@ class Proxy(proxy.Proxy):
attempting to delete a non-existent volume_connector.
:returns: The instance of the volume_connector which was deleted.
:rtype::class:
`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
:rtype:
:class:`~openstack.baremetal.v1.volume_connector.VolumeConnector`.
"""
return self._delete(_volumeconnector.VolumeConnector,
volume_connector, ignore_missing=ignore_missing)
@ -1248,7 +1246,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of volume_target.
:param details: A boolean indicating whether the detailed information
for every volume_target should be returned.
for every volume_target should be returned.
:param dict query: Optional query parameters to be sent to restrict
the volume_targets returned. Available parameters include:
@ -1287,12 +1285,11 @@ class Proxy(proxy.Proxy):
"""Create a new volume_target from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:
`~openstack.baremetal.v1.volume_target.VolumeTarget`.
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`.
:returns: The results of volume_target creation.
:rtype::class:
`~openstack.baremetal.v1.volume_target.VolumeTarget`.
:rtype:
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`.
"""
return self._create(_volumetarget.VolumeTarget, **attrs)
@ -1306,8 +1303,8 @@ class Proxy(proxy.Proxy):
when the volume connector does not exist. When set to `True``,
None will be returned when attempting to find a nonexistent
volume target.
:returns: One :class:
`~openstack.baremetal.v1.volumetarget.VolumeTarget`
:returns: One
:class:`~openstack.baremetal.v1.volumetarget.VolumeTarget`
object or None.
"""
return self._find(_volumetarget.VolumeTarget, vt_id,
@ -1317,14 +1314,13 @@ class Proxy(proxy.Proxy):
"""Get a specific volume_target.
:param volume_target: The value can be the ID of a
volume_target or a :class:
`~openstack.baremetal.v1.volume_target.VolumeTarget
instance.`
volume_target or a
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`
instance.
:param fields: Limit the resource fields to fetch.`
:returns: One
:class:
`~openstack.baremetal.v1.volume_target.VolumeTarget`
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
volume_target matching the name or ID could be found.`
"""
@ -1335,15 +1331,15 @@ class Proxy(proxy.Proxy):
def update_volume_target(self, volume_target, **attrs):
"""Update a volume_target.
:param volume_target:Either the ID of a volume_target
or an instance of
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget.`
:param volume_target: Either the ID of a volume_target
or an instance of
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`.
:param dict attrs: The attributes to update on the
volume_target represented by the ``volume_target`` parameter.`
volume_target represented by the ``volume_target`` parameter.
:returns: The updated volume_target.
:rtype::class:
`~openstack.baremetal.v1.volume_target.VolumeTarget.`
:rtype:
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`
"""
return self._update(_volumetarget.VolumeTarget,
volume_target, **attrs)
@ -1352,14 +1348,14 @@ class Proxy(proxy.Proxy):
"""Apply a JSON patch to the volume_target.
:param volume_target: The value can be the ID of a
volume_target or a :class:
`~openstack.baremetal.v1.volume_target.VolumeTarget`
volume_target or a
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`
instance.
:param patch: JSON patch to apply.
:returns: The updated volume_target.
:rtype::class:
`~openstack.baremetal.v1.volume_target.VolumeTarget.`
:rtype:
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget.`
"""
return self._get_resource(_volumetarget.VolumeTarget,
volume_target).patch(self, patch)
@ -1370,8 +1366,7 @@ class Proxy(proxy.Proxy):
:param volume_target: The value can be either the ID of a
volume_target.VolumeTarget or a
:class:
`~openstack.baremetal.v1.volume_target.VolumeTarget`
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`
instance.
:param bool ignore_missing: When set to ``False``, an exception
:class:`~openstack.exceptions.ResourceNotFound` will be raised
@ -1380,8 +1375,8 @@ class Proxy(proxy.Proxy):
attempting to delete a non-existent volume_target.
:returns: The instance of the volume_target which was deleted.
:rtype::class:
`~openstack.baremetal.v1.volume_target.VolumeTarget`.
:rtype:
:class:`~openstack.baremetal.v1.volume_target.VolumeTarget`.
"""
return self._delete(_volumetarget.VolumeTarget,
volume_target, ignore_missing=ignore_missing)
@ -1390,9 +1385,9 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of deploy_templates.
:param details: A boolean indicating whether the detailed information
for every deploy_templates should be returned.
for every deploy_templates should be returned.
:param dict query: Optional query parameters to be sent to
restrict the deploy_templates to be returned.
restrict the deploy_templates to be returned.
:returns: A generator of Deploy templates instances.
"""
@ -1404,11 +1399,11 @@ class Proxy(proxy.Proxy):
"""Create a new deploy_template from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
:returns: The results of deploy_template creation.
:rtype:
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
"""
return self._create(_deploytemplates.DeployTemplate, **attrs)
@ -1416,15 +1411,15 @@ class Proxy(proxy.Proxy):
"""Update a deploy_template.
:param deploy_template: Either the ID of a deploy_template,
or an instance of
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
or an instance of
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
:param dict attrs: The attributes to update on
the deploy_template represented
by the ``deploy_template`` parameter.
the deploy_template represented
by the ``deploy_template`` parameter.
:returns: The updated deploy_template.
:rtype::class:
`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
:rtype:
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
"""
return self._update(_deploytemplates.DeployTemplate,
deploy_template, **attrs)
@ -1434,9 +1429,9 @@ class Proxy(proxy.Proxy):
"""Delete a deploy_template.
:param deploy_template:The value can be
either the ID of a deploy_template or a
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
instance.
either the ID of a deploy_template or a
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
instance.
:param bool ignore_missing: When set to ``False``,
an exception:class:`~openstack.exceptions.ResourceNotFound`
@ -1448,8 +1443,8 @@ class Proxy(proxy.Proxy):
deploy_template.
:returns: The instance of the deploy_template which was deleted.
:rtype::class:
`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
:rtype:
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`.
"""
return self._delete(_deploytemplates.DeployTemplate,
@ -1466,10 +1461,10 @@ class Proxy(proxy.Proxy):
:param fields: Limit the resource fields to fetch.
:returns: One
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no deployment template matching the name or
ID could be found.
when no deployment template matching the name or
ID could be found.
"""
return self._get_with_fields(_deploytemplates.DeployTemplate,
deploy_template, fields=fields)
@ -1485,8 +1480,8 @@ class Proxy(proxy.Proxy):
:param patch: JSON patch to apply.
:returns: The updated deploy_template.
:rtype::class:
`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
:rtype:
:class:`~openstack.baremetal.v1.deploy_templates.DeployTemplate`
"""
return self._get_resource(_deploytemplates.DeployTemplate,
deploy_template).patch(self, patch)

View File

@ -12,25 +12,28 @@
from openstack.block_storage import _base_proxy
from openstack.block_storage.v2 import backup as _backup
from openstack.block_storage.v2 import quota_set as _quota_set
from openstack.block_storage.v2 import snapshot as _snapshot
from openstack.block_storage.v2 import stats as _stats
from openstack.block_storage.v2 import type as _type
from openstack.block_storage.v2 import volume as _volume
from openstack.identity.v3 import project as _project
from openstack import resource
class Proxy(_base_proxy.BaseBlockStorageProxy):
# ====== SNAPSHOTS ======
def get_snapshot(self, snapshot):
"""Get a single snapshot
:param snapshot: The value can be the ID of a snapshot or a
:class:`~openstack.volume.v2.snapshot.Snapshot`
instance.
:class:`~openstack.block_storage.v2.snapshot.Snapshot`
instance.
:returns: One :class:`~openstack.volume.v2.snapshot.Snapshot`
:returns: One :class:`~openstack.block_storage.v2.snapshot.Snapshot`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_snapshot.Snapshot, snapshot)
@ -38,10 +41,10 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
"""Retrieve a generator of snapshots
:param bool details: When set to ``False``
:class:`~openstack.block_storage.v2.snapshot.Snapshot`
objects will be returned. The default, ``True``, will cause
:class:`~openstack.block_storage.v2.snapshot.SnapshotDetail`
objects to be returned.
:class:`~openstack.block_storage.v2.snapshot.Snapshot`
objects will be returned. The default, ``True``, will cause
:class:`~openstack.block_storage.v2.snapshot.SnapshotDetail`
objects to be returned.
:param kwargs query: Optional query parameters to be sent to limit
the snapshots being returned. Available parameters include:
@ -49,22 +52,22 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
* all_projects: Whether return the snapshots in all projects.
* volume_id: volume id of a snapshot.
* status: Value of the status of the snapshot so that you can
filter on "available" for example.
filter on "available" for example.
:returns: A generator of snapshot objects.
"""
snapshot = _snapshot.SnapshotDetail if details else _snapshot.Snapshot
return self._list(snapshot, **query)
base_path = '/snapshots/detail' if details else None
return self._list(_snapshot.Snapshot, base_path=base_path, **query)
def create_snapshot(self, **attrs):
"""Create a new snapshot from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.volume.v2.snapshot.Snapshot`,
comprised of the properties on the Snapshot class.
a :class:`~openstack.block_storage.v2.snapshot.Snapshot`,
comprised of the properties on the Snapshot class.
:returns: The results of snapshot creation
:rtype: :class:`~openstack.volume.v2.snapshot.Snapshot`
:rtype: :class:`~openstack.block_storage.v2.snapshot.Snapshot`
"""
return self._create(_snapshot.Snapshot, **attrs)
@ -72,28 +75,42 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
"""Delete a snapshot
:param snapshot: The value can be either the ID of a snapshot or a
:class:`~openstack.volume.v2.snapshot.Snapshot`
instance.
:class:`~openstack.block_storage.v2.snapshot.Snapshot`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the snapshot does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent snapshot.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the snapshot does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent snapshot.
:returns: ``None``
"""
self._delete(_snapshot.Snapshot, snapshot,
ignore_missing=ignore_missing)
# ====== SNAPSHOT ACTIONS ======
def reset_snapshot(self, snapshot, status):
"""Reset status of the snapshot
:param snapshot: The value can be either the ID of a backup or a
:class:`~openstack.block_storage.v2.snapshot.Snapshot` instance.
:param str status: New snapshot status
:returns: None
"""
snapshot = self._get_resource(_snapshot.Snapshot, snapshot)
snapshot.reset(self, status)
# ====== TYPES ======
def get_type(self, type):
"""Get a single type
:param type: The value can be the ID of a type or a
:class:`~openstack.volume.v2.type.Type` instance.
:class:`~openstack.block_storage.v2.type.Type` instance.
:returns: One :class:`~openstack.volume.v2.type.Type`
:returns: One :class:`~openstack.block_storage.v2.type.Type`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_type.Type, type)
@ -108,11 +125,11 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
"""Create a new type from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.volume.v2.type.Type`,
comprised of the properties on the Type class.
a :class:`~openstack.block_storage.v2.type.Type`,
comprised of the properties on the Type class.
:returns: The results of type creation
:rtype: :class:`~openstack.volume.v2.type.Type`
:rtype: :class:`~openstack.block_storage.v2.type.Type`
"""
return self._create(_type.Type, **attrs)
@ -120,29 +137,83 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
"""Delete a type
:param type: The value can be either the ID of a type or a
:class:`~openstack.volume.v2.type.Type` instance.
:class:`~openstack.block_storage.v2.type.Type` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the type does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent type.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the type does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent type.
:returns: ``None``
"""
self._delete(_type.Type, type, ignore_missing=ignore_missing)
def get_type_access(self, type):
"""Lists project IDs that have access to private volume type.
:param type: The value can be either the ID of a type or a
:class:`~openstack.block_storage.v2.type.Type` instance.
:returns: List of dictionaries describing projects that have access to
the specified type
"""
res = self._get_resource(_type.Type, type)
return res.get_private_access(self)
def add_type_access(self, type, project_id):
"""Adds private volume type access to a project.
:param type: The value can be either the ID of a type or a
:class:`~openstack.block_storage.v2.type.Type` instance.
:param str project_id: The ID of the project. Volume Type access to
be added to this project ID.
:returns: ``None``
"""
res = self._get_resource(_type.Type, type)
return res.add_private_access(self, project_id)
def remove_type_access(self, type, project_id):
"""Remove private volume type access from a project.
:param type: The value can be either the ID of a type or a
:class:`~openstack.block_storage.v2.type.Type` instance.
:param str project_id: The ID of the project. Volume Type access to
be removed to this project ID.
:returns: ``None``
"""
res = self._get_resource(_type.Type, type)
return res.remove_private_access(self, project_id)
# ====== VOLUMES ======
def get_volume(self, volume):
"""Get a single volume
:param volume: The value can be the ID of a volume or a
:class:`~openstack.volume.v2.volume.Volume` instance.
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:returns: One :class:`~openstack.volume.v2.volume.Volume`
:returns: One :class:`~openstack.block_storage.v2.volume.Volume`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_volume.Volume, volume)
def find_volume(self, name_or_id, ignore_missing=True, **attrs):
"""Find a single volume
:param snapshot: The name or ID a volume
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised
when the volume does not exist.
:returns: One :class:`~openstack.block_storage.v2.volume.Volume`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
"""
return self._find(_volume.Volume, name_or_id,
ignore_missing=ignore_missing)
def volumes(self, details=True, **query):
"""Retrieve a generator of volumes
@ -155,7 +226,7 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
* name: Name of the volume as a string.
* all_projects: Whether return the volumes in all projects
* status: Value of the status of the volume so that you can filter
on "available" for example.
on "available" for example.
:returns: A generator of volume objects.
"""
@ -166,34 +237,40 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
"""Create a new volume from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.volume.v2.volume.Volume`,
comprised of the properties on the Volume class.
a :class:`~openstack.block_storage.v2.volume.Volume`,
comprised of the properties on the Volume class.
:returns: The results of volume creation
:rtype: :class:`~openstack.volume.v2.volume.Volume`
:rtype: :class:`~openstack.block_storage.v2.volume.Volume`
"""
return self._create(_volume.Volume, **attrs)
def delete_volume(self, volume, ignore_missing=True):
def delete_volume(self, volume, ignore_missing=True, force=False):
"""Delete a volume
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.volume.v2.volume.Volume` instance.
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the volume does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent volume.
:class:`~openstack.exceptions.ResourceNotFound` will be raised
when the volume does not exist. When set to ``True``, no
exception will be set when attempting to delete a nonexistent
volume.
:param bool force: Whether to try forcing volume deletion.
:returns: ``None``
"""
self._delete(_volume.Volume, volume, ignore_missing=ignore_missing)
if not force:
self._delete(_volume.Volume, volume, ignore_missing=ignore_missing)
else:
volume = self._get_resource(_volume.Volume, volume)
volume.force_delete(self)
# ====== VOLUME ACTIONS ======
def extend_volume(self, volume, size):
"""Extend a volume
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.volume.v2.volume.Volume` instance.
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param size: New volume size
:returns: None
@ -201,6 +278,137 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
volume = self._get_resource(_volume.Volume, volume)
volume.extend(self, size)
def retype_volume(self, volume, new_type, migration_policy="never"):
"""Retype the volume.
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param str new_type: The new volume type that volume is changed with.
:param str migration_policy: Specify if the volume should be migrated
when it is re-typed. Possible values are on-demand or never.
Default: never.
:returns: None
"""
volume = self._get_resource(_volume.Volume, volume)
volume.retype(self, new_type, migration_policy)
def set_volume_bootable_status(self, volume, bootable):
"""Set bootable status of the volume.
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param bool bootable: Specifies whether the volume should be bootable
or not.
:returns: None
"""
volume = self._get_resource(_volume.Volume, volume)
volume.set_bootable_status(self, bootable)
def reset_volume_status(
self, volume, status, attach_status, migration_status
):
"""Reset volume statuses.
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param str status: The new volume status.
:param str attach_status: The new volume attach status.
:param str migration_status: The new volume migration status (admin
only).
:returns: None
"""
volume = self._get_resource(_volume.Volume, volume)
volume.reset_status(self, status, attach_status, migration_status)
def attach_volume(
self, volume, mountpoint, instance=None, host_name=None
):
"""Attaches a volume to a server.
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param str mountpoint: The attaching mount point.
:param str instance: The UUID of the attaching instance.
:param str host_name: The name of the attaching host.
:returns: None
"""
volume = self._get_resource(_volume.Volume, volume)
volume.attach(self, mountpoint, instance, host_name)
def detach_volume(
self, volume, attachment, force=False, connector=None
):
"""Detaches a volume from a server.
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param str attachment: The ID of the attachment.
:param bool force: Whether to force volume detach (Rolls back an
unsuccessful detach operation after you disconnect the volume.)
:param dict connector: The connector object.
:returns: None
"""
volume = self._get_resource(_volume.Volume, volume)
volume.detach(self, attachment, force, connector)
def unmanage_volume(self, volume):
"""Removes a volume from Block Storage management without removing the
back-end storage object that is associated with it.
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:returns: None
"""
volume = self._get_resource(_volume.Volume, volume)
volume.unmanage(self)
def migrate_volume(
self, volume, host=None, force_host_copy=False,
lock_volume=False
):
"""Migrates a volume to the specified host.
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param str host: The target host for the volume migration. Host
format is host@backend.
:param bool force_host_copy: If false (the default), rely on the volume
backend driver to perform the migration, which might be optimized.
If true, or the volume driver fails to migrate the volume itself,
a generic host-based migration is performed.
:param bool lock_volume: If true, migrating an available volume will
change its status to maintenance preventing other operations from
being performed on the volume such as attach, detach, retype, etc.
:returns: None
"""
volume = self._get_resource(_volume.Volume, volume)
volume.migrate(self, host, force_host_copy, lock_volume)
def complete_volume_migration(
self, volume, new_volume, error=False
):
"""Complete the migration of a volume.
:param volume: The value can be either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume` instance.
:param str new_volume: The UUID of the new volume.
:param bool error: Used to indicate if an error has occured elsewhere
that requires clean up.
:returns: None
"""
volume = self._get_resource(_volume.Volume, volume)
volume.complete_migration(self, new_volume, error)
# ====== BACKEND POOLS ======
def backend_pools(self, **query):
"""Returns a generator of cinder Back-end storage pools
@ -211,6 +419,7 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
"""
return self._list(_stats.Pools, **query)
# ====== BACKUPS ======
def backups(self, details=True, **query):
"""Retrieve a generator of backups
@ -223,13 +432,13 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
* offset: pagination marker
* limit: pagination limit
* sort_key: Sorts by an attribute. A valid value is
name, status, container_format, disk_format, size, id,
created_at, or updated_at. Default is created_at.
The API uses the natural sorting direction of the
sort_key attribute value.
name, status, container_format, disk_format, size, id,
created_at, or updated_at. Default is created_at.
The API uses the natural sorting direction of the
sort_key attribute value.
* sort_dir: Sorts by one or more sets of attribute and sort
direction combinations. If you omit the sort direction
in a set, default is desc.
direction combinations. If you omit the sort direction
in a set, default is desc.
:returns: A generator of backup objects.
"""
@ -260,7 +469,7 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
"""
return self._create(_backup.Backup, **attrs)
def delete_backup(self, backup, ignore_missing=True):
def delete_backup(self, backup, ignore_missing=True, force=False):
"""Delete a CloudBackup
:param backup: The value can be the ID of a backup or a
@ -270,12 +479,18 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
the zone does not exist.
When set to ``True``, no exception will be set when attempting to
delete a nonexistent zone.
:param bool force: Whether to try forcing backup deletion
:returns: ``None``
"""
self._delete(_backup.Backup, backup,
ignore_missing=ignore_missing)
if not force:
self._delete(
_backup.Backup, backup, ignore_missing=ignore_missing)
else:
backup = self._get_resource(_backup.Backup, backup)
backup.force_delete(self)
# ====== BACKUP ACTIONS ======
def restore_backup(self, backup, volume_id, name):
"""Restore a Backup to volume
@ -290,29 +505,41 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
backup = self._get_resource(_backup.Backup, backup)
return backup.restore(self, volume_id=volume_id, name=name)
def wait_for_status(self, res, status='ACTIVE', failures=None,
def reset_backup(self, backup, status):
"""Reset status of the backup
:param backup: The value can be either the ID of a backup or a
:class:`~openstack.block_storage.v3.backup.Backup` instance.
:param str status: New backup status
:returns: None
"""
backup = self._get_resource(_backup.Backup, backup)
backup.reset(self, status)
def wait_for_status(self, res, status='available', failures=None,
interval=2, wait=120):
"""Wait for a resource to be in a particular status.
:param res: The resource to wait on to reach the specified status.
The resource must have a ``status`` attribute.
The resource must have a ``status`` attribute.
:type resource: A :class:`~openstack.resource.Resource` object.
:param status: Desired status.
:param failures: Statuses that would be interpreted as failures.
:type failures: :py:class:`list`
:param interval: Number of seconds to wait before to consecutive
checks. Default to 2.
checks. Default to 2.
:param wait: Maximum number of seconds to wait before the change.
Default to 120.
Default to 120.
:returns: The resource is returned on success.
:raises: :class:`~openstack.exceptions.ResourceTimeout` if transition
to the desired status failed to occur in specified seconds.
to the desired status failed to occur in specified seconds.
:raises: :class:`~openstack.exceptions.ResourceFailure` if the resource
has transited to one of the failure statuses.
has transited to one of the failure statuses.
:raises: :class:`~AttributeError` if the resource does not have a
``status`` attribute.
``status`` attribute.
"""
failures = ['Error'] if failures is None else failures
failures = ['error'] if failures is None else failures
return resource.wait_for_status(
self, res, status, failures, interval, wait)
@ -322,11 +549,177 @@ class Proxy(_base_proxy.BaseBlockStorageProxy):
:param res: The resource to wait on to be deleted.
:type resource: A :class:`~openstack.resource.Resource` object.
:param interval: Number of seconds to wait before to consecutive
checks. Default to 2.
checks. Default to 2.
:param wait: Maximum number of seconds to wait before the change.
Default to 120.
Default to 120.
:returns: The resource is returned on success.
:raises: :class:`~openstack.exceptions.ResourceTimeout` if transition
to delete failed to occur in the specified seconds.
to delete failed to occur in the specified seconds.
"""
return resource.wait_for_delete(self, res, interval, wait)
def get_quota_set(self, project, usage=False, **query):
"""Show QuotaSet information for the project
:param project: ID or instance of
:class:`~openstack.identity.project.Project` of the project for
which the quota should be retrieved
:param bool usage: When set to ``True`` quota usage and reservations
would be filled.
:param dict query: Additional query parameters to use.
:returns: One :class:`~openstack.block_storage.v2.quota_set.QuotaSet`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
"""
project = self._get_resource(_project.Project, project)
res = self._get_resource(
_quota_set.QuotaSet, None, project_id=project.id)
return res.fetch(
self, usage=usage, **query)
def get_quota_set_defaults(self, project):
"""Show QuotaSet defaults for the project
:param project: ID or instance of
:class:`~openstack.identity.project.Project` of the project for
which the quota should be retrieved
:returns: One :class:`~openstack.block_storage.v2.quota_set.QuotaSet`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
"""
project = self._get_resource(_project.Project, project)
res = self._get_resource(
_quota_set.QuotaSet, None, project_id=project.id)
return res.fetch(
self, base_path='/os-quota-sets/defaults')
def revert_quota_set(self, project, **query):
"""Reset Quota for the project/user.
:param project: ID or instance of
:class:`~openstack.identity.project.Project` of the project for
which the quota should be resetted.
:param dict query: Additional parameters to be used.
:returns: ``None``
"""
project = self._get_resource(_project.Project, project)
res = self._get_resource(
_quota_set.QuotaSet, None, project_id=project.id)
if not query:
query = {}
return res.delete(self, **query)
def update_quota_set(self, quota_set, query=None, **attrs):
"""Update a QuotaSet.
:param quota_set: Either the ID of a quota_set or a
:class:`~openstack.block_storage.v2.quota_set.QuotaSet` instance.
:param dict query: Optional parameters to be used with update call.
:attrs kwargs: The attributes to update on the QuotaSet represented
by ``quota_set``.
:returns: The updated QuotaSet
:rtype: :class:`~openstack.block_storage.v2.quota_set.QuotaSet`
"""
res = self._get_resource(_quota_set.QuotaSet, quota_set, **attrs)
if not query:
query = {}
return res.commit(self, **query)
def get_volume_metadata(self, volume):
"""Return a dictionary of metadata for a volume
:param volume: Either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume`.
:returns: A :class:`~openstack.block_storage.v2.volume.Volume` with the
volume's metadata. All keys and values are Unicode text.
:rtype: :class:`~openstack.block_storage.v2.volume.Volume`
"""
volume = self._get_resource(_volume.Volume, volume)
return volume.fetch_metadata(self)
def set_volume_metadata(self, volume, **metadata):
"""Update metadata for a volume
:param volume: Either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume`.
:param kwargs metadata: Key/value pairs to be updated in the volume's
metadata. No other metadata is modified by this call. All keys
and values are stored as Unicode.
:returns: A :class:`~openstack.block_storage.v2.volume.Volume` with the
volume's metadata. All keys and values are Unicode text.
:rtype: :class:`~openstack.block_storage.v2.volume.Volume`
"""
volume = self._get_resource(_volume.Volume, volume)
return volume.set_metadata(self, metadata=metadata)
def delete_volume_metadata(self, volume, keys=None):
"""Delete metadata for a volume
:param volume: Either the ID of a volume or a
:class:`~openstack.block_storage.v2.volume.Volume`.
:param list keys: The keys to delete. If left empty complete
metadata will be removed.
:rtype: ``None``
"""
volume = self._get_resource(_volume.Volume, volume)
if keys is not None:
for key in keys:
volume.delete_metadata_item(self, key)
else:
volume.delete_metadata(self)
def get_snapshot_metadata(self, snapshot):
"""Return a dictionary of metadata for a snapshot
:param snapshot: Either the ID of a snapshot or a
:class:`~openstack.block_storage.v2.snapshot.Snapshot`.
:returns: A
:class:`~openstack.block_storage.v2.snapshot.Snapshot` with the
snapshot's metadata. All keys and values are Unicode text.
:rtype: :class:`~openstack.block_storage.v2.snapshot.Snapshot`
"""
snapshot = self._get_resource(_snapshot.Snapshot, snapshot)
return snapshot.fetch_metadata(self)
def set_snapshot_metadata(self, snapshot, **metadata):
"""Update metadata for a snapshot
:param snapshot: Either the ID of a snapshot or a
:class:`~openstack.block_storage.v2.snapshot.Snapshot`.
:param kwargs metadata: Key/value pairs to be updated in the snapshot's
metadata. No other metadata is modified by this call. All keys
and values are stored as Unicode.
:returns: A
:class:`~openstack.block_storage.v2.snapshot.Snapshot` with the
snapshot's metadata. All keys and values are Unicode text.
:rtype: :class:`~openstack.block_storage.v2.snapshot.Snapshot`
"""
snapshot = self._get_resource(_snapshot.Snapshot, snapshot)
return snapshot.set_metadata(self, metadata=metadata)
def delete_snapshot_metadata(self, snapshot, keys=None):
"""Delete metadata for a snapshot
:param snapshot: Either the ID of a snapshot or a
:class:`~openstack.block_storage.v2.snapshot.Snapshot`.
:param list keys: The keys to delete. If left empty complete
metadata will be removed.
:rtype: ``None``
"""
snapshot = self._get_resource(_snapshot.Snapshot, snapshot)
if keys is not None:
for key in keys:
snapshot.delete_metadata_item(self, key)
else:
snapshot.delete_metadata(self)

View File

@ -122,7 +122,7 @@ class Backup(resource.Resource):
else:
# Just for safety of the implementation (since PUT removed)
raise exceptions.ResourceFailure(
msg="Invalid create method: %s" % self.create_method)
"Invalid create method: %s" % self.create_method)
has_body = (self.has_body if self.create_returns_body is None
else self.create_returns_body)
@ -134,6 +134,14 @@ class Backup(resource.Resource):
return self.fetch(session)
return self
def _action(self, session, body, microversion=None):
"""Preform backup actions given the message body."""
url = utils.urljoin(self.base_path, self.id, 'action')
resp = session.post(url, json=body,
microversion=self._max_microversion)
exceptions.raise_from_response(resp)
return resp
def restore(self, session, volume_id=None, name=None):
"""Restore current backup to volume
@ -156,5 +164,17 @@ class Backup(resource.Resource):
self._translate_response(response, has_body=False)
return self
def force_delete(self, session):
"""Force backup deletion
"""
body = {'os-force_delete': {}}
self._action(session, body)
def reset(self, session, status):
"""Reset the status of the backup
"""
body = {'os-reset_status': {'status': status}}
self._action(session, body)
BackupDetail = Backup

View File

@ -0,0 +1,33 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import quota_set
from openstack import resource
class QuotaSet(quota_set.QuotaSet):
#: Properties
#: The size (GB) of backups that are allowed for each project.
backup_gigabytes = resource.Body('backup_gigabytes', type=int)
#: The number of backups that are allowed for each project.
backups = resource.Body('backups', type=int)
#: The size (GB) of volumes and snapshots that are allowed for each
#: project.
gigabytes = resource.Body('gigabytes', type=int)
#: The number of groups that are allowed for each project.
groups = resource.Body('groups', type=int)
#: The size (GB) of volumes in request that are allowed for each volume.
per_volume_gigabytes = resource.Body('per_volume_gigabytes', type=int)
#: The number of snapshots that are allowed for each project.
snapshots = resource.Body('snapshots', type=int)
#: The number of volumes that are allowed for each project.
volumes = resource.Body('volumes', type=int)

View File

@ -10,11 +10,14 @@
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import metadata
from openstack import exceptions
from openstack import format
from openstack import resource
from openstack import utils
class Snapshot(resource.Resource):
class Snapshot(resource.Resource, metadata.MetadataMixin):
resource_key = "snapshot"
resources_key = "snapshots"
base_path = "/snapshots"
@ -30,41 +33,34 @@ class Snapshot(resource.Resource):
allow_list = True
# Properties
#: A ID representing this snapshot.
id = resource.Body("id")
#: Name of the snapshot. Default is None.
name = resource.Body("name")
#: The current status of this snapshot. Potential values are creating,
#: available, deleting, error, and error_deleting.
status = resource.Body("status")
#: Description of snapshot. Default is None.
description = resource.Body("description")
#: The timestamp of this snapshot creation.
created_at = resource.Body("created_at")
#: Metadata associated with this snapshot.
metadata = resource.Body("metadata", type=dict)
#: The ID of the volume this snapshot was taken of.
volume_id = resource.Body("volume_id")
#: The size of the volume, in GBs.
size = resource.Body("size", type=int)
#: Description of snapshot. Default is None.
description = resource.Body("description")
#: Indicate whether to create snapshot, even if the volume is attached.
#: Default is ``False``. *Type: bool*
is_forced = resource.Body("force", type=format.BoolStr)
#: The size of the volume, in GBs.
size = resource.Body("size", type=int)
#: The current status of this snapshot. Potential values are creating,
#: available, deleting, error, and error_deleting.
status = resource.Body("status")
#: The ID of the volume this snapshot was taken of.
volume_id = resource.Body("volume_id")
def _action(self, session, body, microversion=None):
"""Preform backup actions given the message body."""
url = utils.urljoin(self.base_path, self.id, 'action')
resp = session.post(url, json=body,
microversion=self._max_microversion)
exceptions.raise_from_response(resp)
return resp
def reset(self, session, status):
"""Reset the status of the snapshot.
"""
body = {'os-reset_status': {'status': status}}
self._action(session, body)
class SnapshotDetail(Snapshot):
base_path = "/snapshots/detail"
# capabilities
allow_fetch = False
allow_create = False
allow_delete = False
allow_commit = False
allow_list = True
#: The percentage of completeness the snapshot is currently at.
progress = resource.Body("os-extended-snapshot-attributes:progress")
#: The project ID this snapshot is associated with.
project_id = resource.Body("os-extended-snapshot-attributes:project_id")
SnapshotDetail = Snapshot

View File

@ -10,7 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from openstack import exceptions
from openstack import resource
from openstack import utils
class Type(resource.Resource):
@ -27,11 +29,31 @@ class Type(resource.Resource):
_query_mapping = resource.QueryParameters("is_public")
# Properties
#: A ID representing this type.
id = resource.Body("id")
#: Name of the type.
name = resource.Body("name")
#: A dict of extra specifications. "capabilities" is a usual key.
extra_specs = resource.Body("extra_specs", type=dict)
#: a private volume-type. *Type: bool*
is_public = resource.Body('os-volume-type-access:is_public', type=bool)
def get_private_access(self, session):
url = utils.urljoin(self.base_path, self.id, "os-volume-type-access")
resp = session.get(url)
exceptions.raise_from_response(resp)
return resp.json().get("volume_type_access", [])
def add_private_access(self, session, project_id):
url = utils.urljoin(self.base_path, self.id, "action")
body = {"addProjectAccess": {"project": project_id}}
resp = session.post(url, json=body)
exceptions.raise_from_response(resp)
def remove_private_access(self, session, project_id):
url = utils.urljoin(self.base_path, self.id, "action")
body = {"removeProjectAccess": {"project": project_id}}
resp = session.post(url, json=body)
exceptions.raise_from_response(resp)

View File

@ -9,13 +9,13 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import metadata
from openstack import format
from openstack import resource
from openstack import utils
class Volume(resource.Resource):
class Volume(resource.Resource, metadata.MetadataMixin):
resource_key = "volume"
resources_key = "volumes"
base_path = "/volumes"
@ -31,74 +31,67 @@ class Volume(resource.Resource):
allow_list = True
# Properties
#: A ID representing this volume.
id = resource.Body("id")
#: The name of this volume.
name = resource.Body("name")
#: A list of links associated with this volume. *Type: list*
links = resource.Body("links", type=list)
#: TODO(briancurtin): This is currently undocumented in the API.
attachments = resource.Body("attachments")
#: The availability zone.
availability_zone = resource.Body("availability_zone")
#: To create a volume from an existing volume, specify the ID of
#: the existing volume. If specified, the volume is created with
#: same size of the source volume.
source_volume_id = resource.Body("source_volid")
#: ID of the consistency group.
consistency_group_id = resource.Body("consistencygroup_id")
#: The timestamp of this volume creation.
created_at = resource.Body("created_at")
#: The date and time when the resource was updated.
updated_at = resource.Body("updated_at")
#: The volume description.
description = resource.Body("description")
#: Extended replication status on this volume.
extended_replication_status = resource.Body(
"os-volume-replication:extended_status")
#: The volume's current back-end.
host = resource.Body("os-vol-host-attr:host")
#: The ID of the image from which you want to create the volume.
#: Required to create a bootable volume.
image_id = resource.Body("imageRef")
#: Enables or disables the bootable attribute. You can boot an
#: instance from a bootable volume. *Type: bool*
is_bootable = resource.Body("bootable", type=format.BoolStr)
#: ``True`` if this volume is encrypted, ``False`` if not.
#: *Type: bool*
is_encrypted = resource.Body("encrypted", type=format.BoolStr)
#: The volume ID that this volume's name on the back-end is based on.
migration_id = resource.Body("os-vol-mig-status-attr:name_id")
#: The status of this volume's migration (None means that a migration
#: is not currently in progress).
migration_status = resource.Body("os-vol-mig-status-attr:migstat")
#: The project ID associated with current back-end.
project_id = resource.Body("os-vol-tenant-attr:tenant_id")
#: Data set by the replication driver
replication_driver_data = resource.Body(
"os-volume-replication:driver_data")
#: Status of replication on this volume.
replication_status = resource.Body("replication_status")
#: Scheduler hints for the volume
scheduler_hints = resource.Body('OS-SCH-HNT:scheduler_hints', type=dict)
#: The size of the volume, in GBs. *Type: int*
size = resource.Body("size", type=int)
#: To create a volume from an existing snapshot, specify the ID of
#: the existing volume snapshot. If specified, the volume is created
#: in same availability zone and with same size of the snapshot.
snapshot_id = resource.Body("snapshot_id")
#: The size of the volume, in GBs. *Type: int*
size = resource.Body("size", type=int)
#: The ID of the image from which you want to create the volume.
#: Required to create a bootable volume.
image_id = resource.Body("imageRef")
#: The name of the associated volume type.
volume_type = resource.Body("volume_type")
#: Enables or disables the bootable attribute. You can boot an
#: instance from a bootable volume. *Type: bool*
is_bootable = resource.Body("bootable", type=format.BoolStr)
#: One or more metadata key and value pairs to associate with the volume.
metadata = resource.Body("metadata")
#: One or more metadata key and value pairs about image
volume_image_metadata = resource.Body("volume_image_metadata")
#: To create a volume from an existing volume, specify the ID of
#: the existing volume. If specified, the volume is created with
#: same size of the source volume.
source_volume_id = resource.Body("source_volid")
#: One of the following values: creating, available, attaching, in-use
#: deleting, error, error_deleting, backing-up, restoring-backup,
#: error_restoring. For details on these statuses, see the
#: Block Storage API documentation.
status = resource.Body("status")
#: TODO(briancurtin): This is currently undocumented in the API.
attachments = resource.Body("attachments")
#: The timestamp of this volume creation.
created_at = resource.Body("created_at")
#: The volume's current back-end.
host = resource.Body("os-vol-host-attr:host")
#: The project ID associated with current back-end.
project_id = resource.Body("os-vol-tenant-attr:tenant_id")
#: The user ID associated with the volume
user_id = resource.Body("user_id")
#: The status of this volume's migration (None means that a migration
#: is not currently in progress).
migration_status = resource.Body("os-vol-mig-status-attr:migstat")
#: The volume ID that this volume's name on the back-end is based on.
migration_id = resource.Body("os-vol-mig-status-attr:name_id")
#: Status of replication on this volume.
replication_status = resource.Body("replication_status")
#: Extended replication status on this volume.
extended_replication_status = resource.Body(
"os-volume-replication:extended_status")
#: ID of the consistency group.
consistency_group_id = resource.Body("consistencygroup_id")
#: Data set by the replication driver
replication_driver_data = resource.Body(
"os-volume-replication:driver_data")
#: ``True`` if this volume is encrypted, ``False`` if not.
#: *Type: bool*
is_encrypted = resource.Body("encrypted", type=format.BoolStr)
#: One or more metadata key and value pairs about image
volume_image_metadata = resource.Body("volume_image_metadata")
#: The name of the associated volume type.
volume_type = resource.Body("volume_type")
def _action(self, session, body):
"""Preform volume actions given the message body."""
@ -106,13 +99,93 @@ class Volume(resource.Resource):
# as both Volume and VolumeDetail instances can be acted on, but
# the URL used is sans any additional /detail/ part.
url = utils.urljoin(Volume.base_path, self.id, 'action')
headers = {'Accept': ''}
return session.post(url, json=body, headers=headers)
return session.post(url, json=body, microversion=None)
def extend(self, session, size):
"""Extend a volume size."""
body = {'os-extend': {'new_size': size}}
self._action(session, body)
def set_bootable_status(self, session, bootable=True):
"""Set volume bootable status flag"""
body = {'os-set_bootable': {'bootable': bootable}}
self._action(session, body)
def reset_status(
self, session, status, attach_status, migration_status
):
"""Reset volume statuses (admin operation)"""
body = {'os-reset_status': {
'status': status,
'attach_status': attach_status,
'migration_status': migration_status
}}
self._action(session, body)
def attach(
self, session, mountpoint, instance
):
"""Attach volume to server"""
body = {'os-attach': {
'mountpoint': mountpoint,
'instance_uuid': instance}}
self._action(session, body)
def detach(self, session, attachment, force=False):
"""Detach volume from server"""
if not force:
body = {'os-detach': {'attachment_id': attachment}}
if force:
body = {'os-force_detach': {
'attachment_id': attachment}}
self._action(session, body)
def unmanage(self, session):
"""Unmanage volume"""
body = {'os-unmanage': {}}
self._action(session, body)
def retype(self, session, new_type, migration_policy=None):
"""Change volume type"""
body = {'os-retype': {
'new_type': new_type}}
if migration_policy:
body['os-retype']['migration_policy'] = migration_policy
self._action(session, body)
def migrate(
self, session, host=None, force_host_copy=False,
lock_volume=False
):
"""Migrate volume"""
req = dict()
if host is not None:
req['host'] = host
if force_host_copy:
req['force_host_copy'] = force_host_copy
if lock_volume:
req['lock_volume'] = lock_volume
body = {'os-migrate_volume': req}
self._action(session, body)
def complete_migration(self, session, new_volume_id, error=False):
"""Complete volume migration"""
body = {'os-migrate_volume_completion': {
'new_volume': new_volume_id,
'error': error}}
self._action(session, body)
def force_delete(self, session):
"""Force volume deletion"""
body = {'os-force_delete': {}}
self._action(session, body)
VolumeDetail = Volume

File diff suppressed because it is too large Load Diff

View File

@ -132,7 +132,7 @@ class Backup(resource.Resource):
else:
# Just for safety of the implementation (since PUT removed)
raise exceptions.ResourceFailure(
msg="Invalid create method: %s" % self.create_method)
"Invalid create method: %s" % self.create_method)
has_body = (self.has_body if self.create_returns_body is None
else self.create_returns_body)
@ -144,6 +144,14 @@ class Backup(resource.Resource):
return self.fetch(session)
return self
def _action(self, session, body, microversion=None):
"""Preform backup actions given the message body."""
url = utils.urljoin(self.base_path, self.id, 'action')
resp = session.post(url, json=body,
microversion=self._max_microversion)
exceptions.raise_from_response(resp)
return resp
def restore(self, session, volume_id=None, name=None):
"""Restore current backup to volume
@ -161,10 +169,21 @@ class Backup(resource.Resource):
if not (volume_id or name):
raise exceptions.SDKException('Either of `name` or `volume_id`'
' must be specified.')
response = session.post(url,
json=body)
response = session.post(url, json=body)
self._translate_response(response, has_body=False)
return self
def force_delete(self, session):
"""Force backup deletion
"""
body = {'os-force_delete': {}}
self._action(session, body)
def reset(self, session, status):
"""Reset the status of the backup
"""
body = {'os-reset_status': {'status': status}}
self._action(session, body)
BackupDetail = Backup

View File

@ -0,0 +1,33 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import quota_set
from openstack import resource
class QuotaSet(quota_set.QuotaSet):
#: Properties
#: The size (GB) of backups that are allowed for each project.
backup_gigabytes = resource.Body('backup_gigabytes', type=int)
#: The number of backups that are allowed for each project.
backups = resource.Body('backups', type=int)
#: The size (GB) of volumes and snapshots that are allowed for each
#: project.
gigabytes = resource.Body('gigabytes', type=int)
#: The number of groups that are allowed for each project.
groups = resource.Body('groups', type=int)
#: The size (GB) of volumes in request that are allowed for each volume.
per_volume_gigabytes = resource.Body('per_volume_gigabytes', type=int)
#: The number of snapshots that are allowed for each project.
snapshots = resource.Body('snapshots', type=int)
#: The number of volumes that are allowed for each project.
volumes = resource.Body('volumes', type=int)

View File

@ -10,11 +10,14 @@
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import metadata
from openstack import exceptions
from openstack import format
from openstack import resource
from openstack import utils
class Snapshot(resource.Resource):
class Snapshot(resource.Resource, metadata.MetadataMixin):
resource_key = "snapshot"
resources_key = "snapshots"
base_path = "/snapshots"
@ -31,24 +34,10 @@ class Snapshot(resource.Resource):
allow_list = True
# Properties
#: A ID representing this snapshot.
id = resource.Body("id")
#: Name of the snapshot. Default is None.
name = resource.Body("name")
#: The current status of this snapshot. Potential values are creating,
#: available, deleting, error, and error_deleting.
status = resource.Body("status")
#: Description of snapshot. Default is None.
description = resource.Body("description")
#: The timestamp of this snapshot creation.
created_at = resource.Body("created_at")
#: Metadata associated with this snapshot.
metadata = resource.Body("metadata", type=dict)
#: The ID of the volume this snapshot was taken of.
volume_id = resource.Body("volume_id")
#: The size of the volume, in GBs.
size = resource.Body("size", type=int)
#: Description of snapshot. Default is None.
description = resource.Body("description")
#: Indicate whether to create snapshot, even if the volume is attached.
#: Default is ``False``. *Type: bool*
is_forced = resource.Body("force", type=format.BoolStr)
@ -56,6 +45,42 @@ class Snapshot(resource.Resource):
progress = resource.Body("os-extended-snapshot-attributes:progress")
#: The project ID this snapshot is associated with.
project_id = resource.Body("os-extended-snapshot-attributes:project_id")
#: The size of the volume, in GBs.
size = resource.Body("size", type=int)
#: The current status of this snapshot. Potential values are creating,
#: available, deleting, error, and error_deleting.
status = resource.Body("status")
#: The ID of the volume this snapshot was taken of.
volume_id = resource.Body("volume_id")
def _action(self, session, body, microversion=None):
"""Preform backup actions given the message body."""
url = utils.urljoin(self.base_path, self.id, 'action')
resp = session.post(url, json=body,
microversion=self._max_microversion)
exceptions.raise_from_response(resp)
return resp
def force_delete(self, session):
"""Force snapshot deletion.
"""
body = {'os-force_delete': {}}
self._action(session, body)
def reset(self, session, status):
"""Reset the status of the snapshot.
"""
body = {'os-reset_status': {'status': status}}
self._action(session, body)
def set_status(self, session, status, progress=None):
"""Update fields related to the status of a snapshot.
"""
body = {'os-update_snapshot_status': {
'status': status}}
if progress is not None:
body['os-update_snapshot_status']['progress'] = progress
self._action(session, body)
SnapshotDetail = Snapshot

View File

@ -30,10 +30,6 @@ class Type(resource.Resource):
_query_mapping = resource.QueryParameters("is_public")
# Properties
#: A ID representing this type.
id = resource.Body("id")
#: Name of the type.
name = resource.Body("name")
#: Description of the type.
description = resource.Body("description")
#: A dict of extra specifications. "capabilities" is a usual key.
@ -94,6 +90,30 @@ class Type(resource.Resource):
for key in keys:
self._extra_specs(session.delete, key=key, delete=True)
def get_private_access(self, session):
url = utils.urljoin(self.base_path, self.id, "os-volume-type-access")
resp = session.get(url)
exceptions.raise_from_response(resp)
return resp.json().get("volume_type_access", [])
def add_private_access(self, session, project_id):
url = utils.urljoin(self.base_path, self.id, "action")
body = {"addProjectAccess": {"project": project_id}}
resp = session.post(url, json=body)
exceptions.raise_from_response(resp)
def remove_private_access(self, session, project_id):
url = utils.urljoin(self.base_path, self.id, "action")
body = {"removeProjectAccess": {"project": project_id}}
resp = session.post(url, json=body)
exceptions.raise_from_response(resp)
class TypeEncryption(resource.Resource):
resource_key = "encryption"
@ -108,23 +128,23 @@ class TypeEncryption(resource.Resource):
allow_commit = True
# Properties
#: The encryption algorithm or mode.
cipher = resource.Body("cipher")
#: Notional service where encryption is performed.
control_location = resource.Body("control_location")
#: The date and time when the resource was created.
created_at = resource.Body("created_at")
#: The resource is deleted or not.
deleted = resource.Body("deleted")
#: The date and time when the resource was deleted.
deleted_at = resource.Body("deleted_at")
#: A ID representing this type.
encryption_id = resource.Body("encryption_id", alternate_id=True)
#: The ID of the Volume Type.
volume_type_id = resource.URI("volume_type_id")
#: The Size of encryption key.
key_size = resource.Body("key_size")
#: The class that provides encryption support.
provider = resource.Body("provider")
#: Notional service where encryption is performed.
control_location = resource.Body("control_location")
#: The encryption algorithm or mode.
cipher = resource.Body("cipher")
#: The resource is deleted or not.
deleted = resource.Body("deleted")
#: The date and time when the resource was created.
created_at = resource.Body("created_at")
#: The date and time when the resource was updated.
updated_at = resource.Body("updated_at")
#: The date and time when the resource was deleted.
deleted_at = resource.Body("deleted_at")
#: The ID of the Volume Type.
volume_type_id = resource.URI("volume_type_id")

View File

@ -10,18 +10,21 @@
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import metadata
from openstack import exceptions
from openstack import format
from openstack import resource
from openstack import utils
class Volume(resource.Resource):
class Volume(resource.Resource, metadata.MetadataMixin):
resource_key = "volume"
resources_key = "volumes"
base_path = "/volumes"
_query_mapping = resource.QueryParameters(
'name', 'status', 'project_id', all_projects='all_tenants')
'name', 'status', 'project_id', 'created_at', 'updated_at',
all_projects='all_tenants')
# capabilities
allow_fetch = True
@ -31,102 +34,247 @@ class Volume(resource.Resource):
allow_list = True
# Properties
#: A ID representing this volume.
id = resource.Body("id")
#: The name of this volume.
name = resource.Body("name")
#: A list of links associated with this volume. *Type: list*
links = resource.Body("links", type=list)
#: TODO(briancurtin): This is currently undocumented in the API.
attachments = resource.Body("attachments")
#: The availability zone.
availability_zone = resource.Body("availability_zone")
#: To create a volume from an existing volume, specify the ID of
#: the existing volume. If specified, the volume is created with
#: same size of the source volume.
source_volume_id = resource.Body("source_volid")
#: ID of the consistency group.
consistency_group_id = resource.Body("consistencygroup_id")
#: The timestamp of this volume creation.
created_at = resource.Body("created_at")
#: The date and time when the resource was updated.
updated_at = resource.Body("updated_at")
#: The volume description.
description = resource.Body("description")
#: Extended replication status on this volume.
extended_replication_status = resource.Body(
"os-volume-replication:extended_status")
#: The volume's current back-end.
host = resource.Body("os-vol-host-attr:host")
#: The ID of the image from which you want to create the volume.
#: Required to create a bootable volume.
image_id = resource.Body("imageRef")
#: Enables or disables the bootable attribute. You can boot an
#: instance from a bootable volume. *Type: bool*
is_bootable = resource.Body("bootable", type=format.BoolStr)
#: ``True`` if this volume is encrypted, ``False`` if not.
#: *Type: bool*
is_encrypted = resource.Body("encrypted", type=format.BoolStr)
#: The volume ID that this volume's name on the back-end is based on.
migration_id = resource.Body("os-vol-mig-status-attr:name_id")
#: The status of this volume's migration (None means that a migration
#: is not currently in progress).
migration_status = resource.Body("os-vol-mig-status-attr:migstat")
#: The project ID associated with current back-end.
project_id = resource.Body("os-vol-tenant-attr:tenant_id")
#: Data set by the replication driver
replication_driver_data = resource.Body(
"os-volume-replication:driver_data")
#: Status of replication on this volume.
replication_status = resource.Body("replication_status")
#: Scheduler hints for the volume
scheduler_hints = resource.Body('OS-SCH-HNT:scheduler_hints', type=dict)
#: The size of the volume, in GBs. *Type: int*
size = resource.Body("size", type=int)
#: To create a volume from an existing snapshot, specify the ID of
#: the existing volume snapshot. If specified, the volume is created
#: in same availability zone and with same size of the snapshot.
snapshot_id = resource.Body("snapshot_id")
#: The size of the volume, in GBs. *Type: int*
size = resource.Body("size", type=int)
#: The ID of the image from which you want to create the volume.
#: Required to create a bootable volume.
image_id = resource.Body("imageRef")
#: The name of the associated volume type.
volume_type = resource.Body("volume_type")
#: Enables or disables the bootable attribute. You can boot an
#: instance from a bootable volume. *Type: bool*
is_bootable = resource.Body("bootable", type=format.BoolStr)
#: One or more metadata key and value pairs to associate with the volume.
metadata = resource.Body("metadata")
#: One or more metadata key and value pairs about image
volume_image_metadata = resource.Body("volume_image_metadata")
#: To create a volume from an existing volume, specify the ID of
#: the existing volume. If specified, the volume is created with
#: same size of the source volume.
source_volume_id = resource.Body("source_volid")
#: One of the following values: creating, available, attaching, in-use
#: deleting, error, error_deleting, backing-up, restoring-backup,
#: error_restoring. For details on these statuses, see the
#: Block Storage API documentation.
status = resource.Body("status")
#: TODO(briancurtin): This is currently undocumented in the API.
attachments = resource.Body("attachments")
#: The timestamp of this volume creation.
created_at = resource.Body("created_at")
#: The volume's current back-end.
host = resource.Body("os-vol-host-attr:host")
#: The project ID associated with current back-end.
project_id = resource.Body("os-vol-tenant-attr:tenant_id")
#: The user ID associated with the volume
user_id = resource.Body("user_id")
#: The status of this volume's migration (None means that a migration
#: is not currently in progress).
migration_status = resource.Body("os-vol-mig-status-attr:migstat")
#: The volume ID that this volume's name on the back-end is based on.
migration_id = resource.Body("os-vol-mig-status-attr:name_id")
#: Status of replication on this volume.
replication_status = resource.Body("replication_status")
#: Extended replication status on this volume.
extended_replication_status = resource.Body(
"os-volume-replication:extended_status")
#: ID of the consistency group.
consistency_group_id = resource.Body("consistencygroup_id")
#: Data set by the replication driver
replication_driver_data = resource.Body(
"os-volume-replication:driver_data")
#: ``True`` if this volume is encrypted, ``False`` if not.
#: *Type: bool*
is_encrypted = resource.Body("encrypted", type=format.BoolStr)
#: One or more metadata key and value pairs about image
volume_image_metadata = resource.Body("volume_image_metadata")
#: The name of the associated volume type.
volume_type = resource.Body("volume_type")
def _action(self, session, body):
_max_microversion = "3.60"
def _action(self, session, body, microversion=None):
"""Preform volume actions given the message body."""
# NOTE: This is using Volume.base_path instead of self.base_path
# as both Volume and VolumeDetail instances can be acted on, but
# the URL used is sans any additional /detail/ part.
url = utils.urljoin(Volume.base_path, self.id, 'action')
headers = {'Accept': ''}
return session.post(url, json=body, headers=headers)
resp = session.post(url, json=body,
microversion=self._max_microversion)
exceptions.raise_from_response(resp)
return resp
def extend(self, session, size):
"""Extend a volume size."""
body = {'os-extend': {'new_size': size}}
self._action(session, body)
def set_bootable_status(self, session, bootable=True):
"""Set volume bootable status flag"""
body = {'os-set_bootable': {'bootable': bootable}}
self._action(session, body)
def set_readonly(self, session, readonly):
"""Set volume readonly flag"""
body = {'os-update_readonly_flag': {'readonly': readonly}}
self._action(session, body)
def retype(self, session, new_type, migration_policy):
"""Retype volume considering the migration policy"""
body = {
'os-retype': {
'new_type': new_type,
'migration_policy': migration_policy
}
}
def reset_status(
self, session, status, attach_status, migration_status
):
"""Reset volume statuses (admin operation)"""
body = {'os-reset_status': {
'status': status,
'attach_status': attach_status,
'migration_status': migration_status
}}
self._action(session, body)
def revert_to_snapshot(self, session, snapshot_id):
"""Revert volume to its snapshot"""
utils.require_microversion(session, "3.40")
body = {'revert': {'snapshot_id': snapshot_id}}
self._action(session, body)
def attach(
self, session, mountpoint, instance=None, host_name=None
):
"""Attach volume to server"""
body = {'os-attach': {
'mountpoint': mountpoint}}
if instance is not None:
body['os-attach']['instance_uuid'] = instance
elif host_name is not None:
body['os-attach']['host_name'] = host_name
else:
raise ValueError(
'Either instance_uuid or host_name must be specified')
self._action(session, body)
def detach(self, session, attachment, force=False, connector=None):
"""Detach volume from server"""
if not force:
body = {'os-detach': {'attachment_id': attachment}}
if force:
body = {'os-force_detach': {
'attachment_id': attachment}}
if connector:
body['os-force_detach']['connector'] = connector
self._action(session, body)
def unmanage(self, session):
"""Unmanage volume"""
body = {'os-unmanage': {}}
self._action(session, body)
def retype(self, session, new_type, migration_policy=None):
"""Change volume type"""
body = {'os-retype': {
'new_type': new_type}}
if migration_policy:
body['os-retype']['migration_policy'] = migration_policy
self._action(session, body)
def migrate(
self, session, host=None, force_host_copy=False,
lock_volume=False, cluster=None
):
"""Migrate volume"""
req = dict()
if host is not None:
req['host'] = host
if force_host_copy:
req['force_host_copy'] = force_host_copy
if lock_volume:
req['lock_volume'] = lock_volume
if cluster is not None:
req['cluster'] = cluster
utils.require_microversion(session, "3.16")
body = {'os-migrate_volume': req}
self._action(session, body)
def complete_migration(self, session, new_volume_id, error=False):
"""Complete volume migration"""
body = {'os-migrate_volume_completion': {
'new_volume': new_volume_id,
'error': error}}
self._action(session, body)
def force_delete(self, session):
"""Force volume deletion"""
body = {'os-force_delete': {}}
self._action(session, body)
def upload_to_image(
self, session, image_name, force=False, disk_format=None,
container_format=None, visibility=None, protected=None
):
"""Upload the volume to image service"""
req = dict(image_name=image_name, force=force)
if disk_format is not None:
req['disk_format'] = disk_format
if container_format is not None:
req['container_format'] = container_format
if visibility is not None:
req['visibility'] = visibility
if protected is not None:
req['protected'] = protected
if visibility is not None or protected is not None:
utils.require_microversion(session, "3.1")
body = {'os-volume_upload_image': req}
resp = self._action(session, body).json()
return resp['os-volume_upload_image']
def reserve(self, session):
"""Reserve volume"""
body = {'os-reserve': {}}
self._action(session, body)
def unreserve(self, session):
"""Unreserve volume"""
body = {'os-unreserve': {}}
self._action(session, body)
def begin_detaching(self, session):
"""Update volume status to 'detaching'"""
body = {'os-begin_detaching': {}}
self._action(session, body)
def abort_detaching(self, session):
"""Roll back volume status to 'in-use'"""
body = {'os-roll_detaching': {}}
self._action(session, body)
def init_attachment(self, session, connector):
"""Initialize volume attachment"""
body = {'os-initialize_connection': {'connector': connector}}
self._action(session, body)
def terminate_attachment(self, session, connector):
"""Terminate volume attachment"""
body = {'os-terminate_connection': {'connector': connector}}
self._action(session, body)

View File

@ -14,17 +14,15 @@
# We can't just use list, because sphinx gets confused by
# openstack.resource.Resource.list and openstack.resource2.Resource.list
from openstack.cloud import _normalize
class AcceleratorCloudMixin(_normalize.Normalizer):
class AcceleratorCloudMixin:
def list_deployables(self, filters=None):
"""List all available deployables.
:param filters: (optional) dict of filter conditions to push down
:returns: A list of deployable info.
"""
# Translate None from search interface to empty {} for kwargs below
if not filters:
filters = {}
@ -32,10 +30,10 @@ class AcceleratorCloudMixin(_normalize.Normalizer):
def list_devices(self, filters=None):
"""List all devices.
:param filters: (optional) dict of filter conditions to push down
:returns: A list of device info.
"""
# Translate None from search interface to empty {} for kwargs below
if not filters:
filters = {}
@ -43,10 +41,10 @@ class AcceleratorCloudMixin(_normalize.Normalizer):
def list_device_profiles(self, filters=None):
"""List all device_profiles.
:param filters: (optional) dict of filter conditions to push down
:returns: A list of device profile info.
"""
# Translate None from search interface to empty {} for kwargs below
if not filters:
filters = {}
@ -54,19 +52,20 @@ class AcceleratorCloudMixin(_normalize.Normalizer):
def create_device_profile(self, attrs):
"""Create a device_profile.
:param attrs: The info of device_profile to be created.
:returns: A ``munch.Munch`` of the created device_profile.
"""
return self.accelerator.create_device_profile(**attrs)
def delete_device_profile(self, name_or_id, filters):
"""Delete a device_profile.
:param name_or_id: The Name(or uuid) of device_profile to be deleted.
:param name_or_id: The name or uuid of the device profile to be
deleted.
:param filters: dict of filter conditions to push down
:returns: True if delete succeeded, False otherwise.
"""
device_profile = self.accelerator.get_device_profile(
name_or_id,
filters
@ -74,20 +73,20 @@ class AcceleratorCloudMixin(_normalize.Normalizer):
if device_profile is None:
self.log.debug(
"device_profile %s not found for deleting",
name_or_id
name_or_id,
)
return False
self.accelerator.delete_device_profile(name_or_id=name_or_id)
self.accelerator.delete_device_profile(device_profile=device_profile)
return True
def list_accelerator_requests(self, filters=None):
"""List all accelerator_requests.
:param filters: (optional) dict of filter conditions to push down
:returns: A list of accelerator request info.
"""
# Translate None from search interface to empty {} for kwargs below
if not filters:
filters = {}
@ -95,11 +94,12 @@ class AcceleratorCloudMixin(_normalize.Normalizer):
def delete_accelerator_request(self, name_or_id, filters):
"""Delete a accelerator_request.
:param name_or_id: The Name(or uuid) of accelerator_request.
:param name_or_id: The name or UUID of the accelerator request to
be deleted.
:param filters: dict of filter conditions to push down
:returns: True if delete succeeded, False otherwise.
"""
accelerator_request = self.accelerator.get_accelerator_request(
name_or_id,
filters
@ -107,29 +107,31 @@ class AcceleratorCloudMixin(_normalize.Normalizer):
if accelerator_request is None:
self.log.debug(
"accelerator_request %s not found for deleting",
name_or_id
name_or_id,
)
return False
self.accelerator.delete_accelerator_request(name_or_id=name_or_id)
self.accelerator.delete_accelerator_request(
accelerator_request=accelerator_request,
)
return True
def create_accelerator_request(self, attrs):
"""Create an accelerator_request.
:param attrs: The info of accelerator_request to be created.
:returns: A ``munch.Munch`` of the created accelerator_request.
"""
return self.accelerator.create_accelerator_request(**attrs)
def bind_accelerator_request(self, uuid, properties):
"""Bind an accelerator to VM.
:param uuid: The uuid of the accelerator_request to be binded.
:param properties: The info of VM that will bind the accelerator.
:returns: True if bind succeeded, False otherwise.
"""
accelerator_request = self.accelerator.get_accelerator_request(uuid)
if accelerator_request is None:
self.log.debug(
@ -141,11 +143,11 @@ class AcceleratorCloudMixin(_normalize.Normalizer):
def unbind_accelerator_request(self, uuid, properties):
"""Unbind an accelerator from VM.
:param uuid: The uuid of the accelerator_request to be unbinded.
:param properties: The info of VM that will unbind the accelerator.
:returns:True if unbind succeeded, False otherwise.
:returns: True if unbind succeeded, False otherwise.
"""
accelerator_request = self.accelerator.get_accelerator_request(uuid)
if accelerator_request is None:
self.log.debug(

View File

@ -18,13 +18,12 @@ import warnings
import jsonpatch
from openstack.cloud import _normalize
from openstack.cloud import _utils
from openstack.cloud import exc
from openstack import utils
class BaremetalCloudMixin(_normalize.Normalizer):
class BaremetalCloudMixin:
@property
def _baremetal_client(self):

View File

@ -14,13 +14,12 @@
# We can't just use list, because sphinx gets confused by
# openstack.resource.Resource.list and openstack.resource2.Resource.list
import types # noqa
import warnings
from openstack.cloud import _normalize
from openstack.block_storage.v3 import quota_set as _qs
from openstack.cloud import _utils
from openstack.cloud import exc
from openstack import exceptions
from openstack import proxy
from openstack import utils
def _no_pending_volumes(volumes):
@ -31,7 +30,7 @@ def _no_pending_volumes(volumes):
return True
class BlockStorageCloudMixin(_normalize.Normalizer):
class BlockStorageCloudMixin:
@_utils.cache_on_arguments(should_cache_fn=_no_pending_volumes)
def list_volumes(self, cache=True):
@ -40,56 +39,7 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
:returns: A list of volume ``munch.Munch``.
"""
def _list(data):
volumes.extend(data.get('volumes', []))
endpoint = None
for link in data.get('volumes_links', []):
if 'rel' in link and 'next' == link['rel']:
endpoint = link['href']
break
if endpoint:
try:
_list(proxy._json_response(
self.block_storage.get(endpoint)))
except exc.OpenStackCloudURINotFound:
# Catch and re-raise here because we are making recursive
# calls and we just have context for the log here
self.log.debug(
"While listing volumes, could not find next link"
" {link}.".format(link=data))
raise
if not cache:
warnings.warn('cache argument to list_volumes is deprecated. Use '
'invalidate instead.')
# Fetching paginated volumes can fails for several reasons, if
# something goes wrong we'll have to start fetching volumes from
# scratch
attempts = 5
for _ in range(attempts):
volumes = []
data = proxy._json_response(
self.block_storage.get('/volumes/detail'))
if 'volumes_links' not in data:
# no pagination needed
volumes.extend(data.get('volumes', []))
break
try:
_list(data)
break
except exc.OpenStackCloudURINotFound:
pass
else:
self.log.debug(
"List volumes failed to retrieve all volumes after"
" {attempts} attempts. Returning what we found.".format(
attempts=attempts))
# list volumes didn't complete succesfully so just return what
# we found
return self._normalize_volumes(
self._get_and_munchify(key=None, data=volumes))
return list(self.block_storage.volumes())
@_utils.cache_on_arguments()
def list_volume_types(self, get_extra=True):
@ -98,14 +48,7 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
:returns: A list of volume ``munch.Munch``.
"""
resp = self.block_storage.get(
'/types',
params=dict(is_public='None'))
data = proxy._json_response(
resp,
error_message='Error fetching volume_type list')
return self._normalize_volume_types(
self._get_and_munchify('volume_types', data))
return list(self.block_storage.types())
def get_volume(self, name_or_id, filters=None):
"""Get a volume by name or ID.
@ -138,15 +81,7 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
:param id: ID of the volume.
:returns: A volume ``munch.Munch``.
"""
resp = self.block_storage.get('/volumes/{id}'.format(id=id))
data = proxy._json_response(
resp,
error_message="Error getting volume with ID {id}".format(id=id)
)
volume = self._normalize_volume(
self._get_and_munchify('volume', data))
return volume
return self.block_storage.get_volume(id)
def get_volume_type(self, name_or_id, filters=None):
"""Get a volume type by name or ID.
@ -208,43 +143,20 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
kwargs['imageRef'] = image_obj['id']
kwargs = self._get_volume_kwargs(kwargs)
kwargs['size'] = size
payload = dict(volume=kwargs)
if 'scheduler_hints' in kwargs:
payload['OS-SCH-HNT:scheduler_hints'] = kwargs.pop(
'scheduler_hints', None)
resp = self.block_storage.post(
'/volumes',
json=dict(payload))
data = proxy._json_response(
resp,
error_message='Error in creating volume')
volume = self._get_and_munchify('volume', data)
volume = self.block_storage.create_volume(**kwargs)
self.list_volumes.invalidate(self)
if volume['status'] == 'error':
raise exc.OpenStackCloudException("Error in creating volume")
if wait:
vol_id = volume['id']
for count in utils.iterate_timeout(
timeout,
"Timeout waiting for the volume to be available."):
volume = self.get_volume(vol_id)
self.block_storage.wait_for_status(volume, wait=timeout)
if bootable:
self.block_storage.set_volume_bootable_status(volume, True)
if not volume:
continue
if volume['status'] == 'available':
if bootable is not None:
self.set_volume_bootable(volume, bootable=bootable)
# no need to re-fetch to update the flag, just set it.
volume['bootable'] = bootable
return volume
if volume['status'] == 'error':
raise exc.OpenStackCloudException("Error creating volume")
return self._normalize_volume(volume)
return volume
def update_volume(self, name_or_id, **kwargs):
kwargs = self._get_volume_kwargs(kwargs)
@ -254,16 +166,12 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
raise exc.OpenStackCloudException(
"Volume %s not found." % name_or_id)
resp = self.block_storage.put(
'/volumes/{volume_id}'.format(volume_id=volume.id),
json=dict({'volume': kwargs}))
data = proxy._json_response(
resp,
error_message='Error updating volume')
volume = self.block_storage.update_volume(
volume, **kwargs)
self.list_volumes.invalidate(self)
return self._normalize_volume(self._get_and_munchify('volume', data))
return volume
def set_volume_bootable(self, name_or_id, bootable=True):
"""Set a volume's bootable flag.
@ -283,14 +191,7 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
"Volume {name_or_id} does not exist".format(
name_or_id=name_or_id))
resp = self.block_storage.post(
'volumes/{id}/action'.format(id=volume['id']),
json={'os-set_bootable': {'bootable': bootable}})
proxy._json_response(
resp,
error_message="Error setting bootable on volume {volume}".format(
volume=volume['id'])
)
return self.block_storage.set_volume_bootable_status(volume, bootable)
def delete_volume(self, name_or_id=None, wait=True, timeout=None,
force=False):
@ -307,7 +208,7 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
"""
self.list_volumes.invalidate(self)
volume = self.get_volume(name_or_id)
volume = self.block_storage.find_volume(name_or_id)
if not volume:
self.log.debug(
@ -315,30 +216,15 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
{'name_or_id': name_or_id},
exc_info=True)
return False
with _utils.shade_exceptions("Error in deleting volume"):
try:
if force:
proxy._json_response(self.block_storage.post(
'volumes/{id}/action'.format(id=volume['id']),
json={'os-force_delete': None}))
else:
proxy._json_response(self.block_storage.delete(
'volumes/{id}'.format(id=volume['id'])))
except exc.OpenStackCloudURINotFound:
self.log.debug(
"Volume {id} not found when deleting. Ignoring.".format(
id=volume['id']))
return False
try:
self.block_storage.delete_volume(volume, force=force)
except exceptions.SDKException:
self.log.exception("error in deleting volume")
raise
self.list_volumes.invalidate(self)
if wait:
for count in utils.iterate_timeout(
timeout,
"Timeout waiting for the volume to be deleted."):
if not self.get_volume(volume['id']):
break
self.block_storage.wait_for_delete(volume, wait=timeout)
return True
@ -413,33 +299,13 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudTimeout if wait time exceeded.
:raises: OpenStackCloudException on operation error.
"""
proxy._json_response(self.compute.delete(
'/servers/{server_id}/os-volume_attachments/{volume_id}'.format(
server_id=server['id'], volume_id=volume['id'])),
error_message=(
"Error detaching volume {volume} from server {server}".format(
volume=volume['id'], server=server['id'])))
self.compute.delete_volume_attachment(
volume['id'], server['id'],
ignore_missing=False)
if wait:
for count in utils.iterate_timeout(
timeout,
"Timeout waiting for volume %s to detach." % volume['id']):
try:
vol = self.get_volume(volume['id'])
except Exception:
self.log.debug(
"Error getting volume info %s", volume['id'],
exc_info=True)
continue
if vol['status'] == 'available':
return
if vol['status'] == 'error':
raise exc.OpenStackCloudException(
"Error in detaching volume %s" % volume['id']
)
vol = self.get_volume(volume['id'])
self.block_storage.wait_for_status(vol)
def attach_volume(self, server, volume, device=None,
wait=True, timeout=None):
@ -481,55 +347,26 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
payload = {'volumeId': volume['id']}
if device:
payload['device'] = device
data = proxy._json_response(
self.compute.post(
'/servers/{server_id}/os-volume_attachments'.format(
server_id=server['id']),
json=dict(volumeAttachment=payload)),
error_message="Error attaching volume {volume_id} to server "
"{server_id}".format(volume_id=volume['id'],
server_id=server['id']))
attachment = self.compute.create_volume_attachment(
server=server['id'], **payload)
if wait:
for count in utils.iterate_timeout(
timeout,
"Timeout waiting for volume %s to attach." % volume['id']):
try:
self.list_volumes.invalidate(self)
vol = self.get_volume(volume['id'])
except Exception:
self.log.debug(
"Error getting volume info %s", volume['id'],
exc_info=True)
continue
if self.get_volume_attach_device(vol, server['id']):
break
# TODO(Shrews) check to see if a volume can be in error status
# and also attached. If so, we should move this
# above the get_volume_attach_device call
if vol['status'] == 'error':
raise exc.OpenStackCloudException(
"Error in attaching volume %s" % volume['id']
)
return self._normalize_volume_attachment(
self._get_and_munchify('volumeAttachment', data))
if not hasattr(volume, 'fetch'):
# If we got volume as dict we need to re-fetch it to be able to
# use wait_for_status.
volume = self.block_storage.get_volume(volume['id'])
self.block_storage.wait_for_status(
volume, 'in-use', wait=timeout)
return attachment
def _get_volume_kwargs(self, kwargs):
name = kwargs.pop('name', kwargs.pop('display_name', None))
description = kwargs.pop('description',
kwargs.pop('display_description', None))
if name:
if self.block_storage._version_matches(2):
kwargs['name'] = name
else:
kwargs['display_name'] = name
kwargs['name'] = name
if description:
if self.block_storage._version_matches(2):
kwargs['description'] = description
else:
kwargs['display_description'] = description
kwargs['description'] = description
return kwargs
@_utils.valid_kwargs('name', 'display_name',
@ -556,34 +393,13 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
"""
kwargs = self._get_volume_kwargs(kwargs)
payload = {'volume_id': volume_id, 'force': force}
payload = {'volume_id': volume_id}
payload.update(kwargs)
resp = self.block_storage.post(
'/snapshots',
json=dict(snapshot=payload))
data = proxy._json_response(
resp,
error_message="Error creating snapshot of volume "
"{volume_id}".format(volume_id=volume_id))
snapshot = self._get_and_munchify('snapshot', data)
snapshot = self.block_storage.create_snapshot(**payload)
if wait:
snapshot_id = snapshot['id']
for count in utils.iterate_timeout(
timeout,
"Timeout waiting for the volume snapshot to be available."
):
snapshot = self.get_volume_snapshot_by_id(snapshot_id)
snapshot = self.block_storage.wait_for_status(
snapshot, wait=timeout)
if snapshot['status'] == 'available':
break
if snapshot['status'] == 'error':
raise exc.OpenStackCloudException(
"Error in creating volume snapshot")
# TODO(mordred) need to normalize snapshots. We were normalizing them
# as volumes, which is an error. They need to be normalized as
# volume snapshots, which are completely different objects
return snapshot
def get_volume_snapshot_by_id(self, snapshot_id):
@ -595,14 +411,7 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
param: snapshot_id: ID of the volume snapshot.
"""
resp = self.block_storage.get(
'/snapshots/{snapshot_id}'.format(snapshot_id=snapshot_id))
data = proxy._json_response(
resp,
error_message="Error getting snapshot "
"{snapshot_id}".format(snapshot_id=snapshot_id))
return self._normalize_volume(
self._get_and_munchify('snapshot', data))
return self.block_storage.get_snapshot(snapshot_id)
def get_volume_snapshot(self, name_or_id, filters=None):
"""Get a volume by name or ID.
@ -658,32 +467,14 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
'volume_id': volume_id,
'description': description,
'force': force,
'incremental': incremental,
'is_incremental': incremental,
'snapshot_id': snapshot_id,
}
resp = self.block_storage.post(
'/backups', json=dict(backup=payload))
data = proxy._json_response(
resp,
error_message="Error creating backup of volume "
"{volume_id}".format(volume_id=volume_id))
backup = self._get_and_munchify('backup', data)
backup = self.block_storage.create_backup(**payload)
if wait:
backup_id = backup['id']
msg = ("Timeout waiting for the volume backup {} to be "
"available".format(backup_id))
for _ in utils.iterate_timeout(timeout, msg):
backup = self.get_volume_backup(backup_id)
if backup['status'] == 'available':
break
if backup['status'] == 'error':
raise exc.OpenStackCloudException(
"Error in creating volume backup {id}".format(
id=backup_id))
backup = self.block_storage.wait_for_status(backup, wait=timeout)
return backup
@ -702,14 +493,10 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
:returns: A list of volume snapshots ``munch.Munch``.
"""
endpoint = '/snapshots/detail' if detailed else '/snapshots'
resp = self.block_storage.get(
endpoint,
params=search_opts)
data = proxy._json_response(
resp,
error_message="Error getting a list of snapshots")
return self._get_and_munchify('snapshots', data)
if not search_opts:
search_opts = {}
return list(self.block_storage.snapshots(
details=detailed, **search_opts))
def list_volume_backups(self, detailed=True, search_opts=None):
"""
@ -728,13 +515,11 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
:returns: A list of volume backups ``munch.Munch``.
"""
endpoint = '/backups/detail' if detailed else '/backups'
resp = self.block_storage.get(
endpoint, params=search_opts)
data = proxy._json_response(
resp,
error_message="Error getting a list of backups")
return self._get_and_munchify('backups', data)
if not search_opts:
search_opts = {}
return list(self.block_storage.backups(details=detailed,
**search_opts))
def delete_volume_backup(self, name_or_id=None, force=False, wait=False,
timeout=None):
@ -755,22 +540,10 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
if not volume_backup:
return False
msg = "Error in deleting volume backup"
if force:
resp = self.block_storage.post(
'/backups/{backup_id}/action'.format(
backup_id=volume_backup['id']),
json={'os-force_delete': None})
else:
resp = self.block_storage.delete(
'/backups/{backup_id}'.format(
backup_id=volume_backup['id']))
proxy._json_response(resp, error_message=msg)
self.block_storage.delete_backup(
volume_backup, ignore_missing=False, force=force)
if wait:
msg = "Timeout waiting for the volume backup to be deleted."
for count in utils.iterate_timeout(timeout, msg):
if not self.get_volume_backup(volume_backup['id']):
break
self.block_storage.wait_for_delete(volume_backup, wait=timeout)
return True
@ -792,19 +565,11 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
if not volumesnapshot:
return False
resp = self.block_storage.delete(
'/snapshots/{snapshot_id}'.format(
snapshot_id=volumesnapshot['id']))
proxy._json_response(
resp,
error_message="Error in deleting volume snapshot")
self.block_storage.delete_snapshot(
volumesnapshot, ignore_missing=False)
if wait:
for count in utils.iterate_timeout(
timeout,
"Timeout waiting for the volume snapshot to be deleted."):
if not self.get_volume_snapshot(volumesnapshot['id']):
break
self.block_storage.wait_for_delete(volumesnapshot, wait=timeout)
return True
@ -840,14 +605,7 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
raise exc.OpenStackCloudException(
"VolumeType not found: %s" % name_or_id)
resp = self.block_storage.get(
'/types/{id}/os-volume-type-access'.format(id=volume_type.id))
data = proxy._json_response(
resp,
error_message="Unable to get volume type access"
" {name}".format(name=name_or_id))
return self._normalize_volume_type_accesses(
self._get_and_munchify('volume_type_access', data))
return self.block_storage.get_type_access(volume_type)
def add_volume_type_access(self, name_or_id, project_id):
"""Grant access on a volume_type to a project.
@ -863,15 +621,8 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
if not volume_type:
raise exc.OpenStackCloudException(
"VolumeType not found: %s" % name_or_id)
payload = {'project': project_id}
resp = self.block_storage.post(
'/types/{id}/action'.format(id=volume_type.id),
json=dict(addProjectAccess=payload))
proxy._json_response(
resp,
error_message="Unable to authorize {project} "
"to use volume type {name}".format(
name=name_or_id, project=project_id))
self.block_storage.add_type_access(volume_type, project_id)
def remove_volume_type_access(self, name_or_id, project_id):
"""Revoke access on a volume_type to a project.
@ -885,15 +636,7 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
if not volume_type:
raise exc.OpenStackCloudException(
"VolumeType not found: %s" % name_or_id)
payload = {'project': project_id}
resp = self.block_storage.post(
'/types/{id}/action'.format(id=volume_type.id),
json=dict(removeProjectAccess=payload))
proxy._json_response(
resp,
error_message="Unable to revoke {project} "
"to use volume type {name}".format(
name=name_or_id, project=project_id))
self.block_storage.remove_type_access(volume_type, project_id)
def set_volume_quotas(self, name_or_id, **kwargs):
""" Set a volume quota in a project
@ -905,17 +648,12 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
quota does not exist.
"""
proj = self.get_project(name_or_id)
if not proj:
raise exc.OpenStackCloudException("project does not exist")
proj = self.identity.find_project(
name_or_id, ignore_missing=False)
kwargs['tenant_id'] = proj.id
resp = self.block_storage.put(
'/os-quota-sets/{tenant_id}'.format(tenant_id=proj.id),
json={'quota_set': kwargs})
proxy._json_response(
resp,
error_message="No valid quota or resource")
self.block_storage.update_quota_set(
_qs.QuotaSet(project_id=proj.id),
**kwargs)
def get_volume_quotas(self, name_or_id):
""" Get volume quotas for a project
@ -925,16 +663,11 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
:returns: Munch object with the quotas
"""
proj = self.get_project(name_or_id)
if not proj:
raise exc.OpenStackCloudException("project does not exist")
proj = self.identity.find_project(
name_or_id, ignore_missing=False)
resp = self.block_storage.get(
'/os-quota-sets/{tenant_id}'.format(tenant_id=proj.id))
data = proxy._json_response(
resp,
error_message="cinder client call failed")
return self._get_and_munchify('quota_set', data)
return self.block_storage.get_quota_set(
proj)
def delete_volume_quotas(self, name_or_id):
""" Delete volume quotas for a project
@ -945,12 +678,8 @@ class BlockStorageCloudMixin(_normalize.Normalizer):
:returns: dict with the quotas
"""
proj = self.get_project(name_or_id)
if not proj:
raise exc.OpenStackCloudException("project does not exist")
proj = self.identity.find_project(
name_or_id, ignore_missing=False)
resp = self.block_storage.delete(
'/os-quota-sets/{tenant_id}'.format(tenant_id=proj.id))
return proxy._json_response(
resp,
error_message="cinder client call failed")
return self.block_storage.revert_quota_set(
proj)

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,8 @@ from openstack.cloud import _normalize
from openstack.cloud import _utils
from openstack.cloud import exc
from openstack.cloud import meta
from openstack.compute.v2 import quota_set as _qs
from openstack.compute.v2 import server as _server
from openstack import exceptions
from openstack import proxy
from openstack import utils
@ -72,13 +74,7 @@ class ComputeCloudMixin(_normalize.Normalizer):
@_utils.cache_on_arguments()
def _nova_extensions(self):
extensions = set()
data = proxy._json_response(
self.compute.get('/extensions'),
error_message="Error fetching extension list for nova")
for extension in self._get_and_munchify('extensions', data):
extensions.add(extension['alias'])
extensions = set([e.alias for e in self.compute.extensions()])
return extensions
def _has_nova_extension(self, extension_name):
@ -160,19 +156,14 @@ class ComputeCloudMixin(_normalize.Normalizer):
:returns: A list of flavor ``munch.Munch``.
"""
data = self.compute.flavors(details=True)
flavors = []
for flavor in data:
if not flavor.extra_specs and get_extra:
flavor.fetch_extra_specs(self.compute)
flavors.append(flavor._to_munch(original_names=False))
flavors = list(self.compute.flavors(
details=True, get_extra_specs=get_extra))
return flavors
def list_server_security_groups(self, server):
"""List all security groups associated with the given server.
:returns: A list of security group ``munch.Munch``.
:returns: A list of security group dictionary objects.
"""
# Don't even try if we're a cloud that doesn't have them
@ -183,7 +174,7 @@ class ComputeCloudMixin(_normalize.Normalizer):
server.fetch_security_groups(self.compute)
return self._normalize_secgroups(server.security_groups)
return server.security_groups
def _get_server_security_groups(self, server, security_groups):
if not self._has_secgroups():
@ -328,17 +319,11 @@ class ComputeCloudMixin(_normalize.Normalizer):
def _list_servers(self, detailed=False, all_projects=False, bare=False,
filters=None):
filters = filters or {}
servers = [
# TODO(mordred) Add original_names=False here and update the
# normalize file for server. Then, just remove the normalize call
# and the to_munch call.
self._normalize_server(server._to_munch())
for server in self.compute.servers(
all_projects=all_projects, allow_unknown_params=True,
**filters)]
return [
self._expand_server(server, detailed, bare)
for server in servers
for server in self.compute.servers(
all_projects=all_projects, allow_unknown_params=True,
**filters)
]
def list_server_groups(self):
@ -356,11 +341,10 @@ class ComputeCloudMixin(_normalize.Normalizer):
if different from the current project
:raises: OpenStackCloudException if it's not a valid project
:returns: Munch object with the limits
:returns: :class:`~openstack.compute.v2.limits.Limits` object.
"""
params = {}
project_id = None
error_msg = "Failed to get limits"
if name_or_id:
proj = self.get_project(name_or_id)
@ -368,13 +352,7 @@ class ComputeCloudMixin(_normalize.Normalizer):
raise exc.OpenStackCloudException("project does not exist")
project_id = proj.id
params['tenant_id'] = project_id
error_msg = "{msg} for the project: {project} ".format(
msg=error_msg, project=name_or_id)
data = proxy._json_response(
self.compute.get('/limits', params=params))
limits = self._get_and_munchify('limits', data)
return self._normalize_compute_limits(limits, project_id=project_id)
return self.compute.get_limits(**params)
def get_keypair(self, name_or_id, filters=None):
"""Get a keypair by name or ID.
@ -429,9 +407,9 @@ class ComputeCloudMixin(_normalize.Normalizer):
if not filters:
filters = {}
flavor = self.compute.find_flavor(
name_or_id, get_extra_specs=get_extra, **filters)
if flavor:
return flavor._to_munch(original_names=False)
name_or_id, get_extra_specs=get_extra,
ignore_missing=True, **filters)
return flavor
def get_flavor_by_id(self, id, get_extra=False):
""" Get a flavor by ID
@ -442,8 +420,7 @@ class ComputeCloudMixin(_normalize.Normalizer):
specs.
:returns: A flavor ``munch.Munch``.
"""
flavor = self.compute.get_flavor(id, get_extra_specs=get_extra)
return flavor._to_munch(original_names=False)
return self.compute.get_flavor(id, get_extra_specs=get_extra)
def get_server_console(self, server, length=None):
"""Get the console log for a server.
@ -531,14 +508,11 @@ class ComputeCloudMixin(_normalize.Normalizer):
:param id: ID of the server.
:returns: A server dict or None if no matching server is found.
:returns: A server object or None if no matching server is found.
"""
try:
data = proxy._json_response(
self.compute.get('/servers/{id}'.format(id=id)))
server = self._get_and_munchify('server', data)
return meta.add_server_interfaces(
self, self._normalize_server(server))
server = self.compute.get_server(id)
return meta.add_server_interfaces(self, server)
except exceptions.ResourceNotFound:
return None
@ -756,7 +730,6 @@ class ComputeCloudMixin(_normalize.Normalizer):
raise TypeError(
"create_server() requires either 'image' or 'boot_volume'")
microversion = None
server_json = {'server': kwargs}
# TODO(mordred) Add support for description starting in 2.19
@ -856,7 +829,8 @@ class ComputeCloudMixin(_normalize.Normalizer):
# A tag supported only in server microversion 2.32-2.36 or >= 2.42
# Bumping the version to 2.42 to support the 'tag' implementation
if 'tag' in nic:
microversion = utils.pick_microversion(self.compute, '2.42')
utils.require_microversion(
self.compute, '2.42')
net['tag'] = nic.pop('tag')
if nic:
raise exc.OpenStackCloudException(
@ -865,6 +839,9 @@ class ComputeCloudMixin(_normalize.Normalizer):
networks.append(net)
if networks:
kwargs['networks'] = networks
else:
# If user has not passed networks - let Nova try the best.
kwargs['networks'] = 'auto'
if image:
if isinstance(image, dict):
@ -890,32 +867,27 @@ class ComputeCloudMixin(_normalize.Normalizer):
volumes=volumes, kwargs=kwargs)
kwargs['name'] = name
endpoint = '/servers'
server = self.compute.create_server(**kwargs)
# TODO(mordred) We're only testing this in functional tests. We need
# to add unit tests for this too.
if 'block_device_mapping_v2' in kwargs:
endpoint = '/os-volumes_boot'
with _utils.shade_exceptions("Error in creating instance"):
data = proxy._json_response(
self.compute.post(endpoint, json=server_json,
microversion=microversion))
server = self._get_and_munchify('server', data)
admin_pass = server.get('adminPass') or kwargs.get('admin_pass')
if not wait:
# This is a direct get call to skip the list_servers
# cache which has absolutely no chance of containing the
# new server.
# Only do this if we're not going to wait for the server
# to complete booting, because the only reason we do it
# is to get a server record that is the return value from
# get/list rather than the return value of create. If we're
# going to do the wait loop below, this is a waste of a call
server = self.get_server_by_id(server.id)
if server.status == 'ERROR':
raise exc.OpenStackCloudCreateException(
resource='server', resource_id=server.id)
admin_pass = server.admin_password or kwargs.get('admin_pass')
if not wait:
# This is a direct get call to skip the list_servers
# cache which has absolutely no chance of containing the
# new server.
# Only do this if we're not going to wait for the server
# to complete booting, because the only reason we do it
# is to get a server record that is the return value from
# get/list rather than the return value of create. If we're
# going to do the wait loop below, this is a waste of a call
server = self.compute.get_server(server.id)
if server.status == 'ERROR':
raise exc.OpenStackCloudCreateException(
resource='server', resource_id=server.id)
server = meta.add_server_interfaces(self, server)
if wait:
else:
server = self.wait_for_server(
server,
auto_ip=auto_ip, ips=ips, ip_pool=ip_pool,
@ -923,7 +895,7 @@ class ComputeCloudMixin(_normalize.Normalizer):
nat_destination=nat_destination,
)
server.adminPass = admin_pass
server.admin_password = admin_pass
return server
def _get_boot_from_volume_kwargs(
@ -1107,41 +1079,23 @@ class ComputeCloudMixin(_normalize.Normalizer):
wait=False, timeout=180):
kwargs = {}
if image_id:
kwargs['imageRef'] = image_id
kwargs['image'] = image_id
if admin_pass:
kwargs['adminPass'] = admin_pass
kwargs['admin_password'] = admin_pass
data = proxy._json_response(
self.compute.post(
'/servers/{server_id}/action'.format(server_id=server_id),
json={'rebuild': kwargs}),
error_message="Error in rebuilding instance")
server = self._get_and_munchify('server', data)
server = self.compute.rebuild_server(
server_id,
**kwargs
)
if not wait:
return self._expand_server(
self._normalize_server(server), bare=bare, detailed=detailed)
server, bare=bare, detailed=detailed)
admin_pass = server.get('adminPass') or admin_pass
for count in utils.iterate_timeout(
timeout,
"Timeout waiting for server {0} to "
"rebuild.".format(server_id),
wait=self._SERVER_AGE):
try:
server = self.get_server(server_id, bare=True)
except Exception:
continue
if not server:
continue
if server['status'] == 'ERROR':
raise exc.OpenStackCloudException(
"Error in rebuilding the server",
extra_data=dict(server=server))
if server['status'] == 'ACTIVE':
server.adminPass = admin_pass
break
server = self.compute.wait_for_server(
server, wait=timeout)
if server['status'] == 'ACTIVE':
server.adminPass = admin_pass
return self._expand_server(server, detailed=detailed, bare=bare)
@ -1200,7 +1154,8 @@ class ComputeCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
# If delete_ips is True, we need the server to not be bare.
server = self.get_server(name_or_id, bare=True)
server = self.compute.find_server(
name_or_id, ignore_missing=True)
if not server:
return False
@ -1244,15 +1199,13 @@ class ComputeCloudMixin(_normalize.Normalizer):
if not server:
return False
if delete_ips and self._has_floating_ips():
if delete_ips and self._has_floating_ips() and server['addresses']:
self._delete_server_floating_ips(server, delete_ip_retry)
try:
proxy._json_response(
self.compute.delete(
'/servers/{id}'.format(id=server['id'])),
error_message="Error in deleting server")
except exc.OpenStackCloudURINotFound:
self.compute.delete_server(
server)
except exceptions.ResourceNotFound:
return False
except Exception:
raise
@ -1270,16 +1223,13 @@ class ComputeCloudMixin(_normalize.Normalizer):
and self.get_volumes(server)):
reset_volume_cache = True
for count in utils.iterate_timeout(
timeout,
"Timed out waiting for server to get deleted.",
# if _SERVER_AGE is 0 we still want to wait a bit
# to be friendly with the server.
wait=self._SERVER_AGE or 2):
with _utils.shade_exceptions("Error in deleting server"):
server = self.get_server(server['id'], bare=True)
if not server:
break
if not isinstance(server, _server.Server):
# We might come here with Munch object (at the moment).
# If this is the case - convert it into real server to be able to
# use wait_for_delete
server = _server.Server(id=server['id'])
self.compute.wait_for_delete(
server, wait=timeout)
if reset_volume_cache:
self.list_volumes.invalidate(self)
@ -1308,18 +1258,14 @@ class ComputeCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
server = self.get_server(name_or_id=name_or_id, bare=True)
if server is None:
raise exc.OpenStackCloudException(
"failed to find server '{server}'".format(server=name_or_id))
server = self.compute.find_server(
name_or_id,
ignore_missing=False
)
server = self.compute.update_server(
server, **kwargs)
data = proxy._json_response(
self.compute.put(
'/servers/{server_id}'.format(server_id=server['id']),
json={'server': kwargs}),
error_message="Error updating server {0}".format(name_or_id))
server = self._normalize_server(
self._get_and_munchify('server', data))
return self._expand_server(server, bare=bare, detailed=detailed)
def create_server_group(self, name, policies=[], policy=None):
@ -1393,9 +1339,7 @@ class ComputeCloudMixin(_normalize.Normalizer):
if flavorid == 'auto':
attrs['id'] = None
flavor = self.compute.create_flavor(**attrs)
return flavor._to_munch(original_names=False)
return self.compute.create_flavor(**attrs)
def delete_flavor(self, name_or_id):
"""Delete a flavor
@ -1470,8 +1414,7 @@ class ComputeCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
access = self.compute.get_flavor_access(flavor_id)
return _utils.normalize_flavor_accesses(access)
return self.compute.get_flavor_access(flavor_id)
def list_hypervisors(self, filters={}):
"""List all hypervisors
@ -1643,25 +1586,13 @@ class ComputeCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException if the resource to set the
quota does not exist.
"""
proj = self.get_project(name_or_id)
if not proj:
raise exc.OpenStackCloudException("project does not exist")
# compute_quotas = {key: val for key, val in kwargs.items()
# if key in quota.COMPUTE_QUOTAS}
# TODO(ghe): Manage volume and network quotas
# network_quotas = {key: val for key, val in kwargs.items()
# if key in quota.NETWORK_QUOTAS}
# volume_quotas = {key: val for key, val in kwargs.items()
# if key in quota.VOLUME_QUOTAS}
proj = self.identity.find_project(
name_or_id, ignore_missing=False)
kwargs['force'] = True
proxy._json_response(
self.compute.put(
'/os-quota-sets/{project}'.format(project=proj.id),
json={'quota_set': kwargs}),
error_message="No valid quota or resource")
self.compute.update_quota_set(
_qs.QuotaSet(project_id=proj.id),
**kwargs
)
def get_compute_quotas(self, name_or_id):
""" Get quota for a project
@ -1671,13 +1602,9 @@ class ComputeCloudMixin(_normalize.Normalizer):
:returns: Munch object with the quotas
"""
proj = self.get_project(name_or_id)
if not proj:
raise exc.OpenStackCloudException("project does not exist")
data = proxy._json_response(
self.compute.get(
'/os-quota-sets/{project}'.format(project=proj.id)))
return self._get_and_munchify('quota_set', data)
proj = self.identity.find_project(
name_or_id, ignore_missing=False)
return self.compute.get_quota_set(proj)
def delete_compute_quotas(self, name_or_id):
""" Delete quota for a project
@ -1688,12 +1615,9 @@ class ComputeCloudMixin(_normalize.Normalizer):
:returns: dict with the quotas
"""
proj = self.get_project(name_or_id)
if not proj:
raise exc.OpenStackCloudException("project does not exist")
return proxy._json_response(
self.compute.delete(
'/os-quota-sets/{project}'.format(project=proj.id)))
proj = self.identity.find_project(
name_or_id, ignore_missing=False)
return self.compute.revert_quota_set(proj)
def get_compute_usage(self, name_or_id, start=None, end=None):
""" Get usage for a specific project

View File

@ -15,14 +15,13 @@
# openstack.resource.Resource.list and openstack.resource2.Resource.list
import types # noqa
from openstack.cloud import _normalize
from openstack.cloud import _utils
from openstack.cloud import exc
from openstack import exceptions
from openstack import resource
class DnsCloudMixin(_normalize.Normalizer):
class DnsCloudMixin:
def list_zones(self, filters=None):
"""List all available zones.

View File

@ -82,8 +82,8 @@ class FloatingIPCloudMixin(_normalize.Normalizer):
def _neutron_list_floating_ips(self, filters=None):
if not filters:
filters = {}
data = self.network.get('/floatingips', params=filters)
return self._get_and_munchify('floatingips', data)
data = list(self.network.ips(**filters))
return data
def _nova_list_floating_ips(self):
try:
@ -228,11 +228,8 @@ class FloatingIPCloudMixin(_normalize.Normalizer):
error_message = "Error getting floating ip with ID {id}".format(id=id)
if self._use_neutron_floating():
data = proxy._json_response(
self.network.get('/floatingips/{id}'.format(id=id)),
error_message=error_message)
return self._normalize_floating_ip(
self._get_and_munchify('floatingip', data))
fip = self.network.get_ip(id)
return self._normalize_floating_ip(fip)
else:
data = proxy._json_response(
self.compute.get('/os-floating-ips/{id}'.format(id=id)),
@ -461,10 +458,8 @@ class FloatingIPCloudMixin(_normalize.Normalizer):
def _submit_create_fip(self, kwargs):
# Split into a method to aid in test mocking
data = self.network.post(
"/floatingips", json={"floatingip": kwargs})
return self._normalize_floating_ip(
self._get_and_munchify('floatingip', data))
data = self.network.create_ip(**kwargs)
return self._normalize_floating_ip(data)
def _neutron_create_floating_ip(
self, network_name_or_id=None, server=None,
@ -474,8 +469,9 @@ class FloatingIPCloudMixin(_normalize.Normalizer):
if not network_id:
if network_name_or_id:
network = self.get_network(network_name_or_id)
if not network:
try:
network = self.network.find_network(network_name_or_id)
except exceptions.ResourceNotFound:
raise exc.OpenStackCloudResourceNotFound(
"unable to find network for floating ips with ID "
"{0}".format(network_name_or_id))
@ -612,15 +608,11 @@ class FloatingIPCloudMixin(_normalize.Normalizer):
def _neutron_delete_floating_ip(self, floating_ip_id):
try:
proxy._json_response(self.network.delete(
"/floatingips/{fip_id}".format(fip_id=floating_ip_id),
error_message="unable to delete floating IP"))
except exc.OpenStackCloudResourceNotFound:
self.network.delete_ip(
floating_ip_id, ignore_missing=False
)
except exceptions.ResourceNotFound:
return False
except Exception as e:
raise exc.OpenStackCloudException(
"Unable to delete floating IP ID {fip_id}: {msg}".format(
fip_id=floating_ip_id, msg=str(e)))
return True
def _nova_delete_floating_ip(self, floating_ip_id):
@ -751,14 +743,9 @@ class FloatingIPCloudMixin(_normalize.Normalizer):
if fixed_address is not None:
floating_ip_args['fixed_ip_address'] = fixed_address
return proxy._json_response(
self.network.put(
"/floatingips/{fip_id}".format(fip_id=floating_ip['id']),
json={'floatingip': floating_ip_args}),
error_message=("Error attaching IP {ip} to "
"server {server_id}".format(
ip=floating_ip['id'],
server_id=server['id'])))
return self.network.update_ip(
floating_ip,
**floating_ip_args)
def _nova_attach_ip_to_server(self, server_id, floating_ip_id,
fixed_address=None):
@ -809,13 +796,16 @@ class FloatingIPCloudMixin(_normalize.Normalizer):
f_ip = self.get_floating_ip(id=floating_ip_id)
if f_ip is None or not f_ip['attached']:
return False
exceptions.raise_from_response(
self.network.put(
"/floatingips/{fip_id}".format(fip_id=floating_ip_id),
json={"floatingip": {"port_id": None}}),
error_message=("Error detaching IP {ip} from "
"server {server_id}".format(
ip=floating_ip_id, server_id=server_id)))
try:
self.network.update_ip(
floating_ip_id,
port_id=None
)
except exceptions.SDKException:
raise exceptions.SDKException(
("Error detaching IP {ip} from "
"server {server_id}".format(
ip=floating_ip_id, server_id=server_id)))
return True

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@
# openstack.resource.Resource.list and openstack.resource2.Resource.list
import types # noqa
from openstack.cloud import _normalize
from openstack.cloud import _utils
from openstack.cloud import exc
from openstack import utils
@ -29,7 +28,7 @@ def _no_pending_images(images):
return True
class ImageCloudMixin(_normalize.Normalizer):
class ImageCloudMixin:
def __init__(self):
self.image_api_use_tasks = self.config.config['image_api_use_tasks']
@ -81,7 +80,7 @@ class ImageCloudMixin(_normalize.Normalizer):
images.append(image)
elif image.status.lower() != 'deleted':
images.append(image)
return self._normalize_images(images)
return images
def get_image(self, name_or_id, filters=None):
"""Get an image by name or ID.
@ -112,12 +111,10 @@ class ImageCloudMixin(_normalize.Normalizer):
""" Get a image by ID
:param id: ID of the image.
:returns: An image ``munch.Munch``.
:returns: An image
:class:`openstack.image.v2.image.Image` object.
"""
image = self._normalize_image(
self.image.get_image(image={'id': id}))
return image
return self.image.get_image(image={'id': id})
def download_image(
self, name_or_id, output_path=None, output_file=None,
@ -213,10 +210,10 @@ class ImageCloudMixin(_normalize.Normalizer):
# Task API means an image was uploaded to swift
# TODO(gtema) does it make sense to move this into proxy?
if self.image_api_use_tasks and (
self.image._IMAGE_OBJECT_KEY in image
or self.image._SHADE_IMAGE_OBJECT_KEY in image):
(container, objname) = image.get(
self.image._IMAGE_OBJECT_KEY, image.get(
self.image._IMAGE_OBJECT_KEY in image.properties
or self.image._SHADE_IMAGE_OBJECT_KEY in image.properties):
(container, objname) = image.properties.get(
self.image._IMAGE_OBJECT_KEY, image.properties.get(
self.image._SHADE_IMAGE_OBJECT_KEY)).split('/', 1)
self.delete_object(container=container, name=objname)

View File

@ -17,14 +17,12 @@ import threading
import time
import types # noqa
from openstack.cloud import _normalize
from openstack.cloud import _utils
from openstack.cloud import exc
from openstack import exceptions
from openstack import proxy
class NetworkCloudMixin(_normalize.Normalizer):
class NetworkCloudMixin:
def __init__(self):
self._ports = None
@ -53,9 +51,12 @@ class NetworkCloudMixin(_normalize.Normalizer):
:raises: ``OpenStackCloudException`` if something goes wrong during the
OpenStack API call.
"""
networks = self.list_networks(
filters if isinstance(filters, dict) else None)
return _utils._filter_list(networks, name_or_id, filters)
query = {}
if name_or_id:
query['name'] = name_or_id
if filters:
query.update(filters)
return list(self.network.networks(**query))
def search_routers(self, name_or_id=None, filters=None):
"""Search routers
@ -69,9 +70,12 @@ class NetworkCloudMixin(_normalize.Normalizer):
:raises: ``OpenStackCloudException`` if something goes wrong during the
OpenStack API call.
"""
routers = self.list_routers(
filters if isinstance(filters, dict) else None)
return _utils._filter_list(routers, name_or_id, filters)
query = {}
if name_or_id:
query['name'] = name_or_id
if filters:
query.update(filters)
return list(self.network.routers(**query))
def search_subnets(self, name_or_id=None, filters=None):
"""Search subnets
@ -85,9 +89,12 @@ class NetworkCloudMixin(_normalize.Normalizer):
:raises: ``OpenStackCloudException`` if something goes wrong during the
OpenStack API call.
"""
subnets = self.list_subnets(
filters if isinstance(filters, dict) else None)
return _utils._filter_list(subnets, name_or_id, filters)
query = {}
if name_or_id:
query['name'] = name_or_id
if filters:
query.update(filters)
return list(self.network.subnets(**query))
def search_ports(self, name_or_id=None, filters=None):
"""Search ports
@ -121,11 +128,11 @@ class NetworkCloudMixin(_normalize.Normalizer):
# If the cloud is running nova-network, just return an empty list.
if not self.has_service('network'):
return []
# Translate None from search interface to empty {} for kwargs below
if not filters:
filters = {}
data = self.network.get("/networks", params=filters)
return self._get_and_munchify('networks', data)
return list(self.network.networks(**filters))
def list_routers(self, filters=None):
"""List all available routers.
@ -137,14 +144,11 @@ class NetworkCloudMixin(_normalize.Normalizer):
# If the cloud is running nova-network, just return an empty list.
if not self.has_service('network'):
return []
# Translate None from search interface to empty {} for kwargs below
if not filters:
filters = {}
resp = self.network.get("/routers", params=filters)
data = proxy._json_response(
resp,
error_message="Error fetching router list")
return self._get_and_munchify('routers', data)
return list(self.network.routers(**filters))
def list_subnets(self, filters=None):
"""List all available subnets.
@ -156,11 +160,11 @@ class NetworkCloudMixin(_normalize.Normalizer):
# If the cloud is running nova-network, just return an empty list.
if not self.has_service('network'):
return []
# Translate None from search interface to empty {} for kwargs below
if not filters:
filters = {}
data = self.network.get("/subnets", params=filters)
return self._get_and_munchify('subnets', data)
return list(self.network.subnets(**filters))
def list_ports(self, filters=None):
"""List all available ports.
@ -199,11 +203,10 @@ class NetworkCloudMixin(_normalize.Normalizer):
# If the cloud is running nova-network, just return an empty list.
if not self.has_service('network'):
return []
resp = self.network.get("/ports", params=filters)
data = proxy._json_response(
resp,
error_message="Error fetching port list")
return self._get_and_munchify('ports', data)
if not filters:
filters = {}
return list(self.network.ports(**filters))
def get_qos_policy(self, name_or_id, filters=None):
"""Get a QoS policy by name or ID.
@ -231,6 +234,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
if not self._has_neutron_extension('qos'):
raise exc.OpenStackCloudUnavailableExtension(
'QoS extension is not available on target cloud')
if not filters:
filters = {}
return self.network.find_qos_policy(
@ -253,6 +257,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
if not self._has_neutron_extension('qos'):
raise exc.OpenStackCloudUnavailableExtension(
'QoS extension is not available on target cloud')
query = {}
if name_or_id:
query['name'] = name_or_id
@ -334,7 +339,12 @@ class NetworkCloudMixin(_normalize.Normalizer):
found.
"""
return _utils._get_entity(self, 'network', name_or_id, filters)
if not filters:
filters = {}
return self.network.find_network(
name_or_id=name_or_id,
ignore_missing=True,
**filters)
def get_network_by_id(self, id):
""" Get a network by ID
@ -342,14 +352,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
:param id: ID of the network.
:returns: A network ``munch.Munch``.
"""
resp = self.network.get('/networks/{id}'.format(id=id))
data = proxy._json_response(
resp,
error_message="Error getting network with ID {id}".format(id=id)
)
network = self._get_and_munchify('network', data)
return network
return self.network.get_network(id)
def get_router(self, name_or_id, filters=None):
"""Get a router by name or ID.
@ -374,7 +377,12 @@ class NetworkCloudMixin(_normalize.Normalizer):
found.
"""
return _utils._get_entity(self, 'router', name_or_id, filters)
if not filters:
filters = {}
return self.network.find_router(
name_or_id=name_or_id,
ignore_missing=True,
**filters)
def get_subnet(self, name_or_id, filters=None):
"""Get a subnet by name or ID.
@ -395,7 +403,12 @@ class NetworkCloudMixin(_normalize.Normalizer):
found.
"""
return _utils._get_entity(self, 'subnet', name_or_id, filters)
if not filters:
filters = {}
return self.network.find_subnet(
name_or_id=name_or_id,
ignore_missing=True,
**filters)
def get_subnet_by_id(self, id):
""" Get a subnet by ID
@ -403,14 +416,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
:param id: ID of the subnet.
:returns: A subnet ``munch.Munch``.
"""
resp = self.network.get('/subnets/{id}'.format(id=id))
data = proxy._json_response(
resp,
error_message="Error getting subnet with ID {id}".format(id=id)
)
subnet = self._get_and_munchify('subnet', data)
return subnet
return self.network.get_subnet(id)
def get_port(self, name_or_id, filters=None):
"""Get a port by name or ID.
@ -434,7 +440,12 @@ class NetworkCloudMixin(_normalize.Normalizer):
:returns: A port ``munch.Munch`` or None if no matching port is found.
"""
return _utils._get_entity(self, 'port', name_or_id, filters)
if not filters:
filters = {}
return self.network.find_port(
name_or_id=name_or_id,
ignore_missing=True,
**filters)
def get_port_by_id(self, id):
""" Get a port by ID
@ -442,14 +453,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
:param id: ID of the port.
:returns: A port ``munch.Munch``.
"""
resp = self.network.get('/ports/{id}'.format(id=id))
data = proxy._json_response(
resp,
error_message="Error getting port with ID {id}".format(id=id)
)
port = self._get_and_munchify('port', data)
return port
return self.network.get_port(id)
def create_network(self, name, shared=False, admin_state_up=True,
external=False, provider=None, project_id=None,
@ -487,7 +491,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
network['shared'] = shared
if project_id is not None:
network['tenant_id'] = project_id
network['project_id'] = project_id
if availability_zone_hints is not None:
if not isinstance(availability_zone_hints, list):
@ -535,11 +539,11 @@ class NetworkCloudMixin(_normalize.Normalizer):
if dns_domain:
network['dns_domain'] = dns_domain
data = self.network.post("/networks", json={'network': network})
network = self.network.create_network(**network)
# Reset cache so the new network is picked up
self._reset_network_caches()
return self._get_and_munchify('network', data)
return network
@_utils.valid_kwargs("name", "shared", "admin_state_up", "external",
"provider", "mtu_size", "port_security_enabled",
@ -598,14 +602,11 @@ class NetworkCloudMixin(_normalize.Normalizer):
raise exc.OpenStackCloudException(
"Network %s not found." % name_or_id)
data = proxy._json_response(self.network.put(
"/networks/{net_id}".format(net_id=network.id),
json={"network": kwargs}),
error_message="Error updating network {0}".format(name_or_id))
network = self.network.update_network(network, **kwargs)
self._reset_network_caches()
return self._get_and_munchify('network', data)
return network
def delete_network(self, name_or_id):
"""Delete a network.
@ -621,8 +622,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
self.log.debug("Network %s not found for deleting", name_or_id)
return False
exceptions.raise_from_response(self.network.delete(
"/networks/{network_id}".format(network_id=network['id'])))
self.network.delete_network(network)
# Reset cache so the deleted network is removed
self._reset_network_caches()
@ -643,12 +643,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
if not proj:
raise exc.OpenStackCloudException("project does not exist")
exceptions.raise_from_response(
self.network.put(
'/quotas/{project_id}'.format(project_id=proj.id),
json={'quota': kwargs}),
error_message=("Error setting Neutron's quota for "
"project {0}".format(proj.id)))
self.network.update_quota(proj.id, **kwargs)
def get_network_quotas(self, name_or_id, details=False):
""" Get network quotas for a project
@ -663,14 +658,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
proj = self.get_project(name_or_id)
if not proj:
raise exc.OpenStackCloudException("project does not exist")
url = '/quotas/{project_id}'.format(project_id=proj.id)
if details:
url = url + "/details"
data = proxy._json_response(
self.network.get(url),
error_message=("Error fetching Neutron's quota for "
"project {0}".format(proj.id)))
return self._get_and_munchify('quota', data)
return self.network.get_quota(proj.id, details)
def get_network_extensions(self):
"""Get Cloud provided network extensions
@ -691,11 +679,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
proj = self.get_project(name_or_id)
if not proj:
raise exc.OpenStackCloudException("project does not exist")
exceptions.raise_from_response(
self.network.delete(
'/quotas/{project_id}'.format(project_id=proj.id)),
error_message=("Error deleting Neutron's quota for "
"project {0}".format(proj.id)))
self.network.delete_quota(proj.id)
@_utils.valid_kwargs(
'action', 'description', 'destination_firewall_group_id',
@ -770,7 +754,10 @@ class NetworkCloudMixin(_normalize.Normalizer):
"""
if not filters:
filters = {}
return self.network.find_firewall_rule(name_or_id, **filters)
return self.network.find_firewall_rule(
name_or_id,
ignore_missing=True,
**filters)
def list_firewall_rules(self, filters=None):
"""
@ -894,7 +881,10 @@ class NetworkCloudMixin(_normalize.Normalizer):
"""
if not filters:
filters = {}
return self.network.find_firewall_policy(name_or_id, **filters)
return self.network.find_firewall_policy(
name_or_id,
ignore_missing=True,
**filters)
def list_firewall_policies(self, filters=None):
"""
@ -1093,7 +1083,10 @@ class NetworkCloudMixin(_normalize.Normalizer):
"""
if not filters:
filters = {}
return self.network.find_firewall_group(name_or_id, **filters)
return self.network.find_firewall_group(
name_or_id,
ignore_missing=True,
**filters)
def list_firewall_groups(self, filters=None):
"""
@ -1230,6 +1223,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
if not curr_policy:
raise exc.OpenStackCloudException(
"QoS policy %s not found." % name_or_id)
return self.network.update_qos_policy(curr_policy, **kwargs)
def delete_qos_policy(self, name_or_id):
@ -1248,6 +1242,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
if not policy:
self.log.debug("QoS policy %s not found for deleting", name_or_id)
return False
self.network.delete_qos_policy(policy)
return True
@ -1358,6 +1353,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
"target cloud")
kwargs['max_kbps'] = max_kbps
return self.network.create_qos_bandwidth_limit_rule(policy, **kwargs)
@_utils.valid_kwargs("max_kbps", "max_burst_kbps", "direction")
@ -1703,6 +1699,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
name_or_id=policy_name_or_id))
kwargs['min_kbps'] = min_kbps
return self.network.create_qos_minimum_bandwidth_rule(policy, **kwargs)
@_utils.valid_kwargs("min_kbps", "direction")
@ -1793,19 +1790,11 @@ class NetworkCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
json_body = {}
if subnet_id:
json_body['subnet_id'] = subnet_id
if port_id:
json_body['port_id'] = port_id
return proxy._json_response(
self.network.put(
"/routers/{router_id}/add_router_interface".format(
router_id=router['id']),
json=json_body),
error_message="Error attaching interface to router {0}".format(
router['id']))
return self.network.add_interface_to_router(
router=router,
subnet_id=subnet_id,
port_id=port_id
)
def remove_router_interface(self, router, subnet_id=None, port_id=None):
"""Detach a subnet from an internal router interface.
@ -1824,23 +1813,15 @@ class NetworkCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
json_body = {}
if subnet_id:
json_body['subnet_id'] = subnet_id
if port_id:
json_body['port_id'] = port_id
if not json_body:
if not subnet_id and not port_id:
raise ValueError(
"At least one of subnet_id or port_id must be supplied.")
exceptions.raise_from_response(
self.network.put(
"/routers/{router_id}/remove_router_interface".format(
router_id=router['id']),
json=json_body),
error_message="Error detaching interface from router {0}".format(
router['id']))
self.network.remove_interface_from_router(
router=router,
subnet_id=subnet_id,
port_id=port_id
)
def list_router_interfaces(self, router, interface_type=None):
"""List all interfaces for a router.
@ -1905,7 +1886,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
'admin_state_up': admin_state_up
}
if project_id is not None:
router['tenant_id'] = project_id
router['project_id'] = project_id
if name:
router['name'] = name
ext_gw_info = self._build_external_gateway_info(
@ -1923,10 +1904,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
'target cloud')
router['availability_zone_hints'] = availability_zone_hints
data = proxy._json_response(
self.network.post("/routers", json={"router": router}),
error_message="Error creating router {0}".format(name))
return self._get_and_munchify('router', data)
return self.network.create_router(**router)
def update_router(self, name_or_id, name=None, admin_state_up=None,
ext_gateway_net_id=None, enable_snat=None,
@ -1991,13 +1969,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
raise exc.OpenStackCloudException(
"Router %s not found." % name_or_id)
resp = self.network.put(
"/routers/{router_id}".format(router_id=curr_router['id']),
json={"router": router})
data = proxy._json_response(
resp,
error_message="Error updating router {0}".format(name_or_id))
return self._get_and_munchify('router', data)
return self.network.update_router(curr_router, **router)
def delete_router(self, name_or_id):
"""Delete a logical router.
@ -2012,14 +1984,12 @@ class NetworkCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
router = self.get_router(name_or_id)
router = self.network.find_router(name_or_id, ignore_missing=True)
if not router:
self.log.debug("Router %s not found for deleting", name_or_id)
return False
exceptions.raise_from_response(self.network.delete(
"/routers/{router_id}".format(router_id=router['id']),
error_message="Error deleting router {0}".format(name_or_id)))
self.network.delete_router(router)
return True
@ -2168,9 +2138,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
if use_default_subnetpool:
subnet['use_default_subnetpool'] = True
response = self.network.post("/subnets", json={"subnet": subnet})
return self._get_and_munchify('subnet', response)
return self.network.create_subnet(**subnet)
def delete_subnet(self, name_or_id):
"""Delete a subnet.
@ -2185,13 +2153,13 @@ class NetworkCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
subnet = self.get_subnet(name_or_id)
subnet = self.network.find_subnet(name_or_id, ignore_missing=True)
if not subnet:
self.log.debug("Subnet %s not found for deleting", name_or_id)
return False
exceptions.raise_from_response(self.network.delete(
"/subnets/{subnet_id}".format(subnet_id=subnet['id'])))
self.network.delete_subnet(subnet)
return True
def update_subnet(self, name_or_id, subnet_name=None, enable_dhcp=None,
@ -2276,10 +2244,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
raise exc.OpenStackCloudException(
"Subnet %s not found." % name_or_id)
response = self.network.put(
"/subnets/{subnet_id}".format(subnet_id=curr_subnet['id']),
json={"subnet": subnet})
return self._get_and_munchify('subnet', response)
return self.network.update_subnet(curr_subnet, **subnet)
@_utils.valid_kwargs('name', 'admin_state_up', 'mac_address', 'fixed_ips',
'subnet_id', 'ip_address', 'security_groups',
@ -2346,11 +2311,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
"""
kwargs['network_id'] = network_id
data = proxy._json_response(
self.network.post("/ports", json={'port': kwargs}),
error_message="Error creating port for network {0}".format(
network_id))
return self._get_and_munchify('port', data)
return self.network.create_port(**kwargs)
@_utils.valid_kwargs('name', 'admin_state_up', 'fixed_ips',
'security_groups', 'allowed_address_pairs',
@ -2417,12 +2378,7 @@ class NetworkCloudMixin(_normalize.Normalizer):
raise exc.OpenStackCloudException(
"failed to find port '{port}'".format(port=name_or_id))
data = proxy._json_response(
self.network.put(
"/ports/{port_id}".format(port_id=port['id']),
json={"port": kwargs}),
error_message="Error updating port {0}".format(name_or_id))
return self._get_and_munchify('port', data)
return self.network.update_port(port, **kwargs)
def delete_port(self, name_or_id):
"""Delete a port
@ -2433,15 +2389,14 @@ class NetworkCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
port = self.get_port(name_or_id=name_or_id)
port = self.network.find_port(name_or_id)
if port is None:
self.log.debug("Port %s not found for deleting", name_or_id)
return False
exceptions.raise_from_response(
self.network.delete(
"/ports/{port_id}".format(port_id=port['id'])),
error_message="Error deleting port {0}".format(name_or_id))
self.network.delete_port(port)
return True
def _get_port_ids(self, name_or_id_list, filters=None):

View File

@ -16,11 +16,10 @@
import threading
import types # noqa
from openstack.cloud import _normalize
from openstack.cloud import exc
class NetworkCommonCloudMixin(_normalize.Normalizer):
class NetworkCommonCloudMixin:
"""Shared networking functions used by FloatingIP, Network, Compute classes
"""
@ -94,9 +93,8 @@ class NetworkCommonCloudMixin(_normalize.Normalizer):
if (network['name'] in self._external_ipv4_names
or network['id'] in self._external_ipv4_names):
external_ipv4_networks.append(network)
elif ((('router:external' in network
and network['router:external'])
or network.get('provider:physical_network'))
elif ((network.is_router_external
or network.provider_physical_network)
and network['name'] not in self._internal_ipv4_names
and network['id'] not in self._internal_ipv4_names):
external_ipv4_networks.append(network)
@ -105,8 +103,8 @@ class NetworkCommonCloudMixin(_normalize.Normalizer):
if (network['name'] in self._internal_ipv4_names
or network['id'] in self._internal_ipv4_names):
internal_ipv4_networks.append(network)
elif (not network.get('router:external', False)
and not network.get('provider:physical_network')
elif (not network.is_router_external
and not network.provider_physical_network
and network['name'] not in self._external_ipv4_names
and network['id'] not in self._external_ipv4_names):
internal_ipv4_networks.append(network)
@ -115,7 +113,7 @@ class NetworkCommonCloudMixin(_normalize.Normalizer):
if (network['name'] in self._external_ipv6_names
or network['id'] in self._external_ipv6_names):
external_ipv6_networks.append(network)
elif (network.get('router:external')
elif (network.is_router_external
and network['name'] not in self._internal_ipv6_names
and network['id'] not in self._internal_ipv6_names):
external_ipv6_networks.append(network)
@ -124,7 +122,7 @@ class NetworkCommonCloudMixin(_normalize.Normalizer):
if (network['name'] in self._internal_ipv6_names
or network['id'] in self._internal_ipv6_names):
internal_ipv6_networks.append(network)
elif (not network.get('router:external', False)
elif (not network.is_router_external
and network['name'] not in self._external_ipv6_names
and network['id'] not in self._external_ipv6_names):
internal_ipv6_networks.append(network)
@ -144,7 +142,7 @@ class NetworkCommonCloudMixin(_normalize.Normalizer):
external_ipv4_floating_networks.append(network)
nat_source = network
elif self._nat_source is None:
if network.get('router:external'):
if network.is_router_external:
external_ipv4_floating_networks.append(network)
nat_source = nat_source or network

View File

@ -610,10 +610,19 @@ class Normalizer:
]
def _normalize_floating_ip(self, ip):
ret = munch.Munch()
# Copy incoming floating ip because of shared dicts in unittests
ip = ip.copy()
if isinstance(ip, resource.Resource):
ip = ip.to_dict(ignore_none=True, original_names=True)
location = ip.pop(
'location',
self._get_current_location(project_id=ip.get('owner')))
else:
location = self._get_current_location(
project_id=ip.get('owner'))
# This copy is to keep things from getting epically weird in tests
ip = ip.copy()
ret = munch.Munch(location=location)
fixed_ip_address = ip.pop('fixed_ip_address', ip.pop('fixed_ip', None))
floating_ip_address = ip.pop('floating_ip_address', ip.pop('ip', None))

View File

@ -13,22 +13,15 @@
# import types so that we can reference ListType in sphinx param declarations.
# We can't just use list, because sphinx gets confused by
# openstack.resource.Resource.list and openstack.resource2.Resource.list
import collections
import concurrent.futures
import hashlib
import json
import os
import types # noqa
import urllib.parse
import keystoneauth1.exceptions
from openstack.cloud import _normalize
from openstack.cloud import _utils
from openstack.cloud import exc
from openstack import exceptions
from openstack import proxy
from openstack import utils
DEFAULT_OBJECT_SEGMENT_SIZE = 1073741824 # 1GB
@ -42,7 +35,7 @@ OBJECT_CONTAINER_ACLS = {
}
class ObjectStoreCloudMixin(_normalize.Normalizer):
class ObjectStoreCloudMixin:
@property
def _object_store_client(self):
@ -60,9 +53,7 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
params = dict(format='json', prefix=prefix)
response = self.object_store.get('/', params=params)
return self._get_and_munchify(None, proxy._json_response(response))
return list(self.object_store.containers(prefix=prefix))
def search_containers(self, name=None, filters=None):
"""Search containers.
@ -92,13 +83,10 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
"""
if skip_cache or name not in self._container_cache:
try:
response = self.object_store.head(
self._get_object_endpoint(name)
)
exceptions.raise_from_response(response)
self._container_cache[name] = response.headers
except exc.OpenStackCloudHTTPError as e:
if e.response.status_code == 404:
container = self.object_store.get_container_metadata(name)
self._container_cache[name] = container
except exceptions.HttpException as ex:
if ex.response.status_code == 404:
return None
raise
return self._container_cache[name]
@ -114,11 +102,12 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
container = self.get_container(name)
if container:
return container
exceptions.raise_from_response(self.object_store.put(
self._get_object_endpoint(name)
))
attrs = dict(
name=name
)
if public:
self.set_container_access(name, 'public')
attrs['read_ACL'] = OBJECT_CONTAINER_ACLS['public']
container = self.object_store.create_container(**attrs)
return self.get_container(name, skip_cache=True)
def delete_container(self, name):
@ -127,21 +116,17 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
:param str name: Name of the container to delete.
"""
try:
exceptions.raise_from_response(self.object_store.delete(
self._get_object_endpoint(name)
))
self.object_store.delete_container(name, ignore_missing=False)
self._container_cache.pop(name, None)
return True
except exc.OpenStackCloudHTTPError as e:
if e.response.status_code == 404:
return False
if e.response.status_code == 409:
raise exc.OpenStackCloudException(
'Attempt to delete container {container} failed. The'
' container is not empty. Please delete the objects'
' inside it before deleting the container'.format(
container=name))
raise
except exceptions.NotFoundException:
return False
except exceptions.ConflictException:
raise exc.OpenStackCloudException(
'Attempt to delete container {container} failed. The'
' container is not empty. Please delete the objects'
' inside it before deleting the container'.format(
container=name))
def update_container(self, name, headers):
"""Update the metadata in a container.
@ -158,12 +143,10 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
:param dict headers:
Key/Value headers to set on the container.
"""
exceptions.raise_from_response(
self.object_store.post(
self._get_object_endpoint(name), headers=headers)
)
self.object_store.set_container_metadata(
name, refresh=False, **headers)
def set_container_access(self, name, access):
def set_container_access(self, name, access, refresh=False):
"""Set the access control list on a container.
:param str name:
@ -172,13 +155,17 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
ACL string to set on the container. Can also be ``public``
or ``private`` which will be translated into appropriate ACL
strings.
:param refresh: Flag to trigger refresh of the container properties
"""
if access not in OBJECT_CONTAINER_ACLS:
raise exc.OpenStackCloudException(
"Invalid container access specified: %s. Must be one of %s"
% (access, list(OBJECT_CONTAINER_ACLS.keys())))
header = {'x-container-read': OBJECT_CONTAINER_ACLS[access]}
self.update_container(name, header)
return self.object_store.set_container_metadata(
name,
read_ACL=OBJECT_CONTAINER_ACLS[access],
refresh=refresh
)
def get_container_access(self, name):
"""Get the control list from a container.
@ -188,7 +175,7 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
container = self.get_container(name, skip_cache=True)
if not container:
raise exc.OpenStackCloudException("Container not found: %s" % name)
acl = container.get('x-container-read', '')
acl = container.read_ACL
for key, value in OBJECT_CONTAINER_ACLS.items():
# Convert to string for the comparison because swiftclient
# returns byte values as bytes sometimes and apparently ==
@ -198,39 +185,6 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
raise exc.OpenStackCloudException(
"Could not determine container access for ACL: %s." % acl)
def _get_file_hashes(self, filename):
file_key = "{filename}:{mtime}".format(
filename=filename,
mtime=os.stat(filename).st_mtime)
if file_key not in self._file_hash_cache:
self.log.debug(
'Calculating hashes for %(filename)s', {'filename': filename})
(md5, sha256) = (None, None)
with open(filename, 'rb') as file_obj:
(md5, sha256) = self._calculate_data_hashes(file_obj)
self._file_hash_cache[file_key] = dict(
md5=md5, sha256=sha256)
self.log.debug(
"Image file %(filename)s md5:%(md5)s sha256:%(sha256)s",
{'filename': filename,
'md5': self._file_hash_cache[file_key]['md5'],
'sha256': self._file_hash_cache[file_key]['sha256']})
return (self._file_hash_cache[file_key]['md5'],
self._file_hash_cache[file_key]['sha256'])
def _calculate_data_hashes(self, data):
md5 = utils.md5(usedforsecurity=False)
sha256 = hashlib.sha256()
if hasattr(data, 'read'):
for chunk in iter(lambda: data.read(8192), b''):
md5.update(chunk)
sha256.update(chunk)
else:
md5.update(data)
sha256.update(data)
return (md5.hexdigest(), sha256.hexdigest())
@_utils.cache_on_arguments()
def get_object_capabilities(self):
"""Get infomation about the object-storage service
@ -238,40 +192,11 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
The object-storage service publishes a set of capabilities that
include metadata about maximum values and thresholds.
"""
# The endpoint in the catalog has version and project-id in it
# To get capabilities, we have to disassemble and reassemble the URL
# This logic is taken from swiftclient
endpoint = urllib.parse.urlparse(self.object_store.get_endpoint())
url = "{scheme}://{netloc}/info".format(
scheme=endpoint.scheme, netloc=endpoint.netloc)
return proxy._json_response(self.object_store.get(url))
return self.object_store.get_info()
def get_object_segment_size(self, segment_size):
"""Get a segment size that will work given capabilities"""
if segment_size is None:
segment_size = DEFAULT_OBJECT_SEGMENT_SIZE
min_segment_size = 0
try:
caps = self.get_object_capabilities()
except exc.OpenStackCloudHTTPError as e:
if e.response.status_code in (404, 412):
server_max_file_size = DEFAULT_MAX_FILE_SIZE
self.log.info(
"Swift capabilities not supported. "
"Using default max file size.")
else:
raise
else:
server_max_file_size = caps.get('swift', {}).get('max_file_size',
0)
min_segment_size = caps.get('slo', {}).get('min_segment_size', 0)
if segment_size > server_max_file_size:
return server_max_file_size
if segment_size < min_segment_size:
return min_segment_size
return segment_size
return self.object_store.get_object_segment_size(segment_size)
def is_object_stale(
self, container, name, filename, file_md5=None, file_sha256=None):
@ -287,35 +212,10 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
Pre-calculated sha256 of the file contents. Defaults to None which
means calculate locally.
"""
metadata = self.get_object_metadata(container, name)
if not metadata:
self.log.debug(
"swift stale check, no object: {container}/{name}".format(
container=container, name=name))
return True
if not (file_md5 or file_sha256):
(file_md5, file_sha256) = self._get_file_hashes(filename)
md5_key = metadata.get(
self._OBJECT_MD5_KEY, metadata.get(self._SHADE_OBJECT_MD5_KEY, ''))
sha256_key = metadata.get(
self._OBJECT_SHA256_KEY, metadata.get(
self._SHADE_OBJECT_SHA256_KEY, ''))
up_to_date = self._hashes_up_to_date(
md5=file_md5, sha256=file_sha256,
md5_key=md5_key, sha256_key=sha256_key)
if not up_to_date:
self.log.debug(
"swift checksum mismatch: "
" %(filename)s!=%(container)s/%(name)s",
{'filename': filename, 'container': container, 'name': name})
return True
self.log.debug(
"swift object up to date: %(container)s/%(name)s",
{'container': container, 'name': name})
return False
return self.object_store.is_object_stale(
container, name, filename,
file_md5=file_md5, file_sha256=file_sha256
)
def create_directory_marker_object(self, container, name, **headers):
"""Create a zero-byte directory marker object
@ -385,217 +285,14 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
:raises: ``OpenStackCloudException`` on operation error.
"""
if data is not None and filename:
raise ValueError(
"Both filename and data given. Please choose one.")
if data is not None and not name:
raise ValueError(
"name is a required parameter when data is given")
if data is not None and generate_checksums:
raise ValueError(
"checksums cannot be generated with data parameter")
if generate_checksums is None:
if data is not None:
generate_checksums = False
else:
generate_checksums = True
if not metadata:
metadata = {}
if not filename and data is None:
filename = name
if generate_checksums and (md5 is None or sha256 is None):
(md5, sha256) = self._get_file_hashes(filename)
if md5:
headers[self._OBJECT_MD5_KEY] = md5 or ''
if sha256:
headers[self._OBJECT_SHA256_KEY] = sha256 or ''
for (k, v) in metadata.items():
if not k.lower().startswith('x-object-meta-'):
headers['x-object-meta-' + k] = v
else:
headers[k] = v
endpoint = self._get_object_endpoint(container, name)
if data is not None:
self.log.debug(
"swift uploading data to %(endpoint)s",
{'endpoint': endpoint})
return self._upload_object_data(endpoint, data, headers)
# segment_size gets used as a step value in a range call, so needs
# to be an int
if segment_size:
segment_size = int(segment_size)
segment_size = self.get_object_segment_size(segment_size)
file_size = os.path.getsize(filename)
if self.is_object_stale(container, name, filename, md5, sha256):
self.log.debug(
"swift uploading %(filename)s to %(endpoint)s",
{'filename': filename, 'endpoint': endpoint})
if file_size <= segment_size:
self._upload_object(endpoint, filename, headers)
else:
self._upload_large_object(
endpoint, filename, headers,
file_size, segment_size, use_slo)
def _upload_object_data(self, endpoint, data, headers):
return proxy._json_response(self.object_store.put(
endpoint, headers=headers, data=data))
def _upload_object(self, endpoint, filename, headers):
return proxy._json_response(self.object_store.put(
endpoint, headers=headers, data=open(filename, 'rb')))
def _get_file_segments(self, endpoint, filename, file_size, segment_size):
# Use an ordered dict here so that testing can replicate things
segments = collections.OrderedDict()
for (index, offset) in enumerate(range(0, file_size, segment_size)):
remaining = file_size - (index * segment_size)
segment = _utils.FileSegment(
filename, offset,
segment_size if segment_size < remaining else remaining)
name = '{endpoint}/{index:0>6}'.format(
endpoint=endpoint, index=index)
segments[name] = segment
return segments
def _object_name_from_url(self, url):
'''Get container_name/object_name from the full URL called.
Remove the Swift endpoint from the front of the URL, and remove
the leaving / that will leave behind.'''
endpoint = self.object_store.get_endpoint()
object_name = url.replace(endpoint, '')
if object_name.startswith('/'):
object_name = object_name[1:]
return object_name
def _add_etag_to_manifest(self, segment_results, manifest):
for result in segment_results:
if 'Etag' not in result.headers:
continue
name = self._object_name_from_url(result.url)
for entry in manifest:
if entry['path'] == '/{name}'.format(name=name):
entry['etag'] = result.headers['Etag']
def _upload_large_object(
self, endpoint, filename,
headers, file_size, segment_size, use_slo):
# If the object is big, we need to break it up into segments that
# are no larger than segment_size, upload each of them individually
# and then upload a manifest object. The segments can be uploaded in
# parallel, so we'll use the async feature of the TaskManager.
segment_futures = []
segment_results = []
retry_results = []
retry_futures = []
manifest = []
# Get an OrderedDict with keys being the swift location for the
# segment, the value a FileSegment file-like object that is a
# slice of the data for the segment.
segments = self._get_file_segments(
endpoint, filename, file_size, segment_size)
# Schedule the segments for upload
for name, segment in segments.items():
# Async call to put - schedules execution and returns a future
segment_future = self._pool_executor.submit(
self.object_store.put,
name, headers=headers, data=segment,
raise_exc=False)
segment_futures.append(segment_future)
# TODO(mordred) Collect etags from results to add to this manifest
# dict. Then sort the list of dicts by path.
manifest.append(dict(
path='/{name}'.format(name=name),
size_bytes=segment.length))
# Try once and collect failed results to retry
segment_results, retry_results = self._wait_for_futures(
segment_futures, raise_on_error=False)
self._add_etag_to_manifest(segment_results, manifest)
for result in retry_results:
# Grab the FileSegment for the failed upload so we can retry
name = self._object_name_from_url(result.url)
segment = segments[name]
segment.seek(0)
# Async call to put - schedules execution and returns a future
segment_future = self._pool_executor.submit(
self.object_store.put,
name, headers=headers, data=segment)
# TODO(mordred) Collect etags from results to add to this manifest
# dict. Then sort the list of dicts by path.
retry_futures.append(segment_future)
# If any segments fail the second time, just throw the error
segment_results, retry_results = self._wait_for_futures(
retry_futures, raise_on_error=True)
self._add_etag_to_manifest(segment_results, manifest)
# If the final manifest upload fails, remove the segments we've
# already uploaded.
try:
if use_slo:
return self._finish_large_object_slo(endpoint, headers,
manifest)
else:
return self._finish_large_object_dlo(endpoint, headers)
except Exception:
try:
segment_prefix = endpoint.split('/')[-1]
self.log.debug(
"Failed to upload large object manifest for %s. "
"Removing segment uploads.", segment_prefix)
self.delete_autocreated_image_objects(
segment_prefix=segment_prefix)
except Exception:
self.log.exception(
"Failed to cleanup image objects for %s:",
segment_prefix)
raise
def _finish_large_object_slo(self, endpoint, headers, manifest):
# TODO(mordred) send an etag of the manifest, which is the md5sum
# of the concatenation of the etags of the results
headers = headers.copy()
retries = 3
while True:
try:
return self._object_store_client.put(
endpoint,
params={'multipart-manifest': 'put'},
headers=headers, data=json.dumps(manifest))
except Exception:
retries -= 1
if retries == 0:
raise
def _finish_large_object_dlo(self, endpoint, headers):
headers = headers.copy()
headers['X-Object-Manifest'] = endpoint
retries = 3
while True:
try:
return self._object_store_client.put(endpoint, headers=headers)
except Exception:
retries -= 1
if retries == 0:
raise
return self.object_store.create_object(
container, name,
filename=filename, data=data,
md5=md5, sha256=sha256, use_slo=use_slo,
generate_checksums=generate_checksums,
metadata=metadata,
**headers
)
def update_object(self, container, name, metadata=None, **headers):
"""Update the metadata of an object
@ -609,19 +306,10 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
:raises: ``OpenStackCloudException`` on operation error.
"""
if not metadata:
metadata = {}
metadata_headers = {}
for (k, v) in metadata.items():
metadata_headers['x-object-meta-' + k] = v
headers = dict(headers, **metadata_headers)
return self._object_store_client.post(
self._get_object_endpoint(container, name),
headers=headers)
meta = metadata.copy() or {}
meta.update(**headers)
self.object_store.set_object_metadata(
name, container, **meta)
def list_objects(self, container, full_listing=True, prefix=None):
"""List objects.
@ -636,9 +324,10 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
params = dict(format='json', prefix=prefix)
data = self._object_store_client.get(container, params=params)
return self._get_and_munchify(None, data)
return list(self.object_store.objects(
container=container,
prefix=prefix
))
def search_objects(self, container, name=None, filters=None):
"""Search objects.
@ -669,27 +358,11 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
# TODO(mordred) DELETE for swift returns status in text/plain format
# like so:
# Number Deleted: 15
# Number Not Found: 0
# Response Body:
# Response Status: 200 OK
# Errors:
# We should ultimately do something with that
try:
if not meta:
meta = self.get_object_metadata(container, name)
if not meta:
return False
params = {}
if meta.get('X-Static-Large-Object', None) == 'True':
params['multipart-manifest'] = 'delete'
self._object_store_client.delete(
self._get_object_endpoint(container, name),
params=params)
self.object_store.delete_object(
name, ignore_missing=False, container=container)
return True
except exc.OpenStackCloudHTTPError:
except exceptions.SDKException:
return False
def delete_autocreated_image_objects(self, container=None,
@ -707,30 +380,14 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
delete. If not given, all image upload segments present are
deleted.
"""
if container is None:
container = self._OBJECT_AUTOCREATE_CONTAINER
# This method only makes sense on clouds that use tasks
if not self.image_api_use_tasks:
return False
deleted = False
for obj in self.list_objects(container, prefix=segment_prefix):
meta = self.get_object_metadata(container, obj['name'])
if meta.get(
self._OBJECT_AUTOCREATE_KEY, meta.get(
self._SHADE_OBJECT_AUTOCREATE_KEY)) == 'true':
if self.delete_object(container, obj['name'], meta):
deleted = True
return deleted
return self.object_store._delete_autocreated_image_objects(
container, segment_prefix=segment_prefix
)
def get_object_metadata(self, container, name):
try:
return self._object_store_client.head(
self._get_object_endpoint(container, name)).headers
except exc.OpenStackCloudException as e:
if e.response.status_code == 404:
return None
raise
return self.object_store.get_object_metadata(
name, container
).metadata
def get_object_raw(self, container, obj, query_string=None, stream=False):
"""Get a raw response object for an object.
@ -776,14 +433,11 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
:raises: OpenStackCloudException on operation error.
"""
try:
with self.get_object_raw(
container, obj, query_string=query_string) as response:
for ret in response.iter_content(chunk_size=resp_chunk_size):
yield ret
except exc.OpenStackCloudHTTPError as e:
if e.response.status_code == 404:
return
raise
for ret in self.object_store.stream_object(
obj, container, chunk_size=resp_chunk_size):
yield ret
except exceptions.ResourceNotFound:
return
def get_object(self, container, obj, query_string=None,
resp_chunk_size=1024, outfile=None, stream=False):
@ -807,33 +461,19 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
is not found (404).
:raises: OpenStackCloudException on operation error.
"""
# TODO(mordred) implement resp_chunk_size
endpoint = self._get_object_endpoint(container, obj, query_string)
try:
get_stream = (outfile is not None)
with self._object_store_client.get(
endpoint, stream=get_stream) as response:
response_headers = {
k.lower(): v for k, v in response.headers.items()}
if outfile:
if isinstance(outfile, str):
outfile_handle = open(outfile, 'wb')
else:
outfile_handle = outfile
for chunk in response.iter_content(
resp_chunk_size, decode_unicode=False):
outfile_handle.write(chunk)
if isinstance(outfile, str):
outfile_handle.close()
else:
outfile_handle.flush()
return (response_headers, None)
else:
return (response_headers, response.text)
except exc.OpenStackCloudHTTPError as e:
if e.response.status_code == 404:
return None
raise
obj = self.object_store.get_object(
obj, container=container,
resp_chunk_size=resp_chunk_size,
outfile=outfile,
remember_content=(outfile is None)
)
headers = {
k.lower(): v for k, v in obj._last_headers.items()}
return (headers, obj.data)
except exceptions.ResourceNotFound:
return None
def _wait_for_futures(self, futures, raise_on_error=True):
'''Collect results or failures from a list of running future tasks.'''
@ -860,20 +500,3 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
# can try again
retries.append(completed.result())
return results, retries
def _hashes_up_to_date(self, md5, sha256, md5_key, sha256_key):
'''Compare md5 and sha256 hashes for being up to date
md5 and sha256 are the current values.
md5_key and sha256_key are the previous values.
'''
up_to_date = False
if md5 and md5_key == md5:
up_to_date = True
if sha256 and sha256_key == sha256:
up_to_date = True
if md5 and md5_key != md5:
up_to_date = False
if sha256 and sha256_key != sha256:
up_to_date = False
return up_to_date

View File

@ -15,7 +15,6 @@
# openstack.resource.Resource.list and openstack.resource2.Resource.list
import types # noqa
from openstack.cloud import _normalize
from openstack.cloud import _utils
from openstack.cloud import exc
from openstack.orchestration.util import event_utils
@ -30,7 +29,7 @@ def _no_pending_stacks(stacks):
return True
class OrchestrationCloudMixin(_normalize.Normalizer):
class OrchestrationCloudMixin:
@property
def _orchestration_client(self):
@ -213,13 +212,13 @@ class OrchestrationCloudMixin(_normalize.Normalizer):
"""List all stacks.
:param dict query: Query parameters to limit stacks.
:returns: a list of ``munch.Munch`` containing the stack description.
:returns: a list of :class:`openstack.orchestration.v1.stack.Stack`
objects containing the stack description.
:raises: ``OpenStackCloudException`` if something goes wrong during the
OpenStack API call.
"""
data = self.orchestration.stacks(**query)
return self._normalize_stacks(data)
return list(self.orchestration.stacks(**query))
def get_stack(self, name_or_id, filters=None, resolve_outputs=True):
"""Get exactly one stack.
@ -230,7 +229,8 @@ class OrchestrationCloudMixin(_normalize.Normalizer):
:param resolve_outputs: If True, then outputs for this
stack will be resolved
:returns: a ``munch.Munch`` containing the stack description
:returns: a :class:`openstack.orchestration.v1.stack.Stack`
containing the stack description
:raises: ``OpenStackCloudException`` if something goes wrong during the
OpenStack API call or if multiple matches are found.
@ -248,7 +248,6 @@ class OrchestrationCloudMixin(_normalize.Normalizer):
return []
except exc.OpenStackCloudURINotFound:
return []
stack = self._normalize_stack(stack)
return _utils._filter_list([stack], name_or_id, filters)
return _utils._get_entity(

View File

@ -241,7 +241,8 @@ class SecurityGroupCloudMixin(_normalize.Normalizer):
remote_address_group_id=None,
direction='ingress',
ethertype='IPv4',
project_id=None):
project_id=None,
description=None):
"""Create a new security group rule
:param string secgroup_name_or_id:
@ -285,7 +286,8 @@ class SecurityGroupCloudMixin(_normalize.Normalizer):
:param string project_id:
Specify the project ID this security group will be created
on (admin-only).
:param string description:
Description of the rule, max 255 characters.
:returns: A ``munch.Munch`` representing the new security group rule.
:raises: OpenStackCloudException on operation error.
@ -319,7 +321,8 @@ class SecurityGroupCloudMixin(_normalize.Normalizer):
}
if project_id is not None:
rule_def['tenant_id'] = project_id
if description is not None:
rule_def["description"] = description
return self.network.create_security_group_rule(
**rule_def
)

View File

@ -10,10 +10,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from openstack.cloud import _normalize
class SharedFileSystemCloudMixin(_normalize.Normalizer):
class SharedFileSystemCloudMixin:
def list_share_availability_zones(self):
"""List all availability zones for the Shared File Systems service.

View File

@ -329,7 +329,7 @@ def normalize_role_assignments(assignments):
if scope in assignment['scope']:
new_val[scope] = assignment['scope'][scope]['id']
for assignee in ('user', 'group'):
if assignee in assignment:
if assignment[assignee]:
new_val[assignee] = assignment[assignee]['id']
new_assignments.append(new_val)
return new_assignments
@ -362,7 +362,7 @@ def valid_kwargs(*valid_args):
#
@decorator
def func_wrapper(func, *args, **kwargs):
argspec = inspect.getargspec(func)
argspec = inspect.getfullargspec(func)
for k in kwargs:
if k not in argspec.args[1:] and k not in valid_args:
raise TypeError(

View File

@ -462,11 +462,11 @@ def add_server_interfaces(cloud, server):
# server record. Since we know them, go ahead and set them. In the case
# where they were set previous, we use the values, so this will not break
# clouds that provide the information
if cloud.private and server['private_v4']:
server['accessIPv4'] = server['private_v4']
if cloud.private and server.private_v4:
server.access_ipv4 = server.private_v4
else:
server['accessIPv4'] = server['public_v4']
server['accessIPv6'] = server['public_v6']
server.access_ipv4 = server.public_v4
server.access_ipv6 = server.public_v6
return server
@ -487,7 +487,8 @@ def get_hostvars_from_server(cloud, server, mounts=None):
expand_server_vars if caching is not set up. If caching is set up,
the extra cost should be minimal.
"""
server_vars = add_server_interfaces(cloud, server)
server_vars = obj_to_munch(
add_server_interfaces(cloud, server))
flavor_id = server['flavor'].get('id')
if flavor_id:
@ -514,6 +515,11 @@ def get_hostvars_from_server(cloud, server, mounts=None):
if image_name:
server_vars['image']['name'] = image_name
# During the switch to returning sdk resource objects we need temporarily
# to force convertion to dict. This will be dropped soon.
if hasattr(server_vars['image'], 'to_dict'):
server_vars['image'] = server_vars['image'].to_dict(computed=False)
volumes = []
if cloud.has_service('volume'):
try:

6
openstack/cloud/openstackcloud.py Executable file → Normal file
View File

@ -60,9 +60,9 @@ class _OpenStackCloudMixin:
:param bool strict: Only return documented attributes for each resource
as per the Data Model contract. (Default False)
"""
_OBJECT_MD5_KEY = 'x-object-meta-x-sdk-md5'
_OBJECT_SHA256_KEY = 'x-object-meta-x-sdk-sha256'
_OBJECT_AUTOCREATE_KEY = 'x-object-meta-x-sdk-autocreated'
_OBJECT_MD5_KEY = 'x-sdk-md5'
_OBJECT_SHA256_KEY = 'x-sdk-sha256'
_OBJECT_AUTOCREATE_KEY = 'x-sdk-autocreated'
_OBJECT_AUTOCREATE_CONTAINER = 'images'
# NOTE(shade) shade keys were x-object-meta-x-shade-md5 - we need to check

View File

@ -40,7 +40,7 @@ class Proxy(proxy.Proxy):
"""Get a generator of profile types.
:returns: A generator of objects that are of type
:class:`~openstack.clustering.v1.profile_type.ProfileType`
:class:`~openstack.clustering.v1.profile_type.ProfileType`
"""
return self._list(_profile_type.ProfileType, **query)
@ -48,10 +48,11 @@ class Proxy(proxy.Proxy):
"""Get the details about a profile type.
:param profile_type: The name of the profile_type to retrieve or an
object of :class:`~openstack.clustering.v1.profile_type.ProfileType`.
object of
:class:`~openstack.clustering.v1.profile_type.ProfileType`.
:returns: A :class:`~openstack.clustering.v1.profile_type.ProfileType`
object.
object.
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
profile_type matching the name could be found.
"""
@ -61,7 +62,7 @@ class Proxy(proxy.Proxy):
"""Get a generator of policy types.
:returns: A generator of objects that are of type
:class:`~openstack.clustering.v1.policy_type.PolicyType`
:class:`~openstack.clustering.v1.policy_type.PolicyType`
"""
return self._list(_policy_type.PolicyType, **query)
@ -69,10 +70,10 @@ class Proxy(proxy.Proxy):
"""Get the details about a policy type.
:param policy_type: The name of a poicy_type or an object of
:class:`~openstack.clustering.v1.policy_type.PolicyType`.
:class:`~openstack.clustering.v1.policy_type.PolicyType`.
:returns: A :class:`~openstack.clustering.v1.policy_type.PolicyType`
object.
object.
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
policy_type matching the name could be found.
"""
@ -82,8 +83,8 @@ class Proxy(proxy.Proxy):
"""Create a new profile from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.clustering.v1.profile.Profile`, it is comprised
of the properties on the Profile class.
:class:`~openstack.clustering.v1.profile.Profile`, it is comprised
of the properties on the Profile class.
:returns: The results of profile creation.
:rtype: :class:`~openstack.clustering.v1.profile.Profile`.
@ -109,10 +110,10 @@ class Proxy(proxy.Proxy):
:param str name_or_id: The name or ID of a profile.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.clustering.v1.profile.Profile` object
or None
"""
@ -140,19 +141,19 @@ class Proxy(proxy.Proxy):
* name: The name of a profile.
* type: The type name of a profile.
* metadata: A list of key-value pairs that are associated with a
profile.
profile.
* sort: A list of sorting keys separated by commas. Each sorting
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
* limit: Requests a specified size of returned items from the
query. Returns a number of items up to the specified limit
value.
query. Returns a number of items up to the specified limit
value.
* marker: Specifies the ID of the last-seen item. Use the limit
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
* global_project: A boolean value indicating whether profiles
from all projects will be returned.
from all projects will be returned.
:returns: A generator of profile instances.
"""
@ -175,20 +176,21 @@ class Proxy(proxy.Proxy):
"""Validate a profile spec.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.clustering.v1.profile.ProfileValidate`, it is
comprised of the properties on the Profile class.
:class:`~openstack.clustering.v1.profile.ProfileValidate`, it is
comprised of the properties on the Profile class.
:returns: The results of profile validation.
:rtype: :class:`~openstack.clustering.v1.profile.ProfileValidate`.
"""
return self._create(_profile.ProfileValidate, **attrs)
# ====== CLUSTERS ======
def create_cluster(self, **attrs):
"""Create a new cluster from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.clustering.v1.cluster.Cluster`, it is comprised
of the properties on the Cluster class.
:class:`~openstack.clustering.v1.cluster.Cluster`, it is comprised
of the properties on the Cluster class.
:returns: The results of cluster creation.
:rtype: :class:`~openstack.clustering.v1.cluster.Cluster`.
@ -205,7 +207,7 @@ class Proxy(proxy.Proxy):
the cluster could not be found. When set to ``True``, no exception
will be raised when attempting to delete a non-existent cluster.
:param bool force_delete: When set to ``True``, the cluster deletion
will be forced immediately.
will be forced immediately.
:returns: The instance of the Cluster which was deleted.
:rtype: :class:`~openstack.cluster.v1.cluster.Cluster`.
@ -222,10 +224,10 @@ class Proxy(proxy.Proxy):
:param str name_or_id: The name or ID of a cluster.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.clustering.v1.cluster.Cluster` object
or None
"""
@ -253,17 +255,17 @@ class Proxy(proxy.Proxy):
* name: The name of a cluster.
* status: The current status of a cluster.
* sort: A list of sorting keys separated by commas. Each sorting
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
* limit: Requests a specified size of returned items from the
query. Returns a number of items up to the specified limit
value.
query. Returns a number of items up to the specified limit
value.
* marker: Specifies the ID of the last-seen item. Use the limit
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
* global_project: A boolean value indicating whether clusters
from all projects will be returned.
from all projects will be returned.
:returns: A generator of cluster instances.
"""
@ -282,6 +284,53 @@ class Proxy(proxy.Proxy):
"""
return self._update(_cluster.Cluster, cluster, **attrs)
def get_cluster_metadata(self, cluster):
"""Return a dictionary of metadata for a cluster
:param cluster: Either the ID of a cluster or a
:class:`~openstack.clustering.v3.cluster.Cluster`.
:returns: A :class:`~openstack.clustering.v3.cluster.Cluster` with the
cluster's metadata. All keys and values are Unicode text.
:rtype: :class:`~openstack.clustering.v3.cluster.Cluster`
"""
cluster = self._get_resource(_cluster.Cluster, cluster)
return cluster.fetch_metadata(self)
def set_cluster_metadata(self, cluster, **metadata):
"""Update metadata for a cluster
:param cluster: Either the ID of a cluster or a
:class:`~openstack.clustering.v3.cluster.Cluster`.
:param kwargs metadata: Key/value pairs to be updated in the cluster's
metadata. No other metadata is modified by this call. All keys
and values are stored as Unicode.
:returns: A :class:`~openstack.clustering.v3.cluster.Cluster` with the
cluster's metadata. All keys and values are Unicode text.
:rtype: :class:`~openstack.clustering.v3.cluster.Cluster`
"""
cluster = self._get_resource(_cluster.Cluster, cluster)
return cluster.set_metadata(self, metadata=metadata)
def delete_cluster_metadata(self, cluster, keys=None):
"""Delete metadata for a cluster
:param cluster: Either the ID of a cluster or a
:class:`~openstack.clustering.v3.cluster.Cluster`.
:param list keys: The keys to delete. If left empty complete
metadata will be removed.
:rtype: ``None``
"""
cluster = self._get_resource(_cluster.Cluster, cluster)
if keys is not None:
for key in keys:
cluster.delete_metadata_item(self, key)
else:
cluster.delete_metadata(self)
def add_nodes_to_cluster(self, cluster, nodes):
"""Add nodes to a cluster.
@ -306,7 +355,7 @@ class Proxy(proxy.Proxy):
restrict the nodes to be returned. Available parameters include:
* destroy_after_deletion: A boolean value indicating whether the
deleted nodes to be destroyed right away.
deleted nodes to be destroyed right away.
:returns: A dict containing the action initiated by this operation.
"""
if isinstance(cluster, _cluster.Cluster):
@ -453,7 +502,7 @@ class Proxy(proxy.Proxy):
:param cluster: The value can be either the ID of a cluster or a
:class:`~openstack.clustering.v1.cluster.Cluster` instance.
:param dict params: A dictionary providing the parameters for the
recover action.
recover action.
:returns: A dictionary containing the action ID.
"""
@ -467,7 +516,7 @@ class Proxy(proxy.Proxy):
:class:`~openstack.clustering.v1.cluster.Cluster` instance.
:param operation: A string specifying the operation to be performed.
:param dict params: A dictionary providing the parameters for the
operation.
operation.
:returns: A dictionary containing the action ID.
"""
@ -478,8 +527,8 @@ class Proxy(proxy.Proxy):
"""Create a new node from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.clustering.v1.node.Node`, it is comprised
of the properties on the ``Node`` class.
:class:`~openstack.clustering.v1.node.Node`, it is comprised
of the properties on the ``Node`` class.
:returns: The results of node creation.
:rtype: :class:`~openstack.clustering.v1.node.Node`.
@ -496,7 +545,7 @@ class Proxy(proxy.Proxy):
the node could not be found. When set to ``True``, no exception
will be raised when attempting to delete a non-existent node.
:param bool force_delete: When set to ``True``, the node deletion
will be forced immediately.
will be forced immediately.
:returns: The instance of the Node which was deleted.
:rtype: :class:`~openstack.cluster.v1.node.Node`.
@ -513,12 +562,12 @@ class Proxy(proxy.Proxy):
:param str name_or_id: The name or ID of a node.
:param bool ignore_missing: When set to "False"
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the specified node does not exist.
when set to "True", None will be returned when
attempting to find a nonexistent policy
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the specified node does not exist.
when set to "True", None will be returned when
attempting to find a nonexistent policy
:returns: One :class:`~openstack.clustering.v1.node.Node` object
or None.
or None.
"""
return self._find(_node.Node, name_or_id,
ignore_missing=ignore_missing)
@ -550,20 +599,20 @@ class Proxy(proxy.Proxy):
restrict the nodes to be returned. Available parameters include:
* cluster_id: A string including the name or ID of a cluster to
which the resulted node(s) is a member.
which the resulted node(s) is a member.
* name: The name of a node.
* status: The current status of a node.
* sort: A list of sorting keys separated by commas. Each sorting
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
* limit: Requests at most the specified number of items be
returned from the query.
returned from the query.
* marker: Specifies the ID of the last-seen node. Use the limit
parameter to make an initial limited request and use the ID of
the last-seen node from the response as the marker parameter
value in a subsequent limited request.
parameter to make an initial limited request and use the ID of
the last-seen node from the response as the marker parameter
value in a subsequent limited request.
* global_project: A boolean value indicating whether nodes
from all projects will be returned.
from all projects will be returned.
:returns: A generator of node instances.
"""
@ -588,7 +637,7 @@ class Proxy(proxy.Proxy):
:param node: The value can be either the ID of a node or a
:class:`~openstack.clustering.v1.node.Node` instance.
:param dict params: A dictionary providing the parametes to the check
action.
action.
:returns: A dictionary containing the action ID.
"""
@ -617,19 +666,19 @@ class Proxy(proxy.Proxy):
parameters include:
* type: (Required) A string containing the profile type and
version to be used for node adoption. For example,
``os.nova.sever-1.0``.
version to be used for node adoption. For example,
``os.nova.sever-1.0``.
* identity: (Required) A string including the name or ID of an
OpenStack resource to be adopted as a Senlin node.
OpenStack resource to be adopted as a Senlin node.
* name: (Optional) The name of node to be created. Omitting
this parameter will have the node named automatically.
this parameter will have the node named automatically.
* snapshot: (Optional) A boolean indicating whether a snapshot
of the target resource should be created if possible. Default
is False.
of the target resource should be created if possible. Default
is False.
* metadata: (Optional) A dictionary of arbitrary key-value pairs
to be associated with the adopted node.
to be associated with the adopted node.
* overrides: (Optional) A dictionary of key-value pairs to be used
to override attributes derived from the target resource.
to override attributes derived from the target resource.
:returns: The result of node adoption. If `preview` is set to False
(default), returns a :class:`~openstack.clustering.v1.node.Node`
@ -646,7 +695,7 @@ class Proxy(proxy.Proxy):
:class:`~openstack.clustering.v1.node.Node` instance.
:param operation: A string specifying the operation to be performed.
:param dict params: A dictionary providing the parameters for the
operation.
operation.
:returns: A dictionary containing the action ID.
"""
@ -657,8 +706,8 @@ class Proxy(proxy.Proxy):
"""Create a new policy from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.clustering.v1.policy.Policy`, it is comprised
of the properties on the ``Policy`` class.
:class:`~openstack.clustering.v1.policy.Policy`, it is comprised
of the properties on the ``Policy`` class.
:returns: The results of policy creation.
:rtype: :class:`~openstack.clustering.v1.policy.Policy`.
@ -684,10 +733,10 @@ class Proxy(proxy.Proxy):
:param str name_or_id: The name or ID of a policy.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the specified policy does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent policy.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the specified policy does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent policy.
:returns: A policy object or None.
:rtype: :class:`~openstack.clustering.v1.policy.Policy`
"""
@ -716,17 +765,17 @@ class Proxy(proxy.Proxy):
* name: The name of a policy.
* type: The type name of a policy.
* sort: A list of sorting keys separated by commas. Each sorting
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
* limit: Requests a specified size of returned items from the
query. Returns a number of items up to the specified limit
value.
query. Returns a number of items up to the specified limit
value.
* marker: Specifies the ID of the last-seen item. Use the limit
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
* global_project: A boolean value indicating whether policies from
all projects will be returned.
all projects will be returned.
:returns: A generator of policy instances.
"""
@ -749,8 +798,8 @@ class Proxy(proxy.Proxy):
"""Validate a policy spec.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.clustering.v1.policy.PolicyValidate`, it is
comprised of the properties on the Policy class.
:class:`~openstack.clustering.v1.policy.PolicyValidate`, it is
comprised of the properties on the Policy class.
:returns: The results of Policy validation.
:rtype: :class:`~openstack.clustering.v1.policy.PolicyValidate`.
@ -766,7 +815,7 @@ class Proxy(proxy.Proxy):
restrict the policies to be returned. Available parameters include:
* enabled: A boolean value indicating whether the policy is
enabled on the cluster.
enabled on the cluster.
:returns: A generator of cluster-policy binding instances.
"""
cluster_id = resource.Resource._get_id(cluster)
@ -794,8 +843,8 @@ class Proxy(proxy.Proxy):
"""Create a new receiver from attributes.
:param dict attrs: Keyword arguments that will be used to create a
:class:`~openstack.clustering.v1.receiver.Receiver`, it is
comprised of the properties on the Receiver class.
:class:`~openstack.clustering.v1.receiver.Receiver`, it is
comprised of the properties on the Receiver class.
:returns: The results of receiver creation.
:rtype: :class:`~openstack.clustering.v1.receiver.Receiver`.
@ -834,10 +883,10 @@ class Proxy(proxy.Proxy):
:param str name_or_id: The name or ID of a receiver.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the specified receiver does not exist. When
set to ``True``, None will be returned when attempting to
find a nonexistent receiver.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the specified receiver does not exist. When
set to ``True``, None will be returned when attempting to
find a nonexistent receiver.
:returns: A receiver object or None.
:rtype: :class:`~openstack.clustering.v1.receiver.Receiver`
"""
@ -868,8 +917,8 @@ class Proxy(proxy.Proxy):
* cluster_id: The ID of the associated cluster.
* action: The name of the associated action.
* sort: A list of sorting keys separated by commas. Each sorting
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
* global_project: A boolean value indicating whether receivers
* from all projects will be returned.
@ -898,18 +947,18 @@ class Proxy(proxy.Proxy):
* name: name of action for query.
* target: ID of the target object for which the actions should be
returned.
returned.
* action: built-in action types for query.
* sort: A list of sorting keys separated by commas. Each sorting
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
* limit: Requests a specified size of returned items from the
query. Returns a number of items up to the specified limit
value.
query. Returns a number of items up to the specified limit
value.
* marker: Specifies the ID of the last-seen item. Use the limit
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
:returns: A generator of action instances.
"""
@ -949,23 +998,23 @@ class Proxy(proxy.Proxy):
* obj_name: name string of the object associated with an event.
* obj_type: type string of the object related to an event. The
value can be ``cluster``, ``node``, ``policy`` etc.
value can be ``cluster``, ``node``, ``policy`` etc.
* obj_id: ID of the object associated with an event.
* cluster_id: ID of the cluster associated with the event, if any.
* action: name of the action associated with an event.
* sort: A list of sorting keys separated by commas. Each sorting
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
key can optionally be attached with a sorting direction
modifier which can be ``asc`` or ``desc``.
* limit: Requests a specified size of returned items from the
query. Returns a number of items up to the specified limit
value.
query. Returns a number of items up to the specified limit
value.
* marker: Specifies the ID of the last-seen item. Use the limit
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
parameter to make an initial limited request and use the ID of
the last-seen item from the response as the marker parameter
value in a subsequent limited request.
* global_project: A boolean specifying whether events from all
projects should be returned. This option is subject to access
control checking.
projects should be returned. This option is subject to access
control checking.
:returns: A generator of event instances.
"""
@ -976,22 +1025,22 @@ class Proxy(proxy.Proxy):
"""Wait for a resource to be in a particular status.
:param res: The resource to wait on to reach the specified status.
The resource must have a ``status`` attribute.
The resource must have a ``status`` attribute.
:type resource: A :class:`~openstack.resource.Resource` object.
:param status: Desired status.
:param failures: Statuses that would be interpreted as failures.
:type failures: :py:class:`list`
:param interval: Number of seconds to wait before to consecutive
checks. Default to 2.
checks. Default to 2.
:param wait: Maximum number of seconds to wait before the change.
Default to 120.
Default to 120.
:returns: The resource is returned on success.
:raises: :class:`~openstack.exceptions.ResourceTimeout` if transition
to the desired status failed to occur in specified seconds.
to the desired status failed to occur in specified seconds.
:raises: :class:`~openstack.exceptions.ResourceFailure` if the resource
has transited to one of the failure statuses.
has transited to one of the failure statuses.
:raises: :class:`~AttributeError` if the resource does not have a
``status`` attribute.
``status`` attribute.
"""
failures = [] if failures is None else failures
return resource.wait_for_status(
@ -1003,12 +1052,12 @@ class Proxy(proxy.Proxy):
:param res: The resource to wait on to be deleted.
:type resource: A :class:`~openstack.resource.Resource` object.
:param interval: Number of seconds to wait before to consecutive
checks. Default to 2.
checks. Default to 2.
:param wait: Maximum number of seconds to wait before the change.
Default to 120.
Default to 120.
:returns: The resource is returned on success.
:raises: :class:`~openstack.exceptions.ResourceTimeout` if transition
to delete failed to occur in the specified seconds.
to delete failed to occur in the specified seconds.
"""
return resource.wait_for_delete(self, res, interval, wait)
@ -1016,7 +1065,7 @@ class Proxy(proxy.Proxy):
"""Get a generator of services.
:returns: A generator of objects that are of type
:class:`~openstack.clustering.v1.service.Service`
:class:`~openstack.clustering.v1.service.Service`
"""
return self._list(_service.Service, **query)
@ -1024,10 +1073,11 @@ class Proxy(proxy.Proxy):
"""Get the operation about a profile type.
:param profile_type: The name of the profile_type to retrieve or an
object of :class:`~openstack.clustering.v1.profile_type.ProfileType`.
object of
:class:`~openstack.clustering.v1.profile_type.ProfileType`.
:returns: A :class:`~openstack.clustering.v1.profile_type.ProfileType`
object.
object.
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
profile_type matching the name could be found.
"""

View File

@ -9,13 +9,13 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.clustering.v1 import _async_resource
from openstack.common import metadata
from openstack import resource
from openstack import utils
class Cluster(_async_resource.AsyncResource):
class Cluster(_async_resource.AsyncResource, metadata.MetadataMixin):
resource_key = 'cluster'
resources_key = 'clusters'
base_path = '/clusters'

View File

View File

@ -0,0 +1,138 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack import exceptions
from openstack import resource
from openstack import utils
class MetadataMixin:
#: *Type: list of tag strings*
metadata = resource.Body('metadata', type=dict)
def fetch_metadata(self, session):
"""Lists metadata set on the entity.
:param session: The session to use for making this request.
:return: The dictionary with metadata attached to the entity
"""
url = utils.urljoin(self.base_path, self.id, 'metadata')
response = session.get(url)
exceptions.raise_from_response(response)
json = response.json()
if 'metadata' in json:
self._body.attributes.update({'metadata': json['metadata']})
return self
def set_metadata(self, session, metadata=None, replace=False):
"""Sets/Replaces metadata key value pairs on the resource.
:param session: The session to use for making this request.
:param dict metadata: Dictionary with key-value pairs
:param bool replace: Replace all resource metadata with the new object
or merge new and existing.
"""
url = utils.urljoin(self.base_path, self.id, 'metadata')
if not metadata:
metadata = {}
if not replace:
response = session.post(url, json={'metadata': metadata})
else:
response = session.put(url, json={'metadata': metadata})
exceptions.raise_from_response(response)
self._body.attributes.update({'metadata': metadata})
return self
def replace_metadata(self, session, metadata=None):
"""Replaces all metadata key value pairs on the resource.
:param session: The session to use for making this request.
:param dict metadata: Dictionary with key-value pairs
:param bool replace: Replace all resource metadata with the new object
or merge new and existing.
"""
return self.set_metadata(session, metadata, replace=True)
def delete_metadata(self, session):
"""Removes all metadata on the entity.
:param session: The session to use for making this request.
"""
self.set_metadata(session, None, replace=True)
return self
def get_metadata_item(self, session, key):
"""Get the single metadata item on the entity.
If the metadata key does not exist a 404 will be returned
:param session: The session to use for making this request.
:param str key: The key of a metadata item.
"""
url = utils.urljoin(self.base_path, self.id, 'metadata', key)
response = session.get(url)
exceptions.raise_from_response(
response, error_message='Metadata item does not exist')
meta = response.json().get('meta', {})
# Here we need to potentially init metadata
metadata = self.metadata or {}
metadata[key] = meta.get(key)
self._body.attributes.update({
'metadata': metadata
})
return self
def set_metadata_item(self, session, key, value):
"""Create or replace single metadata item to the resource.
:param session: The session to use for making this request.
:param str key: The key for the metadata item.
:param str value: The value.
"""
url = utils.urljoin(self.base_path, self.id, 'metadata', key)
response = session.put(
url,
json={'meta': {key: value}}
)
exceptions.raise_from_response(response)
# we do not want to update tags directly
metadata = self.metadata
metadata[key] = value
self._body.attributes.update({
'metadata': metadata
})
return self
def delete_metadata_item(self, session, key):
"""Removes a single metadata item from the specified resource.
:param session: The session to use for making this request.
:param str key: The key as a string.
"""
url = utils.urljoin(self.base_path, self.id, 'metadata', key)
response = session.delete(url)
exceptions.raise_from_response(response)
# we do not want to update tags directly
metadata = self.metadata
try:
if metadata:
metadata.pop(key)
else:
metadata = {}
except ValueError:
pass # do nothing!
self._body.attributes.update({
'metadata': metadata
})
return self

View File

@ -0,0 +1,129 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack import exceptions
from openstack import resource
# ATTENTION: Please do not inherit this class for anything else then QuotaSet,
# since attribute processing is here very different!
class QuotaSet(resource.Resource):
resource_key = 'quota_set'
# ATTENTION: different services might be using different base_path
base_path = '/os-quota-sets/%(project_id)s'
# capabilities
allow_create = True
allow_fetch = True
allow_delete = True
allow_commit = True
_query_mapping = resource.QueryParameters(
"usage")
# NOTE(gtema) Sadly this attribute is useless in all the methods, but keep
# it here extra as a reminder
requires_id = False
# Quota-sets are not very well designed. We must keep what is
# there and try to process it on best effort
_allow_unknown_attrs_in_body = True
#: Properties
#: Current reservations
#: *type:dict*
reservation = resource.Body('reservation', type=dict)
#: Quota usage
#: *type:dict*
usage = resource.Body('usage', type=dict)
project_id = resource.URI('project_id')
def fetch(self, session, requires_id=False,
base_path=None, error_message=None, **params):
return super(QuotaSet, self).fetch(
session,
requires_id=False,
base_path=base_path,
error_message=error_message,
**params
)
def _translate_response(self, response, has_body=None, error_message=None):
"""Given a KSA response, inflate this instance with its data
DELETE operations don't return a body, so only try to work
with a body when has_body is True.
This method updates attributes that correspond to headers
and body on this instance and clears the dirty set.
"""
if has_body is None:
has_body = self.has_body
exceptions.raise_from_response(response, error_message=error_message)
if has_body:
try:
body = response.json()
if self.resource_key and self.resource_key in body:
body = body[self.resource_key]
# Do not allow keys called "self" through. Glance chose
# to name a key "self", so we need to pop it out because
# we can't send it through cls.existing and into the
# Resource initializer. "self" is already the first
# argument and is practically a reserved word.
body.pop("self", None)
# Process body_attrs to strip usage and reservation out
normalized_attrs = dict(
reservation={},
usage={},
)
for key, val in body.items():
if isinstance(val, dict):
if 'in_use' in val:
normalized_attrs['usage'][key] = val['in_use']
if 'reserved' in val:
normalized_attrs['reservation'][key] = \
val['reserved']
if 'limit' in val:
normalized_attrs[key] = val['limit']
else:
normalized_attrs[key] = val
self._unknown_attrs_in_body.update(normalized_attrs)
self._body.attributes.update(normalized_attrs)
self._body.clean()
if self.commit_jsonpatch or self.allow_patch:
# We need the original body to compare against
self._original_body = normalized_attrs.copy()
except ValueError:
# Server returned not parsable response (202, 204, etc)
# Do simply nothing
pass
headers = self._consume_header_attrs(response.headers)
self._header.attributes.update(headers)
self._header.clean()
self._update_location()
dict.update(self, self.to_dict())
def _prepare_request_body(self, patch, prepend_key):
body = self._body.dirty
# Ensure we never try to send meta props reservation and usage
body.pop('reservation', None)
body.pop('usage', None)
if prepend_key and self.resource_key is not None:
body = {self.resource_key: body}
return body

127
openstack/common/tag.py Normal file
View File

@ -0,0 +1,127 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack import exceptions
from openstack import resource
from openstack import utils
class TagMixin:
_tag_query_parameters = {
'tags': 'tags',
'any_tags': 'tags-any',
'not_tags': 'not-tags',
'not_any_tags': 'not-tags-any',
}
#: A list of associated tags
#: *Type: list of tag strings*
tags = resource.Body('tags', type=list, default=[])
def fetch_tags(self, session):
"""Lists tags set on the entity.
:param session: The session to use for making this request.
:return: The list with tags attached to the entity
"""
url = utils.urljoin(self.base_path, self.id, 'tags')
session = self._get_session(session)
response = session.get(url)
exceptions.raise_from_response(response)
# NOTE(gtema): since this is a common method
# we can't rely on the resource_key, because tags are returned
# without resource_key. Do parse response here
json = response.json()
if 'tags' in json:
self._body.attributes.update({'tags': json['tags']})
return self
def set_tags(self, session, tags=[]):
"""Sets/Replaces all tags on the resource.
:param session: The session to use for making this request.
:param list tags: List with tags to be set on the resource
"""
url = utils.urljoin(self.base_path, self.id, 'tags')
session = self._get_session(session)
response = session.put(url, json={'tags': tags})
exceptions.raise_from_response(response)
self._body.attributes.update({'tags': tags})
return self
def remove_all_tags(self, session):
"""Removes all tags on the entity.
:param session: The session to use for making this request.
"""
url = utils.urljoin(self.base_path, self.id, 'tags')
session = self._get_session(session)
response = session.delete(url)
exceptions.raise_from_response(response)
self._body.attributes.update({'tags': []})
return self
def check_tag(self, session, tag):
"""Checks if tag exists on the entity.
If the tag does not exist a 404 will be returned
:param session: The session to use for making this request.
:param tag: The tag as a string.
"""
url = utils.urljoin(self.base_path, self.id, 'tags', tag)
session = self._get_session(session)
response = session.get(url)
exceptions.raise_from_response(response,
error_message='Tag does not exist')
return self
def add_tag(self, session, tag):
"""Adds a single tag to the resource.
:param session: The session to use for making this request.
:param tag: The tag as a string.
"""
url = utils.urljoin(self.base_path, self.id, 'tags', tag)
session = self._get_session(session)
response = session.put(url)
exceptions.raise_from_response(response)
# we do not want to update tags directly
tags = self.tags
tags.append(tag)
self._body.attributes.update({
'tags': tags
})
return self
def remove_tag(self, session, tag):
"""Removes a single tag from the specified resource.
:param session: The session to use for making this request.
:param tag: The tag as a string.
"""
url = utils.urljoin(self.base_path, self.id, 'tags', tag)
session = self._get_session(session)
response = session.delete(url)
exceptions.raise_from_response(response)
# we do not want to update tags directly
tags = self.tags
try:
# NOTE(gtema): if tags were not fetched, but request suceeded
# it is ok. Just ensure tag does not exist locally
tags.remove(tag)
except ValueError:
pass # do nothing!
self._body.attributes.update({
'tags': tags
})
return self

File diff suppressed because it is too large Load Diff

View File

@ -36,11 +36,10 @@ class Flavor(resource.Resource):
_max_microversion = '2.61'
# Properties
#: Links pertaining to this flavor. This is a list of dictionaries,
#: each including keys ``href`` and ``rel``.
links = resource.Body('links')
#: The name of this flavor.
name = resource.Body('name')
name = resource.Body('name', alias='original_name')
#: The name of this flavor when returned by server list/show
original_name = resource.Body('original_name')
#: The description of the flavor.
description = resource.Body('description')
#: Size of the disk this flavor offers. *Type: int*

View File

@ -9,8 +9,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.compute.v2 import metadata
from openstack.common import metadata
from openstack import resource
@ -38,8 +37,6 @@ class Image(resource.Resource, metadata.MetadataMixin):
name = resource.Body('name')
#: Timestamp when the image was created.
created_at = resource.Body('created')
#: Metadata pertaining to this image. *Type: dict*
metadata = resource.Body('metadata', type=dict)
#: The mimimum disk size. *Type: int*
min_disk = resource.Body('minDisk', type=int)
#: The minimum RAM size. *Type: int*

View File

@ -75,11 +75,15 @@ class Limits(resource.Resource):
allow_fetch = True
_query_mapping = resource.QueryParameters(
'tenant_id'
)
absolute = resource.Body("absolute", type=AbsoluteLimits)
rate = resource.Body("rate", type=list, list_type=RateLimit)
def fetch(self, session, requires_id=False, error_message=None,
base_path=None):
base_path=None, **params):
"""Get the Limits resource.
:param session: The session to use for making this request.
@ -91,5 +95,8 @@ class Limits(resource.Resource):
# TODO(mordred) We shouldn't have to subclass just to declare
# requires_id = False.
return super(Limits, self).fetch(
session=session, requires_id=False, error_message=error_message,
base_path=base_path)
session=session, requires_id=requires_id,
error_message=error_message,
base_path=base_path,
**params
)

View File

@ -1,101 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack import exceptions
from openstack import utils
class MetadataMixin:
def _metadata(self, method, key=None, clear=False, delete=False,
metadata=None):
metadata = metadata or {}
for k, v in metadata.items():
if not isinstance(v, str):
raise ValueError("The value for %s (%s) must be "
"a text string" % (k, v))
# If we're in a ServerDetail, we need to pop the "detail" portion
# of the URL off and then everything else will work the same.
pos = self.base_path.find("detail")
if pos != -1:
base = self.base_path[:pos]
else:
base = self.base_path
if key is not None:
url = utils.urljoin(base, self.id, "metadata", key)
else:
url = utils.urljoin(base, self.id, "metadata")
kwargs = {}
if metadata or clear:
# 'meta' is the key for singular modifications.
# 'metadata' is the key for mass modifications.
key = "meta" if key is not None else "metadata"
kwargs["json"] = {key: metadata}
headers = {"Accept": ""} if delete else {}
response = method(url, headers=headers, **kwargs)
# ensure Nova API has not returned us an error
exceptions.raise_from_response(response)
# DELETE doesn't return a JSON body while everything else does.
return response.json() if not delete else None
def get_metadata(self, session):
"""Retrieve metadata
:param session: The session to use for this request.
:returns: A dictionary of the requested metadata. All keys and values
are Unicode text.
:rtype: dict
"""
result = self._metadata(session.get)
return result["metadata"]
def set_metadata(self, session, **metadata):
"""Update metadata
This call will replace only the metadata with the same keys
given here. Metadata with other keys will not be modified.
:param session: The session to use for this request.
:param kwargs metadata: key/value metadata pairs to be update on
this server instance. All keys and values
are stored as Unicode.
:returns: A dictionary of the metadata after being updated.
All keys and values are Unicode text.
:rtype: dict
"""
if not metadata:
return dict()
result = self._metadata(session.post, metadata=metadata)
return result["metadata"]
def delete_metadata(self, session, keys):
"""Delete metadata
Note: This method will do a HTTP DELETE request for every key in keys.
:param session: The session to use for this request.
:param list keys: The keys to delete.
:rtype: ``None``
"""
for key in keys:
self._metadata(session.delete, key=key, delete=True)

View File

@ -0,0 +1,72 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack import resource
class Migration(resource.Resource):
resources_key = 'migrations'
base_path = '/os-migrations'
# capabilities
allow_list = True
_query_mapping = resource.QueryParameters(
'host',
'status',
'migration_type',
'source_compute',
'user_id',
'project_id',
changes_since='changes-since',
changes_before='changes-before',
server_id='instance_uuid',
)
#: The date and time when the resource was created.
created_at = resource.Body('created_at')
#: The target compute of the migration.
dest_compute = resource.Body('dest_compute')
#: The target host of the migration.
dest_host = resource.Body('dest_host')
#: The target node of the migration.
dest_node = resource.Body('dest_node')
#: The type of the migration. One of 'migration', 'resize',
#: 'live-migration' or 'evacuation'
migration_type = resource.Body('migration_type')
#: The ID of the old flavor. This value corresponds to the ID of the flavor
#: in the database. This will be the same as new_flavor_id except for
#: resize operations.
new_flavor_id = resource.Body('new_instance_type_id')
#: The ID of the old flavor. This value corresponds to the ID of the flavor
#: in the database.
old_flavor_id = resource.Body('old_instance_type_id')
#: The ID of the project that initiated the server migration (since
#: microversion 2.80)
project_id = resource.Body('project_id')
#: The UUID of the server
server_id = resource.Body('instance_uuid')
#: The source compute of the migration.
source_compute = resource.Body('source_compute')
#: The source node of the migration.
source_node = resource.Body('source_node')
#: The current status of the migration.
status = resource.Body('status')
#: The date and time when the resource was last updated.
updated_at = resource.Body('updated_at')
#: The ID of the user that initiated the server migration (since
#: microversion 2.80)
user_id = resource.Body('user_id')
#: The UUID of the migration (since microversion 2.59)
uuid = resource.Body('uuid', alternate_id=True)
_max_microversion = '2.80'

View File

@ -0,0 +1,57 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import quota_set
from openstack import resource
class QuotaSet(quota_set.QuotaSet):
# We generally only want compute QS support max_microversion. Otherwise be
# explicit and list all the attributes
_max_microversion = '2.56'
#: Properties
#: The number of allowed server cores for each tenant.
cores = resource.Body('cores', type=int)
#: The number of allowed fixed IP addresses for each tenant. Must be
#: equal to or greater than the number of allowed servers.
fixed_ips = resource.Body('fixed_ips', type=int)
#: The number of allowed floating IP addresses for each tenant.
floating_ips = resource.Body('floating_ips', type=int)
#: You can force the update even if the quota has already been used and
#: the reserved quota exceeds the new quota.
force = resource.Body('force', type=bool)
#: The number of allowed bytes of content for each injected file.
injected_file_content_bytes = resource.Body(
'injected_file_content_bytes', type=int)
#: The number of allowed bytes for each injected file path.
injected_file_path_bytes = resource.Body(
'injected_file_path_bytes', type=int)
#: The number of allowed injected files for each tenant.
injected_files = resource.Body('injected_files', type=int)
#: The number of allowed servers for each tenant.
instances = resource.Body('instances', type=int)
#: The number of allowed key pairs for each user.
key_pairs = resource.Body('key_pairs', type=int)
#: The number of allowed metadata items for each server.
metadata_items = resource.Body('metadata_items', type=int)
#: The number of private networks that can be created per project.
networks = resource.Body('networks', type=int)
#: The amount of allowed server RAM, in MiB, for each tenant.
ram = resource.Body('ram', type=int)
#: The number of allowed rules for each security group.
security_group_rules = resource.Body('security_group_rules', type=int)
#: The number of allowed security groups for each tenant.
security_groups = resource.Body('security_groups', type=int)
#: The number of allowed server groups for each tenant.
server_groups = resource.Body('server_groups', type=int)
#: The number of allowed members for each server group.
server_group_members = resource.Body('server_group_members', type=int)

View File

@ -9,8 +9,9 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.compute.v2 import metadata
from openstack.common import metadata
from openstack.common import tag
from openstack.compute.v2 import volume_attachment
from openstack import exceptions
from openstack.image.v2 import image
from openstack import resource
@ -26,7 +27,7 @@ CONSOLE_TYPE_ACTION_MAPPING = {
}
class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
class Server(resource.Resource, metadata.MetadataMixin, tag.TagMixin):
resource_key = 'server'
resources_key = 'servers'
base_path = '/servers'
@ -60,7 +61,7 @@ class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
changes_before="changes-before",
id="uuid",
all_projects="all_tenants",
**resource.TagMixin._tag_query_parameters
**tag.TagMixin._tag_query_parameters
)
_max_microversion = '2.73'
@ -82,7 +83,11 @@ class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
#: A list of an attached volumes. Each item in the list contains at least
#: an "id" key to identify the specific volumes.
attached_volumes = resource.Body(
'os-extended-volumes:volumes_attached')
'os-extended-volumes:volumes_attached',
aka='volumes',
type=list,
list_type=volume_attachment.VolumeAttachment,
default=[])
#: The name of the availability zone this server is a part of.
availability_zone = resource.Body('OS-EXT-AZ:availability_zone')
#: Enables fine grained control of the block device mapping for an
@ -128,6 +133,12 @@ class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
#: instance name template. Appears in the response for administrative users
#: only.
instance_name = resource.Body('OS-EXT-SRV-ATTR:instance_name')
#: The address to use to connect to this server from the current calling
#: context. This will be set to public_ipv6 if the calling host has
#: routable ipv6 addresses, and to private_ipv4 if the Connection was
#: created with private=True. Otherwise it will be set to public_ipv4.
interface_ip = resource.Computed('interface_ip', default='')
# The locked status of the server
is_locked = resource.Body('locked', type=bool)
#: The UUID of the kernel image when using an AMI. Will be null if not.
@ -143,8 +154,6 @@ class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
launched_at = resource.Body('OS-SRV-USG:launched_at')
#: The maximum number of servers to create.
max_count = resource.Body('max_count')
#: Metadata stored for this server. *Type: dict*
metadata = resource.Body('metadata', type=dict)
#: The minimum number of servers to create.
min_count = resource.Body('min_count')
#: A networks object. Required parameter when there are multiple
@ -159,6 +168,17 @@ class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
progress = resource.Body('progress', type=int)
#: The ID of the project this server is associated with.
project_id = resource.Body('tenant_id')
#: The private IPv4 address of this server
private_v4 = resource.Computed('private_v4', default='')
#: The private IPv6 address of this server
private_v6 = resource.Computed('private_v6', default='')
#: The public IPv4 address of this server
public_v4 = resource.Computed('public_v4', default='')
#: The public IPv6 address of this server
public_v6 = resource.Computed('public_v6', default='')
#: The UUID of the ramdisk image when using an AMI. Will be null if not.
#: By default, it appears in the response for administrative users only.
ramdisk_id = resource.Body('OS-EXT-SRV-ATTR:ramdisk_id')
@ -273,16 +293,16 @@ class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
body = {'forceDelete': None}
self._action(session, body)
def rebuild(self, session, name=None, admin_password=None,
preserve_ephemeral=False, image=None,
def rebuild(self, session, image, name=None, admin_password=None,
preserve_ephemeral=None,
access_ipv4=None, access_ipv6=None,
metadata=None, user_data=None):
"""Rebuild the server with the given arguments."""
action = {
'preserve_ephemeral': preserve_ephemeral
'imageRef': resource.Resource._get_id(image)
}
if image is not None:
action['imageRef'] = resource.Resource._get_id(image)
if preserve_ephemeral is not None:
action['preserve_ephemeral'] = preserve_ephemeral
if name is not None:
action['name'] = name
if admin_password is not None:

View File

@ -39,12 +39,18 @@ class ServerGroup(resource.Resource):
policy = resource.Body('policy')
#: The list of members in the server group
member_ids = resource.Body('members')
#: The metadata associated with the server group
#: The metadata associated with the server group. This is always empty and
#: only used for preserving compatibility.
metadata = resource.Body('metadata')
#: The project ID who owns the server group.
project_id = resource.Body('project_id')
#: The rules field, which is a dict, can be applied to the policy
rules = resource.Body('rules', type=list, list_type=dict)
#: The rules field, which is a dict, can be applied to the policy.
#: Currently, only the max_server_per_host rule is supported for the
#: anti-affinity policy. The max_server_per_host rule allows specifying how
#: many members of the anti-affinity group can reside on the same compute
#: host. If not specified, only one member from the same anti-affinity
#: group can reside on a given host.
rules = resource.Body('rules', type=dict)
#: The user ID who owns the server group
user_id = resource.Body('user_id')

View File

@ -0,0 +1,98 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack import exceptions
from openstack import resource
from openstack import utils
class ServerMigration(resource.Resource):
resource_key = 'migration'
resources_key = 'migrations'
base_path = '/servers/%(server_uuid)s/migrations'
# capabilities
allow_fetch = True
allow_list = True
allow_delete = True
#: The ID for the server.
server_id = resource.URI('server_uuid')
#: The date and time when the resource was created.
created_at = resource.Body('created_at')
#: The target host of the migration.
dest_host = resource.Body('dest_host')
#: The target compute of the migration.
dest_compute = resource.Body('dest_compute')
#: The target node of the migration.
dest_node = resource.Body('dest_node')
#: The amount of disk, in bytes, that has been processed during the
#: migration.
disk_processed_bytes = resource.Body('disk_processed_bytes')
#: The amount of disk, in bytes, that still needs to be migrated.
disk_remaining_bytes = resource.Body('disk_remaining_bytes')
#: The total amount of disk, in bytes, that needs to be migrated.
disk_total_bytes = resource.Body('disk_total_bytes')
#: The amount of memory, in bytes, that has been processed during the
#: migration.
memory_processed_bytes = resource.Body('memory_processed_bytes')
#: The amount of memory, in bytes, that still needs to be migrated.
memory_remaining_bytes = resource.Body('memory_remaining_bytes')
#: The total amount of memory, in bytes, that needs to be migrated.
memory_total_bytes = resource.Body('memory_total_bytes')
#: The ID of the project that initiated the server migration (since
#: microversion 2.80)
project_id = resource.Body('project_id')
# FIXME(stephenfin): This conflicts since there is a server ID in the URI
# *and* in the body. We need a field that handles both or we need to use
# different names.
# #: The UUID of the server
# server_id = resource.Body('server_uuid')
#: The source compute of the migration.
source_compute = resource.Body('source_compute')
#: The source node of the migration.
source_node = resource.Body('source_node')
#: The current status of the migration.
status = resource.Body('status')
#: The date and time when the resource was last updated.
updated_at = resource.Body('updated_at')
#: The ID of the user that initiated the server migration (since
#: microversion 2.80)
user_id = resource.Body('user_id')
#: The UUID of the migration (since microversion 2.59)
uuid = resource.Body('uuid', alternate_id=True)
_max_microversion = '2.80'
@classmethod
def _get_microversion_for_action(cls, session):
return cls._get_microversion_for_list(session)
def _action(self, session, body):
"""Preform server migration actions given the message body."""
session = self._get_session(session)
microversion = self._get_microversion_for_list(session)
url = utils.urljoin(
self.base_path % {'server_uuid': self.server_id},
self.id,
'action',
)
response = session.post(url, microversion=microversion, json=body)
exceptions.raise_from_response(response)
return response
def force_complete(self, session):
"""Force on-going live migration to complete."""
body = {'force_complete': None}
self._action(session, body)

View File

@ -23,10 +23,10 @@ class Proxy(proxy.Proxy):
"""Create a new database from attributes
:param instance: This can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
or a :class:`~openstack.database.v1.instance.Instance`
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.database.v1.database.Database`,
comprised of the properties on the Database class.
a :class:`~openstack.database.v1.database.Database`,
comprised of the properties on the Database class.
:returns: The results of server creation
:rtype: :class:`~openstack.database.v1.database.Database`
@ -39,16 +39,16 @@ class Proxy(proxy.Proxy):
"""Delete a database
:param database: The value can be either the ID of a database or a
:class:`~openstack.database.v1.database.Database` instance.
:class:`~openstack.database.v1.database.Database` instance.
:param instance: This parameter needs to be specified when
an ID is given as `database`.
It can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
an ID is given as `database`.
It can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the database does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent database.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the database does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent database.
:returns: ``None``
"""
@ -62,12 +62,12 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a database.
:param instance: This can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
or a :class:`~openstack.database.v1.instance.Instance`
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.database.v1.database.Database` or None
"""
instance = self._get_resource(_instance.Instance, instance)
@ -79,10 +79,10 @@ class Proxy(proxy.Proxy):
"""Return a generator of databases
:param instance: This can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
instance that the interface belongs to.
or a :class:`~openstack.database.v1.instance.Instance`
instance that the interface belongs to.
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of database objects
:rtype: :class:`~openstack.database.v1.database.Database`
@ -94,16 +94,16 @@ class Proxy(proxy.Proxy):
"""Get a single database
:param instance: This parameter needs to be specified when
an ID is given as `database`.
It can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
an ID is given as `database`.
It can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
:param database: The value can be the ID of a database or a
:class:`~openstack.database.v1.database.Database`
instance.
:class:`~openstack.database.v1.database.Database`
instance.
:returns: One :class:`~openstack.database.v1.database.Database`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_database.Database, database)
@ -112,10 +112,10 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a flavor.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.database.v1.flavor.Flavor` or None
"""
return self._find(_flavor.Flavor, name_or_id,
@ -125,11 +125,11 @@ class Proxy(proxy.Proxy):
"""Get a single flavor
:param flavor: The value can be the ID of a flavor or a
:class:`~openstack.database.v1.flavor.Flavor` instance.
:class:`~openstack.database.v1.flavor.Flavor` instance.
:returns: One :class:`~openstack.database.v1.flavor.Flavor`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_flavor.Flavor, flavor)
@ -137,7 +137,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of flavors
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of flavor objects
:rtype: :class:`~openstack.database.v1.flavor.Flavor`
@ -148,8 +148,8 @@ class Proxy(proxy.Proxy):
"""Create a new instance from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.database.v1.instance.Instance`,
comprised of the properties on the Instance class.
a :class:`~openstack.database.v1.instance.Instance`,
comprised of the properties on the Instance class.
:returns: The results of server creation
:rtype: :class:`~openstack.database.v1.instance.Instance`
@ -160,12 +160,12 @@ class Proxy(proxy.Proxy):
"""Delete an instance
:param instance: The value can be either the ID of an instance or a
:class:`~openstack.database.v1.instance.Instance` instance.
:class:`~openstack.database.v1.instance.Instance` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the instance does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent instance.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the instance does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent instance.
:returns: ``None``
"""
@ -177,10 +177,10 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.database.v1.instance.Instance` or None
"""
return self._find(_instance.Instance, name_or_id,
@ -190,12 +190,12 @@ class Proxy(proxy.Proxy):
"""Get a single instance
:param instance: The value can be the ID of an instance or a
:class:`~openstack.database.v1.instance.Instance`
instance.
:class:`~openstack.database.v1.instance.Instance`
instance.
:returns: One :class:`~openstack.database.v1.instance.Instance`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_instance.Instance, instance)
@ -203,7 +203,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of instances
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of instance objects
:rtype: :class:`~openstack.database.v1.instance.Instance`
@ -214,10 +214,10 @@ class Proxy(proxy.Proxy):
"""Update a instance
:param instance: Either the id of a instance or a
:class:`~openstack.database.v1.instance.Instance`
instance.
:class:`~openstack.database.v1.instance.Instance`
instance.
:attrs kwargs: The attributes to update on the instance represented
by ``value``.
by ``value``.
:returns: The updated instance
:rtype: :class:`~openstack.database.v1.instance.Instance`
@ -228,10 +228,10 @@ class Proxy(proxy.Proxy):
"""Create a new user from attributes
:param instance: This can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
or a :class:`~openstack.database.v1.instance.Instance`
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.database.v1.user.User`,
comprised of the properties on the User class.
a :class:`~openstack.database.v1.user.User`,
comprised of the properties on the User class.
:returns: The results of server creation
:rtype: :class:`~openstack.database.v1.user.User`
@ -243,16 +243,16 @@ class Proxy(proxy.Proxy):
"""Delete a user
:param user: The value can be either the ID of a user or a
:class:`~openstack.database.v1.user.User` instance.
:class:`~openstack.database.v1.user.User` instance.
:param instance: This parameter needs to be specified when
an ID is given as `user`.
It can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
an ID is given as `user`.
It can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the user does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent user.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the user does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent user.
:returns: ``None``
"""
@ -265,12 +265,12 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a user.
:param instance: This can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
or a :class:`~openstack.database.v1.instance.Instance`
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.database.v1.user.User` or None
"""
instance = self._get_resource(_instance.Instance, instance)
@ -281,9 +281,9 @@ class Proxy(proxy.Proxy):
"""Return a generator of users
:param instance: This can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
or a :class:`~openstack.database.v1.instance.Instance`
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of user objects
:rtype: :class:`~openstack.database.v1.user.User`
@ -295,15 +295,15 @@ class Proxy(proxy.Proxy):
"""Get a single user
:param user: The value can be the ID of a user or a
:class:`~openstack.database.v1.user.User` instance.
:class:`~openstack.database.v1.user.User` instance.
:param instance: This parameter needs to be specified when
an ID is given as `database`.
It can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
an ID is given as `database`.
It can be either the ID of an instance
or a :class:`~openstack.database.v1.instance.Instance`
:returns: One :class:`~openstack.database.v1.user.User`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
instance = self._get_resource(_instance.Instance, instance)
return self._get(_user.User, user)

View File

@ -55,7 +55,7 @@ class Proxy(proxy.Proxy):
"""Get a zone
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:returns: Zone instance.
:rtype: :class:`~openstack.dns.v2.zone.Zone`
"""
@ -65,7 +65,7 @@ class Proxy(proxy.Proxy):
"""Delete a zone
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist.
@ -108,7 +108,7 @@ class Proxy(proxy.Proxy):
"""Abandon Zone
:param zone: The value can be the ID of a zone to be abandoned
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:returns: None
"""
@ -120,7 +120,7 @@ class Proxy(proxy.Proxy):
"""Trigger update of secondary Zone
:param zone: The value can be the ID of a zone to be abandoned
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:returns: None
"""
@ -132,9 +132,9 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of recordsets
:param zone: The optional value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance. If it is not
given all recordsets for all zones of the tenant would be
retrieved
or a :class:`~openstack.dns.v2.zone.Zone` instance. If it is not
given all recordsets for all zones of the tenant would be
retrieved
:param dict query: Optional query parameters to be sent to limit the
resources being returned.
@ -185,9 +185,9 @@ class Proxy(proxy.Proxy):
"""Get a recordset
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:param recordset: The value can be the ID of a recordset
or a :class:`~openstack.dns.v2.recordset.Recordset` instance.
or a :class:`~openstack.dns.v2.recordset.Recordset` instance.
:returns: Recordset instance
:rtype: :class:`~openstack.dns.v2.recordset.Recordset`
"""
@ -198,10 +198,10 @@ class Proxy(proxy.Proxy):
"""Delete a zone
:param recordset: The value can be the ID of a recordset
or a :class:`~openstack.dns.v2.recordset.Recordset`
instance.
or a :class:`~openstack.dns.v2.recordset.Recordset`
instance.
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist. When set to ``True``, no exception will
@ -221,7 +221,7 @@ class Proxy(proxy.Proxy):
"""Find a single recordset
:param zone: The value can be the ID of a zone
or a :class:`~openstack.dns.v2.zone.Zone` instance.
or a :class:`~openstack.dns.v2.zone.Zone` instance.
:param name_or_id: The name or ID of a zone
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised
@ -268,7 +268,7 @@ class Proxy(proxy.Proxy):
"""Get a zone import record
:param zone: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_import.ZoneImport` instance.
or a :class:`~openstack.dns.v2.zone_import.ZoneImport` instance.
:returns: ZoneImport instance.
:rtype: :class:`~openstack.dns.v2.zone_import.ZoneImport`
"""
@ -278,7 +278,7 @@ class Proxy(proxy.Proxy):
"""Delete a zone import
:param zone_import: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_import.ZoneImport` instance.
or a :class:`~openstack.dns.v2.zone_import.ZoneImport` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist.
@ -310,7 +310,7 @@ class Proxy(proxy.Proxy):
"""Create a new zone export from attributes
:param zone: The value can be the ID of a zone to be exported
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.zone_export.ZoneExport`,
comprised of the properties on the ZoneExport class.
@ -328,7 +328,7 @@ class Proxy(proxy.Proxy):
"""Get a zone export record
:param zone: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:returns: ZoneExport instance.
:rtype: :class:`~openstack.dns.v2.zone_export.ZoneExport`
"""
@ -338,7 +338,7 @@ class Proxy(proxy.Proxy):
"""Get a zone export record as text
:param zone: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:returns: ZoneExport instance.
:rtype: :class:`~openstack.dns.v2.zone_export.ZoneExport`
"""
@ -349,7 +349,7 @@ class Proxy(proxy.Proxy):
"""Delete a zone export
:param zone_export: The value can be the ID of a zone import
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist.
@ -383,8 +383,8 @@ class Proxy(proxy.Proxy):
"""Get a Floating IP
:param floating_ip: The value can be the ID of a floating ip
or a :class:`~openstack.dns.v2.floating_ip.FloatingIP` instance.
The ID is in format "region_name:floatingip_id"
or a :class:`~openstack.dns.v2.floating_ip.FloatingIP` instance.
The ID is in format "region_name:floatingip_id"
:returns: FloatingIP instance.
:rtype: :class:`~openstack.dns.v2.floating_ip.FloatingIP`
"""
@ -402,6 +402,17 @@ class Proxy(proxy.Proxy):
"""
return self._update(_fip.FloatingIP, floating_ip, **attrs)
def unset_floating_ip(self, floating_ip):
"""Unset a Floating IP PTR record
:param floating_ip: ID for the floatingip associated with the
project.
:returns: FloatingIP PTR record.
:rtype: :class:`~openstack.dns.v2.fip.FloatipgIP`
"""
# concat `region:floating_ip_id` as id
attrs = {'ptrdname': None}
return self._update(_fip.FloatingIP, floating_ip, **attrs)
# ======== Zone Transfer ========
def zone_transfer_requests(self, **query):
"""Retrieve a generator of zone transfer requests
@ -421,8 +432,8 @@ class Proxy(proxy.Proxy):
"""Get a ZoneTransfer Request info
:param request: The value can be the ID of a transfer request
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
instance.
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
instance.
:returns: Zone transfer request instance.
:rtype: :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
"""
@ -432,7 +443,7 @@ class Proxy(proxy.Proxy):
"""Create a new ZoneTransfer Request from attributes
:param zone: The value can be the ID of a zone to be transferred
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
or a :class:`~openstack.dns.v2.zone_export.ZoneExport` instance.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`,
comprised of the properties on the ZoneTransferRequest class.
@ -464,8 +475,8 @@ class Proxy(proxy.Proxy):
"""Delete a ZoneTransfer Request
:param request: The value can be the ID of a zone transfer request
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
instance.
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferRequest`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be raised when
the zone does not exist.
@ -495,8 +506,8 @@ class Proxy(proxy.Proxy):
"""Get a ZoneTransfer Accept info
:param request: The value can be the ID of a transfer accept
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferAccept`
instance.
or a :class:`~openstack.dns.v2.zone_transfer.ZoneTransferAccept`
instance.
:returns: Zone transfer request instance.
:rtype: :class:`~openstack.dns.v2.zone_transfer.ZoneTransferAccept`
"""
@ -524,4 +535,24 @@ class Proxy(proxy.Proxy):
def _service_cleanup(self, dry_run=True, client_status_queue=False,
identified_resources=None,
filters=None, resource_evaluation_fn=None):
pass
# Delete all zones
for obj in self.zones():
self._service_cleanup_del_res(
self.delete_zone,
obj,
dry_run=dry_run,
client_status_queue=client_status_queue,
identified_resources=identified_resources,
filters=filters,
resource_evaluation_fn=resource_evaluation_fn)
# Unset all floatingIPs
# NOTE: FloatingIPs are not cleaned when filters are set
for obj in self.floating_ips():
self._service_cleanup_del_res(
self.unset_floating_ip,
obj,
dry_run=dry_run,
client_status_queue=client_status_queue,
identified_resources=identified_resources,
filters=filters,
resource_evaluation_fn=resource_evaluation_fn)

View File

@ -87,7 +87,7 @@ class HttpException(SDKException, _rex.HTTPError):
if self.status_code is not None and (400 <= self.status_code < 500):
self.source = "Client"
def __unicode__(self):
def __str__(self):
# 'Error' is the default value for self.message. If self.message isn't
# 'Error', then someone has set a more informative error message
# and we should use it. If it is 'Error', then we should construct a
@ -106,9 +106,6 @@ class HttpException(SDKException, _rex.HTTPError):
message=super(HttpException, self).__str__(),
remote_error=remote_error)
def __str__(self):
return self.__unicode__()
class BadRequestException(HttpException):
"""HTTP 400 Bad Request."""

View File

@ -31,12 +31,12 @@ class Proxy(proxy.Proxy):
"""Get a single extension
:param extension: The value can be the ID of an extension or a
:class:`~openstack.identity.v2.extension.Extension`
instance.
:class:`~openstack.identity.v2.extension.Extension`
instance.
:returns: One :class:`~openstack.identity.v2.extension.Extension`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no extension can be found.
when no extension can be found.
"""
return self._get(_extension.Extension, extension)
@ -44,8 +44,8 @@ class Proxy(proxy.Proxy):
"""Create a new role from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.identity.v2.role.Role`,
comprised of the properties on the Role class.
a :class:`~openstack.identity.v2.role.Role`,
comprised of the properties on the Role class.
:returns: The results of role creation
:rtype: :class:`~openstack.identity.v2.role.Role`
@ -56,12 +56,12 @@ class Proxy(proxy.Proxy):
"""Delete a role
:param role: The value can be either the ID of a role or a
:class:`~openstack.identity.v2.role.Role` instance.
:class:`~openstack.identity.v2.role.Role` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the role does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent role.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the role does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent role.
:returns: ``None``
"""
@ -72,10 +72,10 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a role.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.identity.v2.role.Role` or None
"""
return self._find(_role.Role, name_or_id,
@ -85,11 +85,11 @@ class Proxy(proxy.Proxy):
"""Get a single role
:param role: The value can be the ID of a role or a
:class:`~openstack.identity.v2.role.Role` instance.
:class:`~openstack.identity.v2.role.Role` instance.
:returns: One :class:`~openstack.identity.v2.role.Role`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_role.Role, role)
@ -97,7 +97,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of roles
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of role instances.
:rtype: :class:`~openstack.identity.v2.role.Role`
@ -108,9 +108,9 @@ class Proxy(proxy.Proxy):
"""Update a role
:param role: Either the ID of a role or a
:class:`~openstack.identity.v2.role.Role` instance.
:class:`~openstack.identity.v2.role.Role` instance.
:attrs kwargs: The attributes to update on the role represented
by ``value``.
by ``value``.
:returns: The updated role
:rtype: :class:`~openstack.identity.v2.role.Role`
@ -121,8 +121,8 @@ class Proxy(proxy.Proxy):
"""Create a new tenant from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.identity.v2.tenant.Tenant`,
comprised of the properties on the Tenant class.
a :class:`~openstack.identity.v2.tenant.Tenant`,
comprised of the properties on the Tenant class.
:returns: The results of tenant creation
:rtype: :class:`~openstack.identity.v2.tenant.Tenant`
@ -133,12 +133,12 @@ class Proxy(proxy.Proxy):
"""Delete a tenant
:param tenant: The value can be either the ID of a tenant or a
:class:`~openstack.identity.v2.tenant.Tenant` instance.
:class:`~openstack.identity.v2.tenant.Tenant` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the tenant does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent tenant.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the tenant does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent tenant.
:returns: ``None``
"""
@ -149,10 +149,10 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a tenant.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.identity.v2.tenant.Tenant` or None
"""
return self._find(_tenant.Tenant, name_or_id,
@ -162,11 +162,11 @@ class Proxy(proxy.Proxy):
"""Get a single tenant
:param tenant: The value can be the ID of a tenant or a
:class:`~openstack.identity.v2.tenant.Tenant` instance.
:class:`~openstack.identity.v2.tenant.Tenant` instance.
:returns: One :class:`~openstack.identity.v2.tenant.Tenant`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_tenant.Tenant, tenant)
@ -174,7 +174,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of tenants
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of tenant instances.
:rtype: :class:`~openstack.identity.v2.tenant.Tenant`
@ -185,9 +185,9 @@ class Proxy(proxy.Proxy):
"""Update a tenant
:param tenant: Either the ID of a tenant or a
:class:`~openstack.identity.v2.tenant.Tenant` instance.
:class:`~openstack.identity.v2.tenant.Tenant` instance.
:attrs kwargs: The attributes to update on the tenant represented
by ``value``.
by ``value``.
:returns: The updated tenant
:rtype: :class:`~openstack.identity.v2.tenant.Tenant`
@ -198,8 +198,8 @@ class Proxy(proxy.Proxy):
"""Create a new user from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.identity.v2.user.User`,
comprised of the properties on the User class.
a :class:`~openstack.identity.v2.user.User`,
comprised of the properties on the User class.
:returns: The results of user creation
:rtype: :class:`~openstack.identity.v2.user.User`
@ -210,12 +210,12 @@ class Proxy(proxy.Proxy):
"""Delete a user
:param user: The value can be either the ID of a user or a
:class:`~openstack.identity.v2.user.User` instance.
:class:`~openstack.identity.v2.user.User` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the user does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent user.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the user does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent user.
:returns: ``None``
"""
@ -226,10 +226,10 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a user.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.identity.v2.user.User` or None
"""
return self._find(_user.User, name_or_id,
@ -239,11 +239,11 @@ class Proxy(proxy.Proxy):
"""Get a single user
:param user: The value can be the ID of a user or a
:class:`~openstack.identity.v2.user.User` instance.
:class:`~openstack.identity.v2.user.User` instance.
:returns: One :class:`~openstack.identity.v2.user.User`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_user.User, user)
@ -251,7 +251,7 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of users
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of user instances.
:rtype: :class:`~openstack.identity.v2.user.User`
@ -262,9 +262,9 @@ class Proxy(proxy.Proxy):
"""Update a user
:param user: Either the ID of a user or a
:class:`~openstack.identity.v2.user.User` instance.
:class:`~openstack.identity.v2.user.User` instance.
:attrs kwargs: The attributes to update on the user represented
by ``value``.
by ``value``.
:returns: The updated user
:rtype: :class:`~openstack.identity.v2.user.User`

File diff suppressed because it is too large Load Diff

View File

@ -62,7 +62,7 @@ class Domain(resource.Resource):
url = utils.urljoin(self.base_path, self.id, 'users',
user.id, 'roles', role.id)
resp = session.head(url,)
if resp.status_code == 201:
if resp.status_code == 204:
return True
return False
@ -89,7 +89,7 @@ class Domain(resource.Resource):
url = utils.urljoin(self.base_path, self.id, 'groups',
group.id, 'roles', role.id)
resp = session.head(url,)
if resp.status_code == 201:
if resp.status_code == 204:
return True
return False

View File

@ -10,7 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from openstack import exceptions
from openstack import resource
from openstack import utils
class Group(resource.Resource):
@ -40,3 +42,31 @@ class Group(resource.Resource):
domain_id = resource.Body('domain_id')
#: Unique group name, within the owning domain. *Type: string*
name = resource.Body('name')
def add_user(self, session, user):
"""Add user to the group"""
url = utils.urljoin(
self.base_path, self.id, 'users', user.id)
resp = session.put(url,)
exceptions.raise_from_response(resp)
def remove_user(self, session, user):
"""Remove user from the group"""
url = utils.urljoin(
self.base_path, self.id, 'users', user.id)
resp = session.delete(url,)
exceptions.raise_from_response(resp)
def check_user(self, session, user):
"""Check whether user belongs to group"""
url = utils.urljoin(
self.base_path, self.id, 'users', user.id)
resp = session.head(url,)
if resp.status_code == 404:
# If we recieve 404 - treat this as False,
# rather then returning exception
return False
exceptions.raise_from_response(resp)
if resp.status_code == 204:
return True
return False

View File

@ -9,12 +9,12 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import resource
from openstack import utils
class Project(resource.Resource, resource.TagMixin):
class Project(resource.Resource, tag.TagMixin):
resource_key = 'project'
resources_key = 'projects'
base_path = '/projects'
@ -33,7 +33,7 @@ class Project(resource.Resource, resource.TagMixin):
'name',
'parent_id',
is_enabled='enabled',
**resource.TagMixin._tag_query_parameters
**tag.TagMixin._tag_query_parameters
)
# Properties
@ -53,8 +53,6 @@ class Project(resource.Resource, resource.TagMixin):
#: for the project are immediately invalidated. Re-enabling a project
#: does not re-enable pre-existing tokens. *Type: bool*
is_enabled = resource.Body('enabled', type=bool)
#: Unique project name, within the owning domain. *Type: string*
name = resource.Body('name')
#: The resource options for the project. Available resource options are
#: immutable.
options = resource.Body('options', type=dict)

View File

@ -15,6 +15,7 @@ import os
from openstack import exceptions
from openstack import proxy
from openstack import utils
class BaseImageProxy(proxy.Proxy, metaclass=abc.ABCMeta):
@ -151,9 +152,9 @@ class BaseImageProxy(proxy.Proxy, metaclass=abc.ABCMeta):
'direct binary object')
if not (md5 or sha256) and validate_checksum:
if filename:
(md5, sha256) = self._connection._get_file_hashes(filename)
(md5, sha256) = utils._get_file_hashes(filename)
elif data and isinstance(data, bytes):
(md5, sha256) = self._connection._calculate_data_hashes(data)
(md5, sha256) = utils._calculate_data_hashes(data)
if allow_duplicates:
current_image = None
else:
@ -167,7 +168,7 @@ class BaseImageProxy(proxy.Proxy, metaclass=abc.ABCMeta):
sha256_key = props.get(
self._IMAGE_SHA256_KEY,
props.get(self._SHADE_IMAGE_SHA256_KEY, ''))
up_to_date = self._connection._hashes_up_to_date(
up_to_date = utils._hashes_up_to_date(
md5=md5, sha256=sha256,
md5_key=md5_key, sha256_key=sha256_key)
if up_to_date:

View File

@ -33,8 +33,8 @@ class Proxy(_base_proxy.BaseImageProxy):
`create_image`.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.image.v1.image.Image`,
comprised of the properties on the Image class.
a :class:`~openstack.image.v1.image.Image`,
comprised of the properties on the Image class.
:returns: The results of image creation
:rtype: :class:`~openstack.image.v1.image.Image`
@ -119,12 +119,12 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Delete an image
:param image: The value can be either the ID of an image or a
:class:`~openstack.image.v1.image.Image` instance.
:class:`~openstack.image.v1.image.Image` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the image does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent image.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the image does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent image.
:returns: ``None``
"""
@ -135,10 +135,10 @@ class Proxy(_base_proxy.BaseImageProxy):
:param name_or_id: The name or ID of a image.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.image.v1.image.Image` or None
"""
return self._find(_image.Image, name_or_id,
@ -148,11 +148,11 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Get a single image
:param image: The value can be the ID of an image or a
:class:`~openstack.image.v1.image.Image` instance.
:class:`~openstack.image.v1.image.Image` instance.
:returns: One :class:`~openstack.image.v1.image.Image`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_image.Image, image)
@ -160,7 +160,7 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Return a generator of images
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of image objects
:rtype: :class:`~openstack.image.v1.image.Image`
@ -171,9 +171,9 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Update a image
:param image: Either the ID of a image or a
:class:`~openstack.image.v1.image.Image` instance.
:class:`~openstack.image.v1.image.Image` instance.
:attrs kwargs: The attributes to update on the image represented
by ``value``.
by ``value``.
:returns: The updated image
:rtype: :class:`~openstack.image.v1.image.Image`
@ -190,22 +190,22 @@ class Proxy(_base_proxy.BaseImageProxy):
:ref:`download_image-stream-true`.
:param image: The value can be either the ID of an image or a
:class:`~openstack.image.v2.image.Image` instance.
:class:`~openstack.image.v2.image.Image` instance.
:param bool stream: When ``True``, return a :class:`requests.Response`
instance allowing you to iterate over the
response data stream instead of storing its entire
contents in memory. See
:meth:`requests.Response.iter_content` for more
details. *NOTE*: If you do not consume
the entirety of the response you must explicitly
call :meth:`requests.Response.close` or otherwise
risk inefficiencies with the ``requests``
library's handling of connections.
instance allowing you to iterate over the
response data stream instead of storing its entire
contents in memory. See
:meth:`requests.Response.iter_content` for more
details. *NOTE*: If you do not consume
the entirety of the response you must explicitly
call :meth:`requests.Response.close` or otherwise
risk inefficiencies with the ``requests``
library's handling of connections.
When ``False``, return the entire
contents of the response.
When ``False``, return the entire
contents of the response.
:param output: Either a file object or a path to store data into.
:param int chunk_size: size in bytes to read from the wire and buffer
at one time. Defaults to 1024

View File

@ -419,22 +419,22 @@ class Proxy(_base_proxy.BaseImageProxy):
:ref:`download_image-stream-true`.
:param image: The value can be either the ID of an image or a
:class:`~openstack.image.v2.image.Image` instance.
:class:`~openstack.image.v2.image.Image` instance.
:param bool stream: When ``True``, return a :class:`requests.Response`
instance allowing you to iterate over the
response data stream instead of storing its entire
contents in memory. See
:meth:`requests.Response.iter_content` for more
details. *NOTE*: If you do not consume
the entirety of the response you must explicitly
call :meth:`requests.Response.close` or otherwise
risk inefficiencies with the ``requests``
library's handling of connections.
instance allowing you to iterate over the
response data stream instead of storing its entire
contents in memory. See
:meth:`requests.Response.iter_content` for more
details. *NOTE*: If you do not consume
the entirety of the response you must explicitly
call :meth:`requests.Response.close` or otherwise
risk inefficiencies with the ``requests``
library's handling of connections.
When ``False``, return the entire
contents of the response.
When ``False``, return the entire
contents of the response.
:param output: Either a file object or a path to store data into.
:param int chunk_size: size in bytes to read from the wire and buffer
at one time. Defaults to 1024
@ -454,12 +454,12 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Delete an image
:param image: The value can be either the ID of an image or a
:class:`~openstack.image.v2.image.Image` instance.
:class:`~openstack.image.v2.image.Image` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the image does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent image.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the image does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent image.
:returns: ``None``
"""
@ -470,10 +470,10 @@ class Proxy(_base_proxy.BaseImageProxy):
:param name_or_id: The name or ID of a image.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.image.v2.image.Image` or None
"""
return self._find(_image.Image, name_or_id,
@ -483,11 +483,11 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Get a single image
:param image: The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
:class:`~openstack.image.v2.image.Image` instance.
:returns: One :class:`~openstack.image.v2.image.Image`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_image.Image, image)
@ -495,7 +495,7 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Return a generator of images
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of image objects
:rtype: :class:`~openstack.image.v2.image.Image`
@ -506,9 +506,9 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Update a image
:param image: Either the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
:class:`~openstack.image.v2.image.Image` instance.
:attrs kwargs: The attributes to update on the image represented
by ``value``.
by ``value``.
:returns: The updated image
:rtype: :class:`~openstack.image.v2.image.Image`
@ -519,7 +519,7 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Deactivate an image
:param image: Either the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
:class:`~openstack.image.v2.image.Image` instance.
:returns: None
"""
@ -530,7 +530,7 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Deactivate an image
:param image: Either the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
:class:`~openstack.image.v2.image.Image` instance.
:returns: None
"""
@ -541,8 +541,8 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Add a tag to an image
:param image: The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance
that the member will be created for.
:class:`~openstack.image.v2.image.Image` instance
that the member will be created for.
:param str tag: The tag to be added
:returns: None
@ -554,8 +554,8 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Remove a tag to an image
:param image: The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance
that the member will be created for.
:class:`~openstack.image.v2.image.Image` instance
that the member will be created for.
:param str tag: The tag to be removed
:returns: None
@ -567,11 +567,11 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Create a new member from attributes
:param image: The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance
that the member will be created for.
:class:`~openstack.image.v2.image.Image` instance
that the member will be created for.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.image.v2.member.Member`,
comprised of the properties on the Member class.
a :class:`~openstack.image.v2.member.Member`,
comprised of the properties on the Member class.
:returns: The results of member creation
:rtype: :class:`~openstack.image.v2.member.Member`
@ -604,13 +604,13 @@ class Proxy(_base_proxy.BaseImageProxy):
:param name_or_id: The name or ID of a member.
:param image: This is the image that the member belongs to,
the value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
the value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.image.v2.member.Member` or None
"""
image_id = resource.Resource._get_id(image)
@ -621,13 +621,13 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Get a single member on an image
:param member: The value can be the ID of a member or a
:class:`~openstack.image.v2.member.Member` instance.
:class:`~openstack.image.v2.member.Member` instance.
:param image: This is the image that the member belongs to.
The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
:returns: One :class:`~openstack.image.v2.member.Member`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
member_id = resource.Resource._get_id(member)
image_id = resource.Resource._get_id(image)
@ -653,12 +653,12 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Update the member of an image
:param member: Either the ID of a member or a
:class:`~openstack.image.v2.member.Member` instance.
:class:`~openstack.image.v2.member.Member` instance.
:param image: This is the image that the member belongs to.
The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
The value can be the ID of a image or a
:class:`~openstack.image.v2.image.Image` instance.
:attrs kwargs: The attributes to update on the member represented
by ``value``.
by ``value``.
:returns: The updated member
:rtype: :class:`~openstack.image.v2.member.Member`
@ -673,7 +673,7 @@ class Proxy(_base_proxy.BaseImageProxy):
:returns: One :class:`~openstack.image.v2.schema.Schema`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_schema.Schema, requires_id=False,
base_path='/schemas/images')
@ -683,7 +683,7 @@ class Proxy(_base_proxy.BaseImageProxy):
:returns: One :class:`~openstack.image.v2.schema.Schema`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_schema.Schema, requires_id=False,
base_path='/schemas/image')
@ -693,7 +693,7 @@ class Proxy(_base_proxy.BaseImageProxy):
:returns: One :class:`~openstack.image.v2.schema.Schema`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_schema.Schema, requires_id=False,
base_path='/schemas/members')
@ -703,7 +703,7 @@ class Proxy(_base_proxy.BaseImageProxy):
:returns: One :class:`~openstack.image.v2.schema.Schema`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_schema.Schema, requires_id=False,
base_path='/schemas/member')
@ -712,7 +712,7 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Return a generator of tasks
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of task objects
:rtype: :class:`~openstack.image.v2.task.Task`
@ -723,11 +723,11 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Get task details
:param task: The value can be the ID of a task or a
:class:`~openstack.image.v2.task.Task` instance.
:class:`~openstack.image.v2.task.Task` instance.
:returns: One :class:`~openstack.image.v2.task.Task`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_task.Task, task)
@ -748,22 +748,22 @@ class Proxy(_base_proxy.BaseImageProxy):
"""Wait for a task to be in a particular status.
:param task: The resource to wait on to reach the specified status.
The resource must have a ``status`` attribute.
The resource must have a ``status`` attribute.
:type resource: A :class:`~openstack.resource.Resource` object.
:param status: Desired status.
:param failures: Statuses that would be interpreted as failures.
:type failures: :py:class:`list`
:param interval: Number of seconds to wait before to consecutive
checks. Default to 2.
checks. Default to 2.
:param wait: Maximum number of seconds to wait before the change.
Default to 120.
Default to 120.
:returns: The resource is returned on success.
:raises: :class:`~openstack.exceptions.ResourceTimeout` if transition
to the desired status failed to occur in specified seconds.
to the desired status failed to occur in specified seconds.
:raises: :class:`~openstack.exceptions.ResourceFailure` if the resource
has transited to one of the failure statuses.
has transited to one of the failure statuses.
:raises: :class:`~AttributeError` if the resource does not have a
``status`` attribute.
``status`` attribute.
"""
if failures is None:
failures = ['failure']
@ -810,7 +810,7 @@ class Proxy(_base_proxy.BaseImageProxy):
:returns: One :class:`~openstack.image.v2.schema.Schema`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_schema.Schema, requires_id=False,
base_path='/schemas/tasks')
@ -820,7 +820,7 @@ class Proxy(_base_proxy.BaseImageProxy):
:returns: One :class:`~openstack.image.v2.schema.Schema`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_schema.Schema, requires_id=False,
base_path='/schemas/task')
@ -838,6 +838,6 @@ class Proxy(_base_proxy.BaseImageProxy):
:returns: One :class:`~openstack.image.v2.service_info.Import`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_si.Import, require_id=False)

View File

@ -9,13 +9,14 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import exceptions
from openstack.image import _download
from openstack import resource
from openstack import utils
class Image(resource.Resource, resource.TagMixin, _download.DownloadMixin):
class Image(resource.Resource, tag.TagMixin, _download.DownloadMixin):
resources_key = 'images'
base_path = '/images'

View File

@ -30,7 +30,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of notifications.
:param kwargs query: Optional query parameters to be sent to
limit the notifications being returned.
limit the notifications being returned.
:returns: A generator of notifications
"""
return self._list(_notification.Notification, **query)
@ -39,13 +39,12 @@ class Proxy(proxy.Proxy):
"""Get a single notification.
:param notification: The value can be the ID of a notification or a
:class:
`~masakariclient.sdk.ha.v1
.notification.Notification` instance.
:returns: One :class:`~masakariclient.sdk.ha.v1
.notification.Notification`
:class:`~masakariclient.sdk.ha.v1.notification.Notification`
instance.
:returns: One
:class:`~masakariclient.sdk.ha.v1.notification.Notification`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_notification.Notification, notification)
@ -53,14 +52,10 @@ class Proxy(proxy.Proxy):
"""Create a new notification.
:param dict attrs: Keyword arguments which will be used to create
a :class:
`masakariclient.sdk.ha.v1
.notification.Notification`,
comprised of the propoerties on the Notification
class.
a :class:`masakariclient.sdk.ha.v1.notification.Notification`,
comprised of the propoerties on the Notification class.
:returns: The result of notification creation
:rtype: :class: `masakariclient.sdk.ha.v1
.notification.Notification`
:rtype: :class:`masakariclient.sdk.ha.v1.notification.Notification`
"""
return self._create(_notification.Notification, **attrs)
@ -68,7 +63,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of segments.
:param kwargs query: Optional query parameters to be sent to
limit the segments being returned.
limit the segments being returned.
:returns: A generator of segments
"""
return self._list(_segment.Segment, **query)
@ -77,11 +72,10 @@ class Proxy(proxy.Proxy):
"""Get a single segment.
:param segment: The value can be the ID of a segment or a
:class:
`~masakariclient.sdk.ha.v1.segment.Segment` instance.
:class:`~masakariclient.sdk.ha.v1.segment.Segment` instance.
:returns: One :class:`~masakariclient.sdk.ha.v1.segment.Segment`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_segment.Segment, segment)
@ -89,11 +83,10 @@ class Proxy(proxy.Proxy):
"""Create a new segment.
:param dict attrs: Keyword arguments which will be used to create
a :class:
`masakariclient.sdk.ha.v1.segment.Segment`,
comprised of the propoerties on the Segment class.
a :class:`masakariclient.sdk.ha.v1.segment.Segment`,
comprised of the propoerties on the Segment class.
:returns: The result of segment creation
:rtype: :class: `masakariclient.sdk.ha.v1.segment.Segment`
:rtype: :class:`masakariclient.sdk.ha.v1.segment.Segment`
"""
return self._create(_segment.Segment, **attrs)
@ -101,14 +94,12 @@ class Proxy(proxy.Proxy):
"""Update a segment.
:param segment: The value can be the ID of a segment or a
:class:
`~masakariclient.sdk.ha.v1.segment.Segment` instance.
:class:`~masakariclient.sdk.ha.v1.segment.Segment` instance.
:param dict attrs: Keyword arguments which will be used to update
a :class:
`masakariclient.sdk.ha.v1.segment.Segment`,
comprised of the propoerties on the Segment class.
a :class:`masakariclient.sdk.ha.v1.segment.Segment`,
comprised of the propoerties on the Segment class.
:returns: The updated segment.
:rtype: :class: `masakariclient.sdk.ha.v1.segment.Segment`
:rtype: :class:`masakariclient.sdk.ha.v1.segment.Segment`
"""
return self._update(_segment.Segment, segment, **attrs)
@ -119,10 +110,10 @@ class Proxy(proxy.Proxy):
The value can be either the ID of a segment or a
:class:`~masakariclient.sdk.ha.v1.segment.Segment` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the segment does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent segment.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the segment does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent segment.
:returns: ``None``
"""
return self._delete(_segment.Segment, segment,
@ -133,7 +124,7 @@ class Proxy(proxy.Proxy):
:param segment_id: The ID of a failover segment.
:param kwargs query: Optional query parameters to be sent to
limit the hosts being returned.
limit the hosts being returned.
:returns: A generator of hosts
"""
@ -144,8 +135,8 @@ class Proxy(proxy.Proxy):
:param segment_id: The ID of a failover segment.
:param dict attrs: Keyword arguments which will be used to create
a :class: `masakariclient.sdk.ha.v1.host.Host`,
comprised of the propoerties on the Host class.
a :class:`masakariclient.sdk.ha.v1.host.Host`,
comprised of the propoerties on the Host class.
:returns: The results of host creation
"""
@ -156,13 +147,13 @@ class Proxy(proxy.Proxy):
:param segment_id: The ID of a failover segment.
:param host: The value can be the ID of a host or a :class:
`~masakariclient.sdk.ha.v1.host.Host` instance.
`~masakariclient.sdk.ha.v1.host.Host` instance.
:returns: One :class:`~masakariclient.sdk.ha.v1.host.Host`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
:raises: :class:`~openstack.exceptions.InvalidRequest`
when segment_id is None.
when segment_id is None.
"""
if segment_id is None:
raise exceptions.InvalidRequest("'segment_id' must be specified.")
@ -175,14 +166,14 @@ class Proxy(proxy.Proxy):
:param segment_id: The ID of a failover segment.
:param host: The value can be the ID of a host or a :class:
`~masakariclient.sdk.ha.v1.host.Host` instance.
`~masakariclient.sdk.ha.v1.host.Host` instance.
:param dict attrs: The attributes to update on the host represented.
:returns: The updated host
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
:raises: :class:`~openstack.exceptions.InvalidRequest`
when segment_id is None.
when segment_id is None.
"""
host_id = resource.Resource._get_id(host)
return self._update(_host.Host, host_id, segment_id=segment_id,
@ -193,18 +184,18 @@ class Proxy(proxy.Proxy):
:param segment_id: The ID of a failover segment.
:param host: The value can be the ID of a host or a :class:
`~masakariclient.sdk.ha.v1.host.Host` instance.
`~masakariclient.sdk.ha.v1.host.Host` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the host does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent host.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the host does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent host.
:returns: ``None``
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
:raises: :class:`~openstack.exceptions.InvalidRequest`
when segment_id is None.
when segment_id is None.
"""
if segment_id is None:

View File

@ -22,8 +22,8 @@ class Proxy(proxy.Proxy):
"""Create a new container from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.key_manager.v1.container.Container`,
comprised of the properties on the Container class.
a :class:`~openstack.key_manager.v1.container.Container`,
comprised of the properties on the Container class.
:returns: The results of container creation
:rtype: :class:`~openstack.key_manager.v1.container.Container`
@ -34,13 +34,13 @@ class Proxy(proxy.Proxy):
"""Delete a container
:param container: The value can be either the ID of a container or a
:class:`~openstack.key_manager.v1.container.Container`
instance.
:class:`~openstack.key_manager.v1.container.Container`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the container does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent container.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the container does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent container.
:returns: ``None``
"""
@ -52,12 +52,12 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a container.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.key_manager.v1.container.Container`
or None
or None
"""
return self._find(_container.Container, name_or_id,
ignore_missing=ignore_missing)
@ -66,12 +66,12 @@ class Proxy(proxy.Proxy):
"""Get a single container
:param container: The value can be the ID of a container or a
:class:`~openstack.key_manager.v1.container.Container`
instance.
:class:`~openstack.key_manager.v1.container.Container`
instance.
:returns: One :class:`~openstack.key_manager.v1.container.Container`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_container.Container, container)
@ -79,7 +79,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of containers
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of container objects
:rtype: :class:`~openstack.key_manager.v1.container.Container`
@ -90,10 +90,10 @@ class Proxy(proxy.Proxy):
"""Update a container
:param container: Either the id of a container or a
:class:`~openstack.key_manager.v1.container.Container`
instance.
:class:`~openstack.key_manager.v1.container.Container`
instance.
:attrs kwargs: The attributes to update on the container represented
by ``value``.
by ``value``.
:returns: The updated container
:rtype: :class:`~openstack.key_manager.v1.container.Container`
@ -104,8 +104,8 @@ class Proxy(proxy.Proxy):
"""Create a new order from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.key_manager.v1.order.Order`,
comprised of the properties on the Order class.
a :class:`~openstack.key_manager.v1.order.Order`,
comprised of the properties on the Order class.
:returns: The results of order creation
:rtype: :class:`~openstack.key_manager.v1.order.Order`
@ -116,13 +116,13 @@ class Proxy(proxy.Proxy):
"""Delete an order
:param order: The value can be either the ID of a order or a
:class:`~openstack.key_manager.v1.order.Order`
instance.
:class:`~openstack.key_manager.v1.order.Order`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the order does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent order.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the order does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent order.
:returns: ``None``
"""
@ -133,10 +133,10 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a order.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.key_manager.v1.order.Order` or None
"""
return self._find(_order.Order, name_or_id,
@ -146,12 +146,12 @@ class Proxy(proxy.Proxy):
"""Get a single order
:param order: The value can be the ID of an order or a
:class:`~openstack.key_manager.v1.order.Order`
instance.
:class:`~openstack.key_manager.v1.order.Order`
instance.
:returns: One :class:`~openstack.key_manager.v1.order.Order`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_order.Order, order)
@ -159,7 +159,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of orders
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of order objects
:rtype: :class:`~openstack.key_manager.v1.order.Order`
@ -170,10 +170,10 @@ class Proxy(proxy.Proxy):
"""Update a order
:param order: Either the id of a order or a
:class:`~openstack.key_manager.v1.order.Order`
instance.
:class:`~openstack.key_manager.v1.order.Order`
instance.
:attrs kwargs: The attributes to update on the order represented
by ``value``.
by ``value``.
:returns: The updated order
:rtype: :class:`~openstack.key_manager.v1.order.Order`
@ -184,8 +184,8 @@ class Proxy(proxy.Proxy):
"""Create a new secret from attributes
:param dict attrs: Keyword arguments which will be used to create a
:class:`~openstack.key_manager.v1.secret.Secret`,
comprised of the properties on the Order class.
:class:`~openstack.key_manager.v1.secret.Secret`,
comprised of the properties on the Order class.
:returns: The results of secret creation
:rtype: :class:`~openstack.key_manager.v1.secret.Secret`
@ -196,13 +196,13 @@ class Proxy(proxy.Proxy):
"""Delete a secret
:param secret: The value can be either the ID of a secret or a
:class:`~openstack.key_manager.v1.secret.Secret`
instance.
:class:`~openstack.key_manager.v1.secret.Secret`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the secret does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent secret.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the secret does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent secret.
:returns: ``None``
"""
@ -213,12 +213,12 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a secret.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.key_manager.v1.secret.Secret` or
None
None
"""
return self._find(_secret.Secret, name_or_id,
ignore_missing=ignore_missing)
@ -227,12 +227,12 @@ class Proxy(proxy.Proxy):
"""Get a single secret
:param secret: The value can be the ID of a secret or a
:class:`~openstack.key_manager.v1.secret.Secret`
instance.
:class:`~openstack.key_manager.v1.secret.Secret`
instance.
:returns: One :class:`~openstack.key_manager.v1.secret.Secret`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_secret.Secret, secret)
@ -240,7 +240,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of secrets
:param kwargs query: Optional query parameters to be sent to limit
the resources being returned.
the resources being returned.
:returns: A generator of secret objects
:rtype: :class:`~openstack.key_manager.v1.secret.Secret`
@ -251,10 +251,10 @@ class Proxy(proxy.Proxy):
"""Update a secret
:param secret: Either the id of a secret or a
:class:`~openstack.key_manager.v1.secret.Secret`
instance.
:class:`~openstack.key_manager.v1.secret.Secret`
instance.
:attrs kwargs: The attributes to update on the secret represented
by ``value``.
by ``value``.
:returns: The updated secret
:rtype: :class:`~openstack.key_manager.v1.secret.Secret`

View File

@ -35,10 +35,9 @@ class Proxy(proxy.Proxy):
"""Create a new load balancer from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.
load_balancer.LoadBalancer`,
comprised of the properties on the
LoadBalancer class.
a :class:`~openstack.load_balancer.v2.load_balancer.LoadBalancer`,
comprised of the properties on the
LoadBalancer class.
:returns: The results of load balancer creation
:rtype: :class:`~openstack.load_balancer.v2.load_balancer.LoadBalancer`
@ -49,11 +48,11 @@ class Proxy(proxy.Proxy):
"""Get a load balancer
:param load_balancer: The value can be the name of a load balancer
or :class:`~openstack.load_balancer.v2.load_balancer.LoadBalancer`
instance.
or :class:`~openstack.load_balancer.v2.load_balancer.LoadBalancer`
instance.
:returns: One
:class:`~openstack.load_balancer.v2.load_balancer.LoadBalancer`
:class:`~openstack.load_balancer.v2.load_balancer.LoadBalancer`
"""
return self._get(_lb.LoadBalancer, *attrs)
@ -62,8 +61,8 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a load balancer
:returns: One :class:`~openstack.load_balancer.v2.load_balancer.
LoadBalancerStats`
:returns: One
:class:`~openstack.load_balancer.v2.load_balancer.LoadBalancerStats`
"""
return self._get(_lb.LoadBalancerStats, lb_id=name_or_id,
requires_id=False)
@ -119,7 +118,7 @@ class Proxy(proxy.Proxy):
:class:`~openstack.load_balancer.v2.load_balancer.LoadBalancer`
instance
:param dict attrs: The attributes to update on the load balancer
represented by ``load_balancer``.
represented by ``load_balancer``.
:returns: The updated load_balancer
:rtype: :class:`~openstack.load_balancer.v2.load_balancer.LoadBalancer`
@ -146,8 +145,8 @@ class Proxy(proxy.Proxy):
"""Create a new listener from attributes
:param dict attrs: Keyword arguments which will be used to create a
:class:`~openstack.load_balancer.v2.listener.Listener`,
comprised of the properties on the Listener class.
:class:`~openstack.load_balancer.v2.listener.Listener`,
comprised of the properties on the Listener class.
:returns: The results of listener creation
:rtype: :class:`~openstack.load_balancer.v2.listener.Listener`
@ -158,12 +157,12 @@ class Proxy(proxy.Proxy):
"""Delete a listener
:param listener: The value can be either the ID of a listner or a
:class:`~openstack.load_balancer.v2.listener.Listener` instance.
:class:`~openstack.load_balancer.v2.listener.Listener` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the listner does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent listener.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the listner does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent listener.
:returns: ``None``
"""
@ -175,13 +174,13 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a listener.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.load_balancer.v2.listener.Listener`
or None
or None
"""
return self._find(_listener.Listener, name_or_id,
ignore_missing=ignore_missing)
@ -190,12 +189,12 @@ class Proxy(proxy.Proxy):
"""Get a single listener
:param listener: The value can be the ID of a listener or a
:class:`~openstack.load_balancer.v2.listener.Listener`
instance.
:class:`~openstack.load_balancer.v2.listener.Listener`
instance.
:returns: One :class:`~openstack.load_balancer.v2.listener.Listener`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_listener.Listener, listener)
@ -203,13 +202,13 @@ class Proxy(proxy.Proxy):
"""Get the listener statistics
:param listener: The value can be the ID of a listener or a
:class:`~openstack.load_balancer.v2.listener.Listener`
instance.
:class:`~openstack.load_balancer.v2.listener.Listener`
instance.
:returns: One :class:`~openstack.load_balancer.v2.listener.
ListenerStats`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
:returns: One
:class:`~openstack.load_balancer.v2.listener.ListenerStats`
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
resource can be found.
"""
return self._get(_listener.ListenerStats, listener_id=listener,
requires_id=False)
@ -218,7 +217,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of listeners
:param dict query: Optional query parameters to be sent to limit
the resources being returned. Valid parameters are:
the resources being returned. Valid parameters are:
:returns: A generator of listener objects
:rtype: :class:`~openstack.load_balancer.v2.listener.Listener`
"""
@ -228,10 +227,10 @@ class Proxy(proxy.Proxy):
"""Update a listener
:param listener: Either the id of a listener or a
:class:`~openstack.load_balancer.v2.listener.Listener`
instance.
:class:`~openstack.load_balancer.v2.listener.Listener`
instance.
:param dict attrs: The attributes to update on the listener
represented by ``listener``.
represented by ``listener``.
:returns: The updated listener
:rtype: :class:`~openstack.load_balancer.v2.listener.Listener`
@ -242,10 +241,8 @@ class Proxy(proxy.Proxy):
"""Create a new pool from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.
pool.Pool`,
comprised of the properties on the
Pool class.
a :class:`~openstack.load_balancer.v2.pool.Pool`, comprised of the
properties on the Pool class.
:returns: The results of Pool creation
:rtype: :class:`~openstack.load_balancer.v2.pool.Pool`
@ -260,7 +257,7 @@ class Proxy(proxy.Proxy):
instance.
:returns: One
:class:`~openstack.load_balancer.v2.pool.Pool`
:class:`~openstack.load_balancer.v2.pool.Pool`
"""
return self._get(_pool.Pool, *attrs)
@ -307,10 +304,10 @@ class Proxy(proxy.Proxy):
"""Update a pool
:param pool: Either the id of a pool or a
:class:`~openstack.load_balancer.v2.pool.Pool`
instance.
:class:`~openstack.load_balancer.v2.pool.Pool`
instance.
:param dict attrs: The attributes to update on the pool
represented by ``pool``.
represented by ``pool``.
:returns: The updated pool
:rtype: :class:`~openstack.load_balancer.v2.pool.Pool`
@ -321,8 +318,8 @@ class Proxy(proxy.Proxy):
"""Create a new member from attributes
:param pool: The pool can be either the ID of a pool or a
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member will be created in.
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member will be created in.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.member.Member`,
comprised of the properties on the Member class.
@ -341,13 +338,13 @@ class Proxy(proxy.Proxy):
The member can be either the ID of a member or a
:class:`~openstack.load_balancer.v2.member.Member` instance.
:param pool: The pool can be either the ID of a pool or a
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the member does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent member.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the member does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent member.
:returns: ``None``
"""
@ -360,16 +357,16 @@ class Proxy(proxy.Proxy):
:param str name_or_id: The name or ID of a member.
:param pool: The pool can be either the ID of a pool or a
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.load_balancer.v2.member.Member`
or None
or None
"""
poolobj = self._get_resource(_pool.Pool, pool)
return self._find(_member.Member, name_or_id,
@ -379,15 +376,15 @@ class Proxy(proxy.Proxy):
"""Get a single member
:param member: The member can be the ID of a member or a
:class:`~openstack.load_balancer.v2.member.Member`
instance.
:class:`~openstack.load_balancer.v2.member.Member`
instance.
:param pool: The pool can be either the ID of a pool or a
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:returns: One :class:`~openstack.load_balancer.v2.member.Member`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
poolobj = self._get_resource(_pool.Pool, pool)
return self._get(_member.Member, member,
@ -397,10 +394,10 @@ class Proxy(proxy.Proxy):
"""Return a generator of members
:param pool: The pool can be either the ID of a pool or a
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:param dict query: Optional query parameters to be sent to limit
the resources being returned. Valid parameters are:
the resources being returned. Valid parameters are:
:returns: A generator of member objects
:rtype: :class:`~openstack.load_balancer.v2.member.Member`
@ -412,13 +409,13 @@ class Proxy(proxy.Proxy):
"""Update a member
:param member: Either the ID of a member or a
:class:`~openstack.load_balancer.v2.member.Member`
instance.
:class:`~openstack.load_balancer.v2.member.Member`
instance.
:param pool: The pool can be either the ID of a pool or a
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:class:`~openstack.load_balancer.v2.pool.Pool` instance
that the member belongs to.
:param dict attrs: The attributes to update on the member
represented by ``member``.
represented by ``member``.
:returns: The updated member
:rtype: :class:`~openstack.load_balancer.v2.member.Member`
@ -442,9 +439,9 @@ class Proxy(proxy.Proxy):
object matching the given name or id or None if nothing matches.
:raises: :class:`openstack.exceptions.DuplicateResource` if more
than one resource is found for this request.
than one resource is found for this request.
:raises: :class:`openstack.exceptions.ResourceNotFound` if nothing
is found and ignore_missing is ``False``.
is found and ignore_missing is ``False``.
"""
return self._find(_hm.HealthMonitor, name_or_id,
ignore_missing=ignore_missing)
@ -453,14 +450,12 @@ class Proxy(proxy.Proxy):
"""Create a new health monitor from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.
healthmonitor.HealthMonitor`,
comprised of the properties on the
HealthMonitor class.
a :class:`~openstack.load_balancer.v2.healthmonitor.HealthMonitor`,
comprised of the properties on the HealthMonitor class.
:returns: The results of HealthMonitor creation
:rtype: :class:`~openstack.load_balancer.v2.
healthmonitor.HealthMonitor`
:rtype:
:class:`~openstack.load_balancer.v2.healthmonitor.HealthMonitor`
"""
return self._create(_hm.HealthMonitor, **attrs)
@ -473,8 +468,8 @@ class Proxy(proxy.Proxy):
instance.
:returns: One health monitor
:rtype: :class:`~openstack.load_balancer.v2.
healthmonitor.HealthMonitor`
:rtype:
:class:`~openstack.load_balancer.v2.healthmonitor.HealthMonitor`
"""
return self._get(_hm.HealthMonitor, healthmonitor)
@ -482,13 +477,13 @@ class Proxy(proxy.Proxy):
"""Retrieve a generator of health monitors
:param dict query: Optional query parameters to be sent to limit
the resources being returned. Valid parameters are:
'name', 'created_at', 'updated_at', 'delay',
'expected_codes', 'http_method', 'max_retries',
'max_retries_down', 'pool_id',
'provisioning_status', 'operating_status',
'timeout', 'project_id', 'type', 'url_path',
'is_admin_state_up'.
the resources being returned. Valid parameters are:
'name', 'created_at', 'updated_at', 'delay',
'expected_codes', 'http_method', 'max_retries',
'max_retries_down', 'pool_id',
'provisioning_status', 'operating_status',
'timeout', 'project_id', 'type', 'url_path',
'is_admin_state_up'.
:returns: A generator of health monitor instances
"""
@ -520,11 +515,11 @@ class Proxy(proxy.Proxy):
:class:`~openstack.load_balancer.v2.healthmonitor.HealthMonitor`
instance
:param dict attrs: The attributes to update on the health monitor
represented by ``healthmonitor``.
represented by ``healthmonitor``.
:returns: The updated health monitor
:rtype: :class:`~openstack.load_balancer.v2.
healthmonitor.HealthMonitor`
:rtype:
:class:`~openstack.load_balancer.v2.healthmonitor.HealthMonitor`
"""
return self._update(_hm.HealthMonitor, healthmonitor,
**attrs)
@ -533,8 +528,8 @@ class Proxy(proxy.Proxy):
"""Create a new l7policy from attributes
:param dict attrs: Keyword arguments which will be used to create a
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`,
comprised of the properties on the L7Policy class.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`,
comprised of the properties on the L7Policy class.
:returns: The results of l7policy creation
:rtype: :class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
@ -545,12 +540,12 @@ class Proxy(proxy.Proxy):
"""Delete a l7policy
:param l7_policy: The value can be either the ID of a l7policy or a
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy` instance.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the l7policy does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent l7policy.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the l7policy does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent l7policy.
:returns: ``None``
"""
@ -562,13 +557,13 @@ class Proxy(proxy.Proxy):
:param name_or_id: The name or ID of a l7policy.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
or None
or None
"""
return self._find(_l7policy.L7Policy, name_or_id,
ignore_missing=ignore_missing)
@ -577,12 +572,12 @@ class Proxy(proxy.Proxy):
"""Get a single l7policy
:param l7_policy: The value can be the ID of a l7policy or a
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance.
:returns: One :class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_l7policy.L7Policy, l7_policy)
@ -590,7 +585,7 @@ class Proxy(proxy.Proxy):
"""Return a generator of l7policies
:param dict query: Optional query parameters to be sent to limit
the resources being returned. Valid parameters are:
the resources being returned. Valid parameters are:
:returns: A generator of l7policy objects
:rtype: :class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
@ -601,10 +596,10 @@ class Proxy(proxy.Proxy):
"""Update a l7policy
:param l7_policy: Either the id of a l7policy or a
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance.
:param dict attrs: The attributes to update on the l7policy
represented by ``l7policy``.
represented by ``l7policy``.
:returns: The updated l7policy
:rtype: :class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
@ -615,8 +610,8 @@ class Proxy(proxy.Proxy):
"""Create a new l7rule from attributes
:param l7_policy: The l7_policy can be either the ID of a l7policy or
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule will be created in.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule will be created in.
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.l7_rule.L7Rule`,
comprised of the properties on the L7Rule class.
@ -635,13 +630,13 @@ class Proxy(proxy.Proxy):
The l7rule can be either the ID of a l7rule or a
:class:`~openstack.load_balancer.v2.l7_rule.L7Rule` instance.
:param l7_policy: The l7_policy can be either the ID of a l7policy or
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the l7rule does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent l7rule.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the l7rule does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent l7rule.
:returns: ``None``
"""
@ -654,16 +649,16 @@ class Proxy(proxy.Proxy):
:param str name_or_id: The name or ID of a l7rule.
:param l7_policy: The l7_policy can be either the ID of a l7policy or
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the resource does not exist.
When set to ``True``, None will be returned when
attempting to find a nonexistent resource.
:returns: One :class:`~openstack.load_balancer.v2.l7_rule.L7Rule`
or None
or None
"""
l7policyobj = self._get_resource(_l7policy.L7Policy, l7_policy)
return self._find(_l7rule.L7Rule, name_or_id,
@ -674,15 +669,15 @@ class Proxy(proxy.Proxy):
"""Get a single l7rule
:param l7rule: The l7rule can be the ID of a l7rule or a
:class:`~openstack.load_balancer.v2.l7_rule.L7Rule`
instance.
:class:`~openstack.load_balancer.v2.l7_rule.L7Rule`
instance.
:param l7_policy: The l7_policy can be either the ID of a l7policy or
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:returns: One :class:`~openstack.load_balancer.v2.l7_rule.L7Rule`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
l7policyobj = self._get_resource(_l7policy.L7Policy, l7_policy)
return self._get(_l7rule.L7Rule, l7rule,
@ -692,10 +687,10 @@ class Proxy(proxy.Proxy):
"""Return a generator of l7rules
:param l7_policy: The l7_policy can be either the ID of a l7_policy or
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:param dict query: Optional query parameters to be sent to limit
the resources being returned. Valid parameters are:
the resources being returned. Valid parameters are:
:returns: A generator of l7rule objects
:rtype: :class:`~openstack.load_balancer.v2.l7_rule.L7Rule`
@ -707,13 +702,13 @@ class Proxy(proxy.Proxy):
"""Update a l7rule
:param l7rule: Either the ID of a l7rule or a
:class:`~openstack.load_balancer.v2.l7_rule.L7Rule`
instance.
:class:`~openstack.load_balancer.v2.l7_rule.L7Rule`
instance.
:param l7_policy: The l7_policy can be either the ID of a l7policy or
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:class:`~openstack.load_balancer.v2.l7_policy.L7Policy`
instance that the l7rule belongs to.
:param dict attrs: The attributes to update on the l7rule
represented by ``l7rule``.
represented by ``l7rule``.
:returns: The updated l7rule
:rtype: :class:`~openstack.load_balancer.v2.l7_rule.L7Rule`
@ -726,8 +721,8 @@ class Proxy(proxy.Proxy):
"""Return a generator of quotas
:param dict query: Optional query parameters to be sent to limit
the resources being returned. Currently no query
parameter is supported.
the resources being returned. Currently no query
parameter is supported.
:returns: A generator of quota objects
:rtype: :class:`~openstack.load_balancer.v2.quota.Quota`
@ -738,13 +733,13 @@ class Proxy(proxy.Proxy):
"""Get a quota
:param quota: The value can be the ID of a quota or a
:class:`~openstack.load_balancer.v2.quota.Quota`
instance. The ID of a quota is the same as the project
ID for the quota.
:class:`~openstack.load_balancer.v2.quota.Quota`
instance. The ID of a quota is the same as the project
ID for the quota.
:returns: One :class:`~openstack.load_balancer.v2.quota.Quota`
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
when no resource can be found.
"""
return self._get(_quota.Quota, quota)
@ -752,11 +747,11 @@ class Proxy(proxy.Proxy):
"""Update a quota
:param quota: Either the ID of a quota or a
:class:`~openstack.load_balancer.v2.quota.Quota`
instance. The ID of a quota is the same as the
project ID for the quota.
:class:`~openstack.load_balancer.v2.quota.Quota`
instance. The ID of a quota is the same as the
project ID for the quota.
:param dict attrs: The attributes to update on the quota represented
by ``quota``.
by ``quota``.
:returns: The updated quota
:rtype: :class:`~openstack.load_balancer.v2.quota.Quota`
@ -774,14 +769,14 @@ class Proxy(proxy.Proxy):
"""Delete a quota (i.e. reset to the default quota)
:param quota: The value can be either the ID of a quota or a
:class:`~openstack.load_balancer.v2.quota.Quota`
instance. The ID of a quota is the same as the
project ID for the quota.
:class:`~openstack.load_balancer.v2.quota.Quota`
instance. The ID of a quota is the same as the
project ID for the quota.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when quota does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent quota.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when quota does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent quota.
:returns: ``None``
"""
@ -805,27 +800,25 @@ class Proxy(proxy.Proxy):
def create_flavor_profile(self, **attrs):
"""Create a new flavor profile from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.
flavor_profile.FlavorProfile`,
comprised of the properties on the
FlavorProfile class.
:param dict attrs: Keyword arguments which will be used to create a
:class:`~openstack.load_balancer.v2.flavor_profile.FlavorProfile`,
comprised of the properties on the FlavorProfile class.
:returns: The results of profile creation creation
:rtype: :class:`~openstack.load_balancer.v2.flavor_profile.
FlavorProfile`
:rtype:
:class:`~openstack.load_balancer.v2.flavor_profile.FlavorProfile`
"""
return self._create(_flavor_profile.FlavorProfile, **attrs)
def get_flavor_profile(self, *attrs):
"""Get a flavor profile
:param flavor_profile: The value can be the name of a flavor profile
or :class:`~openstack.load_balancer.v2.flavor_profile.
FlavorProfile` instance.
:param flavor_profile: The value can be the name of a flavor profile or
:class:`~openstack.load_balancer.v2.flavor_profile.FlavorProfile`
instance.
:returns: One
:class:`~openstack.load_balancer.v2.flavor_profile.FlavorProfile`
:class:`~openstack.load_balancer.v2.flavor_profile.FlavorProfile`
"""
return self._get(_flavor_profile.FlavorProfile, *attrs)
@ -875,11 +868,11 @@ class Proxy(proxy.Proxy):
:class:`~openstack.load_balancer.v2.flavor_profile.FlavorProfile`
instance
:param dict attrs: The attributes to update on the flavor profile
represented by ``flavor_profile``.
represented by ``flavor_profile``.
:returns: The updated flavor profile
:rtype: :class:`~openstack.load_balancer.v2.flavor_profile.
FlavorProfile`
:rtype:
:class:`~openstack.load_balancer.v2.flavor_profile.FlavorProfile`
"""
return self._update(_flavor_profile.FlavorProfile, flavor_profile,
**attrs)
@ -888,9 +881,8 @@ class Proxy(proxy.Proxy):
"""Create a new flavor from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.
flavor.Flavor`, comprised of the properties on the
Flavorclass.
a :class:`~openstack.load_balancer.v2.flavor.Flavor`,
comprised of the properties on the Flavorclass.
:returns: The results of flavor creation creation
:rtype: :class:`~openstack.load_balancer.v2.flavor.Flavor`
@ -901,10 +893,10 @@ class Proxy(proxy.Proxy):
"""Get a flavor
:param flavor: The value can be the name of a flavor
or :class:`~openstack.load_balancer.v2.flavor.Flavor` instance.
or :class:`~openstack.load_balancer.v2.flavor.Flavor` instance.
:returns: One
:class:`~openstack.load_balancer.v2.flavor.Flavor`
:class:`~openstack.load_balancer.v2.flavor.Flavor`
"""
return self._get(_flavor.Flavor, *attrs)
@ -951,7 +943,7 @@ class Proxy(proxy.Proxy):
:param flavor: The flavor can be either the name or a
:class:`~openstack.load_balancer.v2.flavor.Flavor` instance
:param dict attrs: The attributes to update on the flavor
represented by ``flavor``.
represented by ``flavor``.
:returns: The updated flavor
:rtype: :class:`~openstack.load_balancer.v2.flavor.Flavor`
@ -969,10 +961,10 @@ class Proxy(proxy.Proxy):
"""Get a amphora
:param amphora: The value can be the ID of an amphora
or :class:`~openstack.load_balancer.v2.amphora.Amphora` instance.
or :class:`~openstack.load_balancer.v2.amphora.Amphora` instance.
:returns: One
:class:`~openstack.load_balancer.v2.amphora.Amphora`
:class:`~openstack.load_balancer.v2.amphora.Amphora`
"""
return self._get(_amphora.Amphora, *attrs)
@ -1012,15 +1004,14 @@ class Proxy(proxy.Proxy):
def create_availability_zone_profile(self, **attrs):
"""Create a new availability zone profile from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.
availability_zone_profile.AvailabilityZoneProfile`,
comprised of the properties on the
AvailabilityZoneProfile class.
:param dict attrs: Keyword arguments which will be used to create a
:class:`~openstack.load_balancer.v2.availability_zone_profile.AvailabilityZoneProfile`
comprised of the properties on the AvailabilityZoneProfile
class.
:returns: The results of profile creation creation
:rtype: :class:`~openstack.load_balancer.v2.availability_zone_profile.
AvailabilityZoneProfile`
:rtype:
:class:`~openstack.load_balancer.v2.availability_zone_profile.AvailabilityZoneProfile`
"""
return self._create(_availability_zone_profile.AvailabilityZoneProfile,
**attrs)
@ -1029,12 +1020,12 @@ class Proxy(proxy.Proxy):
"""Get an availability zone profile
:param availability_zone_profile: The value can be the name of an
availability_zone profile
or :class:`~openstack.load_balancer.v2.availability_zone_profile.
AvailabilityZoneProfile` instance.
availability_zone profile or
:class:`~openstack.load_balancer.v2.availability_zone_profile.AvailabilityZoneProfile`
instance.
:returns: One
:class:`~openstack.load_balancer.v2.availability_zone_profile.AvailabilityZoneProfile`
:class:`~openstack.load_balancer.v2.availability_zone_profile.AvailabilityZoneProfile`
"""
return self._get(_availability_zone_profile.AvailabilityZoneProfile,
*attrs)
@ -1090,12 +1081,11 @@ class Proxy(proxy.Proxy):
:class:`~openstack.load_balancer.v2.availability_zone_profile.AvailabilityZoneProfile`
instance
:param dict attrs: The attributes to update on the availability_zone
profile represented by
``availability_zone_profile``.
profile represented by ``availability_zone_profile``.
:returns: The updated availability zone profile
:rtype: :class:`~openstack.load_balancer.v2.availability_zone_profile.
AvailabilityZoneProfile`
:rtype:
:class:`~openstack.load_balancer.v2.availability_zone_profile.AvailabilityZoneProfile`
"""
return self._update(_availability_zone_profile.AvailabilityZoneProfile,
availability_zone_profile, **attrs)
@ -1103,10 +1093,9 @@ class Proxy(proxy.Proxy):
def create_availability_zone(self, **attrs):
"""Create a new availability zone from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.load_balancer.v2.
availability_zone.AvailabilityZone`, comprised of
the properties on the AvailabilityZoneclass.
:param dict attrs: Keyword arguments which will be used to create a
:class:`~openstack.load_balancer.v2.availability_zone.AvailabilityZone`
comprised of the properties on the AvailabilityZoneclass.
:returns: The results of availability_zone creation creation
:rtype:
@ -1118,12 +1107,12 @@ class Proxy(proxy.Proxy):
"""Get an availability zone
:param availability_zone: The value can be the name of a
availability_zone or
:class:`~openstack.load_balancer.v2.availability_zone.AvailabilityZone`
instance.
availability_zone or
:class:`~openstack.load_balancer.v2.availability_zone.AvailabilityZone`
instance.
:returns: One
:class:`~openstack.load_balancer.v2.availability_zone.AvailabilityZone`
:class:`~openstack.load_balancer.v2.availability_zone.AvailabilityZone`
"""
return self._get(_availability_zone.AvailabilityZone, *attrs)
@ -1175,7 +1164,7 @@ class Proxy(proxy.Proxy):
:class:`~openstack.load_balancer.v2.availability_zone.AvailabilityZone`
instance
:param dict attrs: The attributes to update on the availability_zone
represented by ``availability_zone``.
represented by ``availability_zone``.
:returns: The updated availability_zone
:rtype:

View File

@ -9,11 +9,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import resource
class HealthMonitor(resource.Resource, resource.TagMixin):
class HealthMonitor(resource.Resource, tag.TagMixin):
resource_key = 'healthmonitor'
resources_key = 'healthmonitors'
base_path = '/lbaas/healthmonitors'
@ -30,7 +30,7 @@ class HealthMonitor(resource.Resource, resource.TagMixin):
'http_method', 'max_retries', 'max_retries_down', 'pool_id',
'provisioning_status', 'operating_status', 'timeout',
'project_id', 'type', 'url_path', is_admin_state_up='admin_state_up',
**resource.TagMixin._tag_query_parameters
**tag.TagMixin._tag_query_parameters
)
#: Properties

View File

@ -9,11 +9,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import resource
class L7Policy(resource.Resource, resource.TagMixin):
class L7Policy(resource.Resource, tag.TagMixin):
resource_key = 'l7policy'
resources_key = 'l7policies'
base_path = '/lbaas/l7policies'
@ -30,7 +30,7 @@ class L7Policy(resource.Resource, resource.TagMixin):
'redirect_pool_id', 'redirect_url', 'provisioning_status',
'operating_status', 'redirect_prefix', 'project_id',
is_admin_state_up='admin_state_up',
**resource.TagMixin._tag_query_parameters
**tag.TagMixin._tag_query_parameters
)
#: Properties

View File

@ -9,11 +9,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import resource
class L7Rule(resource.Resource, resource.TagMixin):
class L7Rule(resource.Resource, tag.TagMixin):
resource_key = 'rule'
resources_key = 'rules'
base_path = '/lbaas/l7policies/%(l7policy_id)s/rules'
@ -29,7 +29,7 @@ class L7Rule(resource.Resource, resource.TagMixin):
'compare_type', 'created_at', 'invert', 'key', 'project_id',
'provisioning_status', 'type', 'updated_at', 'rule_value',
'operating_status', is_admin_state_up='admin_state_up',
l7_policy_id='l7policy_id', **resource.TagMixin._tag_query_parameters
l7_policy_id='l7policy_id', **tag.TagMixin._tag_query_parameters
)
#: Properties

View File

@ -9,11 +9,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import resource
class Listener(resource.Resource, resource.TagMixin):
class Listener(resource.Resource, tag.TagMixin):
resource_key = 'listener'
resources_key = 'listeners'
base_path = '/lbaas/listeners'
@ -34,7 +34,7 @@ class Listener(resource.Resource, resource.TagMixin):
'timeout_member_data', 'timeout_tcp_inspect', 'allowed_cidrs',
'tls_ciphers', 'tls_versions', 'alpn_protocols',
is_admin_state_up='admin_state_up',
**resource.TagMixin._tag_query_parameters
**tag.TagMixin._tag_query_parameters
)
# Properties

View File

@ -9,11 +9,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import resource
class LoadBalancer(resource.Resource, resource.TagMixin):
class LoadBalancer(resource.Resource, tag.TagMixin):
resource_key = 'loadbalancer'
resources_key = 'loadbalancers'
base_path = '/lbaas/loadbalancers'
@ -30,7 +30,7 @@ class LoadBalancer(resource.Resource, resource.TagMixin):
'vip_address', 'vip_network_id', 'vip_port_id', 'vip_subnet_id',
'vip_qos_policy_id', 'provisioning_status', 'operating_status',
'availability_zone', is_admin_state_up='admin_state_up',
**resource.TagMixin._tag_query_parameters
**tag.TagMixin._tag_query_parameters
)
# Properties

View File

@ -9,11 +9,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import resource
class Member(resource.Resource, resource.TagMixin):
class Member(resource.Resource, tag.TagMixin):
resource_key = 'member'
resources_key = 'members'
base_path = '/lbaas/pools/%(pool_id)s/members'
@ -30,7 +30,7 @@ class Member(resource.Resource, resource.TagMixin):
'created_at', 'updated_at', 'provisioning_status', 'operating_status',
'project_id', 'monitor_address', 'monitor_port', 'backup',
is_admin_state_up='admin_state_up',
**resource.TagMixin._tag_query_parameters
**tag.TagMixin._tag_query_parameters
)
# Properties

View File

@ -9,11 +9,11 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack import resource
class Pool(resource.Resource, resource.TagMixin):
class Pool(resource.Resource, tag.TagMixin):
resource_key = 'pool'
resources_key = 'pools'
base_path = '/lbaas/pools'
@ -31,7 +31,7 @@ class Pool(resource.Resource, resource.TagMixin):
'created_at', 'updated_at', 'provisioning_status', 'operating_status',
'tls_enabled', 'tls_ciphers', 'tls_versions', 'alpn_protocols',
is_admin_state_up='admin_state_up',
**resource.TagMixin._tag_query_parameters
**tag.TagMixin._tag_query_parameters
)
#: Properties

View File

@ -24,8 +24,8 @@ class Proxy(proxy.Proxy):
"""Create a new queue from attributes
:param dict attrs: Keyword arguments which will be used to create
a :class:`~openstack.message.v2.queue.Queue`,
comprised of the properties on the Queue class.
a :class:`~openstack.message.v2.queue.Queue`,
comprised of the properties on the Queue class.
:returns: The results of queue creation
:rtype: :class:`~openstack.message.v2.queue.Queue`
@ -65,12 +65,12 @@ class Proxy(proxy.Proxy):
"""Delete a queue
:param value: The value can be either the name of a queue or a
:class:`~openstack.message.v2.queue.Queue` instance.
:class:`~openstack.message.v2.queue.Queue` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the queue does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent queue.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the queue does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent queue.
:returns: ``None``
"""
@ -81,7 +81,7 @@ class Proxy(proxy.Proxy):
:param queue_name: The name of target queue to post message to.
:param messages: List of messages body and TTL to post.
:type messages: :py:class:`list`
:type messages: :py:class:`list`
:returns: A string includes location of messages successfully posted.
"""
@ -133,16 +133,16 @@ class Proxy(proxy.Proxy):
:param queue_name: The name of target queue to delete message from.
:param value: The value can be either the name of a message or a
:class:`~openstack.message.v2.message.Message` instance.
:class:`~openstack.message.v2.message.Message` instance.
:param claim: The value can be the ID or a
:class:`~openstack.message.v2.claim.Claim` instance of
the claim seizing the message. If None, the message has
not been claimed.
:class:`~openstack.message.v2.claim.Claim` instance of
the claim seizing the message. If None, the message has
not been claimed.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the message does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent message.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the message does not exist.
When set to ``True``, no exception will be set when
attempting to delete a nonexistent message.
:returns: ``None``
"""
@ -206,15 +206,15 @@ class Proxy(proxy.Proxy):
"""Delete a subscription
:param queue_name: The name of target queue to delete subscription
from.
from.
:param value: The value can be either the name of a subscription or a
:class:`~openstack.message.v2.subscription.Subscription`
instance.
:class:`~openstack.message.v2.subscription.Subscription`
instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the subscription does not exist.
When set to ``True``, no exception will be thrown when
attempting to delete a nonexistent subscription.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the subscription does not exist.
When set to ``True``, no exception will be thrown when
attempting to delete a nonexistent subscription.
:returns: ``None``
"""
@ -270,12 +270,12 @@ class Proxy(proxy.Proxy):
:param queue_name: The name of target queue to claim messages from.
:param claim: The value can be either the ID of a claim or a
:class:`~openstack.message.v2.claim.Claim` instance.
:class:`~openstack.message.v2.claim.Claim` instance.
:param bool ignore_missing: When set to ``False``
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the claim does not exist.
When set to ``True``, no exception will be thrown when
attempting to delete a nonexistent claim.
:class:`~openstack.exceptions.ResourceNotFound` will be
raised when the claim does not exist.
When set to ``True``, no exception will be thrown when
attempting to delete a nonexistent claim.
:returns: ``None``
"""

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,7 @@ class AddressGroup(resource.Resource):
_query_mapping = resource.QueryParameters(
"sort_key", "sort_dir",
'name', 'description',
project_id='tenant_id'
'project_id'
)
# Properties
@ -44,7 +44,9 @@ class AddressGroup(resource.Resource):
#: The address group name.
description = resource.Body('description')
#: The ID of the project that owns the address group.
project_id = resource.Body('tenant_id')
project_id = resource.Body('project_id', alias='tenant_id')
#: Tenant_id (deprecated attribute).
tenant_id = resource.Body('tenant_id', deprecated=True)
#: The IP addresses of the address group.
addresses = resource.Body('addresses', type=list)

View File

@ -30,7 +30,7 @@ class AddressScope(resource.Resource):
_query_mapping = resource.QueryParameters(
'name', 'ip_version',
project_id='tenant_id',
'project_id',
is_shared='shared',
)
@ -38,7 +38,9 @@ class AddressScope(resource.Resource):
#: The address scope name.
name = resource.Body('name')
#: The ID of the project that owns the address scope.
project_id = resource.Body('tenant_id')
project_id = resource.Body('project_id', alias='tenant_id')
#: Tenant_id (deprecated attribute).
tenant_id = resource.Body('tenant_id', deprecated=True)
#: The IP address family of the address scope.
#: *Type: int*
ip_version = resource.Body('ip_version', type=int)

View File

@ -36,7 +36,9 @@ class AutoAllocatedTopology(resource.Resource):
#: Will return in error if resources have not been configured correctly
#: To use this feature auto-allocated-topology, subnet_allocation,
#: external-net and router extensions must be enabled and set up.
project_id = resource.Body('tenant_id')
project_id = resource.Body('project_id', alias='tenant_id')
#: Tenant_id (deprecated attribute).
tenant_id = resource.Body('tenant_id', deprecated=True)
class ValidateTopology(AutoAllocatedTopology):

View File

@ -9,12 +9,12 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from openstack.common import tag
from openstack.network.v2 import _base
from openstack import resource
class FloatingIP(_base.NetworkResource, resource.TagMixin):
class FloatingIP(_base.NetworkResource, tag.TagMixin):
name_attribute = "floating_ip_address"
resource_name = "floating ip"
resource_key = 'floatingip'
@ -28,12 +28,14 @@ class FloatingIP(_base.NetworkResource, resource.TagMixin):
allow_delete = True
allow_list = True
# For backward compatibility include tenant_id as query param
_query_mapping = resource.QueryParameters(
'description', 'fixed_ip_address',
'floating_ip_address', 'floating_network_id',
'port_id', 'router_id', 'status', 'subnet_id',
project_id='tenant_id',
**resource.TagMixin._tag_query_parameters)
'project_id', 'tenant_id',
tenant_id='project_id',
**tag.TagMixin._tag_query_parameters)
# Properties
#: Timestamp at which the floating IP was created.
@ -68,7 +70,9 @@ class FloatingIP(_base.NetworkResource, resource.TagMixin):
#: The ID of the QoS policy attached to the floating IP.
qos_policy_id = resource.Body('qos_policy_id')
#: The ID of the project this floating IP is associated with.
project_id = resource.Body('tenant_id')
project_id = resource.Body('project_id', alias='tenant_id')
#: Tenant_id (deprecated attribute).
tenant_id = resource.Body('tenant_id', deprecated=True)
#: The ID of an associated router.
router_id = resource.Body('router_id')
#: The floating IP status. Value is ``ACTIVE`` or ``DOWN``.

Some files were not shown because too many files have changed in this diff Show More