środa, 5 listopada 2014

FFmpeg segment & timestamp in filename

Szukałem długi czas jak nagrywać strumień wideo dzieląc go na godzinne części i zapisując w oddzielnych plikach. Z pomocą przychodzi niezawodny pakiet FFmpeg. Kłopot w tym że muxer "segment" umożliwia jedynie numerować kolejne pliki np. "output%03d.ts" i w efekcie otrzymamy pliki output000.ts, output001.ts itd. Na szczęście na blogu Things to remember możemy znaleźć użyteczny patch, który dodaje do ffmpegi opcję "%t"
int av_get_frame_filename(char *buf, int buf_size,
                          const char *path, int number)
{
    const char *p;
    char *q, buf1[30], c;
    int nd, len, percentd_found, percentt_found;
    struct timeval tv;

    q = buf;
    p = path;
    percentd_found = 0;
    percentt_found = 0;
    for(;;) {
        c = *p++;
        if (c == '\0')
            break;
        if (c == '%') {
            do {
                nd = 0;
                while (isdigit(*p)) {
                    nd = nd * 10 + *p++ - '0';
                }
                c = *p++;
            } while (isdigit(c));

            switch(c) {
            case '%':
                goto addchar;
            case 'd':
                if (percentd_found)
                    goto fail;
                percentd_found = 1;
                snprintf(buf1, sizeof(buf1), "%0*d", nd, number);
                len = strlen(buf1);
                if ((q - buf + len) > buf_size - 1)
                    goto fail;
                memcpy(q, buf1, len);
                q += len;
                break;
            case 't':

                if (percentt_found)
                    goto fail;
                percentt_found = 1;

                gettimeofday(&tv, NULL);
                strftime(buf1, sizeof(buf1), "%Y-%m-%d_%H-%M-%S", localtime(&tv.tv_sec));
                len = strlen(buf1);
                if ((q - buf + len) > buf_size - 1)
                    goto fail;
                memcpy(q, buf1, len);
                q += len;
                break;
            default:
                goto fail;
            }
        } else {
        addchar:
            if ((q - buf) < buf_size - 1)
                *q++ = c;
        }
    }
    if (!percentd_found && !percentt_found)
        goto fail;
    *q = '\0';
    return 0;
 fail:
    *q = '\0';
    return -1;
}
Pamiętajmy o dodaniu plików nagłówkowych:
#include <sys/time.h>
#include <stdlib.h>

piątek, 9 maja 2014

MariaDB Galera Multi-Master Replication

Dzisiaj na szybko skonfigurujemy replikację multi-master pomiędzy dwoma serwerami. Instalujemy paczki:
apt-get install software-properties-common
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
add-apt-repository 'deb http://mariadb.kisiek.net//repo/10.0/ubuntu trusty main'

apt-key adv --keyserver keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A
add-apt-repository 'deb http://repo.percona.com/apt trusty main'

apt-get install mariadb-galera-server socat percona-xtrabackup
Następnie rozpoczynamy konfigurację serwerów, na serwerze DB1 o adresie 10.0.0.10 edytujemy plik
vim /etc/mysql/conf.d/mariadb.cnf
dodajemy do niego następujące linijki:
query_cache_size        = 0
binlog_format           = ROW
default_storage_engine  = InnoDB
innodb_autoinc_lock_mode        = 2
innodb_doublewrite      = 1
wsrep_provider          = /usr/lib/galera/libgalera_smm.so
wsrep_provider_options  = "gcache.size=32G"
wsrep_cluster_address   = gcomm://10.0.0.10,10.0.0.20
wsrep_cluster_name      = 'cluster'
wsrep_node_address      = '10.0.0.10'
wsrep_node_name         = 'db1'
wsrep_sst_method        = xtrabackup
wsrep_sst_auth          = sstuser:haslo123
dodatkowo musimy utworzyć użytkownika, z którego będzie korzystął xtrabackup:
CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 'haslo123';
GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';
Konfiguracja serwera DB2 przebiega prawie identycznie:
query_cache_size        = 0
binlog_format           = ROW
default_storage_engine  = InnoDB
innodb_autoinc_lock_mode        = 2
innodb_doublewrite      = 1
wsrep_provider          = /usr/lib/galera/libgalera_smm.so
wsrep_provider_options  = "gcache.size=32G"
wsrep_cluster_address   = gcomm://10.0.0.10,10.0.0.20
wsrep_cluster_name      = 'cluster'
wsrep_node_address      = '10.0.0.20'
wsrep_node_name         = 'db2'
wsrep_sst_method        = xtrabackup
wsrep_sst_auth          = sstuser:haslo123
Na serwerze DB2 również musimy utworzyć użytkownika sstuser z odpowiednim hasłem. Jesteśmy gotowi do uruchomienia naszego klastra. W tym celu na db1 wydajemy polecenie:
service mysql stop
service mysql start --wsrep-new-cluster
a na serwerze db2
service mysql restart
Prawdopodobnie podczas wydawania tych poleceń wyskoczy błąd:
ERROR 1045 (28000): Access denied for user 'debian-sys-maint'@'localhost' (using password: YES)
Musimy z db1 skopiować informacje do logowania z pliku /etc/mysql/debian.cnf do serwera db2, tak aby pliki na obu serwerach były identyczne. Na koniec sprawdzamy w syslogu czy nie wystąpiły żadne błędy. :) Przykładowo u mnie wystąpił błąd:
WSREP: Failed to prepare for incremental state transfer: Local state UUID (00000000-0000-0000-0000-000000000000) does not match group state UUID
remedium:
service mysql stop
rm -f /var/lib/mysql/galera.cache /var/lib/mysql/grastate.dat
service mysql start
Zalecam też ustawić nieco bardziej rystrykcyjne prawa do pliku mariadb.cnf:
chmod o= /etc/mysql/conf.d/mariadb.cnf
chgrp mysql /etc/mysql/conf.d/mariadb.cnf

niedziela, 1 maja 2011

Tunelowanie w putty

Często mamy potrzebę aby stworzyć jakiegoś rodzaju tunel. W celu ominięcia blokady regionalnej, czy jakiegoś firewalla w pracy. ;) Jeżeli mamy dostęp po ssh do odpowiedniego serwera możemy wykorzystać nasze ulubione narzędzie czyli Putty.

Przykładowo dzisiaj zrobimy tunel dzięki, któremu będziemy mogli korzystać z ulubionej przeglądarki www i jednocześnie ukrywając nasz prywatny adres IP. :)

1. Rozwijamy kolejno zakładki "Connection", następnie "SSH" i wybieramy "Tunnels".
2. Wypełniamy pole tekstowe "Source port" dowolnie wybranym portem, u mnie 9595.
3. Zaznaczamy opcję "dynamic".
4. Klikamy przycisk "add".

Ostatecznie wszystko powinno wyglądać tak jak na załączonym obrazku:


Wystarczy teraz zwyczajnie zalogować się na nasz serwer a tunel zostanie utworzony.

Następnie musimy skonfigurować naszą przeglądarkę, tak aby wykorzystywała świeżo utworzony tunel. Podam przykładową konfigurację przeglądarki Firefox, ale ustawienia dla innych przeglądarek będą analogiczne.

1. Wchodzimy do menu opcje.
2. Wybieramy zakładkę "zaawansowane"
3. Wybieramy zakładkę "sieć"
4. Klikamy w przycisk "ustawienia" w sekcji połączenia.
5. Konfigurujemy wszystko tak jak na poniższym obrazku:


Podsumowując, właśnie sprawiliśmy że nasza przeglądarka łączy się z localhost czyli z naszym własnym prywatnym komputerem na porcie 9595. Następnie cały ruch zostanie zaszyfrowany, przesłany na drugi koniec tunelu ssh, odszyfrowany i zostanie pobrana odpowiednia strona oraz cała sytuacja się powtórzy w odwrotną stronę. Oczywiście jest to bardzo uproszczony opis tego co w rzeczywistości się dzieje.

Tunele nie muszą być dynamiczne tj. możemy podczas konfiguracji putty wskazać na konkretny port do którego ma prowadzić tunel. Przykładowo możemy utworzyć tunel do usługi smtp onetu: localhost:9898 <-> smtp.poczta.onet.pl:25 wszystko zależy od tego co jest nam aktualnie potrzebne.

piątek, 11 marca 2011

Bonding w Ubuntu 10.04 LTS

W Ubuntu pojawiły się interfejsy "hot-pluggable", w efekcie zmienił się sposób konfigurowania agregacji portów.

Zaczynamy tradycyjnie przez instalację pakietu ifenslave.

apt-get install ifenslave

Następny krok to już właściwa konfiguracja pliku /etc/network/interfaces

auto lo
iface lo inet loopback

auto bond0
iface bond0 inet static
        bond-slaves none
        bond-mode 4
        bond-miimon 100
        address 192.168.0.25
        netmask 255.255.255.0
        gateway 192.168.0.1

auto eth0
iface eth0 inet manual
        bond-master bond0

auto eth1
iface eth1 inet manual
        bond-master bond0

Istotna jest linia 7, w której ustawiamy typ agregacji na LACP czyli standard 802.3ad, a także linie 15 i 19, w których fizyczne interfejsy eth0 i eth1 są dodawane do wirtualnego bond0.

Uwaga! Tryb LACP wymaga odpowiedniej konfiguracji także po stronie przełącznika sieciowego.