diff --git a/README.md b/README.md index 1e923d8..71824be 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Edge Connect web interfaces under "Support > Rest API" Many, but not all API functions have been implemented yet. Development is underway to continue to add further functions. -As of 0.13.0+ ~62% of non-deprecated Swagger functions are covered. +As of 0.14.0+ 64% of non-deprecated Swagger functions are covered. ## Install diff --git a/_version.py b/_version.py index 7d3ce05..ce4c8f2 100644 --- a/_version.py +++ b/_version.py @@ -1 +1 @@ -version = "0.13.0a3.dev0" +version = "0.14.0a1.dev0" diff --git a/docs/source/release-notes/0.14.0-a1.rst b/docs/source/release-notes/0.14.0-a1.rst new file mode 100644 index 0000000..e65f52f --- /dev/null +++ b/docs/source/release-notes/0.14.0-a1.rst @@ -0,0 +1,40 @@ +0.14.0-a1 -- 2021-07-13 +----------------------- + + +🚀 Features +~~~~~~~~~~~~~ + +Added the following Orchestrator functions from Swagger + +from .orch._license + - get_nx_licensed_appliances + - get_vx_licensed_appliances + - get_portal_licensed_summary + - get_portal_licensed_appliances + - change_appliance_license + - grant_appliance_base_license + - revoke_appliance_base_license + - delete_appliance_license_token + +from .orch._wan_next_hop_health + - get_wan_next_hop_health_config + + +# Custom certs introduced in Orchestrator 9.0.4+ and Edge Connect 9+ + +from .orch._custom_certs + - get_custom_certs + - update_custom_certs + - delete_custom_cert + - get_custom_certs_enabled + - set_custom_certs_enabled + - check_custom_certs_orchestrator_to_portal + - check_custom_certs_appliances_to_portal + - verify_custom_cert + + +📚 Documentation +~~~~~~~~~~~~~~~~~~ + +- Updated README with Swagger coverage % diff --git a/docs/source/release-notes/index.rst b/docs/source/release-notes/index.rst index b49a20e..2566c4c 100644 --- a/docs/source/release-notes/index.rst +++ b/docs/source/release-notes/index.rst @@ -8,4 +8,5 @@ All of the release notes for pyedgeconnect are organized below ================== .. toctree:: + 0.14.0-a1 0.13.0-a1 \ No newline at end of file diff --git a/pyedgeconnect/__init__.py b/pyedgeconnect/__init__.py index 194671a..7e51b64 100644 --- a/pyedgeconnect/__init__.py +++ b/pyedgeconnect/__init__.py @@ -696,6 +696,16 @@ def __init__( from .orch._broadcast_cli import broadcast_cli from .orch._built_in_policies import get_built_in_policies from .orch._custom_appliance_tags import get_custom_appliance_tags + from .orch._custom_certs import ( + check_custom_certs_appliances_to_portal, + check_custom_certs_orchestrator_to_portal, + delete_custom_cert, + get_custom_certs, + get_custom_certs_enabled, + set_custom_certs_enabled, + update_custom_certs, + verify_custom_cert, + ) from .orch._db_partition import delete_db_partition, get_db_partition from .orch._debug_files import ( cancel_debug_file_download, @@ -804,6 +814,16 @@ def __init__( get_ip_allow_list_drops, update_ip_allow_list, ) + from .orch._license import ( + change_appliance_license, + delete_appliance_license_token, + get_nx_licensed_appliances, + get_portal_licensed_appliances, + get_portal_licensed_summary, + get_vx_licensed_appliances, + grant_appliance_base_license, + revoke_appliance_base_license, + ) from .orch._link_integrity import get_link_integrity_test_result from .orch._location import get_location_coordinates_from_address from .orch._logging import get_appliance_syslog_config @@ -1078,6 +1098,7 @@ def __init__( from .orch._vrrp import get_vrrp_interfaes from .orch._vti import get_vti_interfaes from .orch._vxoa_hostname import update_appliance_hostname + from .orch._wan_next_hop_health import get_wan_next_hop_health_config from .orch._wccp import ( get_wccp_service_group_settings, get_wccp_state, diff --git a/pyedgeconnect/orch/_custom_certs.py b/pyedgeconnect/orch/_custom_certs.py new file mode 100644 index 0000000..c72b02f --- /dev/null +++ b/pyedgeconnect/orch/_custom_certs.py @@ -0,0 +1,273 @@ +# MIT License +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP. +# +# customCerts : Custom CA Certificate Trust Store + + +def get_custom_certs(self) -> list: + """Returns list of custom CA certificates from Orchestrator + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - customCerts + - GET + - /customCert + + :return: Returns list of custom certificates in Orchestrator \n + * keyword **alias** (`str`): Alias used to identify the CA + Certificate + * keyword **key** (`str`): The CA Certificate + * keyword **lastUpdatedTimestamp** (`str`): The timestamp of the + last time the CA Certificate was updated in Orchestrator + * keyword **expiration** (`str`): CA Certificate's expiration + date + * keyword **issuer** (`str`): CA Certificate's issuer + * keyword **issuedTo** (`str`): CA Certificate's issued to + :rtype: list + """ + return self._get("/customCert") + + +def update_custom_certs( + self, + alias: str, + key: str, + expiration: str, + issuer: str, + issued_to: str, + last_timestamp: str = "", +) -> bool: + """Add new or update existing custom CA certificate + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - customCerts + - POST + - /customCert + + :param alias: Alias used to identify the CA Certificate + :type alias: str + :param key: The CA Certificate + :type key: str + :param expiration: CA Certificate's expiration date + :type expiration: str + :param issuer: CA Certificate's issuer + :type issuer: str + :param issued_to: CA Certificate's issued to + :type issued_to: str + :param last_timestamp: The timestamp of the last time the CA + Certificate was updated in Orchestrator + :type last_timestamp: str, optional + :return: Returns True/False based on successful call + :rtype: bool + """ + data = { + "alias": alias, + "key": key, + "lastUpdatedTimestamp": last_timestamp, + "expiration": expiration, + "issuer": issuer, + "issuedTo": issued_to, + } + + return self._post( + "/customCert", + data=data, + expected_status=[204], + return_type="bool", + ) + + +def delete_custom_cert( + self, + alias: str, +) -> bool: + """Delete custom CA certificate + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - customCerts + - DELETE + - /customCert/{alias} + + :param alias: Alias used to identify the CA Certificate + :type alias: str + :return: Returns True/False based on successful call + :rtype: bool + """ + return self._delete( + "/customCert/{}".format(alias), + expected_status=[204], + return_type="bool", + ) + + +def get_custom_certs_enabled(self) -> dict: + """Returns whether or not Orchestrator is currently using custom CA + certificate trust store + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - customCerts + - GET + - /customCert/enable + + :return: Returns dictionary of custom certificates status \n + * keyword **enabled** (`bool`): ``True`` if custom CA + certificate trust store is in use, ``False`` if not in use + :rtype: dict + """ + return self._get("/customCert/enable") + + +def set_custom_certs_enabled( + self, + enabled: bool, +) -> dict: + """Enable or disable custom CA certificate trust store + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - customCerts + - POST + - /customCert/enable + + :param enabled: Set to ``True`` to enable use of custom CA + certificates trust store, ``False`` to use default certificates + trust store + :type enabled: bool + :return: Returns True/False based on successful call + :rtype: bool + """ + data = {"Enabled": enabled} + + return self._post( + "/customCert/enable", + data=data, + expected_status=[204], + return_type="bool", + ) + + +def check_custom_certs_orchestrator_to_portal( + self, + custom_certs: bool, +) -> dict: + """Checks whether Orchestrator can connect to Portal using the + default or custom CA certificates + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - customCerts + - GET + - /customCert/orchestratorConnectivity/{custom} + + :return: TBD + :rtype: TBD + """ + return self._get( + "/customCert/orchestratorConnectivity/{}".format(custom_certs) + ) + + +def check_custom_certs_appliances_to_portal( + self, + custom_certs: bool, +) -> dict: + """Checks whether appliances can connect to Portal and Orchestrator + using the default or custom CA certificates + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - customCerts + - GET + - /customCert/applianceConnectivity/{custom} + + :return: TBD + :rtype: TBD + """ + return self._get( + "/customCert/applianceConnectivity/{}".format(custom_certs) + ) + + +def verify_custom_cert( + self, + alias: str, + key: str, + expiration: str, + issuer: str, + issued_to: str, + last_timestamp: str = "", +) -> bool: + """Verify the custom CA certificate + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - customCerts + - POST + - /customCert/verify + + :param alias: Alias used to identify the CA Certificate + :type alias: str + :param key: The CA Certificate + :type key: str + :param expiration: CA Certificate's expiration date + :type expiration: str + :param issuer: CA Certificate's issuer + :type issuer: str + :param issued_to: CA Certificate's issued to + :type issued_to: str + :param last_timestamp: The timestamp of the last time the CA + Certificate was updated in Orchestrator + :type last_timestamp: str, optional + :return: Returns True/False based on successful call + :rtype: bool + """ + data = { + "alias": alias, + "key": key, + "lastUpdatedTimestamp": last_timestamp, + "expiration": expiration, + "issuer": issuer, + "issuedTo": issued_to, + } + + return self._post( + "/customCert/verify", + data=data, + expected_status=[204], + return_type="bool", + ) diff --git a/pyedgeconnect/orch/_license.py b/pyedgeconnect/orch/_license.py new file mode 100644 index 0000000..b07e251 --- /dev/null +++ b/pyedgeconnect/orch/_license.py @@ -0,0 +1,397 @@ +# MIT License +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP. +# +# license : License info about NX, VX, EC, and CPX appliances + + +def get_nx_licensed_appliances(self) -> list: + """Returns list of NX licensed appliances + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - license + - GET + - /license/nx + + :return: Returns list of NX licensed appliances in Orchestrator \n + [`dict`]: licensed appliance object \n + * keyword **hostname** (`str`): Hostname of appliance + * keyword **model** (`str`): Model of appliance + * keyword **serialNum** (`str`): Serial number of appliance + * keyword **saasEnabled** (`bool`): Whether SaaS + optimization is enabled on the appliance + * keyword **applianceId** (`str`): Appliance ID + * keyword **LicenseType** (`str`): Current license type + :rtype: list + """ + return self._get("/license/nx") + + +def get_vx_licensed_appliances(self) -> list: + """Returns list of VX licensed appliances + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - license + - GET + - /license/vx + + :return: Returns list of VX licensed appliances in Orchestrator \n + [`dict`]: licensed appliance object \n + * keyword **hostname** (`str`): Hostname of appliance + * keyword **model** (`str`): Model of appliance + * keyword **serialNum** (`str`): Serial number of appliance + * keyword **saasEnabled** (`bool`): Whether SaaS + optimization is enabled on the appliance + * keyword **applianceId** (`str`): Appliance ID + * keyword **LicenseType** (`str`): Current license type + * keyword **licenseStartDate** (`int`): License start date + in unix epoch + * keyword **licenseExpirationDate** (`int`): License + expiration date in unix epoch + :rtype: list + """ + return self._get("/license/vx") + + +def get_portal_licensed_summary(self) -> dict: + """Retrieves summary of portal licensed appliances + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - license + - GET + - /license/portal/summary + + :return: Returns summary of licensing information from Cloud Portal \n + * keyword **licenses** (`dict`): Account info object \n + * keyword **accountKey** (`dict`): Account key object \n + * keyword **key** (`str`): Account key + * keyword **fx** (`dict`): Standard EC license information \n + * keyword **enable** (`bool`): If licenses are enabled + * keyword **boost** (`int`): The amount of boost + licensed + * keyword **mini** (`int`): Number of mini licenses + * keyword **base** (`int`): Number of base licenses + * keyword **plus** (`int`): Number of plus licenses + * keyword **expire** (`int`): License expiration date in + unix epoch milliseconds + * keyword **boostExpire** (`int`): Boost license + expiration date in unix epoch milliseconds + * keyword **tier** (`dict`): Tiered license info \n + * keyword **1000000000** (`dict`): Unlimited licenses \n + * keyword **display** (`str`): Name of license + * keyword **count** (`int`): Number of licenses + * keyword **2000000** (`dict`): 2G licenses \n + * keyword **display** (`str`): Name of license + * keyword **count** (`int`): Number of licenses + * keyword **1000000** (`dict`): 1G licenses \n + * keyword **display** (`str`): Name of license + * keyword **count** (`int`): Number of licenses + * keyword **500000** (`dict`): 500M licenses \n + * keyword **display** (`str`): Name of license + * keyword **count** (`int`): Number of licenses + * keyword **200000** (`dict`): 200M licenses \n + * keyword **display** (`str`): Name of license + * keyword **count** (`int`): Number of licenses + * keyword **100000** (`dict`): 100M licenses \n + * keyword **display** (`str`): Name of license + * keyword **count** (`int`): Number of licenses + * keyword **50000** (`dict`): 50M licenses \n + * keyword **display** (`str`): Name of license + * keyword **count** (`int`): Number of licenses + * keyword **20000** (`dict`): 20M licenses \n + * keyword **display** (`str`): Name of license + * keyword **count** (`int`): Number of licenses + * keyword **cpx** (`dict`): CPX license information \n + * keyword **enable** (`bool`): If licenses are enabled + * keyword **expire** (`int`): Expiration date in Unix + epoch + * keyword **saas** (`dict`): SaaS Optimization license + information \n + * keyword **enable** (`bool`): If licenses are enabled + * keyword **expire** (`int`): Expiration date in Unix + epoch + * keyword **ecsp** (`dict`): Not documented \n + * keyword **enable** (`bool`): If licenses are enabled + * keyword **metered** (`dict`): Metered license information \n + * keyword **enable** (`bool`): If licenses are enabled + * keyword **expire** (`int`): Expiration date in Unix + epoch, ``null`` if not applicable + * keyword **cloudOrch** (`dict`): Not documented \n + * keyword **enable** (`bool`): If licenses are enabled, + ``null`` if not applicable + * keyword **salesforceExpirationDate** (`int`): + Expiration date in Unix epoch, ``null`` if not + applicable + * keyword **decommissionDate** (`int`): Expiration date + in Unix epoch, ``null`` if not applicable + * keyword **licenseState** (`dict`): License state object \n + * keyword **fx** (`dict`): Standard license state object \n + * keyword **numMini** (`int`): Number of mini licenses + * keyword **numBase** (`int`): Number of base licenses + * keyword **numBoost** (`int`): Boost bandwidth + * keyword **numPlus** (`int`): Number of plus licenses + * keyword **numTier** (`dict`): Tiered licenses \n + * keyword **1000000000** (`int`): Unlimited licenses + * keyword **2000000** (`int`): 2G licenses + * keyword **1000000** (`int`): 1G licenses + * keyword **500000** (`int`): 500M licenses + * keyword **200000** (`int`): 200M licenses + * keyword **100000** (`int`): 100M licenses + * keyword **50000** (`int`): 50M licenses + * keyword **20000** (`int`): 20M licenses + :rtype: dict + """ # noqa: W505 + return self._get("/license/portal/summary") + + +def get_portal_licensed_appliances(self) -> dict: + """Retrieves portal licensed appliances + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - license + - GET + - /license/portal/appliance + + :return: Returns list of licensed appliances from Cloud Portal \n + [`dict`]: Appliance license information object \n + * keyword **applianceId** (`str`): Appliance id in the format of + integer.NE e.g. ``3.NE`` + * keyword **id** (`str`): Not documented + * keyword **enabled** (`bool`): If appliance active + * keyword **hostname** (`str`): Hostname of appliance + * keyword **isPortalLicensed** (`bool`): If appliance is + licensed in Cloud Portal + * keyword **licenses** (`dict`): License state object \n + * keyword **fx** (`dict`): Standard license object \n + * keyword **base** (`dict`): Base license state \n + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **mini** (`dict`): Mini license state \n + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **plus** (`dict`): Plus license state \n + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **tier** (`dict`): Tier license state \n + * keyword **bandwidth** (`int`): Bandwidth + licensed + * keyword **display** (`str`): License display + name + * keyword **boost** (`dict`): Boost license state \n + * keyword **bandwidth** (`int`): Amount of boost + bandwidth in Mbps + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **metered** (`dict`): Metered license object \n + * keyword **boost** (`dict`): Boost license state \n + * keyword **bandwidth** (`int`): Amount of boost + bandwidth in Mbps + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **ecsp** (`dict`): Not documented \n + * keyword **licenseId** (`str`): Not documented \n + * keyword **licenseRequest** (`dict`): License requested + state object \n + * keyword **fx** (`dict`): Standard license object \n + * keyword **base** (`dict`): Base license state \n + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **mini** (`dict`): Mini license state \n + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **plus** (`dict`): Plus license state \n + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **tier** (`dict`): Tier license state \n + * keyword **bandwidth** (`int`): Bandwidth + licensed + * keyword **display** (`str`): License display + name + * keyword **boost** (`dict`): Boost license state \n + * keyword **bandwidth** (`int`): Amount of boost + bandwidth in Mbps + * keyword **enabled** (`bool`): ``True`` if active + * keyword **metered** (`dict`): Metered license object \n + * keyword **boost** (`dict`): Boost license state \n + * keyword **bandwidth** (`int`): Amount of boost + bandwidth in Mbps + * keyword **enabled** (`bool`): ``True`` if + active + * keyword **model** (`str`): Hardware model, e.g. ``EC-M-B`` + * keyword **portalLicenseType** (`int`): Not documented + * keyword **serial** (`str`): Appliance serial number + * keyword **saasEnabled** (`bool`): ``True`` if SaaS + Optimization is enabled + * keyword **expirationDate** (`int`): License expiration in + unix epoch + :rtype: list + """ # noqa: W505 + return self._get("/license/portal/appliance") + + +def change_appliance_license( + self, + ne_pk: str, + boost: bool, + boost_bw: int, + tier_name: str = None, + tier_bw: int = None, + mini: bool = None, + plus: bool = None, +) -> bool: + """Changes ec appliance license settings + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - license + - POST + - /license/portal/ec/{nePk} + + :param ne_pk: Appliance id in the format of integer.NE e.g. ``3.NE`` + :type ne_pk: str + :param boost: ``True`` to request to enable boost on appliance + :type boost: bool + :param boost_bw: Boost bandwidth to request, in Kbps + :type boost_bw: int + :param tier_bw: Tiered bandwidth to request, in Kbps. Accepted + values are ``20000``, ``50000``, ``100000``, ``200000``, + ``500000``, ``1000000``, ``2000000``, and for Unlimited use + ``1000000000`` + :type tier_bw: int, optional + :param tier_name: Display name of tiered license to request. Not + required in presence of using tier_bw parameter. + :type tier_name: str, optional + :return: Returns True/False based on successful call + :rtype: bool + """ + data = { + "license": { + "mini": {}, + "plus": {}, + "tier": {}, + "boost": {"enable": boost, "bandwidth": boost_bw}, + } + } + + if mini is not None: + data["license"]["mini"]["enable"] = mini + if plus is not None: + data["license"]["plus"]["enable"] = plus + if tier_name is not None: + data["license"]["tier"]["display"] = tier_name + if tier_bw is not None: + data["license"]["tier"]["bandwidth"] = tier_bw + + return self._post( + "/license/portal/ec/{}".format(ne_pk), + data=data, + return_type="bool", + ) + + +def grant_appliance_base_license( + self, + ne_pk: str, +) -> bool: + """Grant an appliance a base license via Cloud Portal + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - license + - POST + - /license/portal/appliance/grant/{nePk} + + :param ne_pk: Appliance id in the format of integer.NE e.g. ``3.NE`` + :type ne_pk: str + :return: Returns True/False based on successful call + :rtype: bool + """ + return self._post( + "/license/portal/appliance/grant/{}".format(ne_pk), + return_type="bool", + ) + + +def revoke_appliance_base_license( + self, + ne_pk: str, +) -> bool: + """Revoke base license from appliance via Cloud Portal + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - license + - POST + - /license/portal/appliance/revoke/{nePk} + + :param ne_pk: Appliance id in the format of integer.NE e.g. ``3.NE`` + :type ne_pk: str + :return: Returns True/False based on successful call + :rtype: bool + """ + return self._post( + "/license/portal/appliance/revoke/{}".format(ne_pk), + return_type="bool", + ) + + +def delete_appliance_license_token( + self, + ne_pk: str, +) -> bool: + """Delete an appliance's license token via the appliance. Used after + revoking an appliance. + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - license + - DELETE + - /license/portal/appliance/license/token/{nePk} + + .. warning:: + This will stop the appliance from passing traffic immediately! + + :param ne_pk: Appliance id in the format of integer.NE e.g. ``3.NE`` + :type ne_pk: str + :return: Returns True/False based on successful call + :rtype: bool + """ + return self._delete( + "/license/portal/appliance/license/token/{}".format(ne_pk), + return_type="bool", + ) diff --git a/pyedgeconnect/orch/_wan_next_hop_health.py b/pyedgeconnect/orch/_wan_next_hop_health.py new file mode 100644 index 0000000..8d33c0a --- /dev/null +++ b/pyedgeconnect/orch/_wan_next_hop_health.py @@ -0,0 +1,38 @@ +# MIT License +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP. +# +# wanNextHopHealth : Next hop health config + + +def get_wan_next_hop_health_config( + self, + ne_id: str, + cached: bool, +) -> dict: + """Get wan next hop health config on the appliance + + .. list-table:: + :header-rows: 1 + + * - Swagger Section + - Method + - Endpoint + * - wanNextHopHealth + - GET + - /appliance/wanNextHopHealth/{neId}?cached={cached} + + :param ne_id: Appliance id in the format of integer.NE e.g. ``3.NE`` + :type ne_id: str + :param cached: ``True`` retrieves last known value to Orchestrator, + ``False`` retrieves values directly from Appliance + :type cached: bool + :return: Returns dictionary of WAN Next Hop Health configurations \n + * keyword **enable** (`bool`): Enable or disable health check + * keyword **hold_down_count** (`int`): Hold down count + * keyword **interval** (`int`): Interval in seconds + * keyword **retry_count** (`int`): Retry count + :rtype: dict + """ + return self._get( + "/appliance/wanNextHopHealth/{}?cached={}".format(ne_id, cached) + )