songm 933137cd99 Fix inventory objects list issue
The default return value of  maximum page size is 1000
according to MP container inventory configuration,
we need to concatenate the responses by using url_list
instead of url_get.

Change-Id: I41c8129988f79fda0cdf44dcf73af304d84ec61f
2020-05-27 05:18:55 -07:00

832 lines
32 KiB
Python

# Copyright 2015 VMware, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import netaddr
from oslo_log import log
from oslo_log import versionutils
import requests
from vmware_nsxlib._i18n import _
from vmware_nsxlib.v3 import core_resources
from vmware_nsxlib.v3 import exceptions
from vmware_nsxlib.v3 import nsx_constants
from vmware_nsxlib.v3 import utils
LOG = log.getLogger(__name__)
# TODO(asarfaty): keeping this for backwards compatibility.
# core_resources.SwitchingProfileTypeId and
# core_resources.PacketAddressClassifier should be used.
# This code will be removed in the future.
SwitchingProfileTypeId = core_resources.SwitchingProfileTypeId
PacketAddressClassifier = core_resources.PacketAddressClassifier
class SwitchingProfileTypes(core_resources.SwitchingProfileTypes):
# TODO(asarfaty): keeping this for backwards compatibility.
# This code will be removed in the future.
def __init__(self):
versionutils.report_deprecated_feature(
LOG,
'resources.SwitchingProfileTypes is deprecated. '
'Please use core_resources.SwitchingProfileTypes instead.')
class WhiteListAddressTypes(core_resources.WhiteListAddressTypes):
# TODO(asarfaty): keeping this for backwards compatibility.
# This code will be removed in the future.
def __init__(self):
versionutils.report_deprecated_feature(
LOG,
'resources.WhiteListAddressTypes is deprecated. '
'Please use core_resources.WhiteListAddressTypes instead.')
class SwitchingProfile(core_resources.NsxLibSwitchingProfile):
# TODO(asarfaty): keeping this for backwards compatibility.
# This code will be removed in the future.
def __init__(self, rest_client, *args, **kwargs):
versionutils.report_deprecated_feature(
LOG,
'resources.SwitchingProfile is deprecated. '
'Please use core_resources.NsxLibSwitchingProfile instead.')
super(SwitchingProfile, self).__init__(rest_client)
class LogicalPort(utils.NsxLibApiBase):
@property
def uri_segment(self):
return 'logical-ports'
@property
def resource_type(self):
return 'LogicalPort'
def _build_body_attrs(
self, display_name=None,
admin_state=True, tags=None,
address_bindings=None,
switch_profile_ids=None,
attachment=None,
description=None,
extra_configs=None):
tags = tags or []
switch_profile_ids = switch_profile_ids or []
body = {}
if tags:
body['tags'] = tags
if display_name is not None:
body['display_name'] = display_name
if admin_state is not None:
if admin_state:
body['admin_state'] = nsx_constants.ADMIN_STATE_UP
else:
body['admin_state'] = nsx_constants.ADMIN_STATE_DOWN
if address_bindings:
bindings = []
for binding in address_bindings:
address_classifier = {
'ip_address': binding.ip_address,
'mac_address': binding.mac_address
}
if binding.vlan is not None:
address_classifier['vlan'] = int(binding.vlan)
bindings.append(address_classifier)
body['address_bindings'] = bindings
elif address_bindings is not None:
body['address_bindings'] = []
if switch_profile_ids:
profiles = []
for profile in switch_profile_ids:
profiles.append({
'value': profile.profile_id,
'key': profile.profile_type
})
body['switching_profile_ids'] = profiles
# Note that attachment could be None, meaning reset it.
if attachment is not False:
body['attachment'] = attachment
if description is not None:
body['description'] = description
if extra_configs:
body['extra_configs'] = extra_configs
return body
def _prepare_attachment(self, attachment_type, vif_uuid,
allocate_addresses, vif_type,
parent_vif_id, traffic_tag, app_id, tn_uuid):
if attachment_type and vif_uuid:
attachment = {'attachment_type': attachment_type,
'id': vif_uuid}
if vif_type:
context = {'resource_type': nsx_constants.VIF_RESOURCE_TYPE,
'allocate_addresses': allocate_addresses,
'vif_type': vif_type}
if parent_vif_id:
context['parent_vif_id'] = parent_vif_id
context['traffic_tag'] = traffic_tag
context['app_id'] = app_id
elif tn_uuid:
context['transport_node_uuid'] = tn_uuid
context['app_id'] = app_id
attachment['context'] = context
return attachment
elif attachment_type is None and vif_uuid is None:
return None # reset attachment
else:
return False # no attachment change
def create(self, lswitch_id, vif_uuid, tags=None,
attachment_type=nsx_constants.ATTACHMENT_VIF,
admin_state=True, name=None, address_bindings=None,
parent_vif_id=None, traffic_tag=None,
switch_profile_ids=None, vif_type=None, app_id=None,
allocate_addresses=nsx_constants.ALLOCATE_ADDRESS_NONE,
description=None, tn_uuid=None,
extra_configs=None):
tags = tags or []
body = {'logical_switch_id': lswitch_id}
# NOTE(arosen): If parent_vif_id is specified we need to use
# CIF attachment type.
attachment = self._prepare_attachment(attachment_type, vif_uuid,
allocate_addresses, vif_type,
parent_vif_id, traffic_tag,
app_id, tn_uuid)
body.update(self._build_body_attrs(
display_name=name,
admin_state=admin_state, tags=tags,
address_bindings=address_bindings,
switch_profile_ids=switch_profile_ids,
attachment=attachment,
description=description,
extra_configs=extra_configs))
return self.client.create(self.get_path(), body=body)
def delete(self, lport_id):
self._delete_with_retry('%s?detach=true' % lport_id)
def update(self, lport_id, vif_uuid,
name=None, admin_state=None,
address_bindings=None, switch_profile_ids=None,
tags_update=None, tags=None,
attachment_type=nsx_constants.ATTACHMENT_VIF,
parent_vif_id=None, traffic_tag=None,
vif_type=None, app_id=None,
allocate_addresses=nsx_constants.ALLOCATE_ADDRESS_NONE,
description=None, tn_uuid=None,
extra_configs=None, force=False):
# Do not allow tags & tags_update at the same call
if tags_update and tags:
raise exceptions.ManagerError(
details=_("Can't support updating logical port %s both with "
"tags and tags_update attributes") % lport_id)
attachment = self._prepare_attachment(attachment_type, vif_uuid,
allocate_addresses, vif_type,
parent_vif_id, traffic_tag,
app_id, tn_uuid)
lport = {}
if tags_update is not None:
lport['tags_update'] = tags_update
lport.update(self._build_body_attrs(
display_name=name,
admin_state=admin_state,
address_bindings=address_bindings,
switch_profile_ids=switch_profile_ids,
attachment=attachment,
description=description,
extra_configs=extra_configs,
tags=tags))
headers = None
if force:
headers = {'X-Allow-Overwrite': 'true'}
return self._update_resource(
self.get_path(lport_id), lport, headers=headers, retry=True)
def get_by_attachment(self, attachment_type, attachment_id):
"""Return all logical port matching the attachment type and Id"""
url_suffix = ('?attachment_type=%s&attachment_id=%s' %
(attachment_type, attachment_id))
return self.client.get(self.get_path(url_suffix))
def get_by_logical_switch(self, logical_switch_id):
"""Return all logical port of a logical switch"""
url_suffix = '?logical_switch_id=%s' % logical_switch_id
return self.client.get(self.get_path(url_suffix))
class LogicalRouter(core_resources.NsxLibLogicalRouter):
# TODO(asarfaty): keeping this for backwards compatibility.
# This code will be removed in the future.
def __init__(self, rest_client, *args, **kwargs):
versionutils.report_deprecated_feature(
LOG,
'resources.LogicalRouter is deprecated. '
'Please use core_resources.NsxLibLogicalRouter instead.')
super(LogicalRouter, self).__init__(rest_client)
class LogicalRouterPort(utils.NsxLibApiBase):
@property
def uri_segment(self):
return 'logical-router-ports'
@staticmethod
def _get_relay_binding(relay_service_uuid):
return {'service_id': {'target_type': 'LogicalService',
'target_id': relay_service_uuid}}
def create(self, logical_router_id,
display_name,
tags,
resource_type,
logical_port_id,
address_groups,
edge_cluster_member_index=None,
urpf_mode=None,
relay_service_uuid=None):
body = {'display_name': display_name,
'resource_type': resource_type,
'logical_router_id': logical_router_id,
'tags': tags or []}
if address_groups:
body['subnets'] = address_groups
if resource_type in [nsx_constants.LROUTERPORT_UPLINK,
nsx_constants.LROUTERPORT_DOWNLINK,
nsx_constants.LROUTERPORT_CENTRALIZED]:
body['linked_logical_switch_port_id'] = {
'target_id': logical_port_id}
elif resource_type == nsx_constants.LROUTERPORT_LINKONTIER1:
body['linked_logical_router_port_id'] = {
'target_id': logical_port_id}
elif logical_port_id:
body['linked_logical_router_port_id'] = logical_port_id
if edge_cluster_member_index:
body['edge_cluster_member_index'] = edge_cluster_member_index
if urpf_mode:
body['urpf_mode'] = urpf_mode
if relay_service_uuid:
if (self.nsxlib and
self.nsxlib.feature_supported(
nsx_constants.FEATURE_DHCP_RELAY)):
body['service_bindings'] = [self._get_relay_binding(
relay_service_uuid)]
else:
LOG.error("Ignoring relay_service_uuid for router %s port: "
"This feature is not supported.", logical_router_id)
return self.client.create(self.get_path(), body=body)
def update(self, logical_port_id, **kwargs):
logical_router_port = {}
# special treatment for updating/removing the relay service
if 'relay_service_uuid' in kwargs:
if kwargs['relay_service_uuid']:
if (self.nsxlib and
self.nsxlib.feature_supported(
nsx_constants.FEATURE_DHCP_RELAY)):
logical_router_port['service_bindings'] = [
self._get_relay_binding(
kwargs['relay_service_uuid'])]
else:
LOG.error("Ignoring relay_service_uuid for router "
"port %s: This feature is not supported.",
logical_port_id)
else:
# delete the current one
if 'service_bindings' in logical_router_port:
logical_router_port['service_bindings'] = []
del kwargs['relay_service_uuid']
for k in kwargs:
logical_router_port[k] = kwargs[k]
return self._update_resource(
self.get_path(logical_port_id), logical_router_port, retry=True)
def delete(self, logical_port_id):
self._delete_with_retry(logical_port_id)
def get_by_lswitch_id(self, logical_switch_id):
resource = '?logical_switch_id=%s' % logical_switch_id
router_ports = self.client.url_get(self.get_path(resource))
result_count = int(router_ports.get('result_count', "0"))
if result_count >= 2:
raise exceptions.ManagerError(
details=_("Can't support more than one logical router ports "
"on same logical switch %s ") % logical_switch_id)
elif result_count == 1:
return router_ports['results'][0]
else:
err_msg = (_("Logical router link port not found on logical "
"switch %s") % logical_switch_id)
raise exceptions.ResourceNotFound(
manager=self.client.nsx_api_managers,
operation=err_msg)
def update_by_lswitch_id(self, logical_router_id, ls_id, **payload):
port = self.get_by_lswitch_id(ls_id)
return self.update(port['id'], **payload)
def delete_by_lswitch_id(self, ls_id):
port = self.get_by_lswitch_id(ls_id)
self.delete(port['id'])
def get_by_router_id(self, logical_router_id):
resource = '?logical_router_id=%s' % logical_router_id
logical_router_ports = self.client.url_get(self.get_path(resource))
return logical_router_ports['results']
def get_tier1_link_port(self, logical_router_id):
logical_router_ports = self.get_by_router_id(logical_router_id)
for port in logical_router_ports:
if port['resource_type'] == nsx_constants.LROUTERPORT_LINKONTIER1:
return port
raise exceptions.ResourceNotFound(
manager=self.client.nsx_api_managers,
operation="get router link port")
def get_tier0_uplink_port(self, logical_router_id):
logical_router_ports = self.get_by_router_id(logical_router_id)
for port in logical_router_ports:
if port['resource_type'] == nsx_constants.LROUTERPORT_UPLINK:
return port
def get_tier0_uplink_subnets(self, logical_router_id):
port = self.get_tier0_uplink_port(logical_router_id)
if port:
return port.get('subnets', [])
return []
def get_tier0_uplink_cidrs(self, logical_router_id):
# return a list of tier0 uplink ip/prefix addresses
subnets = self.get_tier0_uplink_subnets(logical_router_id)
cidrs = []
for subnet in subnets:
for ip_address in subnet.get('ip_addresses'):
cidrs.append('%s/%s' % (ip_address,
subnet.get('prefix_length')))
return cidrs
def get_tier0_uplink_ips(self, logical_router_id):
# return a list of tier0 uplink ip addresses
subnets = self.get_tier0_uplink_subnets(logical_router_id)
ips = []
for subnet in subnets:
for ip_address in subnet.get('ip_addresses'):
ips.append(ip_address)
return ips
class MetaDataProxy(core_resources.NsxLibMetadataProxy):
# TODO(asarfaty): keeping this for backwards compatibility.
# This code will be removed in the future.
def __init__(self, rest_client, *args, **kwargs):
versionutils.report_deprecated_feature(
LOG,
'resources.MetaDataProxy is deprecated. '
'Please use core_resources.NsxLibMetadataProxy instead.')
super(MetaDataProxy, self).__init__(rest_client)
class DhcpProfile(core_resources.NsxLibDhcpProfile):
# TODO(asarfaty): keeping this for backwards compatibility.
# This code will be removed in the future.
def __init__(self, rest_client, *args, **kwargs):
versionutils.report_deprecated_feature(
LOG,
'resources.DhcpProfile is deprecated. '
'Please use core_resources.NsxLibDhcpProfile instead.')
super(DhcpProfile, self).__init__(rest_client)
class LogicalDhcpServer(utils.NsxLibApiBase):
def get_dhcp_opt_code(self, name):
return utils.get_dhcp_opt_code(name)
@property
def uri_segment(self):
return 'dhcp/servers'
@property
def resource_type(self):
return 'LogicalDhcpServer'
def _construct_server(self, body, dhcp_profile_id=None, server_ip=None,
name=None, dns_nameservers=None, domain_name=None,
gateway_ip=False, options=None, tags=None):
if name:
body['display_name'] = name
if dhcp_profile_id:
body['dhcp_profile_id'] = dhcp_profile_id
if server_ip:
body['ipv4_dhcp_server']['dhcp_server_ip'] = server_ip
if dns_nameservers is not None:
# Note that [] is valid for dns_nameservers, means deleting it.
body['ipv4_dhcp_server']['dns_nameservers'] = dns_nameservers
if domain_name:
body['ipv4_dhcp_server']['domain_name'] = domain_name
if gateway_ip is not False:
# Note that None is valid for gateway_ip, means deleting it.
body['ipv4_dhcp_server']['gateway_ip'] = gateway_ip
if options:
body['ipv4_dhcp_server']['options'] = options
if tags:
body['tags'] = tags
def create(self, dhcp_profile_id, server_ip, name=None,
dns_nameservers=None, domain_name=None, gateway_ip=False,
options=None, tags=None):
body = {'ipv4_dhcp_server': {}}
self._construct_server(body, dhcp_profile_id, server_ip, name,
dns_nameservers, domain_name, gateway_ip,
options, tags)
return self.client.create(self.get_path(), body=body)
def update(self, uuid, dhcp_profile_id=None, server_ip=None, name=None,
dns_nameservers=None, domain_name=None, gateway_ip=False,
options=None, tags=None):
body = {'ipv4_dhcp_server': {}}
self._construct_server(body, dhcp_profile_id, server_ip, name,
dns_nameservers, domain_name, gateway_ip,
options, tags)
return self._update_with_retry(uuid, body)
def create_binding(self, server_uuid, mac, ip, hostname=None,
lease_time=None, options=None, gateway_ip=False):
body = {'mac_address': mac, 'ip_address': ip}
if hostname:
body['host_name'] = hostname
if lease_time:
body['lease_time'] = lease_time
if options:
body['options'] = options
if gateway_ip is not False:
# Note that None is valid for gateway_ip, means deleting it.
body['gateway_ip'] = gateway_ip
url = "%s/static-bindings" % server_uuid
return self.client.url_post(self.get_path(url), body)
def get_binding(self, server_uuid, binding_uuid):
url = "%s/static-bindings/%s" % (server_uuid, binding_uuid)
return self.get(url)
def update_binding(self, server_uuid, binding_uuid, **kwargs):
body = {}
body.update(kwargs)
url = "%s/static-bindings/%s" % (server_uuid, binding_uuid)
self._update_resource(self.get_path(url), body, retry=True)
def delete_binding(self, server_uuid, binding_uuid):
url = "%s/static-bindings/%s" % (server_uuid, binding_uuid)
return self.delete(url)
class IpPool(utils.NsxLibApiBase):
@property
def uri_segment(self):
return 'pools/ip-pools'
@property
def resource_type(self):
return 'IpPool'
def _generate_ranges(self, cidr, gateway_ip):
"""Create list of ranges from the given cidr.
Ignore the gateway_ip, if defined
"""
ip_set = netaddr.IPSet(netaddr.IPNetwork(cidr))
if gateway_ip:
ip_set.remove(gateway_ip)
return [{"start": str(r[0]),
"end": str(r[-1])} for r in ip_set.iter_ipranges()]
def create(self, cidr, allocation_ranges=None, display_name=None,
description=None, gateway_ip=None, dns_nameservers=None,
tags=None):
"""Create an IpPool.
Arguments:
cidr: (required)
allocation_ranges: (optional) a list of dictionaries, each with
'start' and 'end' keys, and IP values.
If None: the cidr will be used to create the ranges,
excluding the gateway.
display_name: (optional)
description: (optional)
gateway_ip: (optional)
dns_nameservers: (optional) list of addresses
"""
if not cidr:
raise exceptions.InvalidInput(operation="IP Pool create",
arg_name="cidr", arg_val=cidr)
if not allocation_ranges:
# generate ranges from (cidr - gateway)
allocation_ranges = self._generate_ranges(cidr, gateway_ip)
subnet = {"allocation_ranges": allocation_ranges,
"cidr": cidr}
if gateway_ip:
subnet["gateway_ip"] = gateway_ip
if dns_nameservers:
subnet["dns_nameservers"] = dns_nameservers
body = {"subnets": [subnet]}
if description:
body["description"] = description
if display_name:
body["display_name"] = display_name
if tags:
body['tags'] = tags
return self.client.create(self.get_path(), body=body)
def delete(self, pool_id, force=False):
url = pool_id
if force:
url += '?force=%s' % force
return self._delete_by_path_with_retry(self.get_path(url))
def _update_param_in_pool(self, args_dict, key, pool_data):
# update the arg only if it exists in the args dictionary
if key in args_dict:
if args_dict[key]:
pool_data[key] = args_dict[key]
else:
# remove the current value
del pool_data[key]
def update(self, pool_id, **kwargs):
"""Update the given attributes in the current pool configuration."""
# Get the current pool, and remove irrelevant fields
pool = self.get(pool_id)
for key in ["resource_type", "_create_time", "_create_user"
"_last_modified_user", "_last_modified_time"]:
pool.pop(key, None)
# update only the attributes in kwargs
self._update_param_in_pool(kwargs, 'display_name', pool)
self._update_param_in_pool(kwargs, 'description', pool)
self._update_param_in_pool(kwargs, 'tags', pool)
self._update_param_in_pool(kwargs, 'gateway_ip',
pool["subnets"][0])
self._update_param_in_pool(kwargs, 'dns_nameservers',
pool["subnets"][0])
self._update_param_in_pool(kwargs, 'allocation_ranges',
pool["subnets"][0])
self._update_param_in_pool(kwargs, 'cidr',
pool["subnets"][0])
return self.client.update(self.get_path(pool_id), pool)
def allocate(self, pool_id, ip_addr=None, display_name=None, tags=None):
"""Allocate an IP from a pool."""
# Note: Currently the backend does not support allocation of a
# specific IP, so an exception will be raised by the backend.
# Depending on the backend version, this may be allowed in the future
url = "%s?action=ALLOCATE" % pool_id
body = {"allocation_id": ip_addr}
if tags is not None:
body['tags'] = tags
if display_name is not None:
body['display_name'] = display_name
return self.client.url_post(self.get_path(url), body=body)
def release(self, pool_id, ip_addr):
"""Release an IP back to a pool."""
url = "%s?action=RELEASE" % pool_id
body = {"allocation_id": ip_addr}
return self.client.url_post(self.get_path(url), body=body)
def get_allocations(self, pool_id):
"""Return information about the allocated IPs in the pool."""
url = "%s/allocations" % pool_id
return self.client.url_get(self.get_path(url))
class NodeHttpServiceProperties(utils.NsxLibApiBase):
@property
def uri_segment(self):
return 'node/services/http'
@property
def resource_type(self):
return 'NodeHttpServiceProperties'
def get_properties(self):
return self.client.get(self.get_path())
def get_rate_limit(self):
if (self.nsxlib and
not self.nsxlib.feature_supported(
nsx_constants.FEATURE_RATE_LIMIT)):
msg = (_("Rate limit is not supported by NSX version %s") %
self.nsxlib.get_version())
raise exceptions.ManagerError(details=msg)
properties = self.get_properties()
return properties.get('service_properties', {}).get(
'client_api_rate_limit')
def update_rate_limit(self, value):
"""update the NSX rate limit. default value is 40. 0 means no limit"""
if (self.nsxlib and
not self.nsxlib.feature_supported(
nsx_constants.FEATURE_RATE_LIMIT)):
msg = (_("Rate limit is not supported by NSX version %s") %
self.nsxlib.get_version())
raise exceptions.ManagerError(details=msg)
properties = self.get_properties()
if 'service_properties' in properties:
properties['service_properties'][
'client_api_rate_limit'] = int(value)
# update the value using a PUT command, which is expected to return 202
expected_results = [requests.codes.accepted]
self.client.update(self.uri_segment, properties,
expected_results=expected_results)
# restart the http service using POST, which is expected to return 202
restart_url = self.uri_segment + '?action=restart'
self.client.create(restart_url, expected_results=expected_results)
def delete(self, uuid):
"""Not supported"""
msg = _("Delete is not supported for %s") % self.uri_segment
raise exceptions.ManagerError(details=msg)
def get(self, uuid):
"""Not supported"""
msg = _("Get is not supported for %s") % self.uri_segment
raise exceptions.ManagerError(details=msg)
def list(self):
"""Not supported"""
msg = _("List is not supported for %s") % self.uri_segment
raise exceptions.ManagerError(details=msg)
def find_by_display_name(self, display_name):
"""Not supported"""
msg = _("Find is not supported for %s") % self.uri_segment
raise exceptions.ManagerError(details=msg)
class NsxlibClusterNodesConfig(utils.NsxLibApiBase):
@property
def uri_segment(self):
return 'cluster/nodes'
@property
def resource_type(self):
return 'ClusterNodeConfig'
def delete(self, uuid):
"""Not supported"""
msg = _("Delete is not supported for %s") % self.uri_segment
raise exceptions.ManagerError(details=msg)
def get_managers_ips(self):
manager_ips = []
nodes_config = self.client.get(self.get_path())['results']
for node in nodes_config:
if 'manager_role' in node:
manager_conf = node['manager_role']
if 'api_listen_addr' in manager_conf:
list_addr = manager_conf['mgmt_cluster_listen_addr']
ip = list_addr['ip_address']
if ip != '127.0.0.1':
manager_ips.append(list_addr['ip_address'])
return manager_ips
class NsxlibHostSwitchProfiles(utils.NsxLibApiBase):
@property
def uri_segment(self):
return 'host-switch-profiles'
@property
def resource_type(self):
return 'UplinkHostSwitchProfile'
class Inventory(utils.NsxLibApiBase):
"""REST APIs to support inventory service."""
RESOURCES_PATH = {"ContainerCluster": "container-clusters",
"ContainerProject": "container-projects",
"ContainerApplication": "container-applications",
"ContainerApplicationInstance":
"container-application-instances",
"ContainerClusterNode": "container-cluster-nodes",
"ContainerNetworkPolicy": "container-network-policies",
"ContainerIngressPolicy": "container-ingress-policies"}
SEGMENT_URI = 'fabric'
SEGMENT_URI_FOR_UPDATE = 'inventory/container'
@property
def uri_segment(self):
# only serves for get, list and delete. For batch update,
# another base url is used. The reason is update API is internal.
return self.SEGMENT_URI
@property
def resource_type(self):
return 'Inventory'
def update(self, cluster_id, updates):
"""This method supports multiple updates in a batching way."""
items = []
for update_type, update_object in updates:
item = {}
item["object_update_type"] = update_type
item["container_object"] = update_object
items.append(item)
body = {"container_inventory_objects": items}
request_url = "%s/%s?action=updates" % (
self.SEGMENT_URI_FOR_UPDATE, cluster_id)
return self.client.url_post(request_url, body)
def get(self, resource_type, resource_id):
if not resource_type:
msg = "null resource type is not supported"
raise exceptions.ResourceNotFound(details=msg)
request_url = "%s/%s" % (
self.get_path(self._get_path_for_resource(resource_type)),
resource_id)
return self.client.url_get(request_url)
def list(self, cluster_id, resource_type):
if not resource_type:
msg = "null resource type is not supported"
raise exceptions.ResourceNotFound(details=msg)
request_url = "%s?container_cluster_id=%s" % (
self.get_path(self._get_path_for_resource(resource_type)),
cluster_id)
return self.client.url_list(request_url)
def delete(self, resource_type, resource_id):
if not resource_type:
msg = "null resource type is not supported"
raise exceptions.ResourceNotFound(details=msg)
request_url = "%s/%s" % (
self.get_path(self._get_path_for_resource(resource_type)),
resource_id)
return self.client.url_delete(request_url)
def create(self, resource_type, resource):
if not resource_type:
msg = "null resource type is not supported"
raise exceptions.ResourceNotFound(details=msg)
request_url = self.get_path(
self._get_path_for_resource(resource_type))
return self.client.url_post(request_url, resource)
def _get_path_for_resource(self, resource_type):
path = self.RESOURCES_PATH.get(resource_type)
if not path:
msg = "backend resource %s is not supported" % resource_type
raise exceptions.ResourceNotFound(details=msg)
return path
class SystemHealth(utils.NsxLibApiBase):
@property
def uri_segment(self):
return 'systemhealth'
@property
def resource_type(self):
return 'SystemHealth'
def create_ncp_status(self, cluster_id, status):
url = '/container-cluster/ncp/status'
body = {'cluster_id': cluster_id, 'status': status}
return self.client.create(self.get_path(url), body=body)