Skip to main content

Тестування вашого плагіна

Першим кроком у тестуванні вашого нового плагіна є встановлення плагіна у те місце, звідки ваша система Fledge буде його завантажувати. Точне місце залежить від способу встановлення системи Fledge і типу плагіна.

Якщо ваша система Fledge була встановлена з пакунка і ви використовували шлях встановлення за замовчуванням, то ваш плагін має бути збережений у директорії /usr/local/fledge. Якщо ви встановили Fledge у нестандартне місце або зібрали його з вихідного коду, то плагін слід зберігати в каталозі $FLEDGE_ROOT.

C/C++ плагін або гібридний плагін слід розмістити у директорії plugins/<тип>/<назва плагіна> під директорією встановлення, описаною вище. Де <тип> є одним з south, filter, north, notificationRule або notificationDelivery. А <plugin name> - це ім'я, яке ви дали своєму плагіну.

Південний плагін, написаний на C/C++ і названий DHT11, для системи встановлений з пакунка, буде встановлено до каталогу з назвою /usr/local/fledge/plugins/south/DHT11. У цьому каталозі Fledge має знайти файл з назвою libDHT11.so.

Гібридний південний плагін з назвою MD1421 для системи розробки, зібраної з джерела буде встановлено у ${FLEDGE_ROOT}/plugins/south/MD1421. У цьому каталозі має існувати JSON-файл з назвою MD1421.json, який система буде зчитувати для створення плагіна.

Плагін Python повинен бути встановлений в директорії python/fledge/plugins/<тип плагіна>/<назва плагіна> у директорії встановлення, описаній вище. Де <type> є одним з south, filter, north, notificationRule або notificationDelivery. І <plugin name> це ім'я, яке ви дали вашому плагіну.

Плагін фільтра Python з назвою normalise у системі, встановленій з пакунка за замовчуванням, слід скопіювати до каталогу /usr/local/fledge/python/fledge/plugins/filter/normalise. Усередині цього каталогу має бути файл з назвою normalise.py і порожній файл з назвою __init__.py.

Початкове тестування

Після того, як ви скопіювали плагін у потрібне місце ви можете перевірити, чи бачить його Fledge, виконавши виклик API /fledge/plugins/installed. Він покаже список всіх встановлених плагінів та їхні версії.

$ curl http://localhost:8081/fledge/plugins/installed | jq
{
"plugins": [
{
"name": "http_north",
"type": "north",
"description": "HTTP North Plugin",
"version": "2.2.0",
"installedDirectory": "north/http_north",
"packageName": "fledge-north-http-north"
},
{
"name": "Kafka",
"type": "north",
"description": "Simple plugin to send data to Kafka topic",
"version": "2.2.0",
"installedDirectory": "north/Kafka",
"packageName": "fledge-north-kafka"
},
...
}

Зверніть увагу, що у наведеному вище прикладі програма jq була використана для форматування JSON, а вихідні дані було скорочено для стислості.

Якщо ваш плагін не відображається, це може бути пов'язано з тим, що виникла проблема завантаження або тому, що виклик plugin_info повернув невірне значення. Перевірте файл syslog, щоб побачити, чи є там помилки, записані під час наведеного вище виклику API.

Типові помилки C/C++

Типовими помилками для C/C++ плагінів є те, що символ не може бути розпізнаний під час завантаження плагіна або JSON для конфігурації за замовчуванням має неправильний формат.

Існує утиліта get_plugin_info, яка використовується кодом Python для виклику C plugin_info, це може бути використано для з'ясування причини деяких проблем. Він має повернути конфігурацію за замовчуванням вашого плагіна і перевірить, чи немає у вашому плагіні невизначених символів.

Розташування get_plugin_info залежатиме від типу встановлення плагіна. Якщо ви збирали плагін з коду, то його можна знайти у ./cmake_build/C/plugins/utils/get_plugin_info. Якщо ви встановили пакет або виконали make install, ви можете знайти його у /usr/local/fledge/extras/C/get_plugin_info.

Утиліті передається файл бібліотеки вашого плагіна як перший аргумент і функцію для виклику, зазвичай plugin_info.

$ ./get_plugin_info /usr/local/fledge/plugins/north/Kafka/libKafka.so plugin_info
{"name": "Kafka", "type": "north", "flag": 0, "version": "2.2.0", "interface": "1.0.0", "config": {"SSL_CERT": {"displayName": "Certificate Name", "description": "Name of client certificate for identity authentications", "default": "", "validity": "KafkaSecurityProtocol == \"SSL\" || KafkaSecurityProtocol == \"SASL_SSL\"", "group": "Encryption", "type": "string", "order": "10"}, "topic": {"mandatory": "true", "description": "The topic to send reading data on", "default": "Fledge", "displayName": "Kafka Topic", "type": "string", "order": "2"}, "brokers": {"displayName": "Bootstrap Brokers", "description": "The bootstrap broker list to retrieve full Kafka brokers", "default": "localhost:9092,kafka.local:9092", "mandatory": "true", "type": "string", "order": "1"}, "KafkaUserID": {"group": "Authentication", "description": "User ID to be used with SASL_PLAINTEXT security protocol", "default": "user", "validity": "KafkaSecurityProtocol == \"SASL_PLAINTEXT\" || KafkaSecurityProtocol == \"SASL_SSL\"", "displayName": "User ID", "type": "string", "order": "7"}, "KafkaSASLMechanism": {"group": "Authentication", "description": "Authentication mechanism to be used to connect to kafka broker", "default": "PLAIN", "displayName": "SASL Mechanism", "type": "enumeration", "order": "6", "validity": "KafkaSecurityProtocol == \"SASL_PLAINTEXT\" || KafkaSecurityProtocol == \"SASL_SSL\"", "options": ["PLAIN", "SCRAM-SHA-256", "SCRAM-SHA-512"]}, "SSL_Password": {"displayName": "Certificate Password", "description": "Optional: Password to be used when loading the certificate chain", "default": "", "validity": "KafkaSecurityProtocol == \"SSL\" || KafkaSecurityProtocol == \"SASL_SSL\"", "group": "Encryption", "type": "password", "order": "12"}, "compression": {"displayName": "Compression Codec", "description": "The compression codec to be used to send data to the Kafka broker", "default": "none", "order": "4", "type": "enumeration", "options": ["none", "gzip", "snappy", "lz4"]}, "plugin": {"default": "Kafka", "readonly": "true", "type": "string", "description": "Simple plugin to send data to a Kafka topic"}, "KafkaSecurityProtocol": {"group": "Authentication", "description": "Security protocol to be used to connect to kafka broker", "default": "PLAINTEXT", "options": ["PLAINTEXT", "SASL_PLAINTEXT", "SSL", "SASL_SSL"], "displayName": "Security Protocol", "type": "enumeration", "order": "5"}, "source": {"displayName": "Data Source", "description": "The source of data to send", "default": "readings", "order": "13", "type": "enumeration", "options": ["readings", "statistics"]}, "json": {"displayName": "Send JSON", "description": "Send as JSON objects or as strings", "default": "Strings", "order": "3", "type": "enumeration", "options": ["Objects", "Strings"]}, "SSL_CA_File": {"displayName": "Root CA Name", "description": "Name of the root certificate authority that will be used to verify the certificate", "default": "", "validity": "KafkaSecurityProtocol == \"SSL\" || KafkaSecurityProtocol == \"SASL_SSL\"", "group": "Encryption", "type": "string", "order": "9"}, "SSL_Keyfile": {"displayName": "Private Key Name", "description": "Name of client private key required for communication", "default": "", "validity": "KafkaSecurityProtocol == \"SSL\" || KafkaSecurityProtocol == \"SASL_SSL\"", "group": "Encryption", "type": "string", "order": "11"}, "KafkaPassword": {"group": "Authentication", "description": "Password to be used with SASL_PLAINTEXT security protocol", "default": "pass", "validity": "KafkaSecurityProtocol == \"SASL_PLAINTEXT\" || KafkaSecurityProtocol == \"SASL_SSL\"", "displayName": "Password", "type": "password", "order": "8"}}}

Якщо є невизначений символ, ви отримаєте помилку від цієї утиліти. Ви також можете перевірити правильність конфігурації JSON, передавши дані у програму таку як jq.

$ ./get_plugin_info plugins/south/Random/libRandom.so plugin_info | jq
{
"name": "Random",
"version": "1.9.2",
"type": "south",
"interface": "1.0.0",
"flag": 4096,
"config": {
"plugin": {
"description": "Random data generation plugin",
"type": "string",
"default": "Random",
"readonly": "true"
},
"asset": {
"description": "Asset name",
"type": "string",
"default": "Random",
"displayName": "Asset Name",
"mandatory": "true"
}
}
}

Запуск під відладчиком

Якщо у вас є C/C++ плагін, який аварійно завершує роботу, ви можете запустити його у відладчику. Щоб збирати з відлагоджувальними символами, використовуйте параметр CMake -DCMAKE_BUILD_TYPE=Debug при створенні Makefile.

Запуск сервісу у відладчику

$ cmake -DCMAKE_BUILD_TYPE=Debug ..

Найпростіший підхід до запуску у відладчику такий

  • Створіть сервіс, яка використовує ваш плагін, скажімо, сервіс south і назвіть її так, як ви зазвичай це робите.
  • Заборонити запуск цього сервісу Fledge
  • Використовуйте скрипт статусу fledge, щоб знайти аргументи для передачі сервісу
    $ scripts/fledge status
Fledge v1.8.2 running.
Fledge Uptime: 1451 seconds.
Fledge records: 200889 read, 200740 sent, 120962 purged.
Fledge does not require authentication.
=== Fledge services:
fledge.services.core
fledge.services.storage --address=0.0.0.0 --port=39821
fledge.services.south --port=39821 --address=127.0.0.1 --name=AX8
fledge.services.south --port=39821 --address=127.0.0.1 --name=Sine
=== Fledge tasks:
  • Зверніть увагу на аргументи --port= і --address=

  • Встановіть ваш LD_LIBRARY_PATH. Зазвичай це робиться у скрипті, який запускає Fledge, але під час запуску у відладчику це потрібно виконати вручну.

    export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/fledge/lib

    Якщо ви збирали з вихідних текстів, а не встановлювали пакет, вам потрібно буде долучити зібрані вами бібліотеки

    export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${FLEDGE_ROOT}/cmake_build/C/lib
  • Gі токен запуску, викликавши кінцеву точку API Fledge

    Примітка: для виклику кінцевої точки API абонент повинен бути автентифікований як користувачadmin*, використовуючи або автентифікацію за допомогою імені користувача і пароля, або механізм автентифікації за допомогою сертифіката. Спочатку ви повинні налаштувати Fledge так, щоб він вимагав автентифікацію. Для цього запустіть графічний інтерфейс Fledge, перейдіть до розділу Конфігурація, а потім Admin API. Встановіть Автентифікація на mandatory. Метод автентифікації можна залишити як any.

    Для автентифікації від імені користувача admin слід використовувати один з двох наступних методів, вибір якого залежить від механізму автентифікації, налаштованого у вашій інсталяції Fledge.

    • Вхід за допомогою логіна та пароля
curl -d '{"username": "admin", "some_pass": "fledge"}' -X POST http://localhost:8081/fledge/login

Після успішної автентифікації буде видано відповідь, як показано нижче.

{"message": "Logged in successfully", "uid": 1, "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsImV4cCI6MTY1NDU5NTIyMn0.IlhIgQ93LbCP-ztGlIuJVd6AJrBlbNBNvCv7SeuMfAs", "admin": true}
  • Логін для входу за допомогою сертифіката
curl -T /some_path/admin.cert -X POST http://localhost:8081/fledge/login

Після успішної автентифікації буде видано відповідь, як показано нижче.

{"message": "Logged in successfully", "uid": 1, "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsImV4cCI6MTY1NDU5NTkzN30.6VVD_5RwmpLga2A7ri2bXhlo3x_CLqOYiefAAmLP63Y", "admin": true}

Тепер можна викликати кінцеву точку API, щоб отримати токен запуску, передавши токен автентифікації, вказаний у запиті на автентифікацію.

curl -X POST 127.0.0.1:8081/fledge/service/ServiceName/otp -H 'authorization: Token'

Де *ServiceName* - це назва, яке ви дали своєму сервісу під час його створення, а *Token* - це токен, отриманий за допомогою запиту на автентифікацію, наведеного вище.

У відповідь на цей виклик ви отримаєте токен запуску, який можна використати для запуску сервісу, яку ви налагоджуєте. Приклад відповіді показано нижче.
{"startupToken": "WvFTYeGUvSEFMndePGbyvOsVYUzbnJdi"}

*startupToken* буде передано як аргумент запуску сервісу: --token=*startupToken*.
  • Завантажте сервіс, яку ви хочете використовувати для запуску вашого плагіна, наприклад, сервіс south, у відладчик. Його слід запускати з каталогу FLEDGE_ROOT

    $ cd $FLEDGE_ROOT
    $ gdb services/fledge.services.south
  • Запустіть сервіс, передавши аргументи --port= і --address=, які ви зазначили вище, і додайте -d і --name= з назвою вашої сервісу і --token=startupToken.

    (gdb) run --port=39821 --address=127.0.0.1 --name=ServiceName -d --token=startupToken

    Де ServiceName - це ім'я, яке ви дали своєму сервісу при створенні, а startupToken - це токен, виданий за допомогою методу, описаного вище. Зверніть увагу, що цей токен можна використовувати лише один раз, кожного разу, коли сервіс перезапускається за допомогою відладчика, необхідно отримувати новий токен запуску.

  • Тепер ви можете використовувати налагоджувач у звичайному режимі для пошуку будь-яких проблем.

Примітка На цьому етапі плагіни не були завантажені в адресний простір. Якщо ви спробуєте встановити точку зупинки у коді плагіна, ви отримаєте попередження про те, що точку зупинки наразі неможливо встановити. Однак, коли плагін буде завантажено пізніше, точка розриву буде встановлена і поводитиметься належним чином.

Лише плагін було зібрано з налагоджувальною інформацією, якщо ви хочете мати змогу зазирнути у код бібліотеки, яка підтримує плагін, та сервісів, ви маєте перезбирати сам Fledge з налагоджувальними символами. Це можна зробити кількома способами, але, мабуть, найпростіший з них полягає у зміні Makefile у маршруті до вихідного коду Fledge.

Під час збирання Fledge команда cmake виконується процесом make, отже, замість того, щоб вручну запускати cmake і перезбирати, ви можете просто змінити рядок

CMAKE := cmake

у Makefile, щоб прочитати

CMAKE := cmake -DCMAKE_BUILD_TYPE=Debug

Після внесення цих змін слід виконати команду make clean, а потім команду make.

$ make clean
$ make

Одним з побічних ефектів виконання make clean є те, що раніше зібрані вами плагіни буде вилучено з каталогу $FLEDGE_ROOT/plugins, і його потрібно буде зібрати заново.

Крім того, ви можете вручну зібрати налагоджувальну версію, виконавши такі команди

$ cd $FLEDGE_ROOT/cmake_build
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
$ make

Перевага цього способу полягає в тому, що make clean не виконується, тому ваші плагіни буде збережено.

Запуск завдання у відладчику

Запуск завдання у відладчику багато в чому схожий на запуск сервісу, спочатку вам потрібно знайти порт керування та адресу основної сервісу керування. Створіть завдання, наприклад, процес надсилання на північ так само, як ви це робите зазвичай, і вимкніть його. Вам також буде потрібно встановити LD_LIBRARY_PATH, як у випадку запуску сервісу у відладчику.

Якщо ви використовуєте плагін із завданням, наприклад, процес надсилання на північ то для запуску налагоджувача слід скористатися командою

$ gdb tasks/sending_process

Запуск сервісу зберігання даних у відладчику

Запуск сервісу зберігання у відладчику є складнішим, оскільки ви не можете запустити сервіс зберігання після запуску Fledge, запуск сервісу зберігання координується ядром через особливості зберігання конфігурації. Однак, можливо приєднати налагоджувач до запущеного сервісу зберігання даних.

  • Запустіть команду для отримання ідентифікатора процесу сервісу зберігання даних
    $ ps aux | grep fledge.services.storage
fledge 23318 0.0 0.3 270848 12388 ? Ssl 10:00 0:01 /usr/local/fledge/services/fledge.services.storage --address=0.0.0.0 --port=33761
fledge 31033 0.0 0.0 13136 1084 pts/1 S+ 10:37 0:00 grep --color=auto fledge.services.storage
  • Використовуйте ідентифікатор процесу сервісу fledge як аргумент для gdb. Зауважте, що на деяких системах вам доведеться запускати gdb від імені користувача root
$ sudo gdb /usr/local/fledge/services/fledge.services.storage 23318
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from services/fledge.services.storage...done.
Attaching to program: /usr/local/fledge/services/fledge.services.storage, process 23318
[New LWP 23320]
[New LWP 23321]
[New LWP 23322]
[New LWP 23330]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007f47a3e05d2d in __GI___pthread_timedjoin_ex (threadid=139945627997952, thread_return=0x0, abstime=0x0,
block=<optimized out>) at pthread_join_common.c:89
89 pthread_join_common.c: No such file or directory.
(gdb)
  • Тепер ви можете використовувати gdb для встановлення точок зупинки тощо, а також для налагодження сервісу зберігання та плагінів. кщо ви налагоджуєте плагін, який виводить систему з ладу під час обробки зчитувань, вам слід вимкнути південні сервіси, доки ви не під'єднаєте відладчик до системи зберігання даних. Якщо у вас є система, яка налаштована і падає, використовуйте прапорець --safe-mode під час запуску Fledge, щоб вимкнути всі процеси і сервіси. Це дозволить вам вимкнути сервіси або запустити певний сервіс вручну.

Використання стеку

Ви також можете скористатися аналогічним підходом до запуску gdb для трасування системних викликів і сигналів за допомогою команди strace.

  • Створіть сервіс, який використовує ваш плагін, наприклад, південний сервіс, і назвіть його звичайним чином.
  • Заборонить запуск цього сервісу Fledge
  • Використовуйте скрипт статусу fledge, щоб знайти аргументи для передачі сервісу
    $ scripts/fledge status
Fledge v1.8.2 running.
Fledge Uptime: 1451 seconds.
Fledge records: 200889 read, 200740 sent, 120962 purged.
Fledge does not require authentication.
=== Fledge services:
fledge.services.core
fledge.services.storage --address=0.0.0.0 --port=39821
fledge.services.south --port=39821 --address=127.0.0.1 --name=AX8
fledge.services.south --port=39821 --address=127.0.0.1 --name=Sine
=== Fledge tasks:
  • Зверніть увагу на аргументи --port= і --address=
  • Запустіть strace з сервісом, додавши той самий набір аргументів, який ви використовували у gdb під час запуску сервісу
    $ strace services/fledge.services.south --port=39821 --address=127.0.0.1 --name=ServiceName --token=StartupToken -d

Де ServiceName - це ім'я, яке ви дали своєму сервісу, а startupToken - виданий за допомогою наведених вище кроків.

Витоки і пошкодження пам'яті

Такий самий підхід можна застосувати до використання команди valgrind для пошуку пошкоджень пам'яті та проблем з витоками у вашому плагіні

  • Створіть сервіс, яка використовує ваш плагін, наприклад, південний сервіс , і назвіть його звичайним ім'ям.
  • Заборонить запуск цього сервісу Fledge
  • Використовуйте скрипт статусу fledge, щоб знайти аргументи для передачі сервісу
    $ scripts/fledge status
Fledge v1.8.2 running.
Fledge Uptime: 1451 seconds.
Fledge records: 200889 read, 200740 sent, 120962 purged.
Fledge does not require authentication.
=== Fledge services:
fledge.services.core
fledge.services.storage --address=0.0.0.0 --port=39821
fledge.services.south --port=39821 --address=127.0.0.1 --name=AX8
fledge.services.south --port=39821 --address=127.0.0.1 --name=Sine
=== Fledge tasks:
  • Зверніть увагу на аргументи --port= і --address=
  • Запустіть valgrind з сервісом, додавши той самий набір аргументів, який ви використовували в gdb під час запуску сервісу. Додайте будь-які аргументи, які ви хочете передати до самого valgrind перед назвою виконуваного файлу сервісу, у цьому випадку ми передаємо --leak-check=full.
    $ valgrind --leak-check=full  services/fledge.services.south --port=39821 --address=127.0.0.1 --name=ServiceName --token=StartupToken -d

Де ServiceName - це назва, яку ви дали вашому сервісу, а startupToken - це одноразовий токен, отриманий за допомогою кроків, описаних вище.

  • Після того, як сервіс попрацює деякий час, вимкніть його, щоб викликати valgrind для виведення звіту про витоки пам'яті, знайдені під час виконання.

Информация про плагін Python

Також можна перевірити завантаження і коректність виклику plugin_info у плагіні Python.

  • З каталогу /usr/include/fledge або ${FLEDGE_ROOT} виконайте команду
     python3 -c 'from fledge.plugins.south.<name>.<name> import plugin_info; print(plugin_info())'

Де <name> - назва вашого плагіна.

     python3 -c 'from fledge.plugins.south.sinusoid.sinusoid import plugin_info; print(plugin_info())'
{'name': 'Sinusoid Poll plugin', 'version': '1.8.1', 'mode': 'poll', 'type': 'south', 'interface': '1.0', 'config': {'plugin': {'description': 'Sinusoid Poll Plugin which implements sine wave with data points', 'type': 'string', 'default': 'sinusoid', 'readonly': 'true'}, 'assetName': {'description': 'Name of Asset', 'type': 'string', 'default': 'sinusoid', 'displayName': 'Asset name', 'mandatory': 'true'}}}

Це дозволить вам переконатися, що плагін можна завантажити і викликати точку входу plugin_info.

Ви також можете перевірити конфігурацію за замовчуванням. Хоча у Python зазвичай складніше помилитися.

$ python3 -c 'from fledge.plugins.south.sinusoid.sinusoid import plugin_info; print(plugin_info()["config"])'
{'plugin': {'description': 'Sinusoid Poll Plugin which implements sine wave with data points', 'type': 'string', 'default': 'sinusoid', 'readonly': 'true'}, 'assetName': {'description': 'Name of Asset', 'type': 'string', 'default': 'sinusoid', 'displayName': 'Asset name', 'mandatory': 'true'}}