From 84ec4c46d3b4039be33556530d9e332cc9768eab Mon Sep 17 00:00:00 2001 From: Emanuel Winblad Date: Thu, 4 Nov 2021 21:03:57 +0100 Subject: [PATCH] Update device endpoint support and improve dependency management (#3) * Update Client to be compatible with the current Vilfo API * Add pipenv to manage dependencies --- .vscode/settings.json | 3 + Pipfile | 19 ++++ Pipfile.lock | 240 ++++++++++++++++++++++++++++++++++++++++++ requirements-dev.txt | 25 ++++- requirements.txt | 17 ++- test/test_vilfo.py | 213 ++++++++++++++++++++++++++++++------- vilfo/client.py | 59 ++++++++++- 7 files changed, 533 insertions(+), 43 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 Pipfile create mode 100644 Pipfile.lock diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..de288e1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.formatting.provider": "black" +} \ No newline at end of file diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..1c0f12c --- /dev/null +++ b/Pipfile @@ -0,0 +1,19 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +requests = "*" +getmac = "~=0.8" +semver = "*" + +[dev-packages] +black = "*" +responses = "*" + +[requires] +python_version = "3.9" + +[pipenv] +allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..bb1b8b8 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,240 @@ +{ + "_meta": { + "hash": { + "sha256": "1c31aa31bfe24ef719a4a72cace3773661862d56948ae6d741cc276724c5afe5" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.9" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "certifi": { + "hashes": [ + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + ], + "version": "==2021.10.8" + }, + "charset-normalizer": { + "hashes": [ + "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0", + "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b" + ], + "markers": "python_version >= '3'", + "version": "==2.0.7" + }, + "getmac": { + "hashes": [ + "sha256:2e4aef2dd6c3befccd7cf9e18badddd24ab1992b928e2e811d415ed47137c547", + "sha256:d501d20b71856248cfa07a8758192e86a01077910afb8b659a89946c4d52d368" + ], + "index": "pypi", + "version": "==0.8.2" + }, + "idna": { + "hashes": [ + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + ], + "markers": "python_version >= '3'", + "version": "==3.3" + }, + "requests": { + "hashes": [ + "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", + "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + ], + "index": "pypi", + "version": "==2.26.0" + }, + "semver": { + "hashes": [ + "sha256:153511dda7e85ce68673607bc7565e252b6495b23a5f631d73c59138b7aea5db", + "sha256:55dd56b0144d7fa48708300076d861655769bcfc4334b22cbb08486bf976eb6c" + ], + "index": "pypi", + "version": "==3.0.0.dev2" + }, + "urllib3": { + "hashes": [ + "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", + "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.7" + } + }, + "develop": { + "black": { + "hashes": [ + "sha256:6eb7448da9143ee65b856a5f3676b7dda98ad9abe0f87fce8c59291f15e82a5b", + "sha256:a9952229092e325fe5f3dae56d81f639b23f7131eb840781947e4b2886030f33" + ], + "index": "pypi", + "version": "==21.10b0" + }, + "certifi": { + "hashes": [ + "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + ], + "version": "==2021.10.8" + }, + "charset-normalizer": { + "hashes": [ + "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0", + "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b" + ], + "markers": "python_version >= '3'", + "version": "==2.0.7" + }, + "click": { + "hashes": [ + "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", + "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" + ], + "markers": "python_version >= '3.6'", + "version": "==8.0.3" + }, + "idna": { + "hashes": [ + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + ], + "markers": "python_version >= '3'", + "version": "==3.3" + }, + "mypy-extensions": { + "hashes": [ + "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" + ], + "version": "==0.4.3" + }, + "pathspec": { + "hashes": [ + "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", + "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" + ], + "version": "==0.9.0" + }, + "platformdirs": { + "hashes": [ + "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2", + "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d" + ], + "markers": "python_version >= '3.6'", + "version": "==2.4.0" + }, + "regex": { + "hashes": [ + "sha256:0075fe4e2c2720a685fef0f863edd67740ff78c342cf20b2a79bc19388edf5db", + "sha256:0621c90f28d17260b41838b22c81a79ff436141b322960eb49c7b3f91d1cbab6", + "sha256:070336382ca92c16c45b4066c4ba9fa83fb0bd13d5553a82e07d344df8d58a84", + "sha256:075b0fdbaea81afcac5a39a0d1bb91de887dd0d93bf692a5dd69c430e7fc58cb", + "sha256:07e3755e0f070bc31567dfe447a02011bfa8444239b3e9e5cca6773a22133839", + "sha256:0ed3465acf8c7c10aa2e0f3d9671da410ead63b38a77283ef464cbb64275df58", + "sha256:17e095f7f96a4b9f24b93c2c915f31a5201a6316618d919b0593afb070a5270e", + "sha256:1d85ca137756d62c8138c971453cafe64741adad1f6a7e63a22a5a8abdbd19fa", + "sha256:20605bfad484e1341b2cbfea0708e4b211d233716604846baa54b94821f487cb", + "sha256:23f93e74409c210de4de270d4bf88fb8ab736a7400f74210df63a93728cf70d6", + "sha256:2bb7cae741de1aa03e3dd3a7d98c304871eb155921ca1f0d7cc11f5aade913fd", + "sha256:2e3ff69ab203b54ce5c480c3ccbe959394ea5beef6bd5ad1785457df7acea92e", + "sha256:30fe317332de0e50195665bc61a27d46e903d682f94042c36b3f88cb84bd7958", + "sha256:3576e173e7b4f88f683b4de7db0c2af1b209bb48b2bf1c827a6f3564fad59a97", + "sha256:35ed5714467fc606551db26f80ee5d6aa1f01185586a7bccd96f179c4b974a11", + "sha256:41c66bd6750237a8ed23028a6c9173dc0c92dc24c473e771d3bfb9ee817700c3", + "sha256:48b4f4810117a9072a5aa70f7fea5f86fa9efbe9a798312e0a05044bd707cc33", + "sha256:4abf35e16f4b639daaf05a2602c1b1d47370e01babf9821306aa138924e3fe92", + "sha256:4fba661a4966adbd2c3c08d3caad6822ecb6878f5456588e2475ae23a6e47929", + "sha256:5e85dcfc5d0f374955015ae12c08365b565c6f1eaf36dd182476a4d8e5a1cdb7", + "sha256:77f9d16f7970791f17ecce7e7f101548314ed1ee2583d4268601f30af3170856", + "sha256:7ee36d5113b6506b97f45f2e8447cb9af146e60e3f527d93013d19f6d0405f3b", + "sha256:7fab29411d75c2eb48070020a40f80255936d7c31357b086e5931c107d48306e", + "sha256:85289c25f658e3260b00178757c87f033f3d4b3e40aa4abdd4dc875ff11a94fb", + "sha256:886f459db10c0f9d17c87d6594e77be915f18d343ee138e68d259eb385f044a8", + "sha256:897c539f0f3b2c3a715be651322bef2167de1cdc276b3f370ae81a3bda62df71", + "sha256:8fbe1768feafd3d0156556677b8ff234c7bf94a8110e906b2d73506f577a3269", + "sha256:9267e4fba27e6dd1008c4f2983cc548c98b4be4444e3e342db11296c0f45512f", + "sha256:9486ebda015913909bc28763c6b92fcc3b5e5a67dee4674bceed112109f5dfb8", + "sha256:956187ff49db7014ceb31e88fcacf4cf63371e6e44d209cf8816cd4a2d61e11a", + "sha256:a56735c35a3704603d9d7b243ee06139f0837bcac2171d9ba1d638ce1df0742a", + "sha256:ab1fea8832976ad0bebb11f652b692c328043057d35e9ebc78ab0a7a30cf9a70", + "sha256:adf35d88d9cffc202e6046e4c32e1e11a1d0238b2fcf095c94f109e510ececea", + "sha256:af23b9ca9a874ef0ec20e44467b8edd556c37b0f46f93abfa93752ea7c0e8d1e", + "sha256:b3794cea825f101fe0df9af8a00f9fad8e119c91e39a28636b95ee2b45b6c2e5", + "sha256:bb11c982a849dc22782210b01d0c1b98eb3696ce655d58a54180774e4880ac66", + "sha256:be30cd315db0168063a1755fa20a31119da91afa51da2907553493516e165640", + "sha256:c6238d30dcff141de076344cf7f52468de61729c2f70d776fce12f55fe8df790", + "sha256:cb1e44d860345ab5d4f533b6c37565a22f403277f44c4d2d5e06c325da959883", + "sha256:d4bfe3bc3976ccaeb4ae32f51e631964e2f0e85b2b752721b7a02de5ce3b7f27", + "sha256:d8ee91e1c295beb5c132ebd78616814de26fedba6aa8687ea460c7f5eb289b72", + "sha256:e3c00cb5c71da655e1e5161481455479b613d500dd1bd252aa01df4f037c641f", + "sha256:e9cec3a62d146e8e122d159ab93ac32c988e2ec0dcb1e18e9e53ff2da4fbd30c", + "sha256:ef4e53e2fdc997d91f5b682f81f7dc9661db9a437acce28745d765d251902d85", + "sha256:f0148988af0182a0a4e5020e7c168014f2c55a16d11179610f7883dd48ac0ebe", + "sha256:f20f9f430c33597887ba9bd76635476928e76cad2981643ca8be277b8e97aa96", + "sha256:f5930d334c2f607711d54761956aedf8137f83f1b764b9640be21d25a976f3a4", + "sha256:f6a28e87ba69f3a4f30d775b179aac55be1ce59f55799328a0d9b6df8f16b39d", + "sha256:f9ee98d658a146cb6507be720a0ce1b44f2abef8fb43c2859791d91aace17cd5" + ], + "version": "==2021.11.2" + }, + "requests": { + "hashes": [ + "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", + "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + ], + "index": "pypi", + "version": "==2.26.0" + }, + "responses": { + "hashes": [ + "sha256:5955ad3468fe8eb5fb736cdab4943457b7768f8670fa3624b4e26ff52dfe20c0", + "sha256:866757987d1962aa908d9c8b3185739faefd72a359e95459de0c2e4e5369c9b2" + ], + "index": "pypi", + "version": "==0.15.0" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, + "tomli": { + "hashes": [ + "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee", + "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade" + ], + "markers": "python_version >= '3.6'", + "version": "==1.2.2" + }, + "typing-extensions": { + "hashes": [ + "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e", + "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7", + "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34" + ], + "version": "==3.10.0.2" + }, + "urllib3": { + "hashes": [ + "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", + "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.7" + } + } +} diff --git a/requirements-dev.txt b/requirements-dev.txt index 249f6af..dea1084 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,23 @@ -requests -responses \ No newline at end of file +# +# These requirements were autogenerated by pipenv +# To regenerate from the project's Pipfile, run: +# +# pipenv lock --requirements --dev-only +# + +-i https://pypi.org/simple +black==21.10b0 +certifi==2021.10.8 +charset-normalizer==2.0.7; python_version >= '3' +click==8.0.3; python_version >= '3.6' +idna==3.3; python_version >= '3' +mypy-extensions==0.4.3 +pathspec==0.9.0 +platformdirs==2.4.0; python_version >= '3.6' +regex==2021.11.2 +requests==2.26.0 +responses==0.15.0 +six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' +tomli==1.2.2; python_version >= '3.6' +typing-extensions==3.10.0.2 +urllib3==1.26.7; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' diff --git a/requirements.txt b/requirements.txt index 4da9e3c..5fe1105 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,15 @@ -requests -getmac~=0.8 +# +# These requirements were autogenerated by pipenv +# To regenerate from the project's Pipfile, run: +# +# pipenv lock --requirements +# + +-i https://pypi.org/simple +certifi==2021.10.8 +charset-normalizer==2.0.7; python_version >= '3' +getmac==0.8.2 +idna==3.3; python_version >= '3' +requests==2.26.0 +semver==3.0.0.dev2 +urllib3==1.26.7; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4' diff --git a/test/test_vilfo.py b/test/test_vilfo.py index bbd1b2c..ee6c986 100644 --- a/test/test_vilfo.py +++ b/test/test_vilfo.py @@ -2,53 +2,154 @@ import vilfo import responses + class TestVilfo(unittest.TestCase): @responses.activate def test_ping(self): """ Test that ping is working as expected """ - client = vilfo.Client('vilfotestrouter', 'testtoken') + client = vilfo.Client("vilfotestrouter", "testtoken") + + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/system/ping", + json={"message": "Online"}, + status=200, + ) - responses.add(responses.GET, 'http://vilfotestrouter/api/v1/system/ping', - json={'message': 'Online'}, status=200) - resp = client.ping() - self.assertEqual(resp, {'message': 'Online'}) + self.assertEqual(resp, {"message": "Online"}) + + @responses.activate + def test_get_device_legacy(self): + """ + Test that the fetching of devices triggers a call to the appropriate endpoint + """ + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/dashboard/board", + json={ + "version": "1.0.1", + }, + status=200, + ) + + client = vilfo.Client("vilfotestrouter", "testtoken") + + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/devices", + json={ + "data": [ + { + "blocked": False, + "hostname": "box-7", + "displayName": "Box 7", + "ipv4": "192.168.0.7", + "mac_address": "08:00:27:8e:ac:31", + "vendor": "PCS Systemtechnik GmbH", + "vilfo_group": 1, + "bandwidth": {"download": 0.5, "upload": 0.2, "total": 0.7}, + "bypass": True, + "first_seen_at": "2017-09-20T12:42:58+00:00", + } + ] + }, + status=200, + ) + + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/devices/08:00:27:8e:ac:31", + json={ + "data": { + "blocked": False, + "hostname": "box-7", + "displayName": "Box 7", + "ipv4": "192.168.0.7", + "mac_address": "08:00:27:8e:ac:31", + "vendor": "PCS Systemtechnik GmbH", + "vilfo_group": 1, + "bandwidth": {"download": 0.5, "upload": 0.2, "total": 0.7}, + "bypass": True, + "first_seen_at": "2017-09-20T12:42:58+00:00", + "status": { + "online": True, + "online_from": "2017-09-20T12:42:58+00:00", + }, + } + }, + status=200, + ) + + resp = client.get_device("08:00:27:8e:ac:31") + + self.assertIsNotNone(resp) @responses.activate def test_get_device(self): """ Test that the fetching of devices triggers a call to the appropriate endpoint """ - client = vilfo.Client('vilfotestrouter', 'testtoken') - - responses.add(responses.GET, 'http://vilfotestrouter/api/v1/devices/abc:123', - json={ - "data": { - "blocked": False, - "hostname": "box-7", - "displayName": "Box 7", - "ipv4": "192.168.0.7", - "mac_address": "08:00:27:8e:ac:31", - "vendor": "PCS Systemtechnik GmbH", - "vilfo_group": 1, - "bandwidth": { - "download": 0.5, - "upload": 0.2, - "total": 0.7 - }, - "bypass": True, - "first_seen_at": "2017-09-20T12:42:58+00:00", - "status": { - "online": True, - "online_from": "2017-09-20T12:42:58+00:00" - } - } - }, status=200) - - resp = client.get_device('abc:123') + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/dashboard/board", + json={ + "version": "1.1.1", + }, + status=200, + ) + client = vilfo.Client("vilfotestrouter", "testtoken") + + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/devices", + json={ + "data": [ + { + "blocked": False, + "hostname": "box-7", + "displayName": "Box 7", + "ipv4": "192.168.0.7", + "mac_address": "08:00:27:8e:ac:31", + "vendor": "PCS Systemtechnik GmbH", + "vilfo_group": 1, + "bandwidth": {"download": 0.5, "upload": 0.2, "total": 0.7}, + "bypass": True, + "first_seen_at": "2017-09-20T12:42:58+00:00", + } + ] + }, + status=200, + ) + + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/devices/192.168.0.7", + json={ + "data": { + "blocked": False, + "hostname": "box-7", + "displayName": "Box 7", + "ipv4": "192.168.0.7", + "mac_address": "08:00:27:8e:ac:31", + "vendor": "PCS Systemtechnik GmbH", + "vilfo_group": 1, + "bandwidth": {"download": 0.5, "upload": 0.2, "total": 0.7}, + "bypass": True, + "first_seen_at": "2017-09-20T12:42:58+00:00", + "status": { + "online": True, + "online_from": "2017-09-20T12:42:58+00:00", + }, + } + }, + status=200, + ) + + resp = client.get_device("08:00:27:8e:ac:31") self.assertIsNotNone(resp) @@ -57,17 +158,53 @@ def test_is_device_online(self): """ Test that it works as expected to check if a device is online """ - client = vilfo.Client('vilfotestrouter', 'testtoken') - mac_address = 'abc:123' + client = vilfo.Client("vilfotestrouter", "testtoken") + mac_address = "08:00:27:8e:ac:31" + + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/devices", + json={ + "data": [ + { + "blocked": False, + "hostname": "box-7", + "displayName": "Box 7", + "ipv4": "192.168.0.7", + "mac_address": "08:00:27:8e:ac:31", + "vendor": "PCS Systemtechnik GmbH", + "vilfo_group": 1, + "bandwidth": {"download": 0.5, "upload": 0.2, "total": 0.7}, + "bypass": True, + "first_seen_at": "2017-09-20T12:42:58+00:00", + } + ] + }, + status=200, + ) # Device that is supposed to exist and is online - responses.add(responses.GET, 'http://vilfotestrouter/api/v1/devices/abc:123', json={'data': {'status': {'online': True}}}) + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/devices/192.168.0.7", + json={"data": {"status": {"online": True}}}, + ) # Device that is supposed to exist and is offline - responses.add(responses.GET, 'http://vilfotestrouter/api/v1/devices/abc:123', json={'data': {'status': {'online': False}}}) + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/devices/192.168.0.7", + json={"data": {"status": {"online": False}}}, + ) # Device that is not found - responses.add(responses.GET, 'http://vilfotestrouter/api/v1/devices/abc:123', status=404) + responses.add( + responses.GET, "http://vilfotestrouter/api/v1/devices/192.168.0.7", status=404 + ) # Incomplete response data - responses.add(responses.GET, 'http://vilfotestrouter/api/v1/devices/abc:123', json={'data': 'incomplete'}) + responses.add( + responses.GET, + "http://vilfotestrouter/api/v1/devices/192.168.0.7", + json={"data": "incomplete"}, + ) resp = client.is_device_online(mac_address) self.assertTrue(resp) diff --git a/vilfo/client.py b/vilfo/client.py index c9e94ff..e77cdff 100644 --- a/vilfo/client.py +++ b/vilfo/client.py @@ -4,6 +4,7 @@ import ipaddress import json import requests +from semver.version import Version as SemverVersion import vilfo.exceptions @@ -26,12 +27,22 @@ def __init__(self, host, token, ssl=False): self.mac = None self._mac_resolution_failed = False self._cached_mac = None + self._firmware_version = "1.1.0" + + try: + self._firmware_version = self.resolve_firmware_version() + except vilfo.exceptions.VilfoException: + pass try: self.mac = self.resolve_mac_address() except vilfo.exceptions.VilfoException: pass + self._api_v1_supported = SemverVersion.parse(self._firmware_version) >= "1.1.0" + + print(self._api_v1_supported) + def _request(self, method, endpoint, headers=None, data=None, params=None, timeout=None): """Internal method to facilitate performing requests with authentication added to them and appropriate creation of common exceptions if they are encountered. @@ -57,6 +68,15 @@ def _request(self, method, endpoint, headers=None, data=None, params=None, timeo return response + def resolve_firmware_version(self): + """Try to resolve the current firmware version.""" + response = None + try: + response = self.get_board_information() + except requests.exceptions.RequestException as ex: + raise ex + + return response["version"] def resolve_mac_address(self, force_retry=False): """Try to resolve the MAC address for the router itself. @@ -129,11 +149,21 @@ def get_devices(self): return json.loads(response.text) - def get_device(self, mac_address): + def get_device_by_ip(self, ip_address): + """Get information about a specific device by IP address.""" """Get information about a specific device by MAC address. See https://www.vilfo.com/apidocs/#devices-devices-get-1 for more information. """ + response = None + try: + response = self._request('get', '/devices/%s' % ip_address) + except requests.exceptions.RequestException as ex: + raise ex + + return json.loads(response.text) + + def _get_device_by_mac(self, mac_address): response = None try: response = self._request('get', '/devices/%s' % mac_address) @@ -142,6 +172,33 @@ def get_device(self, mac_address): return json.loads(response.text) + def get_device(self, mac_address): + """Get information about a specific device by MAC address. + + See https://www.vilfo.com/apidocs/#devices-devices-get-1 for more information. + """ + if not self._api_v1_supported: + """Use legacy version which fetches devices by MAC address""" + return self._get_device_by_mac(mac_address) + + devices = None + try: + devices = self.get_devices() + except requests.exceptions.RequestException as ex: + raise ex + + try: + device_info = list(filter(lambda device: device['mac_address'] and device['mac_address'] == mac_address, devices['data'])) + except Exception as ex: + device_info = None + + device_current_ip = (device_info.pop())['ipv4'] + + if not device_current_ip: + return None + + return self.get_device_by_ip(device_current_ip) + def is_device_online(self, mac_address): """Returns a boolean indicating whether or not the device is online.