Framework TestInfra jako pythonowy sposób na testowanie infrastruktury

25 Października 2021

Przetestowanie infrastruktury to w skrócie przeprowadzenie walidacji systemowej, czyli określenie czy dany serwer lub też oprogramowanie działa w żądany sposób. Jest ona przeprowadzana jest na różnych poziomach (wraz z systemami monitorowania oraz alarmowania) oraz w różnych fazach cyklu życia danej aplikacji – na przykład przed instalacją, w czasie działania aplikacji lub podczas jej instalacji. Najważniejsze pytanie jakie trzeba sobie zadać to “Na jakiej podstawie jesteśmy w stanie stwierdzić, że instalacja była udana?”. Najprostszym rozwiązaniem wydaje się być zalogowanie na maszynę i sprawdzenie czy żądane serwisy czy też kontenery są uruchomione. Problem zaczyna się gdy nie mamy 1 maszyny tylko 100 – logowanie i weryfikacja każdej z nich staje się czasochłonnym oraz uciążliwym zadaniem – stwarza to ryzyko błędów – czy na pewno zweryfikowaliśmy działanie wszystkich koniecznych elementów? Dodatkowo wymagania wraz z rozwojem projektu się rozszerzają i powstaje coraz dłuższa lista rzeczy do sprawdzenia – nie jest trudno wyobrazić sobie sytuację, w której na jednej z maszyn nie została wykonana walidacja w sposób prawidłowy. Jak uprościć wykonywanie tego typu walidacji? Odpowiedzią jest framework TestInfra.

TestInfra – framework testujący Twoją infrastrukturę

Pisanie testów jednostkowych sprawdzających infrastrukturę to obszerne zagadnienie. Framework Testinfra jest przykładem frameworku, który to zadanie ułatwia. Jest to otwarte rozwiązanie zintegrowane z pythonowym frameworkiem testowym pytest. Framework ten pozwala na utworzenie testów do walidacji aktualnego stanu wskazanych serwerów, które uprzednio zostały skonfigurowane – albo ręcznie albo z użyciem narzędzi automatycznego wdrażania i konfiguracji takich jak Ansible, Salt, Puppet czy też Chef. W teorii narzędzia te weryfikują stan i działanie zainstalowanych serwisów czy pakietów, ale nie zawsze konfiguracja została przeprowadzona we właściwy sposób– coś mogło przestać działać zaraz po zainstalowaniu, zabrakło aktualizacji plików konfiguracyjnych o nowo potrzebną zależność. Dlatego ważnym krokiem jest dodatkowa, niezależna walidacja prawidłowej instalacji i konfiguracji wskazanego serwera. We współczesnym deploymencie oprogramowania większość pracy wykonywana jest automatycznie z użyciem serwerów automatyzacji takich jak Jenkins czy TeamCity, które to przeprowadzają konfigurację wskazanej maszyny, więc odpowiednim kierunkiem wydaje się być dodanie kroku przeprowadzenia testów w potoku konfiguracji danego urządzenia. Podczas automatyzacji tego rodzaju testów korzystnym może być wygenerowanie listy hostów wraz z określeniem sposobu nawiązywania przez nie połączeń. TestInfra oferuje kilka typów połączeń do maszyn, co pozwala na elastyczne dopasowanie testów do własnych potrzeb. TestInfra posiada wbudowaną integrację z:

  • localhost,
  • Paramiko (implementacja SSH w Pythonie),
  • Docker,
  • SSH,
  • Salt,
  • Ansible,
  • Kubernetes (za pośrednictwem kubectl),
  • WinRM.

 

Framework TestInfra współpracuje z pythonowym frameworkiem testowym pytest i wykorzystuje tzw. fixtures – funkcje pomocnicze wstrzykiwane do testów. Główną fixture TestInfra jest host – kontener, który agreguje wszystkie inne udostępniane przez narzędzie atrybuty. Najczęściej używane elementy tej fikstury to:

  • host.ansible – zapewnia pełny dostęp do wszystkich właściwości Ansible podczas działania testu, na przykład do właściwości hosts, inventory i vars,
  • host.addr – narzędzie sieciowe pozwalające na sprawdzenie adresów IPv4 i IPv6 – czy host jest dostępny oraz czy rozwiązać nazwę,
  • host.docker – pośrednik dla API systemu Docker – umożliwia interakcję z kontenerami I sprawdzenie czy one działają,
  • host.interface – narzędzie pomocnicze do sprawdzenia adresów z określonego interfejsu,
  • host.iptables – narzędzie służące do weryfikowania reguł firewall,
  • host.mount_point – sprawdza montowanie oraz typy systemów plików na podstawie ścieżek I opcji montowania,
  • host.package – przeprowadza zapytania o to czy wskazany pakiet jest zainstalowany, a jeśli tak to w jakiej wersji,
  • host.process – sprawdza uruchomione procesy,
  • host.socket – testuje nasłuchiwanie na portach tcp/udp,
  • host.system_info – udostępnia różne rodzaje metadanych systemu , takie jak wersja dystrybucji, wydanie i nazwa kodowa,
  • host.check_output – uruchamia polecenie systemowe, sprawdza jego wyjście oraz weryfikuje czy zwrócony kod polecenia jest różny od 0,
  • host.run – uruchamia polecenie, pozwala sprawdzić zwracaną wartość oraz zawartość strumieni host.stderr oraz host.stdout,
  • host.run_expect – sprawdza czy wartość zwrócona przez polecenie jest zgodna z oczekiwanym.

 

Przetestuj swoją infrastrukturę w pythonie

Do przeprowadzenia testów będzie potrzebny komputer z zainstalowanym pythonem w wersji co najmniej 3.6. Poniższe przykłady zostały zrealizowane z użyciem pythona 3.8 oraz systemu operacyjnego Ubuntu (20.04 LTE).

Do rozpoczęcia pracy konieczne będzie nowe środowisko wirtualne z pytestem:

$ python3 -m venv validation

$ source validation/bin/activate

$(validation) pip install pytest

 

Po instalacji pytest zainstaluj pakiet TestInfra:

$(validation) pip install testinfra

 

Środowisko przygotowane, pora napisać pierwszy test. Tworzymy plik z pierwszym testem:

def test_system_info(host):

    assert host.system_info.type == „linux”, „Host should be running on linux”

    assert host.system_info.distribution == „centos”, „Host should be running on centos”

    assert host.system_info.release == „8”, „Centos should be in 8 version”

 

Dużym plusem TestInfra jest jego czytelność – nawet bez znajomości API widać, co powyższy test robi – sprawdza informacje o systemie – czy zainstalowany jest system linux, czy dystrybucja linuxa to Centos oraz czy zainstalowany Centos jest w wersji 8. Taki test można uruchomić z konsoli z użyciem polecenia:

$(validation) pytest –hosts=’ssh://{adres_hosta_do_sprawdzenia}’ test.py

 

Bardzo często sprawdzanym elementem jest poprawność zainstalowanych pakietów na zdalnej maszynie. Przykładowy test sprawdzający czy pakiet nginx jest zainstalowany w wersji 1.6 wygląda tak:

def test_package_nginx_is_installed_in_version_1_6(host):

    package = host.package(„nginx”)

    assert package.is_installed, „Nginx should be installed”

    assert package.version.startswith(„1.6”), „Nginx should be installed in version 1.6”

 

W przypadku pozytywnego wyniku testu zostanie wyświetlony komunikat:

Jeśli natomiast pakiet nginx nie jest zainstalowany zostanie wyświetlony odpowiedni komunikat:

Najczęściej jednak będziemy testować pojedynczych pakietów a całą ich listę. Wtedy pomocna okazuje się możliwość frameworku pytest do parametryzacji testów. Stosując dekorator @pytest.mark.parametrize jesteśmy w stanie bardzo szybko rozszerzyć test sprawdzania zainstalowanych pakietów o kolejne elementy:

import pytest

@pytest.mark.parametrize(„package_name, package_version”, [(„nginx”, „1.6”), („python3”, „3”), („docker”, „1.6”)])

def test_package__is_installed_in_requested_version(host, package_name, package_version):

    package = host.package(package_name)

    assert package.is_installed, f”Package {package_name} should be installed”

    assert package.version.startswith(package_version), f”Package {package_name} should be installed in version {package_version}”

 

I z jednego testu w szybki sposób uzyskano trzy testy, które to można dalej rozbudowywać w łatwy sposób o kolejne elementy. Po uruchomieniu takiego zestawu  dostajemy informację, które pakiety są zainstalowane, a które nie:

Jak widać z komunikatów frameworka, pakiet nginx nie jest w ogóle zainstalowany, pakiet python3 jest zainstalowany w odpowiedniej wersji, natomiast pakiet docker jest zainstalowany, ale jego wersja (1.5.2) nie odpowiada wersji, która była wymagana (1.6).

Powyższe przykłady to tylko bardzo mała część modułów, jakie udostępnia framework TestInfra, pełną listę modułów wraz z przykładami użycia można znaleźć pod adresem https://testinfra.readthedocs.io/en/latest/modules.html.

 

Podsumowanie

Testowanie infrastruktury jest problemem  nietrywialnym. Bez skutecznej automatyzacji  to proces żmudny i podatny na błędy, jednak dzięki wykorzystaniu nowoczesnych narzędzi staje się automatyczny oraz powtarzalny. TestInfra jest jednym z przykładów narzędzia integrującego się z pythonem i pytestem.. Pozwala na łatwą i szybką weryfikację działania serwisów, sprawdzenie działających kontenerów czy walidację istniejących użytkowników oraz ich uprawnień na wybranym serwerze. Dodając testy do swoich rozwiązań CI jesteśmy w stanie na bieżąco i w powtarzalny sposób monitorować stan maszyn oraz ich działanie, szybko reagować na wykryte nieprawidłowości oraz podnosić jakość deploymentu oprogramowania.

Opublikowane przez: Katarzyna Chojecka

Inne artykuły_