З аутсорсу на розробку (Частина 1)

Всім привіт, мене звуть Сергій Омелянчик. Я є керівником компанії Аудіт-Телеком, головним розробником та автором системи Veliam. Вирішив написати статтю про те, як ми з другом створювали аутсорсингову компанію, написали програмне забезпечення для себе і згодом почали розповсюджувати її всім бажаючим за системою SaaS. Про те, як я категорично не вірив у те, що це можливо. У статті буде не лише розповідь, а й технічні подробиці того, як створювався продукт Veliam. Включаючи деякі шматки вихідного коду. Розповім про те, які помилки робили і як їх потім виправляли. Були сумніви, чи публікуватиме таку статтю. Але я подумав, що краще зробити це, отримати фідбек і виправитися, ніж не публікувати статтю і думати про те, що було б колись…

Передісторія

Працював я в одній компанії ІТ співробітником. Компанія була дуже великою з розгалуженою мережевою структурою. Не зупинятимуся на своїх посадових обов'язках, скажу лише, що в них точно не входила розробка чогось.

У нас був моніторинг, але з академічного інтересу хотілося спробувати написати свій найпростіший. Ідея була така: хотілося, щоб це було в Інтернеті, щоб можна було легко без встановлення будь-яких клієнтів зайти та подивитися, що відбувається з мережею з будь-якого пристрою, включаючи мобільний пристрій через Wi-Fi, а ще дуже хотілося швидко розуміти в якому приміщенні розташоване обладнання, яке “захандрило”, т.к. були дуже жорсткі вимоги до часу реагування на такі проблеми. У результаті в голові народився план написати просту веб сторінку, на якій був фоном jpeg зі схемою мережі, вирізати на цій картинці самі пристрої з їх IP адресами, а поверх картинки в потрібних координатах показувати вже динамічний контент у вигляді зеленого або миготливого червоного IP адреси. Завдання поставлене, приступаємо.

Раніше я займався програмуванням на Delphi, PHP, JS і дуже поверхово C++. Досить непогано знаю роботу мереж. VLAN, Routing (OSPF, EIGRP, BGP), NAT. Цього було достатньо, щоб написати прототип примітивного моніторингу самостійно.

Написав задумане на PHP. Сервер Apache і PHP був у Windows т.к. Linux для мене в той момент був чимось незрозумілим і дуже складним, як виявилося пізніше, я сильно помилявся і в багатьох місцях Linux куди простіше Windows, але це окрема тема і ми всі знаємо скільки холіварів на цю тему. Планувальник завдань Windows смикав з невеликим інтервалом (точно не пам'ятаю, але щось на кшталт одного разу на три секунди) PHP скрипт, який опитував усі об'єкти банальним пінгом та зберігав стан у файл.

system(“ping -n 3 -w 100 {$ip_address}“); 

Так-так, робота з БД на той момент теж для мене не була освоєна. Не знав, що можна паралелити процеси, і прохід всім вузлам мережі займав тривалий час, т.к. це відбувалося в один потік. Особливо проблеми виникали тоді, коли кілька вузлів недоступні, т.к. кожен із них затримував у собі скрипт на 300 мс. На стороні клієнта була проста зациклена функція, яка з інтервалом кілька секунд скачувала оновлену інформацію з Ajax сервера запитом і оновлювала інтерфейс. Та й далі після трьох невдалих пінгів поспіль, якщо на комп'ютері була відкрита веб сторінка з моніторингом, грала весела композиція.

Коли все вийшло, я дуже надихнувся результатом і думав, що можна прикрутити туди ще (через свої знання та можливості). Але мені завжди не подобалися системи з мільйоном графіків, які, як я тоді вважав, та й вважаю досі, в більшості випадків непотрібними. Хотів туди прикручувати тільки те, що мені реально допомагало б у роботі. Цей принцип до сьогодні зберігається як основний при розробці Veliam. Далі, я зрозумів, що було б дуже класно, якби не треба було тримати відкритим моніторинг і знати про проблеми, а коли вона трапилася, вже тоді відкривати сторінку і дивитися, де цей проблемний вузол мережі розташований і що з ним далі робити. Електронну пошту якось тоді не читав, просто не користувався. Натрапив в інтернеті, що є СМС шлюзи, на які можна надіслати GET або POST запит, і вони надішлють мені на мобільний телефон СМС з текстом, який я напишу. Я одразу зрозумів, що дуже хочу цього. І почав вивчати документацію. Через деякий час мені вдалося, і тепер я отримував смс про проблеми на мережі на мобільник з назвою об'єкта, що впав. Хоч система і була примітивною, але вона була написана мною самим, а найголовніше, що мене тоді мотивувало до її розвитку — те, що це прикладна програма, яка реально допомагає мені в роботі.

І ось настав день, коли на роботі впав один із інтернет-каналів, а мій моніторинг мені ніяк не дав про це зрозуміти. Оскільки гуглівські DNS досі чудово пінгувалися. Настав час подумати, як можна моніторити, що канал зв'язку живий. Були різні ідеї, як це зробити. Не до всього обладнання я мав доступ. Доводилося придумати як можна розуміти якийсь із каналів живий, але при цьому не маючи можливості якимось чином подивитися це на мережевому обладнанні. Тоді колега підкинув ідею, що можливо, трасування маршруту до публічних серверів може відрізнятися залежно від того, яким каналом зв'язку зараз здійснюється вихід в інтернет. Перевірив, що так і виявилося. Були різні маршрути під час трасування.

system(“tracert -d -w 500 8.8.8.8”);

Так з'явився ще один скрипт, а точніше трасування навіщось було додано до кінця того ж скрипту, який пінгував усі пристрої в мережі. Адже це ще один довгий процес, який виконувався у тому ж потоці та гальмував роботу всього скрипту. Але тоді це не було так очевидно. Але так чи інакше, він робив свою справу, в коді було жорстко прописано яке мало бути трасування біля кожного з каналів. Так почала працювати система, яка вже моніторила (голосно сказано, тому що не було збору якихось метрик, а просто пінг) мережеві пристрої (роутери, комутатори, wi-fi і т.д.) та канали зв'язку із зовнішнім світом . Справно приходили СМС і на схемі завжди було добре видно де проблема.

Далі, у повсякденній роботі доводилося займатися кросуванням. І щоразу заходити на Cisco комутатори для того, щоб подивитися, який інтерфейс потрібно використовувати набридло. Як було б класно тицьнути на моніторинг на об'єкт і побачити список його інтерфейсів з описами. Це заощадило б мені час. Причому в цій схемі не потрібно було б запускати Putty або SecureCRT вводити обліки та команди. Просто тицьнув у моніторинг, побачив, що треба і пішов робити свою роботу. Почав шукати як можна взаємодіяти із комутаторами. На знижку потрапили відразу два варіанти: SNMP або заходити на комутатор по SSH, вводити необхідні мені команди і парсувати результат. SNMP відмів через складність реалізації, мені не терпілося отримати результат. з SNMP довелося б довго копатися в MIB, на основі цих даних формувати дані про інтерфейси. Є чудова команда у CISCO

show interface status

Вона показує саме те, що мені потрібно для кросировок. Навіщо мучитися з SNMP, коли я просто хочу бачити висновок цієї команди, подумав я. Через деякий час я реалізував таку можливість. Натискав на веб-сторінці на об'єкт. Спрацьовувала подія, за якою AJAX клієнт звертався до сервера, а той у свою чергу підключався по SSH до потрібного мені комутатора (облікові дані були зашиті в код, не було бажання облагороджувати, робити якісь окремі менюшки де можна було б змінювати обліки з інтерфейсу , потрібен був результат і швидше) вводив туди вищезгадану команду і віддавав назад у браузер. Так я почав бачити по одному кліку мишки інформацію про інтерфейси. Це було дуже зручно, особливо коли доводилося дивитися цю інформацію на різних комутаторах одразу.

Моніторинг каналів на основі трасування виявився в результаті не найкращою ідеєю, т.к. іноді проводилися роботи на мережі, і трасування могло змінюватися і моніторинг починав волати про те, що є проблеми з каналом. Але згаявши купу часу на аналіз, розумів, що всі канали працюють, а мій моніторинг мене обманює. У результаті попросив колег, які керували каналоутворюючими комутаторами надсилати мені просто syslog, коли змінювався стан видимості сусідів (neighbor). Відповідно, це було набагато простіше, швидше та правдивіше, ніж трасування. Настала подія виду neighbor lost, і я відразу роблю оповіщення про падіння каналу.

Далі, з'явилися висновки по кліку на об'єкт ще кілька команд і додався SNMP для збору деяких метрик, та й на цьому за великим рахунком все. Більше система не розвивалася. Вона робила все, що мені було потрібно, це був хороший інструмент. Чимало читачів, напевно, мені скажуть, що для вирішення цих завдань вже купа софту в інтернеті. Але насправді, безкоштовних таких продуктів я тоді не нагуглив і дуже хотілося розвивати скіл програмування, а що може краще штовхати до цього, ніж реальне прикладне завдання. На цьому перша версія моніторингу була закінчена і не модифікувалася.

Створення компанії Аудит-телеком

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

Мій друг Павло (теж айтішник) постійно намагався мене спонукати на свій бізнес. Було безліч ідей з різними варіантами своєї справи. Це обговорювалося не один рік. І зрештою ні до чого не мало прийти тому, що я скептик, а Павло фантазер. Щоразу, коли він пропонував якусь ідею, я завжди в неї не вірив і відмовлявся брати участь. Але дуже нам хотілося відкрити свій бізнес.

Нарешті ми змогли знайти варіант, який влаштовує нас обох і зайнятися тим, що ми вміємо. У 2016 році ми вирішили створити IT компанію, яка допомагатиме бізнесу з вирішенням IT завдань. Це розгортання ІТ систем (1С, сервер терміналів, поштовий сервер тощо), їх супровід, класичний HelpDesk для користувачів та адміністрування мережі.

Відверто кажучи, на момент створення компанії, я в неї не вірив приблизно на 99,9%. Але якимось чином Павло зміг мене змусити спробувати, і забігаючи вперед, він мав рацію. Ми скинулися з Павлом по 300 000 рублів, зареєстрували нове ТОВ "Аудит-Телеком", зняли крихітний офіс, наробили крутих візиток, ну загалом як і, напевно, більшість недосвідчених бізнесменів-початківців і почали шукати клієнтів. Пошук клієнтів – це взагалі окрема історія. Можливо, ми напишемо окрему статтю в рамках корпоративного блогу, якщо це комусь буде цікаво. Холодні дзвінки, листівки та інше. Результатів це не давало жодних. Як я вже читаю зараз, з багатьох історій про бізнес так чи інакше багато залежить від удачі. Нам пощастило. і буквально за кілька тижнів після створення фірми, до нас звернувся мій брат Володимир, який і привів до нас першого клієнта. Не стомлюватиму деталями роботи з клієнтами, стаття не про це, скажу лише, що ми поїхали на аудит, виявили критичні місця і ці місця зламалися доки приймалося рішення про те, чи співпрацювати з нами на постійній основі як аутсорсери. Після цього відразу було ухвалено позитивне рішення.

Далі, переважно по сарафану через знайомих, почали з'являтися й інші компанії на обслуговуванні. Helpdesk був в одній системі. Підключення до мережного обладнання та серверів в іншій, а точніше у кого як. Хтось зберігав ярлики, хтось скористався адресними книгами RDP. Моніторинг – ще одна окрема система. Працювати команді у розрізнених системах дуже незручно. Втрачається із виду важлива інформація. Ну, наприклад, недоступний термінальний сервер у клієнта. Відразу надходять заявки від користувачів цього клієнта. Фахівець служби підтримки заводить заявку (вона надійшла телефоном). Якби інциденти та заявки реєструвалися в одній системі, то спеціаліст підтримки відразу б бачив у чому проблема у користувача і сказав би йому про це, паралельно вже підключаючись до потрібного об'єкта для відпрацювання ситуації. Усі в курсі тактичної обстановки та злагоджено працюють. Ми не знайшли такої системи, де це об'єднано. Стало зрозуміло, що час робити свій продукт.

Продовження роботи над системою моніторингу

Зрозуміло було, що система, яка була написана раніше зовсім не підходить під поточні завдання. Ні в плані функціоналу, ні в плані якості. І було ухвалено рішення писати систему з нуля. Графічно це мало вже виглядати зовсім інакше. Це мала бути ієрархічна система, що можна було швидко і зручно відкривати потрібний об'єкт у потрібного клієнта. Схема як і першої версією була у разі абсолютно виправдана, т.к. клієнти різні і зовсім не мало значення, в яких приміщеннях стоїть обладнання. Це вже було перекладено на документацію.

Отже, завдання:

  1. Ієрархічна структура;
  2. Якась серверна частина, яку можна помістити у клієнта у вигляді віртуальної машини для збору необхідних нам метрик та посилки на центральний сервер, який усе це узагальнюватиме і показуватиме нам;
  3. Оповіщення. Такі, які можна пропустити, т.к. на той момент не було можливості комусь сидіти і лише дивитися на монітор;
  4. Система заявок. Почали з'являтися клієнти, у яких ми обслуговували не лише серверне та мережеве обладнання, а й робочі станції;
  5. Можливість швидко підключатися до серверів та обладнання із системи;

Завдання поставлено, починаємо писати. Принагідно обробляючи заявки від клієнтів. На той момент нас уже було 4 особи. Почали писати відразу обидві частини і центральний сервер, і сервер для встановлення клієнтам. До цього моменту Linux був уже не чужим для нас і було ухвалено рішення, що віртуальні машини, які будуть стояти у клієнтів, будуть на Debian. Не буде жодних установників, просто зробимо проект серверної частини на одній віртуальній машині, а потім просто будемо її клонувати до потрібного клієнта. То була чергова помилка. Пізніше стало зрозуміло, що у такій схемі абсолютно не опрацьовано механізму апдейтів. Тобто. ми додавали якусь нову фічу, а потім була ціла проблема розповсюджувати її на всі сервери клієнтів, але до цього повернемося пізніше все по порядку.

Зробили перший зразок. Він умів пінгувати необхідні нам мережні пристрої клієнтів та сервери та надсилати ці дані до нас на центральний сервер. А він, у свою чергу, оновлював ці дані в загальній масі на центральному сервері. Я тут писатиму не лише історію про те, як і що вдавалося, а й які дилетантські помилки робилися і як потім доводилося за це платити часом. Так ось, все дерево об'єктів зберігалося в одному файлі у вигляді серіалізованого об'єкта. Поки ми підключили до системи кілька клієнтів, все було більш-менш нормально, хоч і іноді були якісь артефакти, які були незрозумілі. Але коли ми підключили до системи десяток серверів, почалися чудеса. Іноді, незрозуміло чому, всі об'єкти в системі просто зникали. Тут важливо відзначити, що сервери, які були у клієнтів, надсилали дані на центральний сервер кожні кілька секунд за допомогою запиту POST. Уважний читач і досвідчений програміст вже здогадався, що виникала проблема множинного доступу до того самого файлу, в якому зберігався серіалізований об'єкт з різних потоків одночасно. І саме, коли це відбувалося, виявлялися дива зі зникненням об'єктів. Файл просто ставав порожнім. Але це все виявилося не відразу, а лише в процесі експлуатації з кількома серверами. За цей час було додано функціонал зі сканування портів (сервери надсилали на центральний не тільки інформацію про доступність пристроїв, а й про відкриті на них порти). Зроблено це було шляхом виклику команди:

$connection = @fsockopen($ip, $port, $errno, $errstr, 0.5);

результати часто були неправильними та виконувалося сканування дуже довго. Зовсім забув про пінг, він виконувався через fping:

system("fping -r 3 -t 100 {$this->ip}");

Це все теж не було розпаралелено і тому процес був дуже довгим. Пізніше fping вже передавався відразу весь список необхідних для перевірки IP адрес і назад отримали готовий список тих, хто відгукнувся. На відміну від нас, fping вмів паралелити процеси.

Ще однією частою рутинною роботою було налаштування якихось сервісів через WEB. Наприклад, ECP від ​​MS Exchange. За великим рахунком, це лише посилання. І ми вирішили, що потрібно дати нам можливість додавати такі посилання прямо в систему, щоб не шукати в документації або ще десь в закладках як зайти на ECP конкретного клієнта. Так з'явилося поняття ресурсних посилань для системи, їх функціонал доступний і досі не зазнав змін, ну майже.

Робота ресурсних посилань у Veliam
З аутсорсу на розробку (Частина 1)

Вилучені підключення

Ось як це виглядає у справі у поточній версії Veliam
З аутсорсу на розробку (Частина 1)

Одним із завдань було швидке та зручне підключення до серверів, яких стало вже багато (не одна сотня) та перебирати мільйони заздалегідь збережених RDP ярликів було вкрай незручним. Потрібен був інструмент. Є в інтернеті софт, який представляє собою щось на кшталт адресної книги для таких RDP підключень, але вони не інтегровані з системою моніторингу, і обліки не зберегти. Щоразу вводити обліки для різних клієнтів це справжнє пекло, коли в день ти підключаєшся не один десяток разів на різні сервери. З SSH справи трохи кращі, є багато хорошого софту в якому є можливість розкладати такі підключення по таткам і запам'ятовувати обліки від них. Але є дві проблеми. Перша – для підключень RDP та SSH ми не знайшли єдину програму. Друга — якщо я в якийсь момент не знаходжусь за своїм комп'ютером і мені треба швидко підключитися, або я просто перевстановив систему, мені доведеться лізти в документацію, щоб дивитися облік від цього клієнта. Це незручно і марна трата часу.

Потрібна нам ієрархічна структура по серверам клієнтів вже була у нашому внутрішньому продукті. Потрібно було тільки придумати, як прикрутити туди швидкі підключення до потрібного обладнання. Для початку, хоча б усередині своєї мережі.

З урахуванням того, що клієнтом у нашій системі виступав браузер, який не має доступу до локальних ресурсів комп'ютера, щоб просто взяти і якоюсь командою запустити потрібну нам програму, було придумано зробити все через Windows custom url scheme. Так з'явився якийсь "плагін" до нашої системи, який просто включав до свого складу Putty та Remote Desktop Plus і при встановленні просто реєстрував URI схеми у Windows. Тепер, коли ми хотіли підключитися до об'єкта по RDP або SSH, ми натискали цю дію в нашій системі та спрацювала робота Custom URI. Запускався стандартний mstsc.exe, вбудований у Windows або putty, який йшов до складу “плагіна”. Беру слово плагін у лапки, тому що це не є плагіном браузера у класичному сенсі.

Це було вже хоч щось. Зручна адресна книга. Причому у випадку з Putty все було взагалі добре, йому як вхідні параметри можна було подати і IP підключення і логін і пароль. Тобто. до Linux серверів у мережі ми вже підключалися одним кліком без введення паролів. Але з RDP не все так просто. У стандартний mstsc не можна подати облікові дані як параметри. На допомогу прийшов Remote Desktop Plus. Він дозволяв це робити. Зараз ми вже обходимося без нього, але довгий час він був вірним помічником нашої системи. З HTTP(S) сайтами все просто, такі об'єкти просто відкривалися у браузері та все. Зручно та практично. Але це було щастя лише у внутрішній мережі.

Оскільки переважна кількість проблем ми вирішували віддалено з офісу, найпростішим було зробити VPN'и до клієнтів. І тоді з нашої системи можна було підключатись і до них. Але все одно було трохи незручно. Для кожного клієнта потрібно було тримати на кожному комп'ютері купу запам'ятованих VPN з'єднань і перед підключенням до якогось потрібно було включати відповідний VPN. Таким рішенням ми скористалися досить тривалий час. Але кількість клієнтів збільшується, кількість VPN'ів теж і все це почало напружувати і потрібно було щось робити. Особливо наверталися сльози на очах після переустановки системи, коли потрібно було знову забивати десятки VPN підключень в новому профілі вінди. Досить це терпіти, сказав я і почав думати, що можна з цим зробити.

Так повелося, що у всіх клієнтів як маршрутизатори були пристрої всім відомої фірми Mikrotik. Вони дуже функціональні та зручні для виконання практично будь-яких завдань. З мінусів – їх “викрадають”. Ми вирішили цю проблему просто, закривши всі доступи ззовні. Але треба було якось мати до них доступ, не приїжджаючи до клієнта місце, т.к. це довго. Ми просто зробили до кожного такого мікротика тунелі та виділили їх в окремий пул. без будь-якої маршрутизації, щоб не було об'єднання своєї мережі з мережами клієнтів та їх мереж між собою.

Народилася ідея зробити так, щоб при натисканні на потрібний об'єкт у системі, центральний сервер моніторингу, знаючи облікові записи від SSH всіх клієнтських мікротиків, підключався до потрібного, створював правило прокидання до потрібного хоста з потрібним портом. Тут одразу кілька моментів. Рішення не універсальне — працюватиме тільки для мікротика, як синтаксис команд у всіх роутерів свій. Так само такі прокиди потім треба було якось видаляти, а серверна частина нашої системи по суті не могла відстежувати будь-яким чином, чи закінчив я свій сеанс роботи з RDP. Ну і такий прокид — це дірка для клієнта. А за універсальністю ми не гналися, т.к. продукт використовувався лише всередині нашої компанії та виводити його в паблік навіть думок не було.

Кожна з проблем була вирішена по-своєму. Коли створювалося правило, то прокидання це було доступне тільки для однієї конкретної зовнішньої IP адреси (з якої було ініціалізовано підключення). Тож дірки в безпеці вдалося уникнути. Але при кожному такому підключенні додавалося правило на мікротик на сторінку NAT і не очищалося. А всім відомо, що чим більше там правил, тим більше навантажується процесор роутера. Та й загалом, я не міг прийняти таке, що я зайду одного разу на якийсь мікротик, а там сотні мертвих нікому не потрібних правил.

Якщо наш сервер не може відстежувати стан підключення, нехай мікротик відстежує їх сам. І написав скрипт, який постійно відстежував усі правила прокидання з певним описом (description) і перевіряв чи є TCP підключення відповідне правило. Якщо такого не було вже деякий час, то ймовірно підключення вже завершено і це можна видаляти. Все вийшло, скрипт добре працював.

До речі, ось він:

global atmonrulecounter {"dontDelete"="dontDelete"}
:foreach i in=[/ip firewall nat find comment~"atmon_script_main"] do={ 
	local dstport [/ip firewall nat get value-name="dst-port" $i]
	local dstaddress [/ip firewall nat get value-name="dst-address" $i]
	local dstaddrport "$dstaddress:$dstport"
	#log warning message=$dstaddrport
	local thereIsCon [/ip firewall connection find dst-address~"$dstaddrport"]
	if ($thereIsCon = "") do={
		set ($atmonrulecounter->$dstport) ($atmonrulecounter->$dstport + 1)
		#:log warning message=($atmonrulecounter->$dstport)
		if (($atmonrulecounter->$dstport) > 5) do={
			#log warning message="Removing nat rules added automaticaly by atmon_script"
			/ip firewall nat remove [/ip firewall nat find comment~"atmon_script_main_$dstport"]
			/ip firewall nat remove [/ip firewall nat find comment~"atmon_script_sub_$dstport"]
			set ($atmonrulecounter->$dstport) 0
		}
	} else {
		set ($atmonrulecounter->$dstport) 0
	}
}

Напевно, його можна було зробити красивіше, швидше і т.д., але він працював, не навантажував мікротики і відмінно справлявся. Ми змогли підключатися до серверів і мережевого обладнання клієнтів просто одним натисканням мишки. Не піднімаючи VPN та не вводячи паролі. Із системою стало реально дуже зручно працювати. Час на обслуговування скорочувався, а всі ми витрачали час на роботу, а не на те, щоб підключитися до потрібних об'єктів.

Резервне копіювання Mikrotik

У нас було настроєно резервне копіювання всіх мікротиків на FTP. І загалом усе було добре. Але коли треба було дістати бекап, але треба було відкривати цей FTP та шукати його там. Система, де всі роутери заведені у нас є, спілкуватися з пристроями по SSH ми вміємо. Чого б нам не зробити так, що система сама щодня забиратиме з усіх мікротиків бекапи, подумав я. І взявся реалізовувати. Підключилися, зробили бекап і забрали його у сховище.

Код скрипта на PHP для зняття бекапу з мікротика:

<?php

	$IP = '0.0.0.0';
	$LOGIN = 'admin';
	$PASSWORD = '';
	$BACKUP_NAME = 'test';

    $connection = ssh2_connect($IP, 22);

    if (!ssh2_auth_password($connection, $LOGIN, $PASSWORD)) exit;

    ssh2_exec($connection, '/system backup save name="atmon" password="atmon"');
    stream_get_contents($connection);
    ssh2_exec($connection, '/export file="atmon.rsc"');
    stream_get_contents($connection);
    sleep(40); // Waiting bakup makes

    $sftp = ssh2_sftp($connection);

    // Download backup file
    $size = filesize("ssh2.sftp://$sftp/atmon.backup");
    $stream = fopen("ssh2.sftp://$sftp/atmon.backup", 'r');
    $contents = '';
    $read = 0;
    $len = $size;
    while ($read < $len && ($buf = fread($stream, $len - $read))) {
        $read += strlen($buf);
        $contents .= $buf;
    }
    file_put_contents ($BACKUP_NAME . ‘.backup’,$contents);
    @fclose($stream);

    sleep(3);
    // Download RSC file
    $size = filesize("ssh2.sftp://$sftp/atmon.rsc");
    $stream = fopen("ssh2.sftp://$sftp/atmon.rsc", 'r');
    $contents = '';
    $read = 0;
    $len = $size;
    while ($read < $len && ($buf = fread($stream, $len - $read))) {
        $read += strlen($buf);
        $contents .= $buf;
    }
    file_put_contents ($BACKUP_NAME . ‘.rsc’,$contents);
    @fclose($stream);

    ssh2_exec($connection, '/file remove atmon.backup');
    ssh2_exec($connection, '/file remove atmon.rsc');

?>

Бекап знімається у двох видах – бінарник та текстовий конфіг. Бінарник допомагає швидко ресторувати потрібний конфіг, а текстовий дозволяє розуміти, що треба робити, якщо відбулася вимушена заміна обладнання та бінарник на нього залити не можна. У результаті отримали ще один зручний функціонал у системі. Причому при додаванні нових мікротиків не треба було нічого налаштовувати, просто додав об'єкт у систему і поставив для нього облік від SSH. Далі система сама займалася зніманням бекапів. У поточній версії SaaS Veliam цього функціоналу поки немає, але скоро його портуємо.

Скрини як це виглядало у внутрішній системі
З аутсорсу на розробку (Частина 1)

Перехід на нормальне зберігання у базі даних

Вище я вже писав, що з'являлися артефакти. Іноді просто зникав весь список об'єктів у системі, іноді при редагуванні об'єкта інформація не зберігалася і доводилося по три рази перейменовувати об'єкт. Це дуже дратувало всіх. Зникнення об'єктів відбувалося рідко, і легко відновлювалося шляхом відновлення цього файлу, а ось фейл при редагуванні об'єктів це прям було часто. Ймовірно, я спочатку не зробив це через БД тому, що в умі не вкладалося дерево з усіма зв'язками тримати в плоскій таблиці. Вона ж пласка, а дерево ієрархічне. Але гарне рішення множинного доступу, а згодом (при ускладненні системи) та транзакційного – це СУБД. Я ж, напевно, не перший хто зіткнувся з цією проблемою. Поліз гуглити. Виявилося, що вже все придумано до мене і є кілька алгоритмів, які будують дерево із плоскої таблиці. Подивившись на кожен, я реалізував один із них. Але це була нова версія системи, т.к. по суті, переписувати через це довелося дуже багато. Результат був закономірний, проблеми рандомного поведінки системи пішли. Хтось може сказати, що помилки дуже дилетантські (однопотокові скрипти, зберігання інформації до якої був множинний одночасний доступ з різних потоків у файлі тощо) у сфері розробки програмного забезпечення. Може так і є, але моя основна робота була адміністрування, а програмування було побічним для душі, і я просто не мав досвіду роботи в команді програмістів, там, де такі елементарні речі мені підказали б одразу старші товариші. Тому я всі ці гулі набивав самостійно, але дуже добре засвоїв матеріал. А ще, своя справа - це і зустрічі з клієнтами, і дії спрямовані на спробу розкрутки фірми, і купа адміністративних питань усередині компанії та багато іншого. Але так чи інакше, те, що було вже, було затребуване. Діти і я сам використовували продукт у повсякденній роботі. Були і відверто невдалі ідеї, і рішення, на які було витрачено час, а зрештою стало зрозуміло, що це неробочий інструмент і ним ніхто не користувався і це не потрапило до Veliam.

Служба підтримки — HelpDesk

Не зайвим буде згадати, як формувався HelpDesk. Це окрема історія, т.к. у Veliam це вже 3-я абсолютно нова версія, яка відрізняється від усіх попередніх. Зараз це проста система, інтуїтивно зрозуміла без зайвих рюшок та фінтифлюшок з можливістю інтегруватися з доменом, а також з можливістю доступу до цього профілю користувача з будь-якого місця за посиланням з листа. І що найважливіше, є можливість будь-якої точки (вдома я або в офісі) підключитися до заявника по VNC прямо із заявки без VPN або прокидів портів. Розповім, як ми до цього дійшли, що було до цього і які жахливі рішення були.

Ми підключалися до користувачів через відомий TeamViewer. На всіх комп'ютерах, користувачів яких ми обслуговуємо, встановлено ТВ. Перше, що ми зробили не так, і згодом прибрали це прив'язка кожного клієнта ХД по залізу. Як користувач заходив у систему ХД, щоб залишити заявку? Всім на комп'ютери, крім ТБ була встановлена ​​спеціальна утиліта, написана на Lazarus (тут багато округлять очі, і можливо навіть полізуть гуглити що це таке, але найкраще з компілюваних мов я знав Delphi, а Lazarus це майже те саме, тільки безкоштовне). Загалом користувач запускав у себе спеціальний батник, який запускав цю утиліту, та, у свою чергу, зчитувала HWID системи і після цього запускався браузер і відбувалася авторизація. Навіщо це було зроблено? У деяких компаніях, підрахунок користувачів, що обслуговуються, ведеться поштучно, і ціна обслуговування за кожен місяць формується виходячи з кількості людей. Це зрозуміло, скажете ви, але навіщо прив'язка до заліза. Дуже просто, деякі індивіди приходили додому і робили з домашнього ноутбука заявку в стилі "зробіть мені тут все красиво". Крім зчитування системи HWID, утиліта витягувала з реєстру поточний ID Teamviewer'а і так само передавала до нас. У Teamviewer є API для інтеграції. І ми зробили цю інтеграцію. Але була одна проблема. Через ці API не можна підключитися до комп'ютера користувача, коли він явно не ініціює цю сесію і після спроби підключитися до нього він ще натиснути “підтвердити”. На той момент нам здалося логічним, що без попиту користувача ніхто не повинен підключатися, а якщо людина за комп'ютером, то він і сесію ініціює і ствердно відповість на запит віддаленого підключення. Все виявилося не так. Заявники забували натиснути ініціацію сесії, і доводилося їм говорити в телефонній розмові. Це витрачало час і нервувало обидві сторони процесу. Більше того, аж ніяк не рідкість такі моменти, коли людина залишає заявку, але підключитися дозволяє тільки тоді, коли вона йде на обід. Бо проблема не є критичною і не хоче, щоб його робочий процес переривався. Відповідно, він не натисне жодних кнопок для дозволу підключитися. Так і з'явився додатковий функціонал при авторизації в HelpDesk - зчитування ID Teamviwer. Ми знали постійний пароль, який використовувався під час встановлення Teamviwer. Точніше, його знала лише система, оскільки він був вшитий в установник, і нашу систему. Відповідно була кнопка підключення із заявки з натискання на яку не потрібно було нічого чекати, а відразу відкривався Teamviewer і відбувався коннект. У результаті стали два види можливих підключень. Через офіційний API Teamviewer та наш самопальний. На мій подив, першим майже відразу перестали користуватися, хоч і була вказівка ​​користуватися ним тільки в особливих випадках і коли сам дає на це добро. Все ж таки безпеку зараз подавай. Але виявилось, що заявникам це не потрібно. Вони абсолютно не проти, що до них підключаються без кнопки підтвердження.

Перехід на багатопоточність у Linux

Давно вже почало напрошуватися питання прискорення проходу сканера мережі на предмет відкритості заздалегідь визначеного списку портів і пропінгування об'єктів мережі. Тут само собою перше рішення, яке спадає на думку — багатопоточність. Так як основний час, який витрачається на пінг - це очікування повернення пакета, і наступний пінг не може початися доки не повернеться попередній пакет, в компаніях у яких навіть 20+ серверів плюс мережного обладнання це вже працювало досить повільно. Суть у тому, що один пакет може і зникнути, не повідомляти про це відразу системного адміністратора. Він просто такий спам дуже швидко перестане сприймати. Отже, треба пінгувати кожен об'єкт ще не один раз, перш ніж робити висновок про недоступність. Якщо не вдаватися зовсім у подробиці, то треба паралелити тому, що якщо цього не зробити, то швидше за все, системний адміністратор дізнаватиметься про проблему від клієнта, а не від системи моніторингу.

Сам собою PHP з коробки не вміє багатопоточність. Вміє багатопроцесність, можна форкати. Але, в мене вже по суті був написаний механізм опитування і хотілося зробити так, щоб я одного разу вважав усі потрібні мені вузли з БД, пропінгував усе одразу, дочекався відповіді від кожного і лише після цього одразу писав дані. Це заощаджує на кількості запитів на читання. У цю ідею добре вкладалася багатопоточність. Для PHP є модуль PThreads, який дозволяє робити реальну багатопоточність, правда довелося неабияк повозитися, щоб налаштувати це на PHP 7.2, але справа була зроблена. Сканування портів та пінг стали швидкими. І замість, наприклад, 15 секунд на коло раніше, на цей процес стало йти 2 секунди. Це був добрий результат.

Швидкий аудит нових компаній

Як з'явився функціонал збирання різних метрик та характеристик заліза? Все просто. Іноді нам замовляють просто аудит поточної ІТ інфраструктури. Ну і те ж саме необхідно для прискорення проведення аудиту нового клієнта. Потрібно було щось, що дозволить прийти до середньої чи великої компанії та швидко зорієнтуватися, що в них взагалі є. Пінг у внутрішній мережі блокують, на мій погляд, тільки ті, хто сам собі хоче ускладнити життя, і таких на наш досвід небагато. Але й такі трапляються. Відповідно, можна швидко відсканувати мережі на наявність пристроїв простим пінгом. Далі можна їх додати та просканувати на предмет відкритих портів, які нас цікавлять. По суті, цей функціонал уже був, необхідно тільки було додати команду з центрального сервера на підлеглий, щоб той просканував задані мережі і додав до списку все, що знайде. Забув згадати, передбачалося, що у нас вже є готовий образ із налаштованою системою (підлеглий сервер моніторингу) який ми могли просто розкотити у клієнта при аудиті та підчепити його до своєї хмари.

Але результат аудиту зазвичай включає купу різної інформації і одна з них це - що взагалі за пристрої в мережі. Насамперед нас цікавили Windows сервери та робочі станції Windows у складі домену. Оскільки в середніх і великих компаніях відсутність домену — це, мабуть, виняток із правил. Що б говорити однією мовою, середня, у моїй уяві, це 100+ чоловік. Потрібно було придумати спосіб як зібрати дані з усіх віндових машин та серверів, знаючи їх IP та обліковий запис доменного адміністратора, але при цьому не встановлюючи на кожну з них якийсь софт. На допомогу приходить інтерфейс WMI. Windows Management Instrumentation (WMI) у дослівному перекладі – інструментарій керування Windows. WMI – це одна з базових технологій для централізованого керування та стеження за роботою різних частин комп'ютерної інфраструктури під керуванням платформи Windows. Взято з вікі. Далі довелося знову повозитися, щоб зібрати wmic (це клієнт WMI) для Debian. Після того як все було готове, залишалося просто опитувати через wmic потрібні вузли на предмет потрібної інформації. Через WMI можна дістати з Windows комп'ютера майже будь-яку інформацію, і більше того, через нього можна ще й управляти комп'ютером, наприклад, відправити в перезавантаження. Так з'явився збір інформації про Windows станції та сервери в нашій системі. Плюсом цього йшла і поточна інформація про поточні показники завантаженості системи. Їх ми запитуємо частіше, а інформацію по залізу рідше. Після цього проводити аудит стало трохи приємніше.

Рішення про поширення ПЗ

Ми самі щодня користуємося системою і вона завжди відкрита у кожного технічного співробітника. І ми подумали, що можна з іншими поділитися тим, що вже є. Система була зовсім не готова до того, щоб її поширювати. Необхідно було переробити дуже багато, щоб локальна версія перетворилася на SaaS. Це і зміни різних технічних аспектів у роботі системи (віддалені підключення, служба підтримки), і аналізу модулів щодо ліцензування, і шардування баз даних клієнтів, і масштабування кожного з сервісів, і розробка систем автооновлень для всіх частин. Але про це буде друга частина статті.

Оновити

Друга частина

Джерело: habr.com

Додати коментар або відгук