Skip to content

Scopes

The Scopes module handles hierachical structures such as scopes, sites, collections, and groups.


Device

device

Device(device_attributes=None, central_conn=None, serial=None, from_api=False)

Bases: ScopeBase

This class holds device and all of its attributes & related methods.

Constructor for Device object.

Parameters:

Name Type Description Default
device_attributes dict

Attributes of the Device

None
central_conn NewCentralBase

Instance of NewCentralBase to establish connection to Central

None
serial str

Serial number of the device (required if device_attributes is not provided)

None
from_api bool

Boolean indicates if the device_attributes is from the Central API response

False

Raises:

Type Description
ValueError

If neither serial nor device_attributes is provided

Source code in pycentral/scopes/device.py
def __init__(
    self,
    device_attributes=None,
    central_conn=None,
    serial=None,
    from_api=False,
):
    """Constructor for Device object.

    Args:
        device_attributes (dict, optional): Attributes of the Device
        central_conn (NewCentralBase, optional): Instance of NewCentralBase
            to establish connection to Central
        serial (str, optional): Serial number of the device (required if device_attributes
            is not provided)
        from_api (bool, optional): Boolean indicates if the device_attributes is from the
            Central API response

    Raises:
        ValueError: If neither serial nor device_attributes is provided
    """

    # If device_attributes is provided, use it to set attributes
    self.materialized = False
    self.central_conn = central_conn
    self.type = "device"
    if from_api:
        if device_attributes is None:
            raise ValueError(
                "'device_attributes' must be provided when 'from_api=True'."
            )
        self._apply_api_attributes(device_attributes)
        self.materialized = True
    # If only serial is provided, set it and defer fetching other details
    elif serial:
        self.serial = serial

    # If neither serial nor device_attributes is provided, raise an error
    else:
        raise ValueError(
            "Either 'serial' or 'device_attributes(from api response)' must be provided to create a Device."
        )

get_serial()

Returns the serial number of the device.

Returns:

Type Description
str

Value of self.serial

Source code in pycentral/scopes/device.py
def get_serial(self):
    """Returns the serial number of the device.

    Returns:
        (str): Value of self.serial
    """
    return fetch_attribute(self, "serial")

get()

Fetches the device details from the Central API using the serial number.

Returns:

Type Description
dict

Device attributes as a dictionary

Raises:

Type Description
Exception

If central_conn is not set

Source code in pycentral/scopes/device.py
def get(self):
    """Fetches the device details from the Central API using the serial number.

    Returns:
        (dict): Device attributes as a dictionary

    Raises:
        Exception: If central_conn is not set
    """
    if self.central_conn is None:
        raise Exception(
            "Unable to get device without Central connection. Please provide the central connection with the central_conn variable."
        )

    device_data = MonitoringDevices.get_device_inventory(
        central_conn=self.central_conn,
        filter_str=f"serialNumber eq {self.get_serial()}",
        limit=1,
    )
    self.materialized = len(device_data["items"]) == 1
    if not self.materialized:
        self.central_conn.logger.error(
            f"Unable to fetch device {self.get_serial()} from Central"
        )
    else:
        self._apply_api_attributes(device_data["items"][0])
        self.central_conn.logger.info(
            f"Successfully fetched device {self.get_serial()}'s data from Central."
        )
    return device_data

get_all_devices(central_conn, new_central_provisioned=False) staticmethod

Fetches all devices from Central, optionally filtering for new Central configured devices.

Parameters:

Name Type Description Default
central_conn NewCentralBase

Instance of NewCentralBase to establish connection to Central

required
new_central_provisioned bool

If True, only devices that are provisioned via New Central are returned

False

Returns:

Type Description
list

List of device dictionaries fetched from Central

Source code in pycentral/scopes/device.py
@staticmethod
def get_all_devices(central_conn, new_central_provisioned=False):
    """Fetches all devices from Central, optionally filtering for new Central configured devices.

    Args:
        central_conn (NewCentralBase): Instance of NewCentralBase to establish connection to Central
        new_central_provisioned (bool, optional): If True, only devices that are provisioned
            via New Central are returned

    Returns:
        (list): List of device dictionaries fetched from Central
    """
    device_list = MonitoringDevices.get_all_device_inventory(
        central_conn=central_conn
    )

    if device_list is None:
        central_conn.logger.error(
            "Failed to fetch device inventory from Central API."
        )
        return []

    if new_central_provisioned:
        return [
            device
            for device in device_list
            if device.get("isProvisioned") == "Yes"
        ]
    return device_list

__rename_keys(api_dict, api_attribute_mapping)

Renames the keys of the attributes from the API response.

Parameters:

Name Type Description Default
api_dict dict

Dict from Central API Response

required
api_attribute_mapping dict

Dict mapping API keys to object attributes

required

Returns:

Type Description
dict

Renamed dictionary of object attributes

Source code in pycentral/scopes/device.py
def __rename_keys(self, api_dict, api_attribute_mapping):
    """Renames the keys of the attributes from the API response.

    Args:
        api_dict (dict): Dict from Central API Response
        api_attribute_mapping (dict): Dict mapping API keys to object attributes

    Returns:
        (dict): Renamed dictionary of object attributes
    """
    integer_attributes = {"scopeId"}
    renamed_dict = {}
    for key, value in api_dict.items():
        new_key = api_attribute_mapping.get(key)
        if not new_key:
            continue  # Skip unknown keys
        if key in integer_attributes and value is not None:
            value = int(value)
        if key == "isProvisioned":
            value = True if value == "Yes" else False
        renamed_dict[new_key] = value
    return renamed_dict

ping_test(destination, **kwargs)

Initiates a ping test to the specified destination from the device.

Parameters:

Name Type Description Default
destination str

The IP address or hostname to ping

required
**kwargs (dict, Optional)

Optional arguments specific to device type. See below for details:

{}

Returns: (dict): Result of the ping test

Raises:

Type Description
ValueError

If device type is unsupported

Source code in pycentral/scopes/device.py
def ping_test(self, destination, **kwargs):
    """Initiates a ping test to the specified destination from the device.

    Args:
        destination (str): The IP address or hostname to ping
        **kwargs (dict, Optional): Optional arguments specific to device type. See below for details:

            - CX switches - [Troubleshooting.ping_cx_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.ping_cx_test) parameters.
            - AOS-S switches - [Troubleshooting.ping_aoss_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.ping_aoss_test) parameters.
            - Access Points - [Troubleshooting.ping_aps_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.ping_aps_test) parameters.
            - Gateways - [Troubleshooting.ping_gateways_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.ping_gateways_test) parameters.
    Returns:
        (dict): Result of the ping test

    Raises:
        ValueError: If device type is unsupported
    """
    if (
        self.device_type == "SWITCH"
        and self._identify_switch_os() == CX_API_ENDPOINT
    ):
        return Troubleshooting.ping_cx_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    elif (
        self.device_type == "SWITCH"
        and self._identify_switch_os() == AOS_S_API_ENDPOINT
    ):
        return Troubleshooting.ping_aoss_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    elif self.device_type == "ACCESS_POINT":
        return Troubleshooting.ping_aps_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    elif self.device_type == "GATEWAY":
        return Troubleshooting.ping_gateways_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    else:
        raise ValueError(
            f"Ping test is not supported for device type {self.device_type}."
        )

traceroute_test(destination, **kwargs)

Initiates a traceroute test to the specified destination from the device.

Supported device types: All (aps, cx, aos-s, gateways)

Parameters:

Name Type Description Default
destination str

The IP address or hostname to traceroute

required
**kwargs (dict, Optional)

Optional arguments specific to device type. See below for details:

{}

Returns: (dict): Result of the traceroute test

Raises:

Type Description
ValueError

If device type is unsupported

Source code in pycentral/scopes/device.py
def traceroute_test(self, destination, **kwargs):
    """Initiates a traceroute test to the specified destination from the device.

    Supported device types: All (aps, cx, aos-s, gateways)

    Args:
        destination (str): The IP address or hostname to traceroute
        **kwargs (dict, Optional): Optional arguments specific to device type. See below for details:

            - CX switches - [Troubleshooting.traceroute_cx_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.traceroute_cx_test) parameters.
            - AOS-S switches - [Troubleshooting.traceroute_aoss_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.traceroute_aoss_test) parameters.
            - Access Points - [Troubleshooting.traceroute_aps_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.traceroute_aps_test) parameters.
            - Gateways - [Troubleshooting.traceroute_gateways_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.traceroute_gateways_test) parameters.
    Returns:
        (dict): Result of the traceroute test

    Raises:
        ValueError: If device type is unsupported
    """
    if (
        self.device_type == "SWITCH"
        and self._identify_switch_os() == CX_API_ENDPOINT
    ):
        return Troubleshooting.traceroute_cx_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    elif (
        self.device_type == "SWITCH"
        and self._identify_switch_os() == AOS_S_API_ENDPOINT
    ):
        return Troubleshooting.traceroute_aoss_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    elif self.device_type == "ACCESS_POINT":
        return Troubleshooting.traceroute_aps_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    elif self.device_type == "GATEWAY":
        return Troubleshooting.traceroute_gateways_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    else:
        raise ValueError(
            f"traceroute test is not supported for device type {self.device_type}."
        )

reboot()

Reboots the device.

Supported device types: All (aps, cx, aos-s, gateways)

Returns:

Type Description
dict

Result of the reboot operation

Source code in pycentral/scopes/device.py
def reboot(self):
    """Reboots the device.

    Supported device types: All (aps, cx, aos-s, gateways)

    Returns:
        (dict): Result of the reboot operation
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.reboot_device
    )

locate_test()

Initiates a locate test (LED blinking) on the device.

Supported device types: cx, aps, aos-s (gateways not supported)

Returns:

Type Description
dict

Result of the locate test

Source code in pycentral/scopes/device.py
def locate_test(self):
    """Initiates a locate test (LED blinking) on the device.

    Supported device types: cx, aps, aos-s (gateways not supported)

    Returns:
        (dict): Result of the locate test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.locate_device
    )

disconnect_all_clients()

Disconnects all clients from the specified device.

Supported device types: gateways (other devices not supported)

Returns:

Type Description
dict

Result of the disconnect all clients operation

Source code in pycentral/scopes/device.py
def disconnect_all_clients(self):
    """Disconnects all clients from the specified device.

    Supported device types: gateways (other devices not supported)

    Returns:
        (dict): Result of the disconnect all clients operation
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.disconnect_all_clients
    )

disconnect_all_users()

Disconnects all users from the specified device.

Supported device types: aps (other devices not supported)

Returns:

Type Description
dict

Result of the disconnect all users operation

Source code in pycentral/scopes/device.py
def disconnect_all_users(self):
    """Disconnects all users from the specified device.

    Supported device types: aps (other devices not supported)

    Returns:
        (dict): Result of the disconnect all users operation
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.disconnect_all_users
    )

disconnect_client_mac_addr(mac_address)

Disconnects client with the specified MAC address on the device.

Supported device types: gateways (other devices not supported)

Parameters:

Name Type Description Default
mac_address str

The MAC address from which to disconnect client

required

Returns:

Type Description
dict

Result of the disconnect client operation

Source code in pycentral/scopes/device.py
def disconnect_client_mac_addr(self, mac_address):
    """Disconnects client with the specified MAC address on the device.

    Supported device types: gateways (other devices not supported)

    Args:
        mac_address (str): The MAC address from which to disconnect client

    Returns:
        (dict): Result of the disconnect client operation
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.disconnect_client_mac_addr,
        mac_address=mac_address,
    )

disconnect_user_mac_addr(mac_address)

Disconnects user with the specified MAC address on the device.

Supported device types: aps (other devices not supported)

Parameters:

Name Type Description Default
mac_address str

The MAC address from which to disconnect user

required

Returns:

Type Description
dict

Result of the disconnect user operation

Source code in pycentral/scopes/device.py
def disconnect_user_mac_addr(self, mac_address):
    """Disconnects user with the specified MAC address on the device.

    Supported device types: aps (other devices not supported)

    Args:
        mac_address (str): The MAC address from which to disconnect user

    Returns:
        (dict): Result of the disconnect user operation
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.disconnect_user_mac_addr,
        mac_address=mac_address,
    )

disconnect_all_users_ssid(network)

Disconnects all users from the specified SSID on the device.

Supported device types: aps (other devices not supported)

Parameters:

Name Type Description Default
network str

The SSID from which to disconnect users

required

Returns:

Type Description
dict

Result of the disconnect all users operation

Source code in pycentral/scopes/device.py
def disconnect_all_users_ssid(self, network):
    """Disconnects all users from the specified SSID on the device.

    Supported device types: aps (other devices not supported)

    Args:
        network (str): The SSID from which to disconnect users

    Returns:
        (dict): Result of the disconnect all users operation
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.disconnect_all_users_ssid, network=network
    )

http_test(destination, **kwargs)

Initiates an HTTP test to the specified destination from the device.

Supported device types: cx, aps, gateways

Parameters:

Name Type Description Default
destination str

The IP address or hostname to test

required
**kwargs (dict, Optional)

Optional arguments specific to device type, see Troubleshooting.http_test() for detailed parameter information.

{}

Returns:

Type Description
dict

Result of the HTTP test

Source code in pycentral/scopes/device.py
def http_test(self, destination, **kwargs):
    """Initiates an HTTP test to the specified destination from the device.

    Supported device types: cx, aps, gateways

    Args:
        destination (str): The IP address or hostname to test
        **kwargs (dict, Optional): Optional arguments specific to device
            type, see [Troubleshooting.http_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.http_test)
            for detailed parameter information.

    Returns:
        (dict): Result of the HTTP test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.http_test, destination=destination, **kwargs
    )

https_test(destination, **kwargs)

Initiates an HTTPS test to the specified destination from the device.

Supported device types: aps, gateways, cx (uses HTTP endpoint with HTTPS protocol)

Parameters:

Name Type Description Default
destination str

The IP address or hostname to test

required
**kwargs (dict, Optional)

Optional arguments specific to device type. See below for details:

{}

Returns:

Type Description
dict

Result of the HTTPS test

Raises:

Type Description
ValueError

If device type is unsupported

Source code in pycentral/scopes/device.py
def https_test(self, destination, **kwargs):
    """Initiates an HTTPS test to the specified destination from the device.

    Supported device types: aps, gateways, cx (uses HTTP endpoint with HTTPS protocol)

    Args:
        destination (str): The IP address or hostname to test
        **kwargs (dict, Optional): Optional arguments specific to device type. See below for details:

            - CX switches - [Troubleshooting.https_cx_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.https_cx_test) parameters.
            - Access Points - [Troubleshooting.https_aps_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.https_aps_test) parameters.
            - Gateways - [Troubleshooting.https_gateways_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.https_gateways_test) parameters.

    Returns:
        (dict): Result of the HTTPS test

    Raises:
        ValueError: If device type is unsupported
    """
    self._ensure_materialized()

    if (
        self.device_type == "SWITCH"
        and self._identify_switch_os() == CX_API_ENDPOINT
    ):
        return Troubleshooting.https_cx_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    elif self.device_type == "ACCESS_POINT":
        return Troubleshooting.https_aps_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    elif self.device_type == "GATEWAY":
        return Troubleshooting.https_gateways_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            destination=destination,
            **kwargs,
        )
    else:
        raise ValueError(
            f"HTTPS test is not supported for device type {self.device_type}."
        )

port_bounce_test(ports, **kwargs)

Initiates a port bounce test on the specified ports.

Supported device types: cx, aos-s, gateways

Parameters:

Name Type Description Default
ports list

List of ports to test

required
**kwargs (dict, Optional)

Optional arguments for the port bounce test. See Troubleshooting.port_bounce_test() for detailed parameter information.

{}

Returns:

Type Description
dict

Result of the port bounce test

Source code in pycentral/scopes/device.py
def port_bounce_test(self, ports, **kwargs):
    """Initiates a port bounce test on the specified ports.

    Supported device types: cx, aos-s, gateways

    Args:
        ports (list): List of ports to test
        **kwargs (dict, Optional): Optional arguments for the port bounce test.
            See [Troubleshooting.port_bounce_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.port_bounce_test) for detailed parameter information.

    Returns:
        (dict): Result of the port bounce test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.port_bounce_test, ports=ports, **kwargs
    )

poe_bounce_test(ports, **kwargs)

Initiates a PoE bounce test on the specified ports.

Supported device types: cx, aos-s, gateways

Parameters:

Name Type Description Default
ports list

List of ports to test

required
**kwargs (dict, Optional)

Optional arguments for the PoE bounce test. See Troubleshooting.poe_bounce_test() for detailed parameter information.

{}

Returns:

Type Description
dict

Result of the PoE bounce test

Source code in pycentral/scopes/device.py
def poe_bounce_test(self, ports, **kwargs):
    """Initiates a PoE bounce test on the specified ports.

    Supported device types: cx, aos-s, gateways

    Args:
        ports (list): List of ports to test
        **kwargs (dict, Optional): Optional arguments for the PoE bounce test.
            See [Troubleshooting.poe_bounce_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.poe_bounce_test) for detailed parameter information.

    Returns:
        (dict): Result of the PoE bounce test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.poe_bounce_test, ports=ports, **kwargs
    )

arp_test()

Initiates an ARP table retrieval test on the device.

Supported device types: aos-s, aps, gateways

Returns:

Type Description
dict

Result of the ARP test

Source code in pycentral/scopes/device.py
def arp_test(self):
    """Initiates an ARP table retrieval test on the device.

    Supported device types: aos-s, aps, gateways

    Returns:
        (dict): Result of the ARP test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.retrieve_arp_table_test
    )

nslookup_test(host, **kwargs)

Initiates an NSLOOKUP test on the device.

Supported device types: aps

Parameters:

Name Type Description Default
host str

The hostname or IP address to resolve

required
**kwargs (dict, Optional)

Optional arguments for the NSLOOKUP test. See Troubleshooting.nslookup_test() for detailed parameter information.

{}

Returns:

Type Description
dict

Result of the NSLOOKUP test

Source code in pycentral/scopes/device.py
def nslookup_test(self, host, **kwargs):
    """Initiates an NSLOOKUP test on the device.

    Supported device types: aps

    Args:
        host (str): The hostname or IP address to resolve
        **kwargs (dict, Optional): Optional arguments for the NSLOOKUP test.
            See [Troubleshooting.nslookup_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.nslookup_test) for detailed parameter information.

    Returns:
        (dict): Result of the NSLOOKUP test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.nslookup_test, host=host, **kwargs
    )

speedtest_test(iperf_server_address, **kwargs)

Initiates a speed test using the specified iPerf server address.

Supported device types: aps only

Parameters:

Name Type Description Default
iperf_server_address str

The IP address or hostname of the iPerf server

required
**kwargs (dict, Optional)

Optional arguments for the speed test. See Troubleshooting.speedtest_test() for detailed parameter information.

{}

Returns:

Type Description
dict

Result of the speed test

Source code in pycentral/scopes/device.py
def speedtest_test(self, iperf_server_address, **kwargs):
    """Initiates a speed test using the specified iPerf server address.

    Supported device types: aps only

    Args:
        iperf_server_address (str): The IP address or hostname of the iPerf server
        **kwargs (dict, Optional): Optional arguments for the speed test.
            See [Troubleshooting.speedtest_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.speedtest_test) for detailed parameter information.

    Returns:
        (dict): Result of the speed test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.speedtest_test,
        iperf_server_address=iperf_server_address,
        **kwargs,
    )

tcp_test(host, port, **kwargs)

Initiates a TCP test to the specified host and port from the device.

Supported device types: aps only

Parameters:

Name Type Description Default
host str

The IP address or hostname to test

required
port int

The port number to test

required
**kwargs (dict, Optional)

Optional arguments for the TCP test. See Troubleshooting.tcp_test() for detailed parameter information.

{}

Returns:

Type Description
dict

Result of the TCP test

Source code in pycentral/scopes/device.py
def tcp_test(self, host, port, **kwargs):
    """Initiates a TCP test to the specified host and port from the device.

    Supported device types: aps only

    Args:
        host (str): The IP address or hostname to test
        port (int): The port number to test
        **kwargs (dict, Optional): Optional arguments for the TCP test.
            See [Troubleshooting.tcp_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.tcp_test) for detailed parameter information.

    Returns:
        (dict): Result of the TCP test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.tcp_test, host=host, port=port, **kwargs
    )

aaa_test(radius_server_ip, username, password, **kwargs)

Initiates an AAA test with the specified parameters.

CX devices require auth_method_type as a parameter. Supported device types: aps and cx only

Parameters:

Name Type Description Default
radius_server_ip str

RADIUS server IP address, hostname is valid for APs only

required
username str

Username for authentication

required
password str

Password for authentication

required
**kwargs (dict, Optional)

Optional arguments specific to device type. See below for details:

{}

Returns:

Type Description
dict

Result of the AAA test

Raises:

Type Description
ValueError

If device type is unsupported

Source code in pycentral/scopes/device.py
def aaa_test(self, radius_server_ip, username, password, **kwargs):
    """Initiates an AAA test with the specified parameters.

    CX devices require auth_method_type as a parameter.
    Supported device types: aps and cx only

    Args:
        radius_server_ip (str): RADIUS server IP address, hostname is valid for APs only
        username (str): Username for authentication
        password (str): Password for authentication
        **kwargs (dict, Optional): Optional arguments specific to device type. See below for details:

            - CX switches - `auth_method_type` (str) is required (`chap` or `pap`), [Troubleshooting.aaa_cx_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.aaa_cx_test)
              parameters.
            - Access Points - [Troubleshooting.aaa_aps_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.aaa_aps_test) parameters.

    Returns:
        (dict): Result of the AAA test

    Raises:
        ValueError: If device type is unsupported
    """
    self._ensure_materialized()

    if (
        self.device_type == "SWITCH"
        and self._identify_switch_os() == CX_API_ENDPOINT
    ):
        return Troubleshooting.aaa_cx_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            radius_server_ip=radius_server_ip,
            username=username,
            password=password,
            **kwargs,
        )
    elif self.device_type == "ACCESS_POINT":
        return Troubleshooting.aaa_aps_test(
            central_conn=self.central_conn,
            serial_number=self.serial,
            radius_server_ip=radius_server_ip,
            username=username,
            password=password,
            **kwargs,
        )
    else:
        raise ValueError(
            f"AAA test is not supported for device type {self.device_type}."
        )

cable_test(ports, **kwargs)

Initiates a Cable test on the specified ports.

Supported device types: cx, aos-s

Parameters:

Name Type Description Default
ports list

List of ports to test

required
**kwargs (dict, Optional)

Optional arguments for the cable test. See Troubleshooting.cable_test() for detailed parameter information.

{}

Returns:

Type Description
dict

Result of the Cable test

Source code in pycentral/scopes/device.py
def cable_test(self, ports, **kwargs):
    """Initiates a Cable test on the specified ports.

    Supported device types: cx, aos-s

    Args:
        ports (list): List of ports to test
        **kwargs (dict, Optional): Optional arguments for the cable test.
            See [Troubleshooting.cable_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.cable_test) for detailed parameter information.

    Returns:
        (dict): Result of the Cable test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.cable_test, ports=ports, **kwargs
    )

iperf_test(server_address, **kwargs)

Initiates an iPerf test using the specified server address.

Supported device types: gateways only

Parameters:

Name Type Description Default
server_address str

The IP address or hostname of the iPerf server

required
**kwargs (dict, Optional)

Optional arguments for the iPerf test. See Troubleshooting.iperf_test() for detailed parameter information.

{}

Returns:

Type Description
dict

Result of the iPerf test

Source code in pycentral/scopes/device.py
def iperf_test(self, server_address, **kwargs):
    """Initiates an iPerf test using the specified server address.

    Supported device types: gateways only

    Args:
        server_address (str): The IP address or hostname of the iPerf server
        **kwargs (dict, Optional): Optional arguments for the iPerf test.
            See [Troubleshooting.iperf_test()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.iperf_test) for detailed parameter information.

    Returns:
        (dict): Result of the iPerf test
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.iperf_test,
        server_address=server_address,
        **kwargs,
    )

list_show_commands()

Returns most used/top 'show' commands supported on this device.

Supported device types: aps, gateways, cx, aos-s

Returns:

Type Description
list or dict

List of show commands organized by category if successful, otherwise full response dict

Source code in pycentral/scopes/device.py
def list_show_commands(self):
    """Returns most used/top 'show' commands supported on this device.

    Supported device types: aps, gateways, cx, aos-s

    Returns:
        (list or dict): List of show commands organized by category if successful, otherwise full response dict
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.list_show_commands
    )

run_show_commands(commands, **kwargs)

Runs 'show' command(s) on the device and polls for test result.

All commands must start with 'show '.

Supported device types: aps, gateways, cx, aos-s

Parameters:

Name Type Description Default
commands str or list

Single show command as string (e.g., "show version") or list of show commands (e.g., ["show version", "show ip route"]). Max 20 commands. All commands must start with 'show '.

required
**kwargs (dict, Optional)

Optional arguments for the show command test. See Troubleshooting.run_show_command() for detailed parameter information.

{}

Returns:

Type Description
dict

Response from the test results API

Source code in pycentral/scopes/device.py
def run_show_commands(self, commands, **kwargs):
    """Runs 'show' command(s) on the device and polls for test result.

    All commands must start with 'show '.

    Supported device types: aps, gateways, cx, aos-s

    Args:
        commands (str or list): Single show command as string (e.g., "show version") or
            list of show commands (e.g., ["show version", "show ip route"]). Max 20 commands.
            All commands must start with 'show '.
        **kwargs (dict, Optional): Optional arguments for the show command test.
            See [Troubleshooting.run_show_command()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.run_show_command) for detailed parameter information.

    Returns:
        (dict): Response from the test results API
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.run_show_commands, commands=commands, **kwargs
    )

list_active_tasks()

Retrieves a list of all active or recently completed asynchronous operations for this device, grouped by test name.

Results are sorted by startTime in descending order (most recently started first).

Supported device types: aps, gateways, cx, aos-s

Returns:

Type Description
dict

Response containing list of active tasks grouped by test name

Source code in pycentral/scopes/device.py
def list_active_tasks(self):
    """Retrieves a list of all active or recently completed asynchronous operations for this device, grouped by test name.

    Results are sorted by startTime in descending order (most recently started first).

    Supported device types: aps, gateways, cx, aos-s

    Returns:
        (dict): Response containing list of active tasks grouped by test name
    """
    return self._execute_troubleshooting_command(
        Troubleshooting.list_active_tasks
    )

list_events(**kwargs)

Retrieves a list of Network Events for this device based on the query parameters provided.

Supported device types: All (aps, cx, aos-s, gateways)

Parameters:

Name Type Description Default
**kwargs (dict, Optional)

Arguments for event listing. See Troubleshooting.list_events() for all parameters. Required parameters: site_id and either duration or both start_at and end_at

{}

Returns:

Type Description
dict

Response containing events list, count, total, and pagination cursor

Source code in pycentral/scopes/device.py
def list_events(self, **kwargs):
    """Retrieves a list of Network Events for this device based on the query parameters provided.

    Supported device types: All (aps, cx, aos-s, gateways)

    Args:
        **kwargs (dict, Optional): Arguments for event listing. See [Troubleshooting.list_events()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.list_events) for all parameters.
            Required parameters: site_id and either duration or both start_at and end_at

    Returns:
        (dict): Response containing events list, count, total, and pagination cursor
    """
    self._ensure_materialized()

    return Troubleshooting.list_events(
        central_conn=self.central_conn,
        context_type=self.device_type,
        context_id=self.serial,
        **kwargs,
    )

list_event_filters(**kwargs)

Retrieves available event filter options for this device.

Supported device types: All (aps, cx, aos-s, gateways)

Parameters:

Name Type Description Default
**kwargs (dict, Optional)

Arguments for event filter listing. See Troubleshooting.list_event_filters() for all parameters. Required parameters: site_id and either duration or both start_at and end_at

{}

Returns:

Type Description
dict

Response containing available event filter options

Source code in pycentral/scopes/device.py
def list_event_filters(self, **kwargs):
    """Retrieves available event filter options for this device.

    Supported device types: All (aps, cx, aos-s, gateways)

    Args:
        **kwargs (dict, Optional): Arguments for event filter listing. See [Troubleshooting.list_event_filters()](troubleshooting.md#pycentral.troubleshooting.troubleshooting.Troubleshooting.list_event_filters) for all parameters.
            Required parameters: site_id and either duration or both start_at and end_at

    Returns:
        (dict): Response containing available event filter options
    """
    self._ensure_materialized()

    return Troubleshooting.list_event_filters(
        central_conn=self.central_conn,
        context_type=self.device_type,
        context_id=self.serial,
        **kwargs,
    )

Device Group

device_group

Device_Group(device_group_attributes=None, central_conn=None, from_api=False)

Bases: ScopeBase

This class holds device groups and all of its attributes & related methods.

Constructor for Device Group object.

Parameters:

Name Type Description Default
device_group_attributes dict

Attributes of the Device Group

None
central_conn NewCentralBase

Instance of NewCentralBase to establish connection to Central

None
from_api bool

Boolean indicates if the device_group_attributes is from the Central API response

False

Raises:

Type Description
Exception

If from_api is False (currently not supported)

Source code in pycentral/scopes/device_group.py
def __init__(
    self, device_group_attributes=None, central_conn=None, from_api=False
):
    """Constructor for Device Group object.

    Args:
        device_group_attributes (dict, optional): Attributes of the Device Group
        central_conn (NewCentralBase, optional): Instance of NewCentralBase
            to establish connection to Central
        from_api (bool, optional): Boolean indicates if the device_group_attributes is from the
            Central API response

    Raises:
        Exception: If from_api is False (currently not supported)
    """
    self.materialized = from_api
    self.central_conn = central_conn
    self.type = "device_group"
    if from_api:
        # Rename keys if attributes are from API
        device_group_attributes = self.__rename_keys(
            device_group_attributes, API_ATTRIBUTE_MAPPING
        )
        device_group_attributes["assigned_profiles"] = []
        device_group_attributes["devices"] = []
        for key, value in device_group_attributes.items():
            setattr(self, key, value)
    else:
        raise Exception(
            "Currently, Device Group requires attributes from API response to be created."
        )

__rename_keys(api_dict, api_attribute_mapping)

Renames the keys of the attributes from the API response.

Parameters:

Name Type Description Default
api_dict dict

Dict from Central API Response

required
api_attribute_mapping dict

Dict mapping API keys to object attributes

required

Returns:

Type Description
dict

Renamed dictionary of object attributes

Source code in pycentral/scopes/device_group.py
def __rename_keys(self, api_dict, api_attribute_mapping):
    """Renames the keys of the attributes from the API response.

    Args:
        api_dict (dict): Dict from Central API Response
        api_attribute_mapping (dict): Dict mapping API keys to object attributes

    Returns:
        (dict): Renamed dictionary of object attributes
    """
    integer_attributes = {"id"}
    renamed_dict = {}

    for key, value in api_dict.items():
        new_key = api_attribute_mapping.get(key)
        if not new_key:
            continue  # Skip unknown keys
        if key in integer_attributes and value is not None:
            value = int(value)
        renamed_dict[new_key] = value
    return renamed_dict

Scope Base

scope_base

ScopeBase

Base class for all scope elements, such as Site, Site_Collection, and Device.

Provides common functionality like
  • Returning the object's ID or name.
  • Assigning and unassigning profiles.

get_id()

Fetches the ID of the scope element.

Returns:

Type Description
int

ID of the scope element

Source code in pycentral/scopes/scope_base.py
def get_id(self):
    """Fetches the ID of the scope element.

    Returns:
        (int): ID of the scope element
    """
    return fetch_attribute(self, "id")

get_name()

Fetches the name of the scope element.

Returns:

Type Description
str

Name of the scope element

Source code in pycentral/scopes/scope_base.py
def get_name(self):
    """Fetches the name of the scope element.

    Returns:
        (str): Name of the scope element
    """
    return fetch_attribute(self, "name")

get_type()

Fetches the type of the scope element.

Returns:

Type Description
str

Type of the scope element (e.g., 'site', 'site_collection', 'device')

Source code in pycentral/scopes/scope_base.py
def get_type(self):
    """Fetches the type of the scope element.

    Returns:
        (str): Type of the scope element (e.g., 'site', 'site_collection', 'device')
    """
    return fetch_attribute(self, "type")

assign_profile(profile_name, profile_persona=None)

Assigns a profile with the provided name and persona to the scope.

Parameters:

Name Type Description Default
profile_name str

Name of the profile to assign

required
profile_persona str

Device Persona of the profile to assign. Optional if assigning a profile to a device

None

Returns:

Type Description
bool

True if the profile assignment was successful, False otherwise

Source code in pycentral/scopes/scope_base.py
def assign_profile(self, profile_name, profile_persona=None):
    """Assigns a profile with the provided name and persona to the scope.

    Args:
        profile_name (str): Name of the profile to assign
        profile_persona (str, optional): Device Persona of the profile to assign.
            Optional if assigning a profile to a device

    Returns:
        (bool): True if the profile assignment was successful, False otherwise
    """
    profile_persona = self._resolve_profile_persona(profile_persona)
    if profile_persona is None:
        return False

    resp = scope_maps.associate_profile_to_scope(
        central_conn=self.central_conn,
        scope_id=self.get_id(),
        profile_name=profile_name,
        persona=profile_persona,
    )
    if resp["code"] == 200:
        self.add_profile(name=profile_name, persona=profile_persona)
        return True
    else:
        self.central_conn.logger.error(
            "Unable to assign profile "
            + profile_name
            + " to "
            + self.get_name()
        )
        return False

unassign_profile(profile_name, profile_persona=None)

Unassigns a profile with the provided name and persona from the scope.

Parameters:

Name Type Description Default
profile_name str

Name of the profile to unassign

required
profile_persona str

Persona of the profile to unassign. Optional if unassigning a profile from a device

None

Returns:

Type Description
bool

True if the profile unassignment was successful, False otherwise

Source code in pycentral/scopes/scope_base.py
def unassign_profile(self, profile_name, profile_persona=None):
    """Unassigns a profile with the provided name and persona from the scope.

    Args:
        profile_name (str): Name of the profile to unassign
        profile_persona (str, optional): Persona of the profile to unassign.
            Optional if unassigning a profile from a device

    Returns:
        (bool): True if the profile unassignment was successful, False otherwise
    """
    profile_persona = self._resolve_profile_persona(profile_persona)
    if profile_persona is None:
        return False

    resp = scope_maps.unassociate_profile_from_scope(
        central_conn=self.central_conn,
        scope_id=self.get_id(),
        profile_name=profile_name,
        persona=profile_persona,
    )
    if resp["code"] == 200:
        self.remove_profile(name=profile_name, persona=profile_persona)
        return True
    else:
        self.central_conn.logger.error(
            "Unable to unassign profile "
            + profile_name
            + " to "
            + self.get_name()
        )
        return False

add_profile(name, persona)

Helper function that adds a profile to the assigned profiles of the scope in the SDK.

Parameters:

Name Type Description Default
name str

Name of the profile to add

required
persona str

Device Persona of the profile to add

required
Source code in pycentral/scopes/scope_base.py
def add_profile(self, name, persona):
    """Helper function that adds a profile to the assigned profiles of the scope in the SDK.

    Args:
        name (str): Name of the profile to add
        persona (str): Device Persona of the profile to add
    """
    self.assigned_profiles.append({"persona": persona, "resource": name})

remove_profile(name, persona)

Helper function that removes a profile from the assigned profiles of the scope in the SDK.

Parameters:

Name Type Description Default
name str

Name of the profile to remove

required
persona str

Device Persona of the profile to remove

required

Returns:

Type Description
bool

True if the profile was successfully removed, False otherwise

Source code in pycentral/scopes/scope_base.py
def remove_profile(self, name, persona):
    """Helper function that removes a profile from the assigned profiles of the scope in the SDK.

    Args:
        name (str): Name of the profile to remove
        persona (str): Device Persona of the profile to remove

    Returns:
        (bool): True if the profile was successfully removed, False otherwise
    """
    remove_status = False
    index = None
    for id_element, element in enumerate(self.assigned_profiles):
        if element["persona"] == persona and element["resource"] == name:
            index = id_element
            break
    if index is not None:
        self.assigned_profiles.pop(index)
        remove_status = True
    return remove_status

Scope Maps

scope_maps

ScopeMaps()

Source code in pycentral/scopes/scope_maps.py
def __init__(self):
    pass

get(central_conn)

Perform a GET call to retrieve data for the Global Scope Map.

Parameters:

Name Type Description Default
central_conn NewCentralBase

Established Central connection object

required

Returns:

Type Description
list

List of scope map dictionaries if success, empty list otherwise

Source code in pycentral/scopes/scope_maps.py
def get(self, central_conn):
    """Perform a GET call to retrieve data for the Global Scope Map.

    Args:
        central_conn (NewCentralBase): Established Central connection object

    Returns:
        (list): List of scope map dictionaries if success, empty list otherwise
    """
    scope_maps_list = []
    api_method = "GET"
    api_path = generate_url(SCOPE_URLS["SCOPE-MAPS"])
    resp = central_conn.command(api_method=api_method, api_path=api_path)
    if resp["code"] == 200:
        for mapping in resp["msg"]["scope-map"]:
            mapping["scope-name"] = int(mapping["scope-name"])
        scope_maps_list = resp["msg"]["scope-map"]
    else:
        central_conn.logger.error(
            f"Unable to fetch scope maps data. Error code - {resp['code']}.\n Error Description - {resp['msg']}"
        )
    return scope_maps_list

get_scope_assigned_profiles(central_conn, scope_id)

Performs a GET call to retrieve Global Scope Map then finds matching scope.

Parameters:

Name Type Description Default
central_conn NewCentralBase

Established Central connection object

required
scope_id int

ID of the scope to be matched on

required

Returns:

Type Description
list

List of assigned profile dictionaries for the scope

Source code in pycentral/scopes/scope_maps.py
def get_scope_assigned_profiles(self, central_conn, scope_id):
    """Performs a GET call to retrieve Global Scope Map then finds matching scope.

    Args:
        central_conn (NewCentralBase): Established Central connection object
        scope_id (int): ID of the scope to be matched on

    Returns:
        (list): List of assigned profile dictionaries for the scope
    """
    assigned_profiles = []
    mappings = self.get(central_conn=central_conn)
    if mappings:
        for mapping in mappings:
            if mapping["scope-name"] == scope_id:
                assigned_profiles.append(mapping)
    for profile in assigned_profiles:
        profile.pop("scope-name")
    return assigned_profiles

associate_profile_to_scope(central_conn, scope_id, profile_name, persona)

Performs a POST call to associate a profile with device persona to the provided scope.

Parameters:

Name Type Description Default
central_conn NewCentralBase

Established Central connection object

required
scope_id int or str

ID of the scope to associate the profile

required
profile_name str

Name of the profile to be assigned

required
persona str or list

Device persona(s) to be associated with the profile. Valid values: SERVICE_PERSONA, HYBRID_NAC, CORE_SWITCH, BRIDGE, CAMPUS_AP, IOT, MOBILITY_GW, AGG_SWITCH, BRANCH_GW, VPNC, ACCESS_SWITCH, MICROBRANCH_AP, or "ALL"

required

Returns:

Type Description
dict

JSON Data of returned response from POST call

Source code in pycentral/scopes/scope_maps.py
def associate_profile_to_scope(self, central_conn, scope_id, profile_name, persona):
    """Performs a POST call to associate a profile with device persona to the provided scope.

    Args:
        central_conn (NewCentralBase): Established Central connection object
        scope_id (int or str): ID of the scope to associate the profile
        profile_name (str): Name of the profile to be assigned
        persona (str or list): Device persona(s) to be associated with the profile.
            Valid values: SERVICE_PERSONA, HYBRID_NAC, CORE_SWITCH, BRIDGE,
            CAMPUS_AP, IOT, MOBILITY_GW, AGG_SWITCH, BRANCH_GW, VPNC,
            ACCESS_SWITCH, MICROBRANCH_AP, or "ALL"

    Returns:
        (dict): JSON Data of returned response from POST call
    """
    if not profile_name:
        raise ParameterError("profile_name is required and cannot be empty")
    if not persona or (isinstance(persona, list) and len(persona) == 0):
        raise ParameterError("persona is required and cannot be empty")
    api_method = "POST"
    api_path = generate_url(SCOPE_URLS["SCOPE-MAPS"])
    if isinstance(persona, list) or persona == "ALL":
        if persona == "ALL":
            persona = VALID_PERSONAS
        for p in persona:
            if p not in VALID_PERSONAS:
                central_conn.logger.error(
                    f'{p} is not a valid device persona. Unable to assign profile {profile_name} to "{scope_id}"'
                )
            api_data = {
                "scope-map": [
                    {
                        "scope-name": str(scope_id),
                        "persona": p,
                        "resource": profile_name,
                    }
                ]
            }
            resp = central_conn.command(
                api_method=api_method, api_path=api_path, api_data=api_data
            )
            if resp["code"] == 200:
                central_conn.logger.info(
                    f"Successfully assigned profile {profile_name} to"
                    f" {scope_id} with {p} device persona"
                )
    else:
        api_data = {
            "scope-map": [
                {
                    "scope-name": str(scope_id),
                    "persona": persona,
                    "resource": profile_name,
                }
            ]
        }

        resp = central_conn.command(
            api_method=api_method, api_path=api_path, api_data=api_data
        )

        if resp["code"] == 200:
            central_conn.logger.info(
                f"Successfully assigned profile {profile_name} to "
                f"{scope_id} with {persona} device persona"
            )
    return resp

unassociate_profile_from_scope(central_conn, scope_id, profile_name, persona)

Performs a DELETE call to unassign a profile with device persona from the provided scope.

Parameters:

Name Type Description Default
central_conn NewCentralBase

Established Central connection object

required
scope_id int or str

ID of the scope to unassociate the profile from

required
profile_name str

Name of the profile to be unassigned

required
persona str or list

Device persona(s) to be unassociated from the profile. Valid values: SERVICE_PERSONA, HYBRID_NAC, CORE_SWITCH, BRIDGE, CAMPUS_AP, IOT, MOBILITY_GW, AGG_SWITCH, BRANCH_GW, VPNC, ACCESS_SWITCH, MICROBRANCH_AP, or "ALL"

required

Returns:

Type Description
dict

JSON Data of returned response from DELETE call

Source code in pycentral/scopes/scope_maps.py
def unassociate_profile_from_scope(
    self, central_conn, scope_id, profile_name, persona
):
    """Performs a DELETE call to unassign a profile with device persona from the provided scope.

    Args:
        central_conn (NewCentralBase): Established Central connection object
        scope_id (int or str): ID of the scope to unassociate the profile from
        profile_name (str): Name of the profile to be unassigned
        persona (str or list): Device persona(s) to be unassociated from the profile.
            Valid values: SERVICE_PERSONA, HYBRID_NAC, CORE_SWITCH, BRIDGE,
            CAMPUS_AP, IOT, MOBILITY_GW, AGG_SWITCH, BRANCH_GW, VPNC,
            ACCESS_SWITCH, MICROBRANCH_AP, or "ALL"

    Returns:
        (dict): JSON Data of returned response from DELETE call
    """
    if not profile_name:
        raise ParameterError("profile_name is required and cannot be empty")
    if not persona or (isinstance(persona, list) and len(persona) == 0):
        raise ParameterError("persona is required and cannot be empty")
    api_method = "DELETE"
    api_path = generate_url(SCOPE_URLS["SCOPE-MAPS"])
    if isinstance(persona, list) or "ALL" in persona:
        if "ALL" in persona:
            persona = VALID_PERSONAS
        for p in persona:
            if p not in VALID_PERSONAS:
                central_conn.logger.error(
                    f"{p} is not a valid device persona"
                    f"Unable to unassign profile {profile_name} from"
                    f" {scope_id}"
                )
                continue
            api_data = {
                "scope-map": [
                    {
                        "scope-name": str(scope_id),
                        "persona": p,
                        "resource": profile_name,
                    }
                ]
            }
            resp = central_conn.command(
                api_method=api_method, api_path=api_path, api_data=api_data
            )

            if resp["code"] == 200:
                central_conn.logger.info(
                    f"Successfully unassigned profile {profile_name} from"
                    f" {scope_id} with {p} device persona"
                )
    else:
        api_data = {
            "scope-map": [
                {
                    "scope-name": str(scope_id),
                    "persona": persona,
                    "resource": profile_name,
                }
            ]
        }

        resp = central_conn.command(
            api_method=api_method, api_path=api_path, api_data=api_data
        )

        if resp["code"] == 200:
            central_conn.logger.info(
                f"Successfully unassigned profile {profile_name} from"
                f" {scope_id} with {persona} device persona"
            )
    return resp

Scopes

scopes

Scopes(central_conn)

Bases: ScopeBase

This class holds the Scopes (Global hierarchy) class & methods for managing sites & site collections.

Constructor for Scopes object.

Parameters:

Name Type Description Default
central_conn NewCentralBase

Instance of NewCentralBase to establish connection to Central.

required

Raises:

Type Description
ParameterError

If central_conn is None

Source code in pycentral/scopes/scopes.py
def __init__(self, central_conn):
    """Constructor for Scopes object.

    Args:
        central_conn (NewCentralBase): Instance of NewCentralBase to establish connection to Central.

    Raises:
        ParameterError: If central_conn is None
    """
    if central_conn is None:
        raise ParameterError(
            "Central connection is required to create Scopes object."
        )
    self.central_conn = central_conn
    self.id = None
    self.name = "Global"
    self.type = "global"
    self.materialized = True
    self.assigned_profiles = []
    self._lookup_maps = {"id": {}, "serial": {}, "name": {}}

    self.site_collections = []
    self.sites = []
    self.devices = []
    self.device_groups = []

    self.get()

get()

Performs GET calls to Central to retrieve latest data of all scope elements.

Fetches Global, Site Collections, Sites, Devices, & Device Groups from Central.

Returns:

Type Description
bool

True if all scope elements are successfully fetched, False otherwise

Source code in pycentral/scopes/scopes.py
def get(self):
    """Performs GET calls to Central to retrieve latest data of all scope elements.

    Fetches Global, Site Collections, Sites, Devices, & Device Groups from Central.

    Returns:
        (bool): True if all scope elements are successfully fetched, False otherwise
    """
    try:
        self.central_conn.logger.info(
            "Fetching all scopes (Global, Site Collection, Site, Device, Device Groups)..."
        )
        self.get_all_sites()
        with ThreadPoolExecutor() as executor:
            futures = {
                executor.submit(
                    self.get_all_site_collections
                ): "site_collections",
                executor.submit(self.get_all_devices): "devices",
                executor.submit(
                    self.get_all_device_groups
                ): "device_groups",
            }

        for future in as_completed(futures):
            try:
                future.result()  # Ensure exceptions are raised if any
            except Exception as e:
                self.central_conn.logger.error(
                    f"Error fetching {futures[future]}: {e}"
                )

        self._correlate_scopes()
        self.get_id()
        self.central_conn.logger.info(
            "Mapping configuration profiles to scopes..."
        )
        self.get_scope_profiles()

        self.central_conn.logger.info(
            "Successfully fetched configuration hierarchy details from Central"
        )
        self.materialized = True
        return True

    except Exception as e:
        self.central_conn.logger.error(f"Error in scope get method: {e}")
        return False

get_all_sites()

Performs GET calls to retrieve all the sites from Central.

Returns:

Type Description
list

List of Site objects

Raises:

Type Description
Exception

If sites cannot be fetched from Central

Source code in pycentral/scopes/scopes.py
def get_all_sites(self):
    """Performs GET calls to retrieve all the sites from Central.

    Returns:
        (list): List of Site objects

    Raises:
        Exception: If sites cannot be fetched from Central
    """
    sites_response = get_all_scope_elements(obj=self, scope="site")
    if not sites_response:
        raise Exception(
            "Failed to fetch sites from Central. Sites are a required construct of new Central. Please check your Central account & ensure that you have at least one site created."
        )
    self.sites = [
        Site(
            central_conn=self.central_conn,
            site_attributes=site,
            from_api=True,
        )
        for site in sites_response
    ]
    return self.sites

get_all_site_collections()

Performs GET calls to retrieve all the site collections from Central.

Returns:

Type Description
list

List of Site_Collection objects

Source code in pycentral/scopes/scopes.py
def get_all_site_collections(self):
    """Performs GET calls to retrieve all the site collections from Central.

    Returns:
        (list): List of Site_Collection objects
    """
    site_collections_response = get_all_scope_elements(
        obj=self, scope="site_collection"
    )

    self.site_collections = [
        Site_Collection(
            central_conn=self.central_conn,
            collection_attributes=collection,
            from_api=True,
        )
        for collection in site_collections_response
    ]
    return self.site_collections

get_all_devices()

Performs GET calls to retrieve all the devices from Central.

Returns:

Type Description
list

List of Device objects

Source code in pycentral/scopes/scopes.py
def get_all_devices(self):
    """Performs GET calls to retrieve all the devices from Central.

    Returns:
        (list): List of Device objects
    """
    device_list = Device.get_all_devices(central_conn=self.central_conn)
    self.devices = [
        Device(
            central_conn=self.central_conn,
            device_attributes=device,
            from_api=True,
        )
        for device in device_list
    ]
    self.central_conn.logger.info(
        f"Total devices fetched from account: {len(self.devices)}"
    )
    return self.devices

get_all_device_groups()

Performs GET calls to retrieve all the device groups from Central.

Returns:

Type Description
list

List of device group dictionaries

Source code in pycentral/scopes/scopes.py
def get_all_device_groups(self):
    """Performs GET calls to retrieve all the device groups from Central.

    Returns:
        (list): List of device group dictionaries
    """
    device_groups_list = get_all_scope_elements(
        obj=self, scope="device_group"
    )
    self.device_groups = [
        Device_Group(
            central_conn=self.central_conn,
            device_group_attributes=device_group,
            from_api=True,
        )
        for device_group in device_groups_list
    ]
    return device_groups_list

get_id()

Returns the ID of the Global scope.

If the ID hasn't been set, the function will fetch the ID from Central.

Returns:

Type Description
int or None

ID of global scope, or None if unable to fetch

Source code in pycentral/scopes/scopes.py
def get_id(self):
    """Returns the ID of the Global scope.

    If the ID hasn't been set, the function will fetch the ID from Central.

    Returns:
        (int or None): ID of global scope, or None if unable to fetch
    """
    global_scope_id = None
    if self.id is not None:
        global_scope_id = fetch_attribute(self, "id")
    elif len(self.sites) > 0:
        sample_site = self.sites[0]
        heirarchy = None
        heirarchy = self.get_hierarchy(
            scope="site", id=sample_site.get_id()
        )
        if heirarchy is not None:
            org_data = None
            heirarchy_data = heirarchy[0]["hierarchy"]
            for scope in heirarchy_data:
                if scope["scopeType"] == "org":
                    org_data = scope
                    break
            if org_data is not None:
                global_scope_id = int(org_data["scopeId"])
                self.id = global_scope_id
                self._lookup_maps["id"].update({global_scope_id: self})
                self.central_conn.logger.info(
                    "Global scope ID set successfully."
                )
            else:
                self.central_conn.logger.error(
                    "Unable to get global scope ID"
                )
    else:
        self.central_conn.logger.error(
            "Unable to get global scope ID without having 1 site in the central account."
        )
    return global_scope_id

get_sites(limit=DEFAULT_LIMIT, offset=0, filter_field='', sort='')

Fetches the list of sites from Central based on the provided attributes.

Parameters:

Name Type Description Default
limit int

Number of sites to be fetched, defaults to 100

DEFAULT_LIMIT
offset int

Pagination start index, defaults to 0

0
filter_field str

Field for sorting. Accepted values: scopeName, address, city, state, country, zipcode, collectionName

''
sort str

Direction of sorting. Accepted values: scopeName, address, state, country, city, deviceCount, collectionName, zipcode, timezone, longitude, latitude

''

Returns:

Type Description
list or None

List of sites based on the provided arguments, None if errors occur

Source code in pycentral/scopes/scopes.py
def get_sites(
    self, limit=DEFAULT_LIMIT, offset=0, filter_field="", sort=""
):
    """Fetches the list of sites from Central based on the provided attributes.

    Args:
        limit (int): Number of sites to be fetched, defaults to 100
        offset (int): Pagination start index, defaults to 0
        filter_field (str): Field for sorting. Accepted values: scopeName,
            address, city, state, country, zipcode, collectionName
        sort (str): Direction of sorting. Accepted values: scopeName,
            address, state, country, city, deviceCount, collectionName,
            zipcode, timezone, longitude, latitude

    Returns:
        (list or None): List of sites based on the provided arguments, None if errors occur
    """
    return get_scope_elements(
        obj=self,
        scope="site",
        limit=limit,
        offset=offset,
        filter_field=filter_field,
        sort=sort,
    )

get_site_collections(limit=DEFAULT_LIMIT, offset=0, filter_field='', sort='')

Fetches the list of site collections from Central based on the provided attributes.

Parameters:

Name Type Description Default
limit int

Number of site collections to be fetched, defaults to 100

DEFAULT_LIMIT
offset int

Pagination start index, defaults to 0

0
filter_field str

Field for sorting. Accepted values: scopeName, description

''
sort str

Direction of sorting. Accepted values: scopeName, description, deviceCount, siteCount

''

Returns:

Type Description
list or None

List of site collections based on the provided arguments, None if errors occur

Source code in pycentral/scopes/scopes.py
def get_site_collections(
    self,
    limit=DEFAULT_LIMIT,
    offset=0,
    filter_field="",
    sort="",
):
    """Fetches the list of site collections from Central based on the provided attributes.

    Args:
        limit (int): Number of site collections to be fetched, defaults to 100
        offset (int): Pagination start index, defaults to 0
        filter_field (str): Field for sorting. Accepted values: scopeName,
            description
        sort (str): Direction of sorting. Accepted values: scopeName,
            description, deviceCount, siteCount



    Returns:
        (list or None): List of site collections based on the provided arguments, None if errors occur
    """
    return get_scope_elements(
        obj=self,
        scope="site_collection",
        limit=limit,
        offset=offset,
        filter_field=filter_field,
        sort=sort,
    )

find_site_collection(site_collection_ids=None, site_collection_names=None)

Returns the site collection based on the provided parameters.

Only one of site_collection_ids or site_collection_names is required.

Parameters:

Name Type Description Default
site_collection_ids int or list

ID(s) of site collections to find

None
site_collection_names str or list

Name(s) of site collections to find

None

Returns:

Type Description
Site_Collection or list or None

Found site collection(s) or None if not found

Source code in pycentral/scopes/scopes.py
def find_site_collection(
    self, site_collection_ids=None, site_collection_names=None
):
    """Returns the site collection based on the provided parameters.

    Only one of site_collection_ids or site_collection_names is required.

    Args:
        site_collection_ids (int or list, optional): ID(s) of site collections to find
        site_collection_names (str or list, optional): Name(s) of site collections to find

    Returns:
        (Site_Collection or list or None): Found site collection(s) or None if not found
    """
    site_collections = self._find_scope_element(
        ids=site_collection_ids,
        names=site_collection_names,
        scope="site_collection",
    )
    if not site_collections:
        self.get_all_sites()
        site_collections = self._find_scope_element(
            ids=site_collection_ids,
            names=site_collection_names,
            scope="site_collection",
        )
    return site_collections

find_site(site_ids=None, site_names=None)

Returns the site based on the provided parameters.

Only one of site_ids or site_names is required.

Parameters:

Name Type Description Default
site_ids int or list

ID(s) of site to find

None
site_names str or list

Name(s) of site to find

None

Returns:

Type Description
Site or list or None

Found site(s) or None if not found

Source code in pycentral/scopes/scopes.py
def find_site(self, site_ids=None, site_names=None):
    """Returns the site based on the provided parameters.

    Only one of site_ids or site_names is required.

    Args:
        site_ids (int or list, optional): ID(s) of site to find
        site_names (str or list, optional): Name(s) of site to find

    Returns:
        (Site or list or None): Found site(s) or None if not found
    """
    sites = self._find_scope_element(
        ids=site_ids, names=site_names, scope="site"
    )
    if not sites:
        self.get_all_sites()
        sites = self._find_scope_element(
            ids=site_ids, names=site_names, scope="site"
        )
    return sites

find_device(device_ids=None, device_names=None, device_serials=None)

Returns the device based on the provided parameters.

Only one of device_ids, device_names, or device_serials is required.

Parameters:

Name Type Description Default
device_ids int or list

ID(s) of devices to find

None
device_names str or list

Name(s) of devices to find

None
device_serials str or list

Serial number(s) of devices to find

None

Returns:

Type Description
Device or list or None

Found device(s) or None if not found

Source code in pycentral/scopes/scopes.py
def find_device(
    self, device_ids=None, device_names=None, device_serials=None
):
    """Returns the device based on the provided parameters.

    Only one of device_ids, device_names, or device_serials is required.

    Args:
        device_ids (int or list, optional): ID(s) of devices to find
        device_names (str or list, optional): Name(s) of devices to find
        device_serials (str or list, optional): Serial number(s) of devices to find

    Returns:
        (Device or list or None): Found device(s) or None if not found
    """
    devices = self._find_scope_element(
        ids=device_ids,
        names=device_names,
        serials=device_serials,
        scope="device",
    )
    if not devices:
        self.get_all_devices()
        devices = self._find_scope_element(
            ids=device_ids,
            names=device_names,
            serials=device_serials,
            scope="device",
        )
    return devices

find_device_group(device_group_ids=None, device_group_names=None)

Returns the device group based on the provided parameters.

Only one of device_group_ids or device_group_names is required.

Parameters:

Name Type Description Default
device_group_ids int or list

ID(s) of device groups to find

None
device_group_names str or list

Name(s) of device groups to find

None

Returns:

Type Description
Device_Group or list or None

Found device group(s) or None if not found

Source code in pycentral/scopes/scopes.py
def find_device_group(
    self,
    device_group_ids=None,
    device_group_names=None,
):
    """Returns the device group based on the provided parameters.

    Only one of device_group_ids or device_group_names is required.

    Args:
        device_group_ids (int or list, optional): ID(s) of device groups to find
        device_group_names (str or list, optional): Name(s) of device groups to find

    Returns:
        (Device_Group or list or None): Found device group(s) or None if not found
    """
    device_groups = self._find_scope_element(
        ids=device_group_ids,
        names=device_group_names,
        scope="device_group",
    )
    if not device_groups:
        self.get_all_device_groups()
        device_groups = self._find_scope_element(
            ids=device_group_ids,
            names=device_group_names,
            scope="device_group",
        )
    return device_groups

add_sites_to_site_collection(site_collection_id=None, site_collection_name=None, site_ids=None, site_names=None)

Adds site(s) to a site collection.

Parameters:

Name Type Description Default
site_collection_id int

ID of the site collection. Either site_collection_name or site_collection_id is required.

None
site_collection_name str

Name of the site collection. Either site_collection_name or site_collection_id is required.

None
site_ids int or list

ID(s) of the site(s) to associate. Either site_ids or site_names is required.

None
site_names str or list

Name(s) of the site(s) to associate. Either site_ids or site_names is required.

None

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def add_sites_to_site_collection(
    self,
    site_collection_id=None,
    site_collection_name=None,
    site_ids=None,
    site_names=None,
):
    """Adds site(s) to a site collection.

    Args:
        site_collection_id (int, optional): ID of the site collection.
            Either site_collection_name or site_collection_id is required.
        site_collection_name (str, optional): Name of the site collection.
            Either site_collection_name or site_collection_id is required.
        site_ids (int or list, optional): ID(s) of the site(s) to associate.
            Either site_ids or site_names is required.
        site_names (str or list, optional): Name(s) of the site(s) to associate.
            Either site_ids or site_names is required.

    Returns:
        (bool): True if successful, False otherwise
    """
    site_collection = self.find_site_collection(
        site_collection_ids=site_collection_id,
        site_collection_names=site_collection_name,
    )
    if site_collection:
        sites = self.find_site(site_ids=site_ids, site_names=site_names)
        if isinstance(sites, Site):
            sites = [sites]
        if all(sites):
            site_association = site_collection.associate_site(sites=sites)
            if site_association:
                return True
            else:
                self.central_conn.logger.error(
                    "Unable to complete site association with site collection."
                )
                return False

        else:
            self.central_conn.logger.error(
                "Unable to associate invalid site(s) with site collection. Please provide valid site id(s) or name(s)."
            )
            return False
    elif site_collection is None:
        self.central_conn.logger.error(
            "Unable to associate site(s) with invalid site collection. Please provide a valid site collection id or name."
        )
        return False

remove_sites_from_site_collection(site_ids=None, site_names=None)

Removes site(s) from a site collection.

Parameters:

Name Type Description Default
site_ids int or list

ID(s) of the site(s) to unassociate. Either site_ids or site_names is required.

None
site_names str or list

Name(s) of the site(s) to unassociate. Either site_ids or site_names is required.

None

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def remove_sites_from_site_collection(self, site_ids=None, site_names=None):
    """Removes site(s) from a site collection.

    Args:
        site_ids (int or list, optional): ID(s) of the site(s) to unassociate.
            Either site_ids or site_names is required.
        site_names (str or list, optional): Name(s) of the site(s) to unassociate.
            Either site_ids or site_names is required.

    Returns:
        (bool): True if successful, False otherwise
    """
    sites = self.find_site(site_ids=site_ids, site_names=site_names)
    if not isinstance(sites, list):
        sites = [sites]
    if all(sites):
        api_method = "DELETE"
        api_path = generate_url(SCOPE_URLS["REMOVE_SITE_FROM_COLLECTION"])
        api_params = {
            "siteIds": ",".join([str(site.get_id()) for site in sites])
        }
        resp = self.central_conn.command(
            api_method=api_method, api_path=api_path, api_params=api_params
        )
        if resp["code"] == 200:
            site_name_str = ", ".join(
                [str(site.get_name()) for site in sites]
            )
            self.central_conn.logger.info(
                "Successfully removed sites "
                + site_name_str
                + " from site collection."
            )
            self._update_site_collection_attributes(sites=sites)
            return True
        else:
            self.central_conn.logger.error(resp["msg"])
            return False
    else:
        self.central_conn.logger.error(
            "Unable to remove invalid site(s) from site collection. Please provide valid site id(s) or name(s)."
        )
    return False

create_site(site_attributes, site_collection_id=None, site_collection_name=None)

Creates a new site in Central and optionally associates it with a site collection.

Parameters:

Name Type Description Default
site_attributes dict

Attributes of the site to create

required
site_collection_id int

ID of the site collection. Either site_collection_name or site_collection_id is required if associating.

None
site_collection_name str

Name of the site collection. Either site_collection_name or site_collection_id is required if associating.

None

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def create_site(
    self,
    site_attributes,
    site_collection_id=None,
    site_collection_name=None,
):
    """Creates a new site in Central and optionally associates it with a site collection.

    Args:
        site_attributes (dict): Attributes of the site to create
        site_collection_id (int, optional): ID of the site collection.
            Either site_collection_name or site_collection_id is required if associating.
        site_collection_name (str, optional): Name of the site collection.
            Either site_collection_name or site_collection_id is required if associating.

    Returns:
        (bool): True if successful, False otherwise
    """
    site_obj = Site(
        site_attributes=site_attributes, central_conn=self.central_conn
    )
    site_creation_status = site_obj.create()

    if site_creation_status:
        self.sites.append(site_obj)
        if site_collection_id or site_collection_name:
            self.add_sites_to_site_collection(
                site_collection_id=site_collection_id,
                site_collection_name=site_collection_name,
                site_ids=[site_obj.get_id()],
            )

    else:
        self.central_conn.logger.error(
            f"Unable to create site {site_obj.get_name()}"
        )
    return site_creation_status

delete_site(site_id=None, site_name=None)

Deletes a site in Central.

Parameters:

Name Type Description Default
site_id int

ID of the site to delete. Either site_id or site_name is required.

None
site_name str

Name of the site to delete. Either site_id or site_name is required.

None

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def delete_site(self, site_id=None, site_name=None):
    """Deletes a site in Central.

    Args:
        site_id (int, optional): ID of the site to delete.
            Either site_id or site_name is required.
        site_name (str, optional): Name of the site to delete.
            Either site_id or site_name is required.

    Returns:
        (bool): True if successful, False otherwise
    """
    site_deletion_status = False
    site = self.find_site(site_ids=site_id, site_names=site_name)
    if site:
        site_id = site.get_id()
        site_deletion_status = site.delete()
        if site_deletion_status:
            self._remove_scope_element(
                scope="site", element_id=site.get_id()
            )
            if site.site_collection_id:
                site_collection = self.find_site_collection(
                    site_collection_ids=site.site_collection_id
                )
                site_collection.remove_site(site_id)

        else:
            error_resp = site_deletion_status
            self.central_conn.logger.error(
                "Unable to delete site. "
                + "Error-message -> "
                + error_resp["msg"]["message-code"][0]["code"]
            )
    else:
        self.central_conn.logger.error(
            "Please provide a valid site id or name to be deleted."
        )
    return site_deletion_status

create_site_collection(collection_attributes, site_ids=None, site_names=None)

Creates a new site collection in Central and optionally associates sites with it.

Parameters:

Name Type Description Default
collection_attributes dict

Attributes of the site collection to create

required
site_ids int or list

ID(s) of the site(s) to associate. Either site_ids or site_names is required if associating.

None
site_names str or list

Name(s) of the site(s) to associate. Either site_ids or site_names is required if associating.

None

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def create_site_collection(
    self, collection_attributes, site_ids=None, site_names=None
):
    """Creates a new site collection in Central and optionally associates sites with it.

    Args:
        collection_attributes (dict): Attributes of the site collection to create
        site_ids (int or list, optional): ID(s) of the site(s) to associate.
            Either site_ids or site_names is required if associating.
        site_names (str or list, optional): Name(s) of the site(s) to associate.
            Either site_ids or site_names is required if associating.

    Returns:
        (bool): True if successful, False otherwise
    """
    site_collection_obj = Site_Collection(
        collection_attributes=collection_attributes,
        central_conn=self.central_conn,
    )
    site_collection_creation_status = site_collection_obj.create()
    if site_collection_creation_status:
        self.site_collections.append(site_collection_obj)
        if site_ids or site_names:
            site_addition_status = self.add_sites_to_site_collection(
                site_collection_id=site_collection_obj.get_id(),
                site_ids=site_ids,
                site_names=site_names,
            )
            if site_addition_status:
                self.central_conn.logger.info(
                    f"Successfully associated sites with site collection {site_collection_obj.get_name()}"
                )
            else:
                self.central_conn.logger.error(
                    f"Failed to associate sites with site collection {site_collection_obj.get_name()}"
                )
    else:
        self.central_conn.logger.error(
            f"Unable to create site collection {site_collection_obj.get_name()}"
        )
    return site_collection_creation_status

delete_site_collection(site_collection_id=None, site_collection_name=None, remove_sites=False)

Deletes a site collection in Central.

Optionally removes associated sites first.

Parameters:

Name Type Description Default
site_collection_id int

ID of the site collection to delete. Either site_collection_id or site_collection_name is required.

None
site_collection_name str

Name of the site collection to delete. Either site_collection_id or site_collection_name is required.

None
remove_sites bool

If True, removes sites associated with the site collection before deleting it. If False and sites are associated, deletion will fail.

False

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def delete_site_collection(
    self,
    site_collection_id=None,
    site_collection_name=None,
    remove_sites=False,
):
    """Deletes a site collection in Central.

    Optionally removes associated sites first.

    Args:
        site_collection_id (int, optional): ID of the site collection to delete.
            Either site_collection_id or site_collection_name is required.
        site_collection_name (str, optional): Name of the site collection to delete.
            Either site_collection_id or site_collection_name is required.
        remove_sites (bool): If True, removes sites associated with the site collection
            before deleting it. If False and sites are associated, deletion will fail.

    Returns:
        (bool): True if successful, False otherwise
    """
    site_collection_deletion_status = False
    site_collection = self.find_site_collection(
        site_collection_ids=site_collection_id,
        site_collection_names=site_collection_name,
    )
    if site_collection:
        num_associated_sites = len(site_collection.sites)
        if remove_sites is False and num_associated_sites > 0:
            self.central_conn.logger.error(
                "Unable to delete site collection with "
                f"{num_associated_sites} sites associated with it. "
                "Set remove_sites argument to True to remove sites associated with site collection before deleting it."
            )
            return site_collection_deletion_status
        elif remove_sites and num_associated_sites > 0:
            self.central_conn.logger.info(
                f"Attempting to remove {num_associated_sites} associated sites before deleting site collection "
                + site_collection.get_name()
            )
            site_unassociated_status = (
                self.remove_sites_from_site_collection(
                    site_ids=site_collection.sites
                )
            )
            if site_unassociated_status is not True:
                self.central_conn.logger.info(
                    f"Unable to remove {num_associated_sites} associated sites from site collection "
                    + f"{site_collection.get_name()}."
                )
                return site_unassociated_status
        site_collection_deletion_status = site_collection.delete()
        if site_collection_deletion_status:
            self._remove_scope_element(
                scope="site_collection",
                element_id=site_collection.get_id(),
            )
        else:
            error_resp = site_collection_deletion_status
            self.central_conn.logger.error(
                "Unable to delete site collection. "
                + "Error-message -> "
                + error_resp["msg"]["message-code"][0]["code"]
            )
    else:
        self.central_conn.logger.error(
            "Please provide a valid site collection id or name to be deleted."
        )
    return site_collection_deletion_status

get_hierarchy(scope, id=None, name=None)

Fetches the hierarchy of the specified scope element in the global hierarchy.

Parameters:

Name Type Description Default
scope str

Type of the element (e.g., site, site_collection, device, device_group)

required
id int

ID of the element

None
name str

Name of the element

None

Returns:

Type Description
dict or None

Hierarchy of the specified element, None if unable to fetch

Source code in pycentral/scopes/scopes.py
def get_hierarchy(self, scope, id=None, name=None):
    """Fetches the hierarchy of the specified scope element in the global hierarchy.

    Args:
        scope (str): Type of the element (e.g., site, site_collection, device, device_group)
        id (int, optional): ID of the element
        name (str, optional): Name of the element

    Returns:
        (dict or None): Hierarchy of the specified element, None if unable to fetch
    """
    if scope not in SUPPORTED_SCOPES:
        self.central_conn.logger.error(
            "Unknown scope provided. Please provide one of the supported scopes - "
            ", ".join(SUPPORTED_SCOPES)
        )
        return None

    scope_id = None
    if id:
        scope_id = id
    else:
        if scope == "site":
            site = self.find_site(site_names=name)
            if site is not None:
                scope_id = site.get_id()
        elif scope == "site_collection":
            site_collection = self.find_site_collection(
                site_collection_names=name
            )
            if site_collection is not None:
                scope_id = site.get_id()
        if not scope_id:
            self.central_conn.logger.error(
                f"Unable to find id of specified scope element with name of {name}"
            )
            return None

    api_method = "GET"
    api_path = generate_url(SCOPE_URLS["HIERARCHY"])
    api_params = {"scopeId": scope_id, "scopeType": scope.lower()}
    resp = self.central_conn.command(
        api_method=api_method, api_path=api_path, api_params=api_params
    )
    if resp["code"] == 200:
        self.central_conn.logger.info(
            f"Successfully fetched scope heirarchy of {scope} with id {id}"
        )
        return resp["msg"]["items"]
    else:
        self.central_conn.logger.error(
            f"Unable to fetch scope heirarchy of {scope} with id {id}"
        )
        return None

__str__()

Returns a string representation of the Global scope.

Returns:

Type Description
str

String representation of the Global scope

Source code in pycentral/scopes/scopes.py
def __str__(self):
    """Returns a string representation of the Global scope.

    Returns:
        (str): String representation of the Global scope
    """
    return f"Global ID - {self.id}"

get_scope_profiles()

Fetches all configuration profiles associated with different scope elements.

Source code in pycentral/scopes/scopes.py
def get_scope_profiles(self):
    """Fetches all configuration profiles associated with different scope elements."""
    scope_map_list = scope_maps.get(central_conn=self.central_conn)
    self.central_conn.logger.info(
        f"Total scope mappings fetched from account: {len(scope_map_list)}"
    )
    unknown_scopes = []
    for mapping in scope_map_list:
        scope_id = mapping.pop("scope-name")
        if scope_id in unknown_scopes:
            continue
        required_scope_element = self._find_scope_element(ids=scope_id)
        if required_scope_element:
            required_scope_element.add_profile(
                name=mapping["resource"],
                persona=mapping["persona"],
            )
        else:
            unknown_scopes.append(scope_id)

assign_profile_to_scope(profile_name, profile_persona=None, scope=None, scope_name=None, scope_id=None)

Assigns a configuration profile to the specified scope.

Parameters:

Name Type Description Default
profile_name str

Name of the configuration profile

required
profile_persona str

Device Persona of the profile. Optional if assigning to a device.

None
scope str

Type of the scope (e.g., global, site, site_collection, device)

None
scope_name str

Name of the scope element. Either scope_name or scope_id is required.

None
scope_id int

ID of the scope element. Either scope_name or scope_id is required.

None

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def assign_profile_to_scope(
    self,
    profile_name,
    profile_persona=None,
    scope=None,
    scope_name=None,
    scope_id=None,
):
    """Assigns a configuration profile to the specified scope.

    Args:
        profile_name (str): Name of the configuration profile
        profile_persona (str, optional): Device Persona of the profile.
            Optional if assigning to a device.
        scope (str, optional): Type of the scope (e.g., global, site, site_collection, device)
        scope_name (str, optional): Name of the scope element.
            Either scope_name or scope_id is required.
        scope_id (int, optional): ID of the scope element.
            Either scope_name or scope_id is required.

    Returns:
        (bool): True if successful, False otherwise
    """
    return self._profile_to_scope_helper(
        "assign",
        profile_name,
        profile_persona,
        scope,
        scope_name,
        scope_id,
    )

unassign_profile_to_scope(profile_name, profile_persona=None, scope=None, scope_name=None, scope_id=None)

Unassigns a configuration profile from the specified scope.

Parameters:

Name Type Description Default
profile_name str

Name of the configuration profile

required
profile_persona str

Device Persona of the profile. Optional if unassigning from a device.

None
scope str

Type of the scope (e.g., global, site, site_collection, device)

None
scope_name str

Name of the scope element. Either scope_name or scope_id is required.

None
scope_id int

ID of the scope element. Either scope_name or scope_id is required.

None

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def unassign_profile_to_scope(
    self,
    profile_name,
    profile_persona=None,
    scope=None,
    scope_name=None,
    scope_id=None,
):
    """Unassigns a configuration profile from the specified scope.

    Args:
        profile_name (str): Name of the configuration profile
        profile_persona (str, optional): Device Persona of the profile.
            Optional if unassigning from a device.
        scope (str, optional): Type of the scope (e.g., global, site, site_collection, device)
        scope_name (str, optional): Name of the scope element.
            Either scope_name or scope_id is required.
        scope_id (int, optional): ID of the scope element.
            Either scope_name or scope_id is required.

    Returns:
        (bool): True if successful, False otherwise
    """
    return self._profile_to_scope_helper(
        "unassign",
        profile_name,
        profile_persona,
        scope,
        scope_name,
        scope_id,
    )

move_devices_between_sites(current_site, new_site, device_serial, device_type=None, device_identifier=None, deployment_mode=None)

Moves devices between sites.

Note: Moving devices between sites via NBAPI is not currently supported.

Parameters:

Name Type Description Default
current_site int or str or Site

ID, name, or Site instance of the current site

required
new_site int or str or Site

ID, name, or Site instance of the destination site

required
device_serial str

Serial number of device to move

required
device_type str

Type of device. For example: AP, SWITCH, GATEWAY

None
device_identifier str

Additional device identifier

None
deployment_mode str

Deployment type. For example: Standalone, Virtual Controller

None

Returns:

Type Description
bool

True if successful, False otherwise

Source code in pycentral/scopes/scopes.py
def move_devices_between_sites(
    self,
    current_site,
    new_site,
    device_serial,
    device_type=None,
    device_identifier=None,
    deployment_mode=None,
):
    """Moves devices between sites.

    Note: Moving devices between sites via NBAPI is not currently supported.

    Args:
        current_site (int or str or Site): ID, name, or Site instance of the current site
        new_site (int or str or Site): ID, name, or Site instance of the destination site
        device_serial (str): Serial number of device to move
        device_type (str, optional): Type of device. For example: AP, SWITCH, GATEWAY
        device_identifier (str, optional): Additional device identifier
        deployment_mode (str, optional): Deployment type. For example: Standalone, Virtual Controller

    Returns:
        (bool): True if successful, False otherwise
    """
    print(
        "Moving devices between sites via NBAPI is not currently supported"
    )
    return False

Site

site

Site(site_attributes, central_conn=None, from_api=False)

Bases: ScopeBase

This class holds site and all of its attributes & related methods.

Constructor for Site object.

Parameters:

Name Type Description Default
site_attributes dict

Attributes of the site collection

required
central_conn NewCentralBase

Instance of NewCentralBase to establish connection to Central.

None
from_api bool

Boolean indicates if the site_attributes is from the Central API response.

False

Raises:

Type Description
ValueError

If unexpected or missing attributes are provided

Source code in pycentral/scopes/site.py
def __init__(self, site_attributes, central_conn=None, from_api=False):
    """Constructor for Site object.

    Args:
        site_attributes (dict): Attributes of the site collection
        central_conn (NewCentralBase, optional): Instance of NewCentralBase to establish
            connection to Central.
        from_api (bool, optional): Boolean indicates if the site_attributes is from
            the Central API response.

    Raises:
        ValueError: If unexpected or missing attributes are provided
    """
    if from_api:
        site_attributes = rename_keys(
            site_attributes, API_ATTRIBUTE_MAPPING
        )

    self.materialized = from_api
    self.central_conn = central_conn
    self.id = None
    self.type = "site"

    missing_required_attributes = [
        attr for attr in REQUIRED_ATTRIBUTES if attr not in site_attributes
    ]
    if missing_required_attributes:
        raise ValueError(
            f"Missing required attributes: {', '.join(missing_required_attributes)}"
        )
    valid_attributes = REQUIRED_ATTRIBUTES + list(
        OPTIONAL_ATTRIBUTES.keys()
    )
    unexpected_attributes = [
        attr for attr in site_attributes if attr not in valid_attributes
    ]
    if unexpected_attributes:
        raise ValueError(
            f"Unexpected attributes: {', '.join(unexpected_attributes)}.\n If site is being created based off api_response ensure that the from_api flag is set to True"
        )
    set_attributes(
        obj=self,
        attributes_dict=site_attributes,
        required_attributes=REQUIRED_ATTRIBUTES,
        optional_attributes=OPTIONAL_ATTRIBUTES,
    )

create()

Perform a POST call to create a site on Central.

Returns:

Type Description
bool

True if site was created, False otherwise

Raises:

Type Description
Exception

If site already exists or central connection is missing

Source code in pycentral/scopes/site.py
def create(self):
    """Perform a POST call to create a site on Central.

    Returns:
        (bool): True if site was created, False otherwise

    Raises:
        Exception: If site already exists or central connection is missing
    """
    if self.materialized:
        raise Exception("Unable to create a site that already exists")

    if self.central_conn is None:
        raise Exception(
            "Unable to create site without Central connection. Please provide the central connection with the central_conn variable."
        )

    site_creation_status = False
    api_method = "POST"
    api_path = generate_url(SCOPE_URLS["SITE"])
    api_data = self.__generate_api_body()

    resp = self.central_conn.command(
        api_method=api_method, api_path=api_path, api_data=api_data
    )
    if resp["code"] == 200:
        try:
            site_id = resp["msg"]["items"][0]
            self.id = int(site_id)
            self.materialized = True
            site_creation_status = True
            self.get()
            self.central_conn.logger.info(
                f"Successfully created site {self.get_name()} in Central"
            )
        except KeyError:
            self.central_conn.logger.info(
                f"Failed to set site id of site {self.get_name()}"
            )
            pass
    else:
        self.central_conn.logger.error(
            f"Failed to create site {self.get_name()} in Central.\nError message - {resp['msg']}"
        )
    return site_creation_status

get()

Performs a GET call to retrieve data of a site then sets attributes of self.

Returns:

Type Description
dict

JSON Data of GET call if success, None otherwise

Raises:

Type Description
Exception

If site doesn't exist or central connection is missing

Source code in pycentral/scopes/site.py
def get(self):
    """Performs a GET call to retrieve data of a site then sets attributes of self.

    Returns:
        (dict): JSON Data of GET call if success, None otherwise

    Raises:
        Exception: If site doesn't exist or central connection is missing
    """
    if not self.materialized:
        raise Exception("Unable to get a site that does not exist")

    if self.central_conn is None:
        raise Exception(
            "Unable to create site without Central connection. Please provide the central connection with the central_conn variable."
        )

    site_data = get_scope_element(
        obj=self, scope="site", scope_id=self.get_id()
    )
    if not site_data:
        self.materialized = False
        self.central_conn.logger.error(
            f"Unable to fetch site {self.get_name()} from Central"
        )
    else:
        site_attributes = rename_keys(site_data, API_ATTRIBUTE_MAPPING)
        set_attributes(
            obj=self,
            attributes_dict=site_attributes,
            required_attributes=REQUIRED_ATTRIBUTES,
            optional_attributes=OPTIONAL_ATTRIBUTES,
        )
        self.central_conn.logger.info(
            f"Successfully fetched site {self.get_name()} from Central."
        )
    return site_data

update()

Performs a PUT call to update attributes of site on Central if changes are detected.

The source of truth is self.

Returns:

Type Description
bool

True if modifications were made, False otherwise

Raises:

Type Description
Exception

If site doesn't exist on Central or central connection is missing

Source code in pycentral/scopes/site.py
def update(self):
    """Performs a PUT call to update attributes of site on Central if changes are detected.

    The source of truth is self.

    Returns:
        (bool): True if modifications were made, False otherwise

    Raises:
        Exception: If site doesn't exist on Central or central connection is missing
    """
    if not self.materialized:
        raise Exception(
            "Unable to update a site that does not exist on Central"
        )

    if self.central_conn is None:
        raise Exception(
            "Unable to create site without Central connection. Please provide the central connection with the central_conn variable."
        )

    modified = False
    site_data = get_scope_element(
        obj=self, scope="site", scope_id=self.get_id()
    )

    if not site_data:
        self.materialized = False
        raise Exception(
            "Unable to upate site as it could not be found in Central."
        )

    site_attributes = rename_keys(site_data, API_ATTRIBUTE_MAPPING)

    object_attributes = {
        key: getattr(self, key) for key in API_ATTRIBUTE_MAPPING.values()
    }

    if site_attributes != object_attributes:
        api_method = "PUT"
        api_path = generate_url(SCOPE_URLS["SITE"])
        api_data = self.__generate_api_body()

        resp = self.central_conn.command(
            api_method=api_method, api_path=api_path, api_data=api_data
        )
        if resp["code"] == 200:
            modified = True
            self.central_conn.logger.info(
                f"Successfully updated site {self.get_name()} in Central"
            )
        else:
            self.central_conn.logger.info(
                f"Failed to update site {self.get_name()} in Central.\n Error message - {resp['msg']}"
            )
    return modified

delete()

Performs DELETE call to delete Site.

Returns:

Type Description
bool

True if DELETE was successful, False otherwise

Raises:

Type Description
Exception

If site doesn't exist on Central or central connection is missing

Source code in pycentral/scopes/site.py
def delete(self):
    """Performs DELETE call to delete Site.

    Returns:
        (bool): True if DELETE was successful, False otherwise

    Raises:
        Exception: If site doesn't exist on Central or central connection is missing
    """
    if not self.materialized:
        raise Exception(
            "Unable to delete a site that doesn't exist on Central"
        )

    if self.central_conn is None:
        raise Exception(
            "Unable to create site without Central connection. Please provide the central connection with the central_conn variable."
        )

    site_deletion_status = False
    api_method = "DELETE"
    api_path = generate_url(SCOPE_URLS["SITE"])
    api_params = {"scopeId": self.get_id()}
    resp = self.central_conn.command(
        api_method=api_method, api_path=api_path, api_params=api_params
    )
    if resp["code"] == 200:
        self.id = None
        self.materialized = False
        site_deletion_status = True
        self.central_conn.logger.info(
            f"Successfully deleted site {self.get_name()}"
        )

    else:
        self.central_conn.logger.error(
            f"Failed to delete site {self.get_name()}.\n Error message - {resp['msg']}"
        )
    return site_deletion_status

get_site_collection_attributes()

Returns dictionary of site collection attributes of the site.

Returns:

Type Description
dict or None

Dictionary of site collection attributes with 'id' and 'name' keys, or None if site collection id is not defined

Source code in pycentral/scopes/site.py
def get_site_collection_attributes(self):
    """Returns dictionary of site collection attributes of the site.

    Returns:
        (dict or None): Dictionary of site collection attributes with 'id' and 'name' keys,
            or None if site collection id is not defined
    """
    if fetch_attribute(self, "site_collection_id"):
        return {
            "id": fetch_attribute(self, "site_collection_id"),
            "name": fetch_attribute(self, "site_collection_name"),
        }
    return None

add_site_collection(site_collection_id, site_collection_name)

Sets the attributes site collection id and name of this site object.

Parameters:

Name Type Description Default
site_collection_id int or str

Site collection id

required
site_collection_name str

Site collection name

required
Source code in pycentral/scopes/site.py
def add_site_collection(self, site_collection_id, site_collection_name):
    """Sets the attributes site collection id and name of this site object.

    Args:
        site_collection_id (int or str): Site collection id
        site_collection_name (str): Site collection name
    """
    update_attribute(
        self, attribute="site_collection_id", new_value=site_collection_id
    )

    update_attribute(
        self,
        attribute="site_collection_name",
        new_value=site_collection_name,
    )

remove_site_collection()

Sets the attributes of site collection id and name to None.

Source code in pycentral/scopes/site.py
def remove_site_collection(self):
    """Sets the attributes of site collection id and name to None."""

    update_attribute(self, attribute="site_collection_id", new_value=None)
    update_attribute(self, attribute="site_collection_name", new_value=None)

__str__()

Returns string containing the Site id and name.

Returns:

Type Description
str

String representation of this class

Source code in pycentral/scopes/site.py
def __str__(self):
    """Returns string containing the Site id and name.

    Returns:
        (str): String representation of this class
    """
    return f"Site ID - {self.get_id()}, Site Name - {self.get_name()}"

__generate_api_body()

Returns the dictionary of site attributes needed for making API calls.

Returns:

Type Description
dict

Dictionary of site attributes needed for making API calls to Central

Source code in pycentral/scopes/site.py
def __generate_api_body(self):
    """Returns the dictionary of site attributes needed for making API calls.

    Returns:
        (dict): Dictionary of site attributes needed for making API calls to Central
    """
    # Validate location attributes follow ISO 3166 before building API body
    validate_iso_location(
        country=self.country, state=self.state, city=self.city
    )

    api_body = {
        "name": self.get_name(),
        "address": self.address,
        "city": self.city,
        "state": self.state,
        "country": self.country,
        "zipcode": self.zipcode,
        "timezone": self.__get_timezone_attributes(),
    }
    if self.materialized:
        api_body["scopeId"] = str(self.get_id())
        optional_attributes = list(
            set(API_ATTRIBUTE_MAPPING.values())
            - set(api_body.keys())
            - set(["id"])
        )
        for key in optional_attributes:
            if hasattr(self, key):
                api_key = next(
                    (
                        k
                        for k, v in API_ATTRIBUTE_MAPPING.items()
                        if v == key
                    ),
                    None,
                )
                if api_key:
                    api_body[api_key] = getattr(self, key)

    return api_body

__get_timezone_attributes()

Returns the dictionary of timezone attributes needed for making API calls.

Returns:

Type Description
dict

Dictionary of timezone attributes with 'rawOffset', 'timezoneId', and 'timezoneName' keys needed for site management API calls to Central

Source code in pycentral/scopes/site.py
def __get_timezone_attributes(self):
    """Returns the dictionary of timezone attributes needed for making API calls.

    Returns:
        (dict): Dictionary of timezone attributes with 'rawOffset', 'timezoneId',
            and 'timezoneName' keys needed for site management API calls to Central
    """
    timezone = pytz.timezone(self.timezone)
    current_time = datetime.now(timezone)
    raw_offset = int(current_time.utcoffset().total_seconds() * 1_000)

    return {
        "rawOffset": raw_offset,
        "timezoneId": self.timezone,
        "timezoneName": current_time.tzname(),
    }

Site Collection

site_collection

Site_Collection(collection_attributes, central_conn=None, from_api=False)

Bases: ScopeBase

This class holds site collection and all of its attributes & related methods.

Constructor for Site Collection object.

Parameters:

Name Type Description Default
collection_attributes dict

Attributes of the site collection

required
central_conn NewCentralBase

Instance of NewCentralBase to establish connection to Central.

None
from_api bool

Boolean indicates if the collection_attributes is from the Central API response.

False

Raises:

Type Description
ValueError

If unexpected or missing attributes are provided

Source code in pycentral/scopes/site_collection.py
def __init__(
    self, collection_attributes, central_conn=None, from_api=False
):
    """Constructor for Site Collection object.

    Args:
        collection_attributes (dict): Attributes of the site collection
        central_conn (NewCentralBase, optional): Instance of NewCentralBase to establish
            connection to Central.
        from_api (bool, optional): Boolean indicates if the collection_attributes is from
            the Central API response.

    Raises:
        ValueError: If unexpected or missing attributes are provided
    """
    if from_api:
        collection_attributes = self.__rename_keys(collection_attributes)
    else:
        valid_attributes = REQUIRED_ATTRIBUTES + ["sites"]
        for attribute in collection_attributes:
            if attribute not in valid_attributes:
                raise ValueError(
                    f"Unexpected attribute: {attribute}. For collection_attributes(not via API) only the following attributes are supported - {', '.join(valid_attributes)}"
                )
    self.materialized = from_api
    self.central_conn = central_conn
    self.type = "site_collection"
    self.id = None

    missing_required_attributes = [
        attr
        for attr in REQUIRED_ATTRIBUTES
        if attr not in collection_attributes
    ]
    if missing_required_attributes:
        raise ValueError(
            f"Missing required attributes: {', '.join(missing_required_attributes)}"
        )

    valid_attributes = (
        REQUIRED_ATTRIBUTES
        + list(OPTIONAL_ATTRIBUTES.keys())
        + list(OBJECT_ATTRIBUTES.keys())
    )
    unexpected_attributes = [
        attr
        for attr in collection_attributes
        if attr not in valid_attributes
    ]
    if unexpected_attributes:
        raise ValueError(
            f"Unexpected attributes: {', '.join(unexpected_attributes)}.\n If site_collections is being created based off api_response ensure that the from_api flag is set to True"
        )
    set_attributes(
        obj=self,
        attributes_dict=collection_attributes,
        required_attributes=REQUIRED_ATTRIBUTES,
        optional_attributes=OPTIONAL_ATTRIBUTES,
        object_attributes=OBJECT_ATTRIBUTES,
    )

create()

Perform a POST call to create a site collection on Central.

Returns:

Type Description
bool

True if site collection was created, False otherwise

Raises:

Type Description
Exception

If site collection already exists or central connection is missing

Source code in pycentral/scopes/site_collection.py
def create(self):
    """Perform a POST call to create a site collection on Central.

    Returns:
        (bool): True if site collection was created, False otherwise

    Raises:
        Exception: If site collection already exists or central connection is missing
    """
    if self.materialized:
        raise Exception(
            "Unable to create a site collection that already exists"
        )

    if self.central_conn is None:
        raise Exception(
            "Unable to create site collection without Central connection. Please provide the central connection with the central_conn variable."
        )

    site_collection_creation_status = False
    api_method = "POST"
    api_path = generate_url(SCOPE_URLS["SITE_COLLECTION"])
    api_data = self.__generate_api_body()

    resp = self.central_conn.command(
        api_method=api_method, api_path=api_path, api_data=api_data
    )
    if resp["code"] == 200:
        try:
            site_collection_id = resp["msg"]["items"][0]
            self.id = int(site_collection_id)
            self.materialized = True
            site_collection_creation_status = True
            self.get()
            self.central_conn.logger.info(
                f"Successfully created site collection {self.get_name()} in Central"
            )
        except KeyError:
            self.central_conn.logger.info(
                f"Failed to set site collection id of site collection {self.get_name()}"
            )
            pass
    else:
        self.central_conn.logger.error(
            f"Failed to create site collection {self.get_name()} in Central.\nError message - {resp['msg']}"
        )
    return site_collection_creation_status

get()

Performs a GET call to retrieve data of a site collection then sets attributes.

Returns:

Type Description
dict

JSON Data of GET call if success, None otherwise

Raises:

Type Description
Exception

If site collection doesn't exist or central connection is missing

Source code in pycentral/scopes/site_collection.py
def get(self):
    """Performs a GET call to retrieve data of a site collection then sets attributes.

    Returns:
        (dict): JSON Data of GET call if success, None otherwise

    Raises:
        Exception: If site collection doesn't exist or central connection is missing
    """
    if not self.materialized:
        raise Exception(
            "Unable to get a site collection that does not exist"
        )

    if self.central_conn is None:
        raise Exception(
            "Unable to create site collection without Central connection. Please provide the central connection with the central_conn variable."
        )

    site_collection_data = get_scope_element(
        obj=self, scope="site_collection", scope_id=self.get_id()
    )

    if not site_collection_data:
        self.materialized = False
        self.central_conn.logger.error(
            f"Unable to fetch site collection {self.get_name()} from Central"
        )
    else:
        collection_attributes = self.__rename_keys(site_collection_data)
        set_attributes(
            obj=self,
            attributes_dict=collection_attributes,
            required_attributes=REQUIRED_ATTRIBUTES,
            optional_attributes=OPTIONAL_ATTRIBUTES,
        )
        self.central_conn.logger.info(
            f"Successfully fetched site collection {self.get_name()} from Central."
        )
    return site_collection_data

update()

Performs a PUT call to update attributes of site collection on Central if changes are detected.

The source of truth is self.

Returns:

Type Description
bool

True if modifications were made, False otherwise

Raises:

Type Description
Exception

If site collection doesn't exist on Central or central connection is missing

Source code in pycentral/scopes/site_collection.py
def update(self):
    """Performs a PUT call to update attributes of site collection on Central if changes are detected.

    The source of truth is self.

    Returns:
        (bool): True if modifications were made, False otherwise

    Raises:
        Exception: If site collection doesn't exist on Central or central connection is missing
    """
    if not self.materialized:
        raise Exception(
            "Unable to update a site collection that does not exist on Central"
        )

    if self.central_conn is None:
        raise Exception(
            "Unable to create site collection without Central connection. Please provide the central connection with the central_conn variable."
        )

    modified = False
    site_collection_data = get_scope_element(
        obj=self, scope="site_collection", scope_id=self.get_id()
    )

    if not site_collection_data:
        self.materialized = False
        raise Exception(
            "Unable to upate site collection as it could not be found in Central."
        )

    collection_attributes = self.__rename_keys(site_collection_data)

    object_attributes = {
        key: getattr(self, key) for key in API_ATTRIBUTE_MAPPING.values()
    }

    if collection_attributes != object_attributes:
        api_method = "PUT"
        api_path = generate_url(SCOPE_URLS["SITE_COLLECTION"])
        api_data = self.__generate_api_body()

        resp = self.central_conn.command(
            api_method=api_method, api_path=api_path, api_data=api_data
        )
        if resp["code"] == 200:
            modified = True
            self.central_conn.logger.info(
                f"Successfully updated site collection {self.get_name()} in Central"
            )
        else:
            self.central_conn.logger.info(
                f"Failed to update site collection {self.get_name()} in Central.\n Error message - {resp['msg']}"
            )
    return modified

delete()

Performs DELETE call to delete Site Collection.

Returns:

Type Description
bool

True if DELETE was successful, False otherwise

Raises:

Type Description
Exception

If site collection doesn't exist on Central or central connection is missing

Source code in pycentral/scopes/site_collection.py
def delete(self):
    """Performs DELETE call to delete Site Collection.

    Returns:
        (bool): True if DELETE was successful, False otherwise

    Raises:
        Exception: If site collection doesn't exist on Central or central connection is missing
    """
    if not self.materialized:
        raise Exception(
            "Unable to delete a site collection that doesn't exist on Central"
        )

    if self.central_conn is None:
        raise Exception(
            "Unable to create site collection without Central connection. Please provide the central connection with the central_conn variable."
        )

    site_collection_deletion_status = False
    api_method = "DELETE"
    api_path = generate_url(SCOPE_URLS["SITE_COLLECTION"])
    api_params = {"scopeId": self.get_id()}
    resp = self.central_conn.command(
        api_method=api_method, api_path=api_path, api_params=api_params
    )
    if resp["code"] == 200:
        self.id = None
        self.materialized = False
        site_collection_deletion_status = True
        self.central_conn.logger.info(
            f"Successfully deleted site collection {self.get_name()}"
        )
    else:
        self.central_conn.logger.error(
            f"Failed to delete site collection {self.get_name()}.\n Error message - {resp['msg']}"
        )
    return site_collection_deletion_status

associate_site(sites)

Performs POST call to associate sites with a site collection.

Parameters:

Name Type Description Default
sites list

List of Site objects or list of site IDs (int) to associate with this site collection

required

Returns:

Type Description
bool

True if site association was successful, False otherwise

Raises:

Type Description
ParameterError

If sites parameter is not a list of Site or int types

Source code in pycentral/scopes/site_collection.py
def associate_site(self, sites):
    """Performs POST call to associate sites with a site collection.

    Args:
        sites (list): List of Site objects or list of site IDs (int) to associate
            with this site collection

    Returns:
        (bool): True if site association was successful, False otherwise

    Raises:
        ParameterError: If sites parameter is not a list of Site or int types
    """
    api_method = "POST"
    api_path = generate_url(SCOPE_URLS["ADD_SITE_TO_COLLECTION"])

    if all(isinstance(site, Site) for site in sites):
        site_ids = [str(site.get_id()) for site in sites]
    elif all(isinstance(site_id, int) for site_id in sites):
        site_ids = [str(site_id) for site_id in sites]
    else:
        raise ParameterError(
            "sites parameter should only be a list of type Site or int"
        )

    api_data = {
        "siteCollectionId": str(self.get_id()),
        "siteIds": site_ids,
    }
    resp = self.central_conn.command(
        api_method=api_method, api_path=api_path, api_data=api_data
    )
    if resp["code"] == 200 and len(resp["msg"]["items"]) == len(site_ids):
        self.central_conn.logger.info(
            f"Successfully associated site(s) {', '.join([str(site.name) for site in sites])} to site collection {self.name}"
        )
        self.get()
        for site in sites:
            if isinstance(site, Site):
                self.add_site(site_id=site.get_id())
                site.add_site_collection(
                    site_collection_id=self.get_id(),
                    site_collection_name=self.get_name,
                )
            elif isinstance(site, int):
                self.add_site(site_id=site)
        return True
    else:
        self.central_conn.logger.error(
            f"Failed to associate site(s) {', '.join([str(site.name) for site in sites])} to site collection {self.name}.\n Error message - {resp['msg']}"
        )
        return False

unassociate_site(sites)

Performs DELETE call to unassociate sites with a site collection.

Parameters:

Name Type Description Default
sites list

List of Site objects or list of site IDs (int) to unassociate from this site collection

required

Returns:

Type Description
bool

True if site unassociation was successful, False otherwise

Raises:

Type Description
ParameterError

If sites parameter is not a list of Site or int types

Source code in pycentral/scopes/site_collection.py
def unassociate_site(self, sites):
    """Performs DELETE call to unassociate sites with a site collection.

    Args:
        sites (list): List of Site objects or list of site IDs (int) to unassociate
            from this site collection

    Returns:
        (bool): True if site unassociation was successful, False otherwise

    Raises:
        ParameterError: If sites parameter is not a list of Site or int types
    """
    api_method = "DELETE"
    api_path = generate_url(SCOPE_URLS["REMOVE_SITE_FROM_COLLECTION"])
    if all(isinstance(site, Site) for site in sites):
        site_ids = [str(site.get_id()) for site in sites]
    elif all(isinstance(site_id, int) for site_id in sites):
        site_ids = [str(site_id) for site_id in sites]
    else:
        raise ParameterError(
            "sites parameter should only be a list of type Site or int"
        )
    api_params = {"siteIds": site_ids}
    resp = self.central_conn.command(
        api_method=api_method, api_path=api_path, api_params=api_params
    )
    if resp["code"] == 200 and len(resp["msg"]["items"]) == len(site_ids):
        self.central_conn.logger.info(
            f"Successfully unassociated site(s) {', '.join([str(site.name) for site in sites])} from site collection {self.name}"
        )
        self.get()
        for site in sites:
            if isinstance(site, Site):
                site.remove_site_collection()
                self.remove_site(site_id=site.get_id())
            elif isinstance(site, int):
                self.remove_site(site_id=site)
        return True
    else:
        self.central_conn.logger.error(
            f"Failed to unassociate site(s) {', '.join([str(site.name) for site in sites])} to site collection {self.name}.\n Error message - {resp['msg']}"
        )
        return False

add_site(site_id)

Adds the site details (site ID) to the site collection attributes.

Parameters:

Name Type Description Default
site_id int or str

Site ID of the site

required

Returns:

Type Description
bool

True if site details were successfully updated, False otherwise

Source code in pycentral/scopes/site_collection.py
def add_site(self, site_id):
    """Adds the site details (site ID) to the site collection attributes.

    Args:
        site_id (int or str): Site ID of the site

    Returns:
        (bool): True if site details were successfully updated, False otherwise
    """
    if int(site_id):
        self.sites.append(int(site_id))
        return True
    return False

remove_site(site_id)

Removes the site details (site ID) from the site collection attributes.

Parameters:

Name Type Description Default
site_id int

Site ID of the site

required

Returns:

Type Description
bool

True if site details were removed, False otherwise

Source code in pycentral/scopes/site_collection.py
def remove_site(self, site_id):
    """Removes the site details (site ID) from the site collection attributes.

    Args:
        site_id (int): Site ID of the site

    Returns:
        (bool): True if site details were removed, False otherwise
    """
    if site_id in self.sites:
        self.sites.remove(site_id)
        return True
    return False

__str__()

Returns the string containing the name and ID of the site collection.

Returns:

Type Description
str

String representation of this class

Source code in pycentral/scopes/site_collection.py
def __str__(self):
    """Returns the string containing the name and ID of the site collection.

    Returns:
        (str): String representation of this class
    """
    return f"Site Collection ID - {self.get_id()}, Site Collection Name - {self.get_name()}"

__rename_keys(api_attributes)

Renames the keys of the site collection attributes from the API response.

Parameters:

Name Type Description Default
api_attributes dict

Site collection attributes from Central API Response

required

Returns:

Type Description
dict

Renamed dictionary of site collection attributes mapped to object attributes

Raises:

Type Description
ValueError

If unknown attribute is found in API response

Source code in pycentral/scopes/site_collection.py
def __rename_keys(self, api_attributes):
    """Renames the keys of the site collection attributes from the API response.

    Args:
        api_attributes (dict): Site collection attributes from Central API Response

    Returns:
        (dict): Renamed dictionary of site collection attributes mapped to object attributes

    Raises:
        ValueError: If unknown attribute is found in API response
    """
    extra_keys = ["type", "scopeId"]
    for key in extra_keys:
        if key in extra_keys:
            del api_attributes[key]

    integer_attributes = ["id", "siteCount", "deviceCount"]
    renamed_dict = {}
    for key, value in api_attributes.items():
        new_key = API_ATTRIBUTE_MAPPING.get(key)
        if new_key:
            if key in integer_attributes:
                value = int(value)
            renamed_dict[new_key] = value
        else:
            raise ValueError(
                f"Unknown attribute {key} found in API response"
            )
    return renamed_dict

__generate_api_body()

Returns the dictionary of site collection attributes needed for making API calls.

Returns:

Type Description
dict

Dictionary of site collection attributes needed for making API calls to Central

Source code in pycentral/scopes/site_collection.py
def __generate_api_body(self):
    """Returns the dictionary of site collection attributes needed for making API calls.

    Returns:
        (dict): Dictionary of site collection attributes needed for making API calls to Central
    """
    api_body = {
        "scopeName": self.name,
        "description": self.description,
    }
    if self.materialized:
        api_body["scopeId"] = str(self.get_id())
    elif len(self.sites) > 0:
        api_body["siteIds"] = [str(site_id) for site_id in self.sites]

    return api_body