"""
State module for NSX-T segment
"""
import logging
log = logging.getLogger(__name__)
try:
from saltext.nsxt.modules import nsxt_policy_segment
HAS_POLICY_SEGMENT = True
except ImportError:
HAS_POLICY_SEGMENT = False
def __virtual__():
if not HAS_POLICY_SEGMENT:
return False, "'nsxt_policy_segment' binary not found on system"
return "nsxt_policy_segment"
[docs]def present(
name,
hostname,
username,
password,
display_name,
verify_ssl=True,
cert=None,
cert_common_name=None,
state=None,
tags=None,
description=None,
address_bindings=None,
admin_state=None,
advanced_config=None,
bridge_profiles=None,
connectivity_path=None,
dhcp_config_path=None,
extra_configs=None,
l2_extension=None,
tier0_display_name=None,
tier0_id=None,
tier1_display_name=None,
tier1_id=None,
domain_name=None,
transport_zone_display_name=None,
transport_zone_id=None,
enforcementpoint_id=None,
site_id=None,
vlan_ids=None,
subnets=None,
segment_ports=None,
):
"""
Creates or Updates(if present with same display_name) segment and its sub-resources with the given
specifications.
Note: To delete any subresource of segment state parameter as absent
CLI Example:
.. code-block:: bash
salt vm_minion nsxt_policy_segment.present hostname=nsxt-manager.local username=admin ...
.. code-block:: yaml
nsxt_policy_segment.present:
- name: Create segment
hostname: <hostname>
username: <username>
password: <password>
cert: <certificate>
verify_ssl: <False/True>
display_name: test-seg-4
state: present
domain_name: dn1
transport_zone_display_name: "1-transportzone-730"
replication_mode: "SOURCE"
advanced_config:
- address_pool_display_name: small-2-pool
connectivity: "OFF"
hybrid: False
local_egress: True
admin_state: UP
connectivity_path: "/infra/tier-1s/d082bc25-a9b2-4d13-afe5-d3cecad4b854"
subnets:
- gateway_address: "40.1.1.1/16"
segment_ports:
- display_name: test-sp-1
state: present
tags:
- scope: "scope-1"
tag: "tag-2"
extra_configs:
- config_pair:
key: key
value: value
ignored_address_bindings:
- ip_address: "10.1.2.122"
- display_name: test-sp-2
state: present
- display_name: test-sp-3
state: present
hostname
The host name of NSX-T manager
username
Username to connect to NSX-T manager
password
Password to connect to NSX-T manager
verify_ssl
(Optional) Option to enable/disable SSL verification. Enabled by default.
If set to False, the certificate validation is skipped.
cert
(Optional) Path to the SSL client certificate file to connect to NSX-T manager.
The certificate can be retrieved from browser.
cert_common_name
(Optional) By default, the hostname parameter and the common name in certificate is compared for host name
verification. If the client certificate common name and hostname do not match (in case of self-signed
certificates), specify the certificate common name as part of this parameter. This value is then used to
compare against
display_name:
description: Display name.If resource ID is not specified, display_name will be used as ID.
type: str
state:
choices:
- present
- absent
description: State can be either 'present' or 'absent'.'present' is used to create or update resource.'absent' is used to delete resource.
tags:
description: Opaque identifiers meaningful to the API user.
required: False
description:
description: Segment description.
address_bindings:
description: Address bindings for the Segment
required: False
type: list
elements: dict
suboptions:
ip_address:
description: IP Address for port binding
type: str
mac_address:
description: Mac address for port binding
type: str
vlan_id:
description: VLAN ID for port binding
type: int
admin_state:
description: Represents Desired state of the Segment
required: False
type: str
choices:
- UP
- DOWN
default: UP
advanced_config:
description: Advanced configuration for Segment.
required: False
type: dict
suboptions:
address_pool_id:
description: IP address pool ID
type: str
address_pool_name:
description: IP address pool display name
type: str
connectivity:
description: Connectivity configuration to manually connect
(ON) or disconnect (OFF) a logical entity from
network topology. Only valid for Tier1 Segment
type: str
hybrid:
description:
- Flag to identify a hybrid logical switch
- When set to true, all the ports created on this segment
will behave in a hybrid fashion. The hybrid port
indicates to NSX that the VM intends to operate in
underlay mode, but retains the ability to forward egress
traffic to the NSX overlay network. This property is only
applicable for segment created with transport zone type
OVERLAY_STANDARD. This property cannot be modified after
segment is created.
type: bool
local_egress:
description:
- Flag to enable local egress
- This property is used to enable proximity routing with
local egress. When set to true, logical router interface
(downlink) connecting Segment to Tier0/Tier1 gateway is
configured with prefix-length 32.
type: bool
local_egress_routing_policies:
description: An ordered list of routing policies to forward
traffic to the next hop.
type: list
elements: dict
suboptions:
nexthop_address:
required: true
description: Next hop address for proximity routing
type: str
prefix_list_paths:
required: true
description:
- Policy path to prefix lists, max 1 element
- The destination address of traffic matching a
prefix-list is forwarded to the nexthop_address.
Traffic matching a prefix list with Action DENY
will be dropped. Individual prefix-lists
specified could have different actions.
type: list
elements: str
multicast:
description:
- Enable multicast on the downlink
- Enable multicast for a segment. Only applicable for
segments connected to Tier0 gateway.
type: bool
uplink_teaming_policy_name:
description:
- Uplink Teaming Policy Name
- The name of the switching uplink teaming policy for the
Segment. This name corresponds to one of the switching
uplink teaming policy names listed in TransportZone
associated with the Segment. When this property is
not specified, the segment will not have a teaming policy
associated with it and the host switch's default teaming
policy will be used by MP.
type: str
bridge_profiles:
description: Bridge Profile Configuration
required: False
type: list
elements: dict
suboptions:
bridge_profile_path:
description:
- Policy path to L2 Bridge profile
- Same bridge profile can be configured on different
segments. Each bridge profile on a segment must unique.
type: str
uplink_teaming_policy_name:
description:
- Uplink Teaming Policy Name
- The name of the switching uplink teaming policy for the
bridge endpoint. This name corresponds to one of the
switching uplink teaming policy names listed in the
transport zone. When this property is not specified, the
teaming policy is assigned by MP.
type: str
vlan_ids:
description: VLAN specification for bridge endpoint. Either
VLAN ID or VLAN ranges can be specified. Not both.
type: str
vlan_transport_zone_path:
description:
- Policy path to VLAN Transport Zone
- VLAN transport zone should belong to the enforcment-point
as the transport zone specified in the segment.
type: str
connectivity_path:
description: Policy path to the connecting Tier-0 or Tier-1. Valid only
for segments created under Infra
required: False
type: str
dhcp_config_path:
description:
- Policy path to DHCP configuration
- Policy path to DHCP server or relay configuration to use for all
IPv4 & IPv6 subnets configured on this segment.
required: False
type: str
extra_configs:
description:
- Extra configs on Segment
- This property could be used for vendor specific configuration in
key value string pairs, the setting in extra_configs will be
automatically inheritted by segment ports in the Segment.
type: list
required: False
elements: dict
suboptions:
config_pair:
description: Key value pair in string for the configuration
type: dict
required: true
suboptions:
key:
description: Key
type: str
required: true
value:
description: Value
type: str
required: true
l2_extension:
description: Configuration for extending Segment through L2 VPN
required: False
type: dict
suboptions:
l2vpn_paths:
description: Policy paths corresponding to the associated L2
VPN sessions
type: list
elements: str
local_egress:
description: Local Egress
type: dict
suboptions:
optimized_ips:
description: Gateway IP for Local Egress. Local egress
is enabled only when this list is not empty
type: list
elements: str
tunnel_id:
description: Tunnel ID
type: int
mac_pool_id:
description: Allocation mac pool associated with the Segment
type: str
metadata_proxy_paths:
description: Metadata Proxy Configuration Paths
type: list
elements: str
tier0_display_name:
description: Same as tier_0_id. Either one can be specified.
If both are specified, tier_0_id takes
precedence.
required: False
type: str
tier0_id:
description: The Uplink of the Policy Segment.Mutually exclusive with tier_1_id.
type: str
tier1_display_name:
description: Same as tier_1_id. Either one can be specified.
If both are specified, tier_1_id takes
precedence.
type: str
tier1_id:
description: The Uplink of the Policy Segment.Mutually exclusive with tier_0_id but takes precedence.
type: str
domain_name:
description: Domain name associated with the Policy Segment.
type: str
transport_zone_display_name:
description: Same as transport_zone_id. Either one can be specified.
If both are specified, transport_zone_id takes
precedence.
type: str
transport_zone_id:
description: The TZ associated with the Policy Segment.
type: str
enforcementpoint_id:
description: The EnforcementPoint ID where the TZ is located.
Required if transport_zone_id is specified.
default: default
type: str
site_id:
description: The site ID where the EnforcementPoint is located.
Required if transport_zone_id is specified.
default: default
type: str
vlan_ids:
description: VLAN ids for a VLAN backed Segment.
Can be a VLAN id or a range of VLAN ids specified with '-'
in between.
type: list
subnets:
description: Subnets that belong to this Policy Segment.
type: dict
suboptions:
dhcp_ranges:
description: DHCP address ranges for dynamic IP allocation.
DHCP address ranges are used for dynamic IP
allocation. Supports address range and CIDR
formats. First valid host address from the first
value is assigned to DHCP server IP address.
Existing values cannot be deleted or modified, but
additional DHCP ranges can be added.
Formats, e.g. 10.12.2.64/26, 10.12.2.2-10.12.2.50
type: list
gateway_address:
description: Gateway IP address.
Gateway IP address in CIDR format for both IPv4
and IPv6.
type: str
segment_ports:
type: list
description: Add the Segment Ports to be create, updated, or deleted in this section
element: dict
suboptions:
address_bindings:
description: Static address binding used for the port.
type: list
elements: dict
suboptions:
ip_address:
description: IP Address for port binding.
type: str
mac_address:
description: Mac address for port binding.
type: str
vlan_id:
description: VLAN ID for port binding.
type: str
attachment:
description: VIF attachment.
type: dict
suboptions:
allocate_addresses:
description: Indicate how IP will be
allocated for the port.
type: str
choices:
- IP_POOL
- MAC_POOL
- BOTH
- NONE
app_id:
description: ID used to identify/look up a
child attachment behind a
parent attachment.
type: str
context_id:
description: Parent VIF ID if type is CHILD,
Transport node ID if type is
INDEPENDENT.
type: str
id:
description: VIF UUID on NSX Manager.
type: str
traffic_tag:
description:
- VLAN ID
- Not valid when type is INDEPENDENT, mainly
used to identify traffic from different ports
in container use case
type: int
type:
description: Type of port attachment.
type: str
choices:
- PARENT
- CHILD
- INDEPENDENT
display_name:
description:
- Segment Port display name.
- Either this or id must be specified. If both are
specified, id takes precedence.
type: str
description:
description:
- Segment description.
type: str
extra_configs:
description:
- Extra configs on segment port
- This property could be used for vendor specific
configuration in key value string pairs. Segment port
setting will override segment setting if the same key was
set on both segment and segment port.
type: list
element: dict
suboptions:
config_pair:
description: Key value pair in string for the
configuration
type: dict
required: true
suboptions:
key:
description: Key
type: str
value:
description: Value
type: str
id:
description: The id of the Policy Segment Port.
type: str
ignored_address_bindings:
description:
- Address bindings to be ignored by IP Discovery module
IP Discovery module uses various mechanisms to discover
address bindings being used on each segment port. If a
user would like to ignore any specific discovered address
bindings or prevent the discovery of a particular set of
discovered bindings, then those address bindings can be
provided here. Currently IP range in CIDR format is not
supported.
type: dict
suboptions:
ip_address:
description: IP Address for port binding.
type: str
mac_address:
description: Mac address for port binding.
type: str
vlan_id:
description: VLAN ID for port binding.
type: str
state:
choices:
- present
- absent
description:
- State can be either 'present' or 'absent'. 'present' is
used to create or update resource. 'absent' is used to
delete resource
- Required if I(id != null)
tags:
description: Opaque identifiers meaningful to the API user.
type: dict
suboptions:
scope:
description: Tag scope.
type: str
tag:
description: Tag value.
type: str
"""
ret = {"name": name, "result": True, "comment": "", "changes": {}}
if state and str(state).lower() == "absent":
ret["result"] = False
ret["comment"] = (
"Use absent method to delete segment resource. "
"Only segment port is allowed to be deleted here."
)
return ret
segment_response = __salt__["nsxt_policy_segment.get_by_display_name"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
display_name=display_name,
)
if "error" in segment_response:
ret["result"] = False
ret["comment"] = "Failed to get segment from NSX-T Manager : {}".format(
segment_response["error"]
)
return ret
result_count = len(segment_response["results"])
if result_count > 1:
ret["result"] = False
ret["comment"] = "More than one segment exist with same display name : {}".format(
display_name
)
return ret
segment_dict = segment_response["results"][0] if result_count > 0 else None
if __opts__["test"]:
if result_count == 0:
ret["result"] = None
ret["comment"] = "Segment will be created in NSX-T Manager"
else:
ret["result"] = None
ret["comment"] = "Segment would be updated in NSX-T Manager"
return ret
if result_count == 0:
# Create of segment will trigger in this flow
log.info("Creating new segment in NSX-T with display_name %s", display_name)
execution_logs_create = __salt__["nsxt_policy_segment.create_or_update"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
display_name=display_name,
tags=tags,
description=description,
address_bindings=address_bindings,
admin_state=admin_state,
advanced_config=advanced_config,
bridge_profiles=bridge_profiles,
connectivity_path=connectivity_path,
dhcp_config_path=dhcp_config_path,
extra_configs=extra_configs,
l2_extension=l2_extension,
tier0_display_name=tier0_display_name,
tier0_id=tier0_id,
tier1_display_name=tier1_display_name,
tier1_id=tier1_id,
domain_name=domain_name,
transport_zone_display_name=transport_zone_display_name,
transport_zone_id=transport_zone_id,
enforcementpoint_id=enforcementpoint_id,
site_id=site_id,
vlan_ids=vlan_ids,
subnets=subnets,
segment_ports=segment_ports,
)
log.info("Execution logs for segment create : {}".format(execution_logs_create))
if "error" in execution_logs_create[len(execution_logs_create) - 1]:
ret["result"] = False
ret["comment"] = "Failed while doing create segment or its sub resource: {}".format(
execution_logs_create
)
return ret
segment_execution_log = next(
(
execution_log
for execution_log in execution_logs_create
if execution_log.get("resourceType") == "segments"
),
None,
)
segment_id = segment_execution_log.get("results").get("id")
segment_hierarchy = __salt__["nsxt_policy_segment.get_hierarchy"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
segment_id=segment_id,
)
if "error" in segment_hierarchy:
ret["result"] = False
ret["comment"] = "Failed while querying segment and its sub-resources: {}".format(
segment_hierarchy["error"]
)
return ret
ret["comment"] = "Created segment {display_name} successfully".format(
display_name=display_name
)
ret["changes"]["new"] = segment_hierarchy
return ret
else:
# Update of segment will be triggered
segment_id = segment_dict.get("id")
log.info("Updating existing segment with display_name %s", display_name)
segment_hierarchy_response = __salt__["nsxt_policy_segment.get_hierarchy"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
segment_id=segment_id,
)
if "error" in segment_hierarchy_response:
ret["result"] = False
ret["comment"] = "Failed while querying segment and its sub-resources: {}".format(
segment_hierarchy_response["error"]
)
return ret
execution_logs_update = __salt__["nsxt_policy_segment.create_or_update"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
display_name=display_name,
tags=tags,
description=description,
address_bindings=address_bindings,
admin_state=admin_state,
advanced_config=advanced_config,
bridge_profiles=bridge_profiles,
connectivity_path=connectivity_path,
dhcp_config_path=dhcp_config_path,
extra_configs=extra_configs,
l2_extension=l2_extension,
tier0_display_name=tier0_display_name,
tier0_id=tier0_id,
tier1_display_name=tier1_display_name,
tier1_id=tier1_id,
domain_name=domain_name,
transport_zone_display_name=transport_zone_display_name,
transport_zone_id=transport_zone_id,
enforcementpoint_id=enforcementpoint_id,
site_id=site_id,
vlan_ids=vlan_ids,
subnets=subnets,
segment_ports=segment_ports,
)
log.info("Execution logs for updating segment : {}".format(execution_logs_update))
if "error" in execution_logs_update[len(execution_logs_update) - 1]:
ret["result"] = False
ret["comment"] = "Failed while updating segment and sub-resources: {}".format(
execution_logs_update
)
return ret
segment_hierarchy_response_after_update = __salt__["nsxt_policy_segment.get_hierarchy"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
segment_id=segment_id,
)
if "error" in segment_hierarchy_response_after_update:
ret["result"] = False
ret["comment"] = "Failed while querying segment and its sub-resources: {}".format(
segment_hierarchy_response_after_update["error"]
)
return ret
ret["comment"] = "Updated segment {display_name} successfully".format(
display_name=display_name
)
ret["changes"]["new"] = segment_hierarchy_response_after_update
ret["changes"]["old"] = segment_hierarchy_response
return ret
[docs]def absent(
name,
hostname,
username,
password,
display_name,
verify_ssl=None,
cert=None,
cert_common_name=None,
):
"""
Deletes segment with the given display_name and all its sub-resources
CLI Example:
.. code-block:: bash
salt vm_minion nsxt_policy_segment.absent hostname=nsxt-manager.local username=admin ...
delete_segment:
nsxt_policy_segment.absent:
- name: <Name of the operation>
hostname: <hostname>
username: <username>
password: <password>
display_name: <display name of segment>
cert: <certificate>
verify_ssl: <False/True>
name
Name of the operation to perform
hostname
The host name of NSX-T manager
username
Username to connect to NSX-T manager
password
Password to connect to NSX-T manager
display_name
Display name of the segment to delete
verify_ssl
(Optional) Option to enable/disable SSL verification. Enabled by default.
If set to False, the certificate validation is skipped.
cert
(Optional) Path to the SSL certificate file to connect to NSX-T manager.
The certificate can be retrieved from browser.
cert_common_name
(Optional) By default, the hostname parameter and the common name in certificate is compared for host name
verification. If the client certificate common name and hostname do not match (in case of self-signed
certificates), specify the certificate common name as part of this parameter. This value is then used to
compare against certificate common name.
"""
ret = {"name": name, "result": True, "comment": "", "changes": {}}
segment_response = __salt__["nsxt_policy_segment.get_by_display_name"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
display_name=display_name,
)
segment_dict, segment_id = None, None
if "error" in segment_response:
ret["result"] = False
ret["comment"] = "Failed to get the segment response : {}".format(segment_response["error"])
return ret
segment_response_by_display_name = segment_response["results"]
if len(segment_response_by_display_name) > 1:
ret["result"] = False
ret["comment"] = "More than one segment exist with same display name : {}".format(
display_name
)
return ret
segment_dict = (
segment_response_by_display_name[0] if len(segment_response_by_display_name) > 0 else None
)
if segment_dict is not None:
segment_id = segment_dict["id"]
if segment_id is None:
ret["comment"] = "No segment exist with display name %s" % display_name
return ret
if __opts__.get("test"):
log.info("absent is called with test option")
if segment_dict is not None:
ret["result"] = None
ret["comment"] = "Segment will be deleted in NSX-T Manager"
else:
ret["result"] = None
ret["comment"] = "State absent will do nothing , since segment is not existing"
return ret
segment_hierarchy = __salt__["nsxt_policy_segment.get_hierarchy"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
segment_id=segment_id,
)
if "error" in segment_hierarchy:
ret["result"] = False
ret["comment"] = "Failure while querying segment and its sub-resources: {}".format(
segment_hierarchy["error"]
)
return ret
execution_logs_delete = __salt__["nsxt_policy_segment.delete"](
hostname=hostname,
username=username,
password=password,
verify_ssl=verify_ssl,
cert=cert,
cert_common_name=cert_common_name,
segment_id=segment_id,
)
log.info("Execution logs for deleting segment : {}".format(execution_logs_delete))
if "error" in execution_logs_delete[len(execution_logs_delete) - 1]:
ret["result"] = False
ret["comment"] = "Failed to delete segment : {}".format(execution_logs_delete)
return ret
else:
ret[
"comment"
] = "Segment with display_name: {} and its sub-resources deleted successfully".format(
display_name
)
ret["changes"]["old"] = segment_hierarchy
ret["changes"]["new"] = {}
return ret