def delete_device( cmd, app_id: str, device_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ) -> dict: """ Delete a device from IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: {"result": "success"} on success Raises error on failure """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id) headers = _utility.get_headers(token, cmd) response = requests.delete(url, headers=headers) return _utility.try_extract_result(response)
def create_device_template( cmd, app_id: str, device_template_id: str, payload: dict, token: str, central_dns_suffix="azureiotcentral.com", ) -> list: """ Create a device template in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_template_id: case sensitive device template id, payload: see example payload available in <repo-root>/azext_iot/tests/central/json/device_template_int_test.json or check here for more information https://docs.microsoft.com/en-us/rest/api/iotcentral/devicetemplates token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_template_id) headers = _utility.get_headers(token, cmd, has_json_payload=True) response = requests.put(url, headers=headers, json=payload) return _utility.try_extract_result(response)
def get_device( cmd, app_id: str, device_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ) -> Device: """ Get device info given a device id Args: cmd: command passed into az device_id: unique case-sensitive device id, app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id) headers = _utility.get_headers(token, cmd) response = requests.get(url, headers=headers) result = _utility.try_extract_result(response) return Device(result)
def get_api_token_list( cmd, app_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Get the list of API tokens for a central app. Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: tokens: dict """ url = "https://{}.{}/{}".format(app_id, central_dns_suffix, BASE_PATH) headers = _utility.get_headers(token, cmd) response = requests.get(url, headers=headers) return _utility.try_extract_result(response)
def get_api_token( cmd, app_id: str, token: str, token_id: str, api_version=ApiVersion.v1.value, central_dns_suffix=CENTRAL_ENDPOINT, ) -> dict: """ Get information about a specified API token. Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') token_id: Unique ID for the API token. central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: token: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, token_id) headers = _utility.get_headers(token, cmd) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version response = requests.get(url, headers=headers, params=query_parameters) return _utility.try_extract_result(response)
def get_device_template( cmd, app_id: str, device_template_id: str, token: str, central_dns_suffix="azureiotcentral.com", ) -> dict: """ Get a specific device template from IoTC Args: cmd: command passed into az device_template_id: case sensitive device template id, app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_template_id) headers = _utility.get_headers(token, cmd) response = requests.get(url, headers=headers) return _utility.try_extract_result(response)
def delete_user( cmd, app_id: str, token: str, assignee: str, central_dns_suffix=CENTRAL_ENDPOINT, ): """ delete user from theapp. Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') assignee: unique ID of the user central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: users: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, assignee) headers = _utility.get_headers(token, cmd) response = requests.delete(url, headers=headers) return _utility.try_extract_result(response)
def run_manual_failback( cmd, app_id: str, device_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Execute a manual failback for device. Reverts the previously executed failover command by moving the device back to it's original IoT Hub. Args: cmd: command passed into az app_id: id of an app (used for forming request URL) device_id: unique case-sensitive device id token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: result (currently a 200) """ url = "https://{}.{}/{}/{}/manual-failback".format( app_id, central_dns_suffix, "system/iothub/devices", device_id ) headers = _utility.get_headers(token, cmd) response = requests.post( url, headers=headers, verify=not should_disable_connection_verify() ) _utility.log_response_debug(response=response, logger=logger) return _utility.try_extract_result(response)
def list_device_templates( cmd, app_id: str, token: str, central_dns_suffix="azureiotcentral.com", ) -> list: """ Get a list of all device templates in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ url = "https://{}.{}/{}".format(app_id, central_dns_suffix, BASE_PATH) headers = _utility.get_headers(token, cmd) response = requests.get(url, headers=headers) result = _utility.try_extract_result(response) if "value" not in result: raise CLIError("Value is not present in body: {}".format(result)) return result["value"]
def delete_device_template( cmd, app_id: str, device_template_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, api_version=ApiVersion.v1.value, ) -> dict: """ Delete a device template from IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_template_id: case sensitive device template id, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_template_id) headers = _utility.get_headers(token, cmd) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version response = requests.delete(url, headers=headers, params=query_parameters) return _utility.try_extract_result(response)
def get_component_command_history( cmd, app_id: str, token: str, device_id: str, interface_id: str, command_name: str, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Get component command history Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id interface_id: interface id where command exists command_name: name of command to view execution history token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: Command history (List) - currently limited to 1 item """ url = "https://{}.{}/{}/{}/components/{}/commands/{}".format( app_id, central_dns_suffix, BASE_PATH, device_id, interface_id, command_name) headers = _utility.get_headers(token, cmd) response = requests.get(url, headers=headers) return _utility.try_extract_result(response)
def add_service_principal( cmd, app_id: str, assignee: str, tenant_id: str, object_id: str, role: Role, token: str, central_dns_suffix=CENTRAL_ENDPOINT, api_version=ApiVersion.v1.value, ) -> dict: """ Add a user to a Central app Args: cmd: command passed into az tenant_id: tenant id of service principal to be added object_id: object id of service principal to be added app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: user: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, assignee) if api_version == ApiVersion.v1.value: user_type = UserTypeV1.service_principal.value else: user_type = UserTypePreview.service_principal.value payload = { "tenantId": tenant_id, "objectId": object_id, "type": user_type, "roles": [{ "role": role.value }], } headers = _utility.get_headers(token, cmd, has_json_payload=True) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version response = requests.put(url, headers=headers, json=payload, params=query_parameters) return _utility.try_extract_result(response)
def list_roles( cmd, app_id: str, token: str, max_pages=1, central_dns_suffix=CENTRAL_ENDPOINT, api_version=ApiVersion.preview.value, ) -> List[central_models.RolePreview]: """ Get a list of all roles in IoTC app Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch role details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: list of roles """ roles = [] url = "https://{}.{}/{}".format(app_id, central_dns_suffix, BASE_PATH) headers = _utility.get_headers(token, cmd) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version pages_processed = 0 while (pages_processed <= max_pages) and url: response = requests.get(url, headers=headers, params=query_parameters, verify=not should_disable_connection_verify()) result = _utility.try_extract_result(response) if "value" not in result: raise CLIError("Value is not present in body: {}".format(result)) roles = roles + [ central_models.RolePreview(role) for role in result["value"] ] try: url = result.get("nextLink", params=query_parameters) except: pass pages_processed = pages_processed + 1 return roles
def run_component_command( cmd, app_id: str, token: str, device_id: str, interface_id: str, command_name: str, payload: dict, central_dns_suffix=CENTRAL_ENDPOINT, api_version=ApiVersion.v1.value, ): """ Execute a direct method on a device Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id interface_id: interface id where command exists command_name: name of command to execute payload: params for command token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: result (currently a 201) """ url = "https://{}.{}/{}/{}/components/{}/commands/{}".format( app_id, central_dns_suffix, BASE_PATH, device_id, interface_id, command_name ) headers = _utility.get_headers(token, cmd) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version response = requests.post( url, headers=headers, json=payload, params=query_parameters ) # execute command response has caveats in it due to Async/Sync device methods # return the response if we get 201, otherwise try to apply generic logic if response.status_code == 201: return response.json() return _utility.try_extract_result(response)
def create_device( cmd, app_id: str, device_id: str, device_name: str, instance_of: str, simulated: bool, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ) -> Device: """ Create a device in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id device_name: (non-unique) human readable name for the device instance_of: (optional) string that maps to the device_template_id of the device template that this device is to be an instance of simulated: if IoTC is to simulate data for this device token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ if not device_name: device_name = device_id url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id) headers = _utility.get_headers(token, cmd, has_json_payload=True) payload = { "displayName": device_name, "simulated": simulated, "approved": True, } if instance_of: payload["instanceOf"] = instance_of response = requests.put(url, headers=headers, json=payload) result = _utility.try_extract_result(response) return Device(result)
def get_device_registration_summary( cmd, app_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ) -> dict: """ Get device registration summary for a given app Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: registration summary """ registration_summary = {status.value: 0 for status in DeviceStatus} url = "https://{}.{}/{}?api-version={}".format( app_id, central_dns_suffix, BASE_PATH, ApiVersion.v1.value ) headers = _utility.get_headers(token, cmd) logger.warning( "This command may take a long time to complete if your app contains a lot of devices" ) while url: response = requests.get( url, headers=headers, verify=not should_disable_connection_verify() ) result = _utility.try_extract_result(response) if "value" not in result: raise CLIError("Value is not present in body: {}".format(result)) for device in result["value"]: registration_summary[ central_models.DeviceV1(device).device_status.value ] += 1 print("Processed {} devices...".format(sum(registration_summary.values()))) url = result.get("nextLink") return registration_summary
def create_device_template( cmd, app_id: str, device_template_id: str, payload: dict, token: str, central_dns_suffix=CENTRAL_ENDPOINT, api_version=ApiVersion.v1.value, ) -> Union[central_models.TemplatePreview, central_models.TemplateV1]: """ Create a device template in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_template_id: case sensitive device template id, payload: see example payload available in <repo-root>/azext_iot/tests/central/json/device_template_int_test.json or check here for more information https://docs.microsoft.com/en-us/rest/api/iotcentral/devicetemplates token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_template_id) headers = _utility.get_headers(token, cmd, has_json_payload=True) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version response = requests.put(url, headers=headers, json=payload, params=query_parameters) if api_version == ApiVersion.preview.value: return central_models.TemplatePreview( _utility.try_extract_result(response)) else: return central_models.TemplateV1(_utility.try_extract_result(response))
def add_api_token( cmd, app_id: str, token_id: str, role: Role, token: str, api_version=ApiVersion.v1.value, central_dns_suffix=CENTRAL_ENDPOINT, ) -> dict: """ Add an API token to a Central app Args: cmd: command passed into az app_id: name of app (used for forming request URL) token_id: Unique ID for the API token. role : permission level to access the application token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: token: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, token_id) payload = { "roles": [{ "role": role.value }], } # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version headers = _utility.get_headers(token, cmd, has_json_payload=True) response = requests.put(url, headers=headers, json=payload, params=query_parameters) return _utility.try_extract_result(response)
def run_manual_failover( cmd, app_id: str, device_id: str, ttl_minutes: int = None, token: str = None, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Execute a manual failover of device across multiple IoT Hubs to validate device firmware's ability to reconnect using DPS to a different IoT Hub. Args: cmd: command passed into az app_id: id of an app (used for forming request URL) device_id: unique case-sensitive device id ttl_minutes: (OPTIONAL) An optional value to specify the expiration time of this manual failover test before the device moves back to it's original IoT Hub. This has a default value of 30 minutes, but can optionally be any positive integer between 1 and 30. token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix:(OPTIONAL) {centralDnsSuffixInPath} as found in docs Returns: result (currently a 200) """ url = "https://{}.{}/{}/{}/manual-failover".format( app_id, central_dns_suffix, "system/iothub/devices", device_id ) headers = _utility.get_headers(token, cmd) json = {} if ttl_minutes: json = {"ttl": ttl_minutes} else: print( """Using default time to live - see https://github.com/iot-for-all/iot-central-high-availability-clients#readme for more information""" ) response = requests.post( url, headers=headers, verify=not should_disable_connection_verify(), json=json ) _utility.log_response_debug(response=response, logger=logger) return _utility.try_extract_result(response)
def get_device( cmd, app_id: str, device_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, api_version=ApiVersion.v1.value, ) -> Union[central_models.DevicePreview, central_models.DeviceV1]: """ Get device info given a device id Args: cmd: command passed into az device_id: unique case-sensitive device id, app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id) headers = _utility.get_headers(token, cmd) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version response = requests.get( url, headers=headers, params=query_parameters, verify=not should_disable_connection_verify(), ) result = _utility.try_extract_result(response) if api_version == ApiVersion.preview.value: return central_models.DevicePreview(result) else: return central_models.DeviceV1(result)
def list_device_templates( cmd, app_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, api_version=ApiVersion.v1.value, ) -> List[Union[central_models.TemplatePreview, central_models.TemplateV1]]: """ Get a list of all device templates in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ url = "https://{}.{}/{}".format(app_id, central_dns_suffix, BASE_PATH) headers = _utility.get_headers(token, cmd) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version response = requests.get(url, headers=headers, params=query_parameters) result = _utility.try_extract_result(response) if "value" not in result: raise CLIError("Value is not present in body: {}".format(result)) if api_version == ApiVersion.preview.value: return [ central_models.TemplatePreview(item) for item in result["value"] ] else: return [central_models.TemplateV1(item) for item in result["value"]]
def list_devices( cmd, app_id: str, token: str, max_pages=1, central_dns_suffix=CENTRAL_ENDPOINT, ) -> List[Device]: """ Get a list of all devices in IoTC app Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: list of devices """ devices = [] url = "https://{}.{}/{}".format(app_id, central_dns_suffix, BASE_PATH) headers = _utility.get_headers(token, cmd) pages_processed = 0 while (pages_processed <= max_pages) and url: response = requests.get(url, headers=headers) result = _utility.try_extract_result(response) if "value" not in result: raise CLIError("Value is not present in body: {}".format(result)) devices = devices + [Device(device) for device in result["value"]] url = result.get("nextLink") pages_processed = pages_processed + 1 return devices
def add_email( cmd, app_id: str, assignee: str, email: str, role: Role, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Add a user to a Central app Args: cmd: command passed into az email: email of user to be added app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: user: dict """ url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, assignee) payload = { "email": email, "type": UserType.email.value, "roles": [{ "role": role.value }], } headers = _utility.get_headers(token, cmd, has_json_payload=True) response = requests.put(url, headers=headers, json=payload) return _utility.try_extract_result(response)
def create_device( cmd, app_id: str, device_id: str, device_name: str, template: str, simulated: bool, token: str, central_dns_suffix=CENTRAL_ENDPOINT, api_version=ApiVersion.v1.value, ) -> Union[central_models.DevicePreview, central_models.DeviceV1]: """ Create a device in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id device_name: (non-unique) human readable name for the device template: (optional) string that maps to the device_template_id of the device template that this device is to be an instance of simulated: if IoTC is to simulate data for this device token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ if not device_name: device_name = device_id url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id) headers = _utility.get_headers(token, cmd, has_json_payload=True) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version if api_version == ApiVersion.preview.value: payload = { "displayName": device_name, "simulated": simulated, "approved": True, } if template: payload["instanceOf"] = template else: payload = { "displayName": device_name, "simulated": simulated, "enabled": True, } if template: payload["template"] = template response = requests.put(url, headers=headers, json=payload, params=query_parameters) result = _utility.try_extract_result(response) if api_version == ApiVersion.preview.value: return central_models.DevicePreview(result) else: return central_models.DeviceV1(result)