logo

NJP

Service Mapping for Netscaler Content Switching via NITRO API

New article articles in ServiceNow Community · Oct 23, 2026 · article

 

Context

The OOB Citrix Netscaler pattern can’t follow Content Switching (CS) policies to the backend, so the Service Mapping map stops at the load balancer. This post extends the connection section using the NITRO API to resolve CS >> LB >> Service Group >> Members and complete the map.

 

If you map applications published behind a Netscaler with Content Switching (CS vServer), you have probably hit the same wall. The connection section of the OOB Citrix Netscaler pattern handles entry points that point directly to an LB vServer well. When traffic enters through a CS vServer and is routed by policies (for example, by URL path), the pattern can’t find the pool, and the map stops at the load balancer.

The Netscaler Loadbalancer - NITRO pattern provides full horizontal discovery via API, including CS vServers and CS → LB vServer relationships. However, it has no connection section, so it doesn’t help with top-down mapping.

This post shows an extension to the connection section of the Citrix Netscaler pattern that uses the NITRO API to follow the chain:

Entry point (URL) >> CS policy >> CS action >> LB vServer >> Service Group >> Members

and create the connection to the backend servers.


Prerequisites

  • Experience developing and extending patterns (Pattern Designer)
  • HTTPS access from the MID Server to the NetScaler management IP (/nitro/v1/...)
  • A Basic Auth credential with read permission on NITRO

Solution logic

  1. Run only when the OOB flow didn’t find a pool.
  2. Retrieve the CS policies and filter by the rule that contains the entry point path.
  3. Resolve the CS action to get the target LB vServer.
  4. Get the service group bound to the LB vServer.
  5. Get the service group members
  6. Keep only those that are UP (optional)
  7. Create a CLUSTER connection with the members’ IPs and ports.
  8. End the execution once the connection is created.

Implementation (key steps)

1. Precondition: run only if the OOB flow didn’t find a pool

 

match {
    is_empty {get_attr {"pre_cmdb_ci_lb_pool.name"}}
    terminate_op = terminate
    terminate_msg = ""
}

2. Retrieve the CS policies

All calls use custom_operation with the HTTP GET operation and the JSON parsing strategy. Here is the full example; the others follow the same model, changing only the URL and fields.

 

custom_operation {
    attributes {
        attribute { name = "required_authentication" value = "true" }
        attribute {
            name = "url"
            value = concat {
                "https://"
                get_attr {"computer_system.managementIP"}
                "/nitro/v1/config/cspolicy"
            }
        }
    }
    to_var_names = table {
        name = "policies"
        col_names = "policy","action","rule"
    }
    // xpaths: /root/cspolicy/policyname, /action, /rule
}

3. Extract the entry point path and filter the policies

 

parse_var_to_var {
    from_var_name = "entry_point.url"
    to_var_names = "entry_point_filtered"
    parsing_strategy = regex_parsing {regex = "(?<=https://.*/)(.*)"}
}

filter {
    src_table_name = "policies"
    target_table_name = "policies"
    condition = contains {
        get_attr {"policies[].rule"}
        get_attr {"entry_point_filtered"}
    }
}

If no policy matches, the execution terminates gracefully.

4. Chain the NITRO calls

Call Endpoint Extracted field
CS action /nitro/v1/config/csaction/<action> targetlbvserver
Service group /nitro/v1/config/lbvserver_servicegroup_binding/<lbvserver> name
Members /nitro/v1/config/lbvserver_servicegroupmember_binding/<servicegroup> ipv46, port, curstate

5. Keep only UP members

 

filter {
    src_table_name = "connections"
    target_table_name = "connections"
    condition = eq { get_attr {"connections[].state"} "UP" }
}

6. Create the connection

 

create_connection {
    connection_type = CLUSTER
    cluster_name = get_attr {"entry_point_filtered"}
    entry_point_type = get_attr {"entry_point_obj.type"}
    attributes {
        attribute { name = "port" value = get_attr {"connections[*].service_port"} }
        attribute { name = "ip_address" value = get_attr {"connections[*].ip_address"} }
        attribute { name = "host_name" value = get_attr {"entry_point.host_name"} }
    }
    is_artificial = "false"
    traffic_based = "false"
}

Next, a match with is_empty {get_attr {"connections"}} and terminate_op = graceful ends the execution once the connection has been created.


Result

The map now continues from the Netscaler to the actual backend servers of the LB vServer selected by the CS policy, instead of stopping at the load balancer.

Picture1.png


Known limitations

  • Default partition only.
  • URL path-based policies only; hostname or header-based policies are not handled (evaluate and adjust for your use case if necessary).
  • LB vServers with service groups only (not lbvserver_service_binding).
  • Follows only the first policy and the first service group found (evaluate and adjust for your use case if necessary).
  • The policy is not validated against the entry point’s CS vServer (csvserver_cspolicy_binding). In environments with similar rules on different CS vServers, adding this validation is recommended (evaluate and adjust for your use case if necessary).
  • Members not in the UP state are discarded, so the map may change depending on backend health (evaluate and adjust for your use case if necessary).

Final thoughts

This approach works regardless of how the Netscaler horizontal discovery is done, whether via SNMP or the NITRO pattern, because it only acts on the connection section used by Service Mapping. Test it in a sub-production instance before promoting, and feel free to comment with improvements.

 

View original source

https://www.servicenow.com/community/itom-articles/service-mapping-for-netscaler-content-switching-via-nitro-api/ta-p/3612604