Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add parsing for onboarding key #238

Merged
merged 2 commits into from
Apr 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions hm_pyhelper/hardware_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi3-64'],
'SPIBUS': 'spidev1.2',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 38,
'MAC': 'eth0',
'STATUS': 25,
Expand All @@ -48,6 +49,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi3-64'],
'SPIBUS': 'spidev1.2',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 38,
'MAC': 'eth0',
'STATUS': 25,
Expand All @@ -71,6 +73,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['rockpi-4b-rk3399'],
'SPIBUS': 'spidev32766.0',
'SWARM_KEY_URI': ['ecc://i2c-7:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-7:96?slot=0'],
'RESET': 149,
'MAC': 'eth0',
'STATUS': 156,
Expand All @@ -96,6 +99,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberry-pi'],
'SPIBUS': 'spidev1.2',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 22,
'MAC': 'wlan0',
'STATUS': 24,
Expand All @@ -117,6 +121,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberry-pi'],
'SPIBUS': 'spidev1.2',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 22,
'MAC': 'wlan0',
'STATUS': 24,
Expand All @@ -138,6 +143,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['radxa-zero'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-3:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-3:96?slot=0'],
'RESET': 415,
'MAC': 'wlan0',
'STATUS': 421,
Expand All @@ -159,6 +165,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberry-pi'],
'SPIBUS': 'spidev1.2',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 4,
'MAC': 'wlan0',
'STATUS': 26,
Expand All @@ -180,6 +187,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['beaglebone-black'],
'SPIBUS': 'spidev1.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 60,
'MAC': 'eth0',
'STATUS': 31,
Expand All @@ -201,6 +209,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['beaglebone-pocket'],
'SPIBUS': 'spidev1.2',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 60,
'MAC': 'wlan0',
'STATUS': 31,
Expand All @@ -222,6 +231,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['rockpi-4b-rk3399'],
'SPIBUS': 'spidev32766.0',
'SWARM_KEY_URI': ['ecc://i2c-7:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-7:96?slot=0'],
'RESET': 149,
'MAC': 'eth0',
'STATUS': 156,
Expand All @@ -245,6 +255,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['asus-tinker-board'],
'SPIBUS': 'spidev2.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 167,
'MAC': 'eth0',
'STATUS': 163,
Expand All @@ -266,6 +277,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi4-64'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 25,
'MAC': 'wlan0',
'STATUS': 20,
Expand Down Expand Up @@ -309,6 +321,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi4-64'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 17,
'MAC': 'wlan0',
'STATUS': 22,
Expand All @@ -330,6 +343,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi4-64'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 23,
'MAC': 'wlan0',
'STATUS': 22,
Expand All @@ -351,6 +365,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi4-64'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 17,
'MAC': 'wlan0',
'STATUS_LED': {
Expand All @@ -377,6 +392,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi4-64'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-0:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-0:96?slot=0'],
'RESET': 23,
'MAC': 'eth0',
'STATUS': 17,
Expand All @@ -398,6 +414,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi4-64'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 4,
'MAC': 'wlan0',
'STATUS_LED': {
Expand Down Expand Up @@ -426,6 +443,7 @@ def is_raspberry_pi() -> bool:
'raspberrypi4-64'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 22,
'MAC': 'eth0',
'STATUS': 20,
Expand All @@ -449,6 +467,7 @@ def is_raspberry_pi() -> bool:
'raspberrypi4-64'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 17,
'MAC': 'eth0',
'STATUS': 20,
Expand All @@ -470,6 +489,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypicm4-ioboard'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 17,
'MAC': 'wlan0',
'STATUS': 22,
Expand All @@ -491,6 +511,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['radxa-cm3-rpicm4-ioboard'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 17,
'MAC': 'wlan0',
'STATUS': 22,
Expand All @@ -512,6 +533,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypicm4-ioboard'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-10:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-10:96?slot=0'],
'RESET': 23,
'MAC': 'wlan0',
'STATUS': 22,
Expand Down Expand Up @@ -577,6 +599,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi4-64'],
'SPIBUS': 'spidev0.0', # There is a CSN1 pin which is connected to GPIO6 (HAT Pin 31)
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 22,
'MAC': 'eth0',
'STATUS': 21, # Stub. There is no status LED on X3. I2C-3 is used for display
Expand All @@ -599,6 +622,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypi3-64'],
'SPIBUS': 'spidev1.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 38,
'MAC': 'eth0',
'STATUS': 25,
Expand All @@ -620,6 +644,7 @@ def is_raspberry_pi() -> bool:
'BALENA_DEVICE_TYPE': ['raspberrypicm4-ioboard'],
'SPIBUS': 'spidev0.0',
'SWARM_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-1:96?slot=0'],
'RESET': 17,
'MAC': 'wlan0',
'STATUS': 22,
Expand Down
44 changes: 44 additions & 0 deletions hm_pyhelper/miner_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,50 @@ def get_ecc_location() -> str:
return ecc_location


def get_onboarding_location() -> str:
onboarding_list = get_variant_attribute(os.getenv('VARIANT'), 'ONBOARDING_KEY_URI')
onboarding_location = None

try:
with open("/var/nebra/onboarding_file", 'r') as data:
generated_onboarding_location = str(data.read()).rstrip('\n')

if len(generated_onboarding_location) < 10:
generated_onboarding_location = None
else:
LOGGER.info("Generated onboarding key location file found: "
+ generated_onboarding_location)
except FileNotFoundError:
# No onboarding key location file found, create variable with value None
generated_onboarding_location = None

if os.getenv('ONBOARDING_KEY_URI_OVERRIDE'):
onboarding_location = os.getenv('ONBOARDING_KEY_URI_OVERRIDE')
elif generated_onboarding_location is not None:
onboarding_location = generated_onboarding_location
elif len(onboarding_list) == 1:
onboarding_location = onboarding_list[0]
else:
for location in onboarding_list:
parse_result = urlparse(location)
i2c_bus = parse_i2c_bus(parse_result.hostname)
i2c_address = parse_i2c_address(parse_result.port)
command = f'i2cdetect -y {i2c_bus}'
parameter = f'{i2c_address} --'

if config_search_param(command, parameter):
onboarding_location = location
with open("/var/nebra/onboarding_file", "w") as file:
file.write(onboarding_location)
return onboarding_location

if not onboarding_location:
LOGGER.error("Can't find onboarding key. Ensure ONBOARDING_KEY_URI is "
"correct in hardware definitions.")

return onboarding_location


def get_gateway_mfr_command(sub_command: str, slot: int = False) -> list:
gateway_mfr_path = get_gateway_mfr_path()
command = [gateway_mfr_path]
Expand Down
80 changes: 77 additions & 3 deletions hm_pyhelper/tests/test_miner_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import sys
from unittest.mock import ANY, mock_open, patch, Mock
from packaging.version import Version
from hm_pyhelper.exceptions import ECCMalfunctionException, \
from hm_pyhelper.exceptions import ECCMalfunctionException, UnknownVariantAttributeException, \
MinerFailedToFetchMacAddress, GatewayMFRInvalidVersion, GatewayMFRExecutionException, \
GatewayMFRFileNotFoundException, UnsupportedGatewayMfrVersion
GatewayMFRFileNotFoundException, UnsupportedGatewayMfrVersion, UnknownVariantException
from hm_pyhelper.lock_singleton import ResourceBusyError
from hm_pyhelper.miner_param import retry_get_region, await_spi_available, \
provision_key, run_gateway_mfr, get_gateway_mfr_path, config_search_param, get_ecc_location, \
did_gateway_mfr_test_result_include_miner_key_pass, parse_i2c_address, parse_i2c_bus, \
get_mac_address, get_public_keys_rust, get_gateway_mfr_version, get_gateway_mfr_command
get_mac_address, get_public_keys_rust, get_gateway_mfr_version, get_gateway_mfr_command, \
get_onboarding_location

sys.path.append("..")

Expand Down Expand Up @@ -64,10 +65,12 @@
'NEBHNT-WITH-ECC-ADDRESS': {
'KEY_STORAGE_BUS': '/dev/i2c-X',
'SWARM_KEY_URI': ['ecc://i2c-X:96?slot=0'],
'ONBOARDING_KEY_URI': ['ecc://i2c-X:96?slot=0'],
},
'NEBHNT-NO-ECC-ADDRESS': {
'NO_KEY_STORAGE_BUS': '/dev/i2c-X',
'NO_KEY_SWARM_KEY_URI': ['ecc://i2c-X:96?slot=0'],
'NO_ONBOARDING_KEY_URI': ['ecc://i2c-X:96?slot=0'],
},
'NEBHNT-MULTIPLE-ECC-ADDRESS': {
'KEY_STORAGE_BUS': '/dev/i2c-2',
Expand All @@ -78,6 +81,8 @@

ECC_FILE_DATA = 'ecc://i2c-Y:96?slot=1'
ECC_FILE_DATA_BLANK = None
ONBOARDING_FILE_DATA = 'ecc://i2c-Z:96?slot=10'
ONBOARDING_FILE_DATA_BLANK = None


class SubprocessResult(object):
Expand Down Expand Up @@ -278,6 +283,64 @@ def test_get_ecc_location_generated_ecc(self):
expected_result = 'ecc://i2c-Y:96?slot=1'
self.assertEqual(actual_result, expected_result)

@patch("builtins.open", mock_open(read_data=ONBOARDING_FILE_DATA))
def test_get_onboarding_location_generated_ecc(self):
actual_result = get_onboarding_location()
expected_result = 'ecc://i2c-Z:96?slot=10'
self.assertEqual(actual_result, expected_result)

@patch.dict('os.environ', {"ONBOARDING_KEY_URI_OVERRIDE": "override-test"})
def test_get_onboarding_override(self):
actual_result = get_onboarding_location()
expected_result = "override-test"
self.assertEqual(actual_result, expected_result)

@patch("builtins.open", mock_open(read_data=ONBOARDING_FILE_DATA_BLANK))
@patch.dict('os.environ', {"VARIANT": "NEBHNT-MULTIPLE-ECC-ADDRESS"})
@patch('subprocess.Popen')
def test_get_onboarding_key_multi_KEY_URI(self, mock_subproc_popen):
process_mock = Mock()
attrs = {'communicate.return_value': (str.encode("60 --"), 'error')}
process_mock.configure_mock(**attrs)
mock_subproc_popen.return_value = process_mock

actual_result = get_onboarding_location()
expected_result = 'ecc://i2c-3:96?slot=0'
self.assertEqual(actual_result, expected_result)

@patch("builtins.open", mock_open(read_data=ONBOARDING_FILE_DATA_BLANK))
@patch.dict('os.environ', {"VARIANT": "NEBHNT-MULTIPLE-ECC-ADDRESS"})
@patch('subprocess.Popen')
def test_get_onboarding_key_multi_KEY_58(self, mock_subproc_popen):
process_mock = Mock()
attrs = {'communicate.return_value': (str.encode("58 --"), 'error')}
process_mock.configure_mock(**attrs)
mock_subproc_popen.return_value = process_mock

actual_result = get_onboarding_location()
expected_result = 'ecc://i2c-4:88?slot=15'
self.assertEqual(actual_result, expected_result)

@patch.dict('os.environ', {"VARIANT": "NEBHNT-NO-ECC-ADDRESS"})
def test_get_onboarding_key_missing(self):
with self.assertRaises(UnknownVariantAttributeException):
get_onboarding_location()

@patch.dict('os.environ', {"VARIANT": "NEBHNT-NO-ECC-ADDRESS"})
def test_get_ecc_key_missing(self):
with self.assertRaises(UnknownVariantAttributeException):
get_ecc_location()

@patch.dict('os.environ', {"VARIANT": "MISSING"})
def test_get_onboarding_key_missing_variant(self):
with self.assertRaises(UnknownVariantException):
get_onboarding_location()

@patch.dict('os.environ', {"VARIANT": "MISSING"})
def test_get_ecc_key_missing_variant(self):
with self.assertRaises(UnknownVariantException):
get_ecc_location()

@patch('hm_pyhelper.miner_param.get_gateway_mfr_command',
return_value=['gateway_mfr', 'arg1', 'arg2'])
@patch('subprocess.run', side_effect=FileNotFoundError())
Expand Down Expand Up @@ -450,6 +513,17 @@ def test_incorrect_param(self, mock_subproc_popen):
result = config_search_param("somecommand", "60--")
self.assertEqual(result, False)

@patch('subprocess.Popen')
def test_error_command(self, mock_subproc_popen):
process_mock = Mock()
attrs = {'communicate.return_value': (str.encode(''),
"Error: Could not open file `/dev/i2c-1' or `/dev/i2c/1': "
"No such file or directory")}
process_mock.configure_mock(**attrs)
mock_subproc_popen.return_value = process_mock
result = config_search_param("somecommand", "60--")
self.assertEqual(result, False)

def test_types(self):
self.assertRaises(TypeError, config_search_param, 1, 2)
self.assertRaises(TypeError, config_search_param, "123321", 1)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

setup(
name='hm_pyhelper',
version='0.14.1',
version='0.14.2',
author="Nebra Ltd",
author_email="[email protected]",
description="Helium Python Helper",
Expand Down