Merge "Merge feature/r1 branch into master"
This commit is contained in:
commit
12fa1370bc
72
.zuul.yaml
72
.zuul.yaml
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
12
doc/source/user/resources/block_storage/v2/quota_set.rst
Normal file
12
doc/source/user/resources/block_storage/v2/quota_set.rst
Normal 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:
|
12
doc/source/user/resources/block_storage/v3/quota_set.rst
Normal file
12
doc/source/user/resources/block_storage/v3/quota_set.rst
Normal 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:
|
@ -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
|
||||
|
12
doc/source/user/resources/compute/v2/migration.rst
Normal file
12
doc/source/user/resources/compute/v2/migration.rst
Normal 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:
|
12
doc/source/user/resources/compute/v2/quota_set.rst
Normal file
12
doc/source/user/resources/compute/v2/quota_set.rst
Normal 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:
|
13
doc/source/user/resources/compute/v2/server_migration.rst
Normal file
13
doc/source/user/resources/compute/v2/server_migration.rst
Normal 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:
|
@ -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
|
||||
|
@ -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:
|
@ -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
|
||||
|
13
doc/source/user/resources/shared_file_system/v2/limit.rst
Normal file
13
doc/source/user/resources/shared_file_system/v2/limit.rst
Normal 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:
|
13
doc/source/user/resources/shared_file_system/v2/share.rst
Normal file
13
doc/source/user/resources/shared_file_system/v2/share.rst
Normal 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:
|
@ -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:
|
@ -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:
|
@ -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:
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
33
openstack/block_storage/v2/quota_set.py
Normal file
33
openstack/block_storage/v2/quota_set.py
Normal 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)
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
@ -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
|
||||
|
33
openstack/block_storage/v3/quota_set.py
Normal file
33
openstack/block_storage/v3/quota_set.py
Normal 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)
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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):
|
||||
|
@ -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
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
@ -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)
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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.
|
||||
|
@ -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(
|
||||
|
@ -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
6
openstack/cloud/openstackcloud.py
Executable file → Normal 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
|
||||
|
@ -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.
|
||||
"""
|
||||
|
@ -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'
|
||||
|
0
openstack/common/__init__.py
Normal file
0
openstack/common/__init__.py
Normal file
138
openstack/common/metadata.py
Normal file
138
openstack/common/metadata.py
Normal 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
|
129
openstack/common/quota_set.py
Normal file
129
openstack/common/quota_set.py
Normal 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
127
openstack/common/tag.py
Normal 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
@ -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*
|
||||
|
@ -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*
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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)
|
72
openstack/compute/v2/migration.py
Normal file
72
openstack/compute/v2/migration.py
Normal 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'
|
57
openstack/compute/v2/quota_set.py
Normal file
57
openstack/compute/v2/quota_set.py
Normal 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)
|
@ -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:
|
||||
|
@ -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')
|
||||
|
||||
|
98
openstack/compute/v2/server_migration.py
Normal file
98
openstack/compute/v2/server_migration.py
Normal 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)
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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."""
|
||||
|
@ -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
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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`
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user