bumblebee-sdk-test 1.0.3
Access the Bumblebee Networks Controller API and define account, endpoint node, service node, app service, endpoint, and user classes.

# Bumblebee Networks SDK

## Purpose:
* This is a Python package that simplifies interaction with the Bumblebee Networks controller API by streamlining the steps of making API requests and handling responses.

## Getting Started:
### Installation/Setup Steps:
1. Set up and activate your virtual environment
    - On macOS/Linux:
        - python3 -m venv <virtual-environment-name>
        - source venv/bin/activate
    - On Windows:
        - python -m venv venv
        - venv\Scripts\activate
2. Install the package using pip
    - pip install bumblebee-sdk-test
3. Install the required packages listed in requirements.txt: pip install -r requirements.txt
4. Configure your env variables by creating an .env file in the root directory and listing your login information as following:
    - username="your-email"
    - password="your-password"
5. Import the required classes/methods
    - import bbt

## API Reference:
### The bbt class
The bbt class is used to simplify interactions with the Bumblebee Networks controller API by providing methods that manage accounts, IAM users, SAML SSO, service node groups, service nodes, app services, endpoint node groups, endpoint nodes, endpoints, user agents. It also provides methods to manage the database, get messages, download OVA files, get stats, billing, and contact information.

### Initialization:
- `get_bt(api_url, access_key_id, access_key_secret, verbose)`
    - Initializes the Bt client
    - Parameters:
        - `api_url` (string) - base URL of the API
        - `access_key_url` (string) - email/username for login and authentication
        - `access_key_secret` (string) - password for login and authentication
        - `verbose` (boolean) - set to `True`
    - Returns:
        - an instance of the `Bt` class
    ```
    bt = get_bt(api_url="https://apiurl.com",
        access_key_id="access_key_id",
        access_key_secret="access_key_secret"
    )
    ```

### Methods:
- `auth_header()`
    - Returns the authorization header required for making API requests
    - Parameters:
        - None
    - Returns:
        - The authorization header required for making API requests
        - Response structure: `dict` if authorization successful, `None` if unsuccessful
    ```
    headers = bt.auth_header()
    ```

#### Account methods:
- `create_account(username, password, headers=None)`
    - Creates a new account with the inputted username and password
    - Parameters:
        - `username` (string): email/username for the new account
        - `password` (string): password for the new account
        - `headers` (string): headers for making the request (optional)
    - Returns:
        - An `Account` object that represents the newly created account if account creation is successful
        - `None` if the account creation is unsuccessful
        - Error message (dict) if error in account creation
    ```
    account, error = bt.create_account(username="new_email@gmail.com", password="new_password")
    if error:
        print(f"Error creating account: {error}")
    else:
        print(f"Account created: {account}")
    ```

- `get_account(username=None)`
    - Retrieves account information for the inputted username
    - Parameters:
        - `username` (string): username to retrieve account information for (optional)
    - Returns:
        - a list of `Account` objects representing a list of the retrieved accounts
        - `None` if the account retrieval fails
        - Error message (dict) if error in account retrieval
    ```
    accounts, error_msg = bt.get_account(username="new_email@gmail.com")
    assert error_msg == None, f"Account get failed, error = {error_msg}"
    for act in accounts:
        print("\nAccount Information: ", act.to_dict())
    ```

- `remove_account(username)`
    - Removes the account with the inputted username
    - Parameters:
        - `username` (string): username of the account to be removed
    - Returns:
        - Response JSON (dict) if account removal is successful
        - `None` if account removal unsuccessful
        - Error message (dict) if error in account removal
    ```
    removal_response, error = bt.remove_account(username="new_email@gmail.com")
    if error:
        print(f"Error removing account: {error}")
    else:
        print(f"Successful account removal: {removal_response}")
    ```

- `clean_account_resources(target_account_id)`
    - Cleans up the account resources associated with the inputted account ID
    - Parameters:
        - `target_account_id` (string): the ID of the account that will have its resources cleaned up
    - Returns:
        - Response JSON (dict) if account clean up is successful
        - `None` if account clean up unsuccessful
        - Error message (dict) if error in account clean up
    ```
    cleanup_response, error = bt.clean_account_resources(target_account_id='account_id')
    if error:
        print(f"Error cleaning account resources: {error}")
    else:
        print(f"Successful account clean-up: {cleanup_response}")
    ```

- `enable_account_trial(target_account_id, trial_period_days)`
    - Enables a trial period for the account associated with the inputted account ID
    - Parameters:
        - `target_account_id` (string): the ID of the account to enable the trial for
        - `trial_period_days` (string): the number of days the trial period should last
    - Returns:
        - Response JSON (dict) if account trial is successfully enabled
        - `None` if enabling account trial fails
        - Error message (dict) if error in enabling account trial
    ```
    enable_response, error = bt.enable_account_trial(target_account_id="account_id", trial_period_days="10")
    if error:
        print(f"Error enabling account trial: {error}")
    else:
        print(f"Successfully enabled account trial: {enable_response}")
    ```

- `disable_account_trial(target_account_id)`
    - Disables the trial period for the account associated with the inputted account ID
    - Parameters:
        - `target_account_id` (str): the ID of the account to disable the trial for
    - Returns:
        - Response JSON (dict) if account trial is successfully disabled
        - `None` if disabling account trial fails
        - Error message (dict) if error in disabling account trial
    ```
    disable_response, error = bt.disable_account_trial(target_account_id="account_id")
    if error:
        print(f"Error disabling account trial: {error}")
    else:
        print(f"Successfully disabled account trial: {disable_response}")
    ```

#### IAM User methods:
- `create_iam_user(account_id, username, role)`
    - Creates a new IAM user with the inputted account ID, username, and role
    - Parameters:
        - `account_id` (string): the ID of the IAM user account
        - `username` (string): the username/email for the new IAM user
        - `role` (string): the role of the new IAM user
    - Returns:
        - JSON response (dict) if the IAM user creation is successful
        - `None` if IAM user creation fails
        - Error message (dict) if error in creating IAM user
    ```
    iam_creation_response, error = bt.create_iam_user(account_id="account_id", username="username@gmail.com", role="role")
    if error:
        print(f"Error creating IAM user: {error}")
    else:
        print(f"Successful IAM user creation: {iam_creation_response}")
    ```

-  `get_iam_users(username)`
    - Retrieves IAM user information for the inputted username
    - Parameters:
        -  `username` (string): the username/email for the new IAM user
    - Returns:
        - JSON response (dict) if the IAM user retrieval is successful
        - `None` if IAM users retrieval fails
        - Error message (dict) if error in retrieving IAM user information
    ```
    get_response, error = bt.get_iam_users(username="existing_email@gmail.com")
    if error:
        print(f"Error retrieving IAM users: {error}")
    else:
        print(f"Successful IAM users retrieval: {get_response}")
    ```

- `set_new_iam_user_password(iam_user_token, password)`
    - Sets a new password for the IAM user associated with the inputted IAM user token
    - Parameters:
        - `iam_user_token` (string): the user token that is associated with the IAM user
        - `password` (string): the new password you want to set for the IAM user
    - Returns:
        - JSON response (dict) if setting the new IAM password is successful
        - `None` if setting the new IAM user password fails
        - Error message (dict) if error in setting new IAM user password
    ```
    new_password_response, error = bt.set_new_iam_user_password(iam_user_token="user_token", password="password")
    if error:
        print(f"Error setting new IAM user password: {error}")
    else:
        print(f"New IAM user password successfully set: {new_password_response}")
    ```

- `update_iam_user(name, email, address, phone, password)`
    - Updates the IAM user information (name, email, address, phone, password) with the inputted values
    - Parameters:
        - `name` (string): the new name for the IAM user (optional)
        - `email` (string): the new email for the IAM user (optional)
        - `address` (string): the new address for the IAM user (optional)
        - `phone` (string): the new phone for the IAM user (optional)
        - `password` (string): the new password for the IAM user (optional)
    - Returns:
        - JSON response (dict) if updating the new IAM information is successful
        - `None` if updating the new IAM information fails
        - Error message (dict) if error in updating new IAM user information
    ```
    update_response, error = bt.update_iam_user(name="new_name", email="new_email@example.com", address="new_address", phone="new_phone", password="new_password")
    if error:
        print(f"Error updating IAM user information: {error}")
    else:
        print(f"IAM user successfully updated: {update_response}")
    ```

-  `iam_user_enable_mfa(type)`
    - Enabales MFA (multi-factor authentication) for the IAM user
    - Parameters:
        - `type` (string): the type of MFA to enable (optional)
    - Returns:
        - JSON response (dict) if enabling the MFA type is successful
        - `None` if enabling the MFA type fails
        - Error message (dict) if error in enabling the MFA type
    ```
    MFA_response, error = bt.iam_user_enable_mfa(type="MFA_type")
    if error:
        print(f"Error enabling MFA: {error}")
    else:
        print(f"MFA successfully enabled: {MFA_response}")
    ```

- `iam_user_disable_mfa()`
    - Disables MFA (multi-factor authentication) for the IAM user
    - Parameters:
        - None
    - Returns:
        - JSON response (dict) if disabling the MFA type is successful
        - `None` if disabling the MFA type fails
        - Error message (dict) if error in disabling the MFA type
    ```
    MFA_response, error = bt.iam_user_disable_mfa()
    if error:
        print(f"Error disabling MFA: {error}")
    else:
        print(f"MFA successfully disabled: {MFA_response}")
    ```

- `iam_user_update_role(new_role, iam_user_id)`
    - Updates the role of the IAM user to the inputted new role
    - Parameters:
        - `new_role` (string): the updated new role of the IAM user
        - `iam_user_id` (string): the ID of the IAM user to update
    - Returns:
        - JSON response (dict) if updating the IAM user role is successful
        - `None` if updating the IAM user role fails
        - Error message (dict) if error in updating the IAM user role
    ```
    update_role_response, error = bt.iam_user_update_role(new_role="new_role", iam_user_id="user_id")
    if error:
        print(f"Error updating IAM user role: {error}")
    else:
        print(f"IAM user role successfully updated: {update_role_response}")
    ```

#### SAML SSO methods:
- `create_account_idp(idp_name, entity_id, issuer, sso_url, certificate)`
    - Creates a new IDP (identity provider) for the account with the inputted values
    - Parameters:
        - `idp_name` (string): the name of the IDP
        - `entity_id` (string): the entity ID of the IDP
        - `issuer` (string): the issuer of the IDP
        - `sso_url` (string): the SSO (single sign-on) URL of the IDP
        - `certificate` (string): the certificate of the IDP
    - Returns:
        - JSON response (dict) if creating the IDP is successful
        - `None` if creating the IDP fails
        - Error message (dict) if error in creating the IDP
    ```
    creation_response, error = bt.create_account_idp(idp_name="ExampleIDP",entity_id="entity_id", issuer="issuer", sso_url="https://ssoexample.com", certificate="certificate")
    if error:
        print(f"Error creating account IDP: {error}")
    else:
        print(f"Account IDP successfully created: {creation_response}")
    ```

- `get_account_idp()`
    - Retrieves the IDP information of the account
    - Parameters:
        - None
    - Returns:
        - JSON response (dict) if retrieving the IDP account information is successful
        - `None` if retrieving the IDP account information fails
        - Error message (dict) if error in retrieving the IDP account information
    ```
    get_IDP_response, error = bt.get_account_idp()
    if error:
        print(f"Error retrieving account IDP: {error}")
    else:
        print(f"Account IDP information: {get_IDP_response}")
    ```

- `remove_account_idp`
    - Removes the account IDP
    - Parameters:
        - None
    - Returns:
        - JSON response (dict) if removing account IDP is successful
        - `None` if removing account IDP fails
        - Error message (dict) if error in removing account IDP
    ```
    remove_IDP_response, error = bt.get_account_idp()
    if error:
        print(f"Error removing account IDP: {error}")
    else:
        print(f"Remove account IDP successful: {remove_IDP_response}")
    ```

- `update_account_idp(idp_name, entity_id, issuer, sso_url, certificate)`
    - Updates the IDP details for the account with the inputted information
    - Parameters:
        - `idp_name` (string): the new name of the IDP (optional)
        - `entity_id` (string): the new entity ID of the IDP (optional)
        - `issuer` (string): the new issuer of the IDP (optional)
        - `sso_url` (string): the new SSO URL of the IDP (optional)
        - `certificate` (string): the new certificate of the IDP (optional)
    - Returns:
        - JSON response (dict) if updating the IDP account information is successful
        - `None` if updating the IDP account information fails
        - Error message (dict) if error in updating the IDP account information
    ```
    update_idp_response, error = bt.update_account_idp(idp_name="NewExampleIDP",entity_id="new_entity_id", issuer="new_issuer", sso_url="https://newssoexample.com", certificate="new_certificate")
    if error:
        print(f"Error updating account IDP: {error}")
    else:
        print(f"Account IDP successfully updated: {update_idp_response}")
    ```

#### Serivce Node methods:
- `create_service_node(service_node_group_id, service_node_name, new_service_node_group, service_node_group_name)`
    - Creates a new service node with the inputted parameters
    - Parameters:
        - `service_node_group_id` (string): the service node group ID of the new service node
        - `service_node_name`(string): the name of the service node
        - `new_service_node_group` (boolean): boolean representing if a new service node group should be created (optional). default status is set as False
        - `service_node_group_name` (string): the name of the new service node group (optional: if `new_service_node_group` is True, then `service_node_group_name` is required)
    - Returns:
        - an instance of the `ServiceNode` class if the creation is successful
        - `None` if service node creation fails
        - Error message (dict) if error in service node creation
    ```
    creation_response, error = bt.create_service_node(service_node_group_id="existing_group_id",service_node_name="NewServiceNode", new_service_node_group=False)
    if error:
        print(f"Error creating service node: {error}")
    else:
        print(f"Service node successfully created: {creation_response}")
    ```

- `get_service_node(service_node_group_id, service_node_name)`
    - Retrieves the service node information
    - Parameters:
        - `service_node_group_id` (string): the ID of the service node group
        - `service_node_name` (string): the service node name (optional)
    - Returns:
        - a list of `ServiceNode` instances if the service node retrieval is successful
        - `None` if the service node retrieval fails
        - Error message (dict) if error in service node retrieval
    ```
    SN_retrieval_response, error = bt.get_service_node(service_node_group_id="group_id")
    if error:
        print(f"Error retrieving service node: {error}")
    else:
        print(f"Service nodes: {SN_retrieval_response}")
    ```

- `remove_service_node(service_node_id)`
    - Removes the service node associated to the inputted service node ID
    - Parameters:
        - `service_node_id` (string): the ID of the service node to remove
    - Returns:
        - JSON response (dict) if service node removal is successful
        - `None` if the service node removal fails
        - Error message if error in service node removal
    ```
    SN_removal_response, error = bt.remove_service_node(service_node_id="node_id")
    if error:
        print(f"Error removing service node: {error}")
    else:
        print(f"Service node successfully removed: {SN_removal_response}")
    ```

- `get_service_node_details(service_node_id)`
    - Retrieves the details of the service node associated with the inputted service node ID
    - Parameters:
        - `service_node_id` (string): the ID of the service node to retrieve information of
    - Returns:
        - JSON response (dict) if service node details retrieval is successful
        - `None` if service node details retrieval fails
        - Error message if error in service node details retrieval
    ```
    SN_details_response, error = bt.get_service_node_detail(service_node_id="service_node_id")
    if error:
        print(f"Error retrieving service node details: {error}")
    else:
        print(f"Service node details: {response}")
    ```

- `set_service_node_form_factor(service_node_id, form_factor, shipping_addr)`
    - Sets the form factor and shipping address (optional) for the service node associated with the inputted service node ID
    - Parameters:
        - `service_node_id` (string): the ID of the service node
        - `form_factor` (string): the form factor of the service node
        - `shipping_addr` (string): the shipping address of the service node
    - Returns:
        - JSON response (dict) if setting service node form factor is successful
        - `None` if the setting service node form factor fails
        - Error message if error in setting service node form factor
    ```
    response, error = bt.set_service_node_form_factor(service_node_id="service_node_id", form_factor="new_form_factor", shipping_addr="1234 Shipping Address St")
    if error:
        print(f"Error setting service node form factor: {error}")
    else:
        print(f"Service node form factor successfully set: {response}")
    ```

#### App Service methods:
- `create_app_service(app_service_name, location, region, cloud_endpoint_service_name, service_node_group_id, fqdn, proto, port, network_mode_enabled, real_subnets, address_translation_enabled, virtual_subnet_pools, bgp_enabled, bgp_local_asn, bgp_peer_asn, bgp_peer_ip)`
    - Creates a new app service with the inputted parameters
    - Parameters:
        - `app_service_name` (string): the name of the app service
        - `location` (string): the location of the app service (aws, azure, or onprem)
        - `region` (string): the region for the app service (required for aws and azure)
        - `cloud_endpoint_service_name` (string): the cloud endpoint service name (required for aws and azure)
        - `service_node_group_id` (string): the service node group ID (required for onprem)
        - `fqdn` (string): the FQDN (fully qualified domain name) for the app service (required for onprem)
        - `proto` (string): the protocol for the app service (required)
        - `port` (string): the port number for the application service (required)
        - `network_mode_enabled` (boolean): a boolean representing if network mode is enabled (required for onprem). default status is set as False.
        - `real_subnets` (string): the real subnets for the app service (required for onprem)
        - `address_translation_enabled` (boolean): a boolean representing if address translation is enabled (required for onprem). default status is set as False.
        - `virtual_subnet_pools` (string): the virtual subnet pools for the app service (required for onprem)
        - `bgp_enabled` (boolean): a boolean representing if BGP is enabled (required for onprem). default status is set as False
        - `bgp_local_asn` (string): the BGP local ASN (required for onprem if `bgp_enabled` is True)
        - `bgp_peer_asn` (string): the BGP peer ASN (required for onprem if `bgp_enabled` is True)
        - `bgp_peer_ip` (string): the BGP peer IP (required for onprem if `bgp_enabled` is True)
    - Returns:
        - an instance of the `AppService` class if app service creation is successful
        - `None` if app service creation fails
        - Error message (dict) if error in app service creation.
    ```
    AS_creation_response, error = bt.create_app_service(
        app_service_name="ExampleAppService",
        location="aws",
        region="us-west-2",
        cloud_endpoint_service_name="cloud_service_name",
        service_node_group_id=None,
        fqdn=None,
        proto="https",
        port="443")

    if error:
        print(f"Error creating app service: {error}")
    else:
        print(f"App service successfully created: {AS_creation_response}")
    ```

- `get_app_service(app_service_name)`
    - Retrieves the app service with the inputted name
    - Parameters:
        - `app_service_name` (string): the name of the app service
    - Returns:
        - a list of `AppService` instances if app service retrieval is successful
        - `None` if the app service retrieval fails
        - Error message (dict) if error in app service retrieval
    ```
    response, error = bt.get_app_service(app_service_name="example-app-service")

    if error:
        print(f"Error retrieving app service: {error}")
    else:
        print(f"App service: {response}")
    ```

- `remove_app_service(app_service_id)`
    - Removes the app service associated with the inputted app service ID
    - Parameters:
        - `app_service_id` (string): the ID of the app service to remove
    - Returns:
        - JSON response (dict) if the app service removal is successful
        - `None` if the app service removal fails
        - Error message (dict) if error in app service removal
    ```
    AS_removal_response, error = bt.remove_app_service(app_service_id="service_id")

    if error:
        print(f"Error removing app service: {error}")
    else:
    print(f"App service successfully removed: {AS_removal_response}")
    ```

- `get_app_service_detail(app_service_id)`
    - Retrieves details of the app service associated with the inputted app service ID
    - Parameters:
        - `app_service_id` (string): the ID of the app service that will have its details retrieved
    - Returns:
        - JSON response (dict) if the app service details retrieval is successful
        - `None` if the app service details retrieval fails
        - Error message (dict) if error in app service details retrieval
    ```
    AS_details_response, error = bt.get_app_service_detail(app_service_id="service_id")
    if error:
        print(f"Error retrieving app service details: {error}")
    else:
        print(f"App service details: {AS_details_response}")
    ```

- `add_app_service_hosting(app_service_id, location, region, cloud_endpoint_service_name, service_node_group_id, fqdn)`
    - Adds inputted hosting details to the app service associated with the inputted app service ID
    - Parameters:
        - `app_service_id` (string): the ID of the app service
        - `location` (string): the hosting location of the app service (aws, azure, or onprem)
        - `region` (string): the region for the hosting location (required for aws and azure)
        - `cloud_endpoint_service_name` (string): the cloud endpoint service name (required for aws and azure)
        - `service_node_group_id` (string): the service node group ID (required for onprem)
        - `fqdn` (string): the FQDN (fully qualified domain name) for the app service (required for onprem)
    - Returns:
        - an instance of the `AppService` class if adding hosting to the app service is successful
        - `None` if adding hosting to the app service fails
        - Error message (dict) if error in adding hosting to the app service
    ```
    response, error = bt.add_app_service_hosting(
    app_service_id="app_service_id",
    location="aws",
    region="us-west-2",
    cloud_endpoint_service_name="cloud_service_name",
    service_node_group_id=None,
    fqdn=None)

    if error:
        print(f"Error adding app service hosting: {error}")
    else:
        print(f"App service hosting successfully added: {response}")
    ```

- `get_app_service_hosting(app_service_id, hosting_type)`
    - Retrieves hosting details for the app service associated with the inputted app service ID
    - Parameters:
        - `app_service_id` (string): the app service ID that will have its hosting details retrieved
        - `hosting_type` (string): the type of hosting to retrieve (optional)
    - Returns:
        - JSON response (dict) if the app service hosting retrieval is successful
        - `None` if the app service hosting retrieval fails
        - Error message (dict) if error in app service hosting
    ```
    response, error = bt.get_app_service_hosting(app_service_id="app_service_id")
    if error:
        print(f"Error retrieving app service hosting: {error}")
    else:
        print(f"App service hosting: {response}")
    ```

- `remove_app_service_hosting(app_service_id, hosting_id)`
    - Removes hosting details from the app service associated with the inputted app service ID
    - Parameters:
        - `app_service_id` (string): the app service ID that will have its hosting details removed
        - `hosting_id` (string): the ID of the hosting to remove
    - Returns:
        - an instance of the `AppService` class if hosting removal from the app service is successful
        - `None` if hosting removal from the app service fails
        - Error message (dict) if error in hosting removal from the app service
    ```
    response, error = bt.remove_app_service_hosting( app_service_id="app_service_id", hosting_id="hosting_id")

    if error:
        print(f"Error removing app service hosting: {error}")
    else:
        print(f"App service hosting successfully removed: {response}")
    ```

- `resize_app_service(app_service_id, hosting_id, direction)`
    - Changes the throughput of the app service associated with the inputted app service ID by the inputted direction (up or down)
    - Parameters:
        - `app_service_id` (string): the app service ID that will be resized
        - `hosting_id` (string): the ID of the hosting
        - `direction` (string): the direction to resize (e.g. `up` or `down`)
            - `up`: increases the throughput of the app service, thereby handling more endpoints
            - `down`: reduces the throghput of the app service, thereby handling less endpoints 
    - Returns:
        - JSON response (dict) if the app service hosting resizing is successful
        - `None` if app service resizing fails
        - Error message (dict) if error in app service resizing
    ```
    response, error = bt.resize_app_service(app_service_id="app_service_id", hosting_id="hosting_id", direction="up")
    if error:
        print(f"Error resizing app service: {error}")
    else:
        print(f"App service successfully resized: {response}")
    ```

- `update_app_service_contacts(app_service_id, primary_contact_id, secondary_contact_id)`
    - Updates the primary and secondary contact details for the app service associated with the inputted app service ID
    - Parameters:
        - `app_service_id` (string): the app service ID that will have its contacts updated
        - `primary_contact_id` (string): the ID of the primary contact (optional)
        - `secondary_contact_id` (string): the ID of the secondary contact (optional)
    - Returns:
        - a boolean representing if updating the contact details is successful
        - `None` if updating the contact details fails
        - Error message (dict) if error in updating the contact details 
    ```
    success, error = bt.update_app_service_contacts(app_service_id="app_service_id", primary_contact_id="primary_contact_id", secondary_contact_id="secondary_contact_id")
    
    if not success:
        print(f"Error updating app service contacts: {error}")
    else:
        print("App service contacts successfully updated.")
    ```

#### Endpoint Node Group methods:
- `create_ep_node_group(ep_node_group_name, ep_node_name)`
    - Creates a new endpoint node group with the inputted parameters
    - Parameters:
        - `ep_node_group_name` (string): the endpoint node group name
        - `ep_node_name` (string): the endpoint node name (optional)
    - Returns:
        - an instance of the `EpNodeGroup` class if endpoint node group creation is successful
        - `None` if endpoint node group creation fails
        - Error message (dict) if error in endpoint node group creation
    ```
    EP_node_group_response, error = bbt.create_ep_node_group(ep_node_group_name="example_ep_node_group_name", ep_node_name="example_ep_node_name")

    if error:
        print(f"Error creating endpoint node group: {error}")
    else:
        print(f"Endpoint node group successfully created: {EP_node_group_response}")
    ```

- `get_ep_node_groups(ep_node_group_name)`
    - Retrieves a list of endpoint node groups
    - Parameters:
        - `ep_node_group_name` (string): the endpoint node group name to filter by
    - Returns:
        - a list of `EpNodeGroup` instances if endpoint node group retrieval is successful
        - `None` if endpoint node group retrieval fails
        - Error message (dict) if error in endpoint node group retrieval
    ```
    ep_node_groups, error = bt.get_ep_node_groups(ep_node_group_name="group_name")
    
    if error:
        print(f"Error retrieving endpoint node groups: {error}")
    else:
        print(f"Endpoint node groups: {ep_node_groups}")
    ```

- `remove_ep_node_group(ep_node_group_id)`
    - Removes the endpoint node group associated with the inputted endpoint group ID
    - Parameters:
        - `ep_node_group_id` (string): the endpoint node group ID to remove
    - Returns:
        - JSON response (dict) if the endpoint node group removal is successful
        - `None` if endpoint node group removal fails
        - Error message (dict) if error in endpoint node group removal
    ```
    response, error = bt.remove_ep_node_group(ep_node_group_id="ep_node_group_id")
    
    if error:
        print(f"Error removing endpoint node group: {error}")
    else:
        print(f"Endpoint node group successfully removed: {response}")
    ```

#### Endpoint Node methods
- `create_ep_node(ep_node_group_id, ep_node_name)`
    - Creates a new endpoint node with its endpoint node group as the specified endpoint node group
    - Parameters:
        - `ep_node_group_id` (string): the endpoint node group ID to identify the endpoint node group that the new endpoint would fall under
        - `ep_node_name` (string): the name of the new endpoint node to be created
    - Returns:
        - an instance of the `EpNode` class if endpoint node creation is successful
        - `None` if endpoint node creation fails
        - Error message (dict) if error in endpoint node creation
    ```
    ep_node, error = bt.create_ep_node(ep_node_group_id="ep_node_group_id", ep_node_name="ep_node_name")
    
    if error:
        print(f"Error creating endpoint node: {error}")
    else:
        print(f"Endpoint node successfully created: {ep_node}")
    ```

- `get_ep_nodes(ep_node_group_id, ep_node_name)`
    - Retrieves a list of endpoint nodes in the specified endpoint node group
    - Parameters:
        - `ep_node_group_id` (string): the endpoint node group ID
        - `ep_node_name` (string): the name of the endpoint node to filter by (optional)
    - Returns:
        - a list of `EpNode` instances if endpoint nodes retrieval is successful
        - `None` if endpoint nodes retrieval fails
        - Error message (dict) if error in endpoint nodes retrieval
    ```
    ep_nodes, error = bt.get_ep_nodes(ep_node_group_id="ep_node_group_id", ep_node_name="ep_node_name")
    
    if error:
        print(f"Error retrieving endpoint nodes: {error}")
    else:
        print(f"Endpoint nodes: {ep_nodes}")
    ```

- `remove_ep_node(ep_node_group_id, ep_node_id)`
    - Removes the specified endpoint node from the endpoint node group
    - Parameters:
        - `ep_node_group_id` (string): the ID of the endpoint node group
        - `ep_node_id` (string): the ID of the endpoint node to remove from the endpoint node group
    - Returns:
        - JSON response if the endpoint node removal is successful
        - `None` if the endpoint node removal fails
        - Error message (dict) if error in endpoint node removal
    ```
    response, error = bt.remove_ep_node(ep_node_group_id="ep_node_group_id", ep_node_id="ep_node_id")

    if error:
        print(f"Error removing endpoint node: {error}")
    else:
        print(f"Endpoint node removed: {response}")
    ```

- `get_endpoint_node_detail(ep_node_id)`
    - Retrieves the endpoint node details of the endpoint associated with the inputted endpoint node ID
    - Parameters:
        -  `ep_node_id` (string): the endpoint node ID of the endpoint node that will have its details retrieved
    - Returns:
        - JSON response if the endpoint node details retrieval is successful
        - `None` if the endpoint node details retrieval fails
        - Error message (dict) if error in endpoint node details retrieval
    ```
    endpoint_node_details, error = bt.get_endpoint_node_detail(ep_node_id="ep_node_id")
    
    if error:
        print(f"Error retrieving endpoint node detail: {error}")
    else:
        print(f"Endpoint node detail: {endpoint_node_details}")
    ```

- `add_endpoint_node_secondary_ips(ep_node_id, secondary_ips)`
    - Adds secondary IPs to the endpoint node associated with the inputted endpoint node ID
    - Parameters:
        - `ep_node_id` (string): the ID of the endpoint node that will have secondary IPs added to it
        - `secondary_ips` (string): the secondary IPs to add to the endpoint node
    - Returns:
        - JSON response if adding the secondary IPs to the endpoint node is successful
        - `None` if adding the secondary IPs to the endpoint node fails
        - Error message (dict) if error in adding the secondary IPs to the endpoint node
    ```
    response, error = bt.add_endpoint_node_secondary_ips(ep_node_id="ep_node_id", secondary_ips="192.123.1.2, 192.123.1.3")
    
    if error:
        print(f"Error adding secondary IPs: {error}")
    else:
        print(f"Secondary IPs successfully added: {response}")
    ```

- `set_endpoint_node_form_factor(ep_node_id, form_factor, shipping_addr)`
    - Sets the form factor for the endpoint node associated with the inputted endpoint node ID
    - Parameters:
        - `ep_node_id` (string): the ID of the endpoint node that will have its form factor set up
        - `form_factor` (string): the form factor to set to the endpoint node
        - `shipping_addr` (string): the shipping address (optional)
    - Returns:
        - JSON response if setting up the form factor for the endpoint node is successful
        - `None` if the endpoint node form factor setup fails
        - Error message (dict) if error in endpoint node form factor setup

#### Endpoint methods
- `create_ep(create_ep(app_service_id, ep_node_group_id, ep_node_id, ep_name, ep_deployment, region, consumer_principle, verbose, real_subnets, bgp_enabled, bgp_local_asn, bgp_peer_asn, bgp_peer_ip)`
    - Creates a new endpoint with the inputted parameters
    - Parameters:
        - `app_service_id` (string): the app service's ID
        - `ep_node_group_id` (string): the endpoint node group ID
        - `ep_node_id` (string): the endpoint node ID
        - `ep_name` (string): the name of the endpoint to be created
        - `ep_deployment` (string): the deployment type of the endpoint (agent, onprem, or aws)
        - `region` (string): the region for AWS deployment (required for AWS)
        - `consumer_principle` (string): the allowed principal principle (required for AWS)
        - `verbose` (boolean): a boolean representing whether the input data should be printed (optional). default status is set as False
        - `real_subnets` (string): the real subnets (required for onprem)
        - `bgp_enabled` (boolean): a boolean indicating if BGP is enabled (required for onprem)
        - `bgp_local_asn` (string): the local ASN for BGP (required for onprem)
        - `bgp_peer_asn` (string): the peer ASN for BGP (required for onprem)
        - `bgp_peer_ip` (string): the peer IP for BGP (required for onprem)
    - Returns:
        - an instance of the `Ep` class if the endpoint creation is successful 
        - `None` if the endpoint creation fails
        - Error message (dict) if error in endpoint creation
    ```
    response, error = bt.create_ep(
        app_service_id="app_service_id",
        ep_node_group_id="ep_node_group_id",
        ep_node_id="ep_node_id",
        ep_name="ep_name",
        ep_deployment="onprem",
        real_subnets="192.168.1.0/24",
        bgp_enabled=True,
        bgp_local_asn="65101",
        bgp_peer_asn="65102",
        bgp_peer_ip="192.168.1.1")
    if error:
        print(f"Error creating EP: {error}")
    else:
        print(f"Successfully created EP: {response}")
    ```

- `get_eps(app_service_id, ep_node_id, ep_name, verbose)`
    - Retrieves a list of endpoints based on inputted filters
    - Parameters:
        - `app_service_id` (string): the app service ID to filter the retrieval by (optional)
        - `ep_ndoe_id` (string): the endpoint node ID to filter the retrieval by (optional)
        - `ep_name` (string): the endpoint name to filter the retrieval by (optional)
        - `verbose` (boolean): a boolean representing if each item in the result should be printed (optional). default status is set as True
    - Returns:
        - a list of `Ep` objects representing a list of the retrieved endpoints if the endpoint retrieval is successful
        - `None` if the endpoint retrieval fails
        - Error message (dict) if error in retrieving the endpoints
    ```
    eps, error = bt.get_eps(app_service_id="app_service_id", ep_node_id="ep_node_id", verbose=True)
    
    if error:
        print(f"Error retrieving EPs: {error}")
    else:
        print(f"Successfully retrieved EPs: {eps}")
    ```

- `remove_ep(ep_id)`
    - Removes the endpoint associated with the inputted endpoint ID
    - Parameters:
        - `ep_id` (string): the endpoint ID to be removed
    - Returns:
        - JSON response (dict) if the endpoint removal is successful
        - `None` if the endpoint removal fails
        - Error message (dict) if error in endpoint remova