Komu je určený tento článok?
Tento článok môže byť zaujímavý pre správcov systému, ktorí stoja pred úlohou vytvoriť službu „jednorazových“ pracovných staníc.
prológ
Oddelenie IT podpory mladej dynamicky sa rozvíjajúcej spoločnosti s malou regionálnou sieťou bolo požiadané o organizáciu „samoobslužných staníc“ pre svojich externých klientov. Tieto stanice mali slúžiť na registráciu na externých firemných portáloch, sťahovanie dát z externých zariadení a prácu s portálmi štátnej správy.
Dôležitým aspektom bola skutočnosť, že väčšina softvéru bola navrhnutá pre MS Windows (napríklad „Vyhlásenie“) a napriek prechodu na otvorené formáty zostáva MS Office dominantným štandardom pre výmenu elektronických dokumentov. Preto opustenie MS Windows Tento problém sme nedokázali vyriešiť.
Hlavným problémom bola možnosť hromadenia rôznych dát z užívateľských relácií, čo by mohlo viesť k ich úniku tretím stranám. . Ale na rozdiel od kvázi štátnej (štátnej autonómnej inštitúcie) MFC, neštátne organizácie budú za takéto nedostatky trestané oveľa prísnejšie. Ďalším najkritickejším problémom bola požiadavka na prácu s externými pamäťovými médiami, ktoré by určite obsahovali kopu škodlivého malvéru. Pravdepodobnosť importu malvéru z internetu sa považovala za menej pravdepodobnú z dôvodu obmedzení prístupu na internet pomocou bieleho zoznamu adries.Do vývoja požiadaviek sa zapojili aj zamestnanci z iných oddelení, ktorí predstavili svoje požiadavky a želania, finálne požiadavky vyzerali Páči sa ti to:
Požiadavky na informačnú bezpečnosť
- Po použití musia byť všetky používateľské údaje (vrátane dočasných súborov a kľúčov databázy Registry) vymazané.
- Všetky procesy spustené používateľom musia byť po dokončení práce ukončené.
- Prístup na internet pomocou bieleho zoznamu adries.
- Obmedzenia možnosti spúšťať kód tretích strán.
- Ak je relácia nečinná dlhšie ako 5 minút, relácia by sa mala automaticky ukončiť a stanica by sa mala vyčistiť.
Požiadavky zákazníkov
- Počet klientskych staníc na pobočku nie je väčší ako 4.
- Minimálna doba čakania, kým bude systém pripravený, od momentu, keď ste si „sadli“ až po začiatok práce s klientskym softvérom.
- Možnosť pripojenia periférnych zariadení (skenery, flash disky) priamo z miesta inštalácie „samoobslužnej stanice“.
- Priania zákazníka
- Ukážka reklamných materiálov (obrázkov), keď je areál nečinný.
Návaly kreativity
Keď sme sa veľa pohrali s Windows livecd, dospeli sme k jednomyseľnému záveru, že výsledné riešenie nespĺňa minimálne 3 kritické body. Buď sa dlho načítavajú, alebo nie sú celkom živé, alebo ich prispôsobenie bolo spojené s divokými bolesťami. Možno sme nehľadali dobre a môžete mi odporučiť sadu nástrojov, budem vám vďačný.
Potom sme sa začali obzerať po VDI, ale na túto úlohu je väčšina riešení buď príliš drahá, alebo si vyžaduje zvýšenú pozornosť. Chcel som však jednoduchý nástroj s minimálnou dávkou mágie, ktorého väčšina problémov by sa dala vyriešiť jednoduchým reštartom/reštartom služby. Našťastie sme mali z vyraďovanej služby serverové vybavenie, low-end triedy v pobočkách, ktoré sme mohli využiť na technologickú základňu.
Čo sa stalo na konci? Ale nemôžem vám povedať, čo sa nakoniec stalo, pretože je to NDA, ale v procese hľadania sme vyvinuli zaujímavú schému, ktorá sa dobre ukázala v laboratórnych testoch, hoci sa nedostala do výroby.
Niekoľko upozornení: autor netvrdí, že navrhované riešenie úplne rieši všetky uvedené problémy, a robí tak dobrovoľne a s vyznamenaním. Autor vopred súhlasí s tvrdením, že „Sein Englishe sprache“ je veľmi zlý. Keďže riešenie sa už nevyvíja, nemôžete sa spoliehať na opravy chýb ani zmeny funkčnosti; všetko je vo vašich rukách. Autor predpokladá, že ste aspoň trochu oboznámení s KVM, prečítali ste si prehľadový článok o protokole Spice a trochu ste s ním pracovali. Centos alebo iný GNU Linux distribúcia.
V tomto článku by som sa rád venoval jadru výsledného riešenia, konkrétne interakcii klient-server a podstate procesov životného cyklu virtuálneho počítača v rámci riešenia. Ak bude článok zaujímavý pre verejnosť, popíšem detaily implementácie živých obrazov pre vytváranie tenkých klientov založených na Fedore a rozoberiem detaily konfigurácie virtuálnych počítačov a... KVM servery na optimalizáciu výkonu a zabezpečenia.
Ak vezmete farebný papier,
Farby, štetce a lepidlo,
A trochu viac zručnosti...
Môžete zarobiť sto rubľov!
Schéma a popis skúšobnej stolice

Všetky zariadenia sú umiestnené vo vnútri pobočkovej siete, len internetový kanál ide von. Proxy server tu už historicky bol, nie je to nič výnimočné. No práve na ňom bude okrem iného prebiehať filtrovanie návštevnosti z virtuálnych strojov (skr. VM nižšie v texte). Nič vám nebráni umiestniť túto službu na KVM server, jediné, čo musíte sledovať, je, ako sa od neho mení zaťaženie diskového subsystému.
Klientska stanica je vlastne „samoobslužná stanica“, „front-end“ našej služby. Sú to nettopy Lenovo IdeaCentre. Čo je dobré na tejto jednotke? Áno, takmer každého, poteší najmä veľké množstvo USB konektorov a čítačka kariet na prednom paneli. V našej schéme je do čítačky kariet vložená SD karta so zapnutou hardvérovou ochranou proti zápisu, na ktorú je zaznamenaný upravený živý obraz Fedory 28. K nettopu je samozrejme pripojený monitor, klávesnica a myš.
Switch je neprehliadnuteľný hardvérový prepínač druhej úrovne, ktorý stojí v serverovej miestnosti a bliká. Nie je pripojený k iným sieťam ako sieť „samoobslužných staníc“.
KVM_Server je jadrom systému; v benchmarkových testoch si Core 2 Quad Q9650 s 8 GB RAM s istotou poradil s 3 virtuálnymi počítačmi. Windows10. Diskový subsystém – Adaptec 3405, 2 disky Raid 1 a SSD. V terénnych testoch si Xeon 1220 a výkonnejší LSI 9260 s SSD bez problémov poradili s 5 – 6 virtuálnymi počítačmi. Servery by boli zdedené po vyradenom poskytovateľovi služieb, takže kapitálové výdavky by boli minimálne. Na týchto serveroch je nasadená virtualizácia KVM s fondom virtuálnych počítačov pool_Vm.
Vm je virtuálny stroj, backend našej služby. Je to miesto, kde prebieha práca používateľa.
Enp5s0 je sieťové rozhranie orientované na sieť „samoobslužných staníc“, na ňom žijú dhcpd, ntpd, httpd a xinetd počúva „signálny“ port.
Lo0 je pseudo loopback rozhranie. Štandardné.
Spice_console – Veľmi zaujímavou vecou je, že na rozdiel od klasického RDP sa po rozšírení balíka protokolu KVM+Spice objaví ďalšia entita – konzolový port virtuálneho stroja. V skutočnosti pripojením k tomuto portu TCP získame konzolu Vm bez toho, aby sme sa museli pripájať k Vm cez jej sieťové rozhranie. Server preberá všetku interakciu s Vm na prenos signálu. Funkčne najbližší analóg je IPKVM. Tie. Na tento port sa prenáša obraz monitora VM, prenášajú sa naň aj údaje o pohybe myši a (čo je najdôležitejšie) interakcia cez protokol Spice umožňuje bezproblémové presmerovanie USB zariadení na virtuálny stroj, ako keby bolo toto zariadenie pripojené k samotnému Vm. Testované pre flash disky, skenery, webové kamery.
Virtuálne sieťové karty Vnet0, virbr0 a Vm tvoria sieť virtuálnych strojov.
Ako to funguje
Z klientskej stanice
Klientska stanica bootuje v grafickom režime z upraveného živého obrazu Fedory 28, prijíma IP adresu cez dhcp zo sieťového adresného priestoru 169.254.24.0/24. Počas procesu sťahovania sa vytvoria pravidlá brány firewall, ktoré umožňujú pripojenie k portom „signal“ a „spice“ servera. Po dokončení sťahovania stanica čaká na autorizáciu používateľa „Klient“. Po autorizácii používateľa sa spustí správca plochy „openbox“ a spustí sa skript automatického spustenia v mene oprávneného používateľa. Autorun skript okrem iného spúšťa skript remote.sh.
$HOME/.config/openbox/scripts/remote.sh
#!/bin/sh
server_ip=$(/usr/bin/cat /etc/client.conf |/usr/bin/grep "server_ip"
|/usr/bin/cut -d "=" -f2)
vdi_signal_port=$(/usr/bin/cat /etc/client.conf |/usr/bin/grep "vdi_signal_port"
|/usr/bin/cut -d "=" -f2)
vdi_spice_port=$(/usr/bin/cat /etc/client.conf |/usr/bin/grep "vdi_spice_port"
|/usr/bin/cut -d "=" -f2)
animation_folder=$(/usr/bin/cat /etc/client.conf |/usr/bin/grep "animation_folder"
|/usr/bin/cut -d "=" -f2)
process=/usr/bin/remote-viewer
while true
do
if [ -z `/usr/bin/pidof feh` ]
then
/usr/bin/echo $animation_folder
/usr/bin/feh -N -x -D1 $animation_folder &
else
/usr/bin/echo
fi
/usr/bin/nc -i 1 $server_ip $vdi_signal_port |while read line
do
if /usr/bin/echo "$line" |/usr/bin/grep "RULE ADDED, CONNECT NOW!"
then
/usr/bin/killall feh
pid_process=$($process "spice://$server_ip:$vdi_spice_port"
"--spice-disable-audio" "--spice-disable-effects=animation"
"--spice-preferred-compression=auto-glz" "-k"
"--kiosk-quit=on-disconnect" | /bin/echo $!)
/usr/bin/wait $pid_process
/usr/bin/killall -u $USER
exit
else
/usr/bin/echo $line >> /var/log/remote.log
fi
done
done
/etc/client.conf
server_ip=169.254.24.1
vdi_signal_port=5905
vdi_spice_port=5906
animation_folder=/usr/share/backgrounds/animation
background_folder=/usr/share/backgrounds2/fedora-workstation
Popis premenných súboru client.conf
server_ip — adresa KVM_Servera
vdi_signal_port – port KVM_Server, na ktorom „sedí“ xinetd
vdi_spice_port — sieťový port KVM_Server, z ktorého bude požiadavka na pripojenie presmerovaná z klienta vzdialeného prehliadača na port korenia vyhradeného Vm (podrobnosti nižšie)
animation_folder - priečinok, z ktorého sú prevzaté obrázky pre demonštráciu animácie bullshit
background_folder – priečinok, z ktorého sa preberajú obrázky na zobrazovanie prezentácií v pohotovostnom režime. Viac podrobností o animácii v ďalšej časti článku.
Skript remote.sh preberá nastavenia z konfiguračného súboru /etc/client.conf a používa nc na pripojenie k portu „vdi_signal_port“ servera KVM a prijíma dátový tok zo servera, medzi ktorým očakáva riadky „RULE ADDED“ , PRIPOJTE SA TERAZ“. Po prijatí požadovaného reťazca sa spustí proces vzdialeného prehliadača v režime kiosku, čím sa vytvorí spojenie s portom servera „vdi_spice_port“. Vykonávanie skriptu je pozastavené, kým vzdialený prehliadač nedokončí vykonávanie.
Remote-viewer pripájajúci sa k portu „vdi_spice_port“ sa vďaka presmerovaniu na strane servera dostane na port „spice_console“ rozhrania lo0, t.j. do konzoly virtuálneho počítača a práca používateľa prebieha priamo. Používateľovi sa počas čakania na pripojenie zobrazuje hovadinová animácia, vo forme prezentácie jpeg súborov, cesta k adresáru s obrázkami je určená hodnotou premennej animation_folder z konfiguračného súboru.
Ak dôjde k strate spojenia s portom „spice_console“ virtuálneho stroja, čo signalizuje vypnutie/reštart virtuálneho stroja (t. j. skutočný koniec relácie používateľa), všetky procesy bežiace v mene oprávneného používateľa sa ukončia, čo vedie reštartovať lightdm a vrátiť sa na autorizačnú obrazovku.
Zo strany servera KVM
Na „signálnom“ porte sieťovej karty enp5s0 čaká na pripojenie xinetd. Po pripojení k portu „signal“ spustí xinetd skript vm_manager.sh bez toho, aby mu odovzdal akékoľvek vstupné parametre a presmeruje výsledok skriptu do relácie Client Station nc.
/etc/xinetd.d/test-server
service vdi_signal
{
port = 5905
socket_type = stream
protocol = tcp
wait = no
user = root
server = /home/admin/scripts_vdi_new/vm_manager.sh
}
/home/admin/scripts_vdi_new/vm_manager.sh
#!/usr/bin/sh
#<SET LOCAL VARIABLES FOR SCRIPT>#
SRV_SCRIPTS_DIR=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "srv_scripts_dir" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo "SRV_SCRIPTS_DIR=$SRV_SCRIPTS_DIR"
export SRV_SCRIPTS_DIR=$SRV_SCRIPTS_DIR
SRV_POOL_SIZE=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "srv_pool_size" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo "SRV_POOL_SIZE=$SRV_POOL_SIZE"
export "SRV_POOL_SIZE=$SRV_POOL_SIZE"
SRV_START_PORT_POOL=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "srv_start_port_pool" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo SRV_START_PORT_POOL=$SRV_START_PORT_POOL
export SRV_START_PORT_POOL=$SRV_START_PORT_POOL
SRV_TMP_DIR=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "srv_tmp_dir" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo "SRV_TMP_DIR=$SRV_TMP_DIR"
export SRV_TMP_DIR=$SRV_TMP_DIR
date=$(/usr/bin/date)
#</SET LOCAL VARIABLES FOR SCRIPT>#
/usr/bin/echo "# $date START EXECUTE VM_MANAGER.SH #"
make_connect_to_vm() {
#<READING CLEAR.LIST AND CHECK PORT FOR NETWORK STATE>#
/usr/bin/echo "READING CLEAN.LIST AND CHECK PORT STATE"
#<CHECK FOR NO ONE PORT IN CLEAR.LIST>#
if [ -z `/usr/bin/cat $SRV_TMP_DIR/clear.list` ]
then
/usr/bin/echo "NO AVALIBLE PORTS IN CLEAN.LIST FOUND"
/usr/bin/echo "Will try to make housekeeper, and create new vm"
make_housekeeper
else
#<MINIMUN ONE PORT IN CLEAR.LIST FOUND>#
/usr/bin/cat $SRV_TMP_DIR/clear.list |while read line
do
clear_vm_port=$(($line))
/bin/echo "FOUND PORT $clear_vm_port IN CLEAN.LIST. TRY NETSTAT"
"CHECK FOR PORT=$clear_vm_port"
#<NETSTAT LISTEN CHECK FOR PORT FROM CLEAN.LIST>#
if /usr/bin/netstat -lnt |/usr/bin/grep ":$clear_vm_port" > /dev/null
then
/bin/echo "$clear_vm_port IS LISTEN"
#<PORT IS LISTEN. CHECK FOR IS CONNECTED NOW>#
if /usr/bin/netstat -nt |/usr/bin/grep ":$clear_vm_port"
|/usr/bin/grep "ESTABLISHED" > /dev/null
then
#<PORT LISTEN AND ALREADY CONNECTED! MOVE PORT FROM CLEAR.LIST
# TO WASTE.LIST>#
/bin/echo "$clear_vm_port IS ALREADY CONNECTED, MOVE PORT TO WASTE.LIST"
/usr/bin/sed -i "/$clear_vm_port/d" $SRV_TMP_DIR/clear.list
/usr/bin/echo $clear_vm_port >> $SRV_TMP_DIR/waste.list
else
#<PORT LISTEN AND NO ONE CONNECT NOW. MOVE PORT FROM CLEAR.LIST TO
# CONN_WAIT.LIST AND CREATE IPTABLES RULES>##
/usr/bin/echo "OK, $clear_vm_port IS NOT ALREADY CONNECTED"
/usr/bin/sed -i "/$clear_vm_port/d" $SRV_TMP_DIR/clear.list
/usr/bin/echo $clear_vm_port >> $SRV_TMP_DIR/conn_wait.list
$SRV_SCRIPTS_DIR/vm_connect.sh $clear_vm_port
#<TRY TO CLEAN VM IN WASTE.LIST AND CREATE NEW WM>#
/bin/echo "TRY TO CLEAN VM IN WASTE.LIST AND CREATE NEW VM"
make_housekeeper
/usr/bin/echo "# $date STOP EXECUTE VM_MANAGER.SH#"
exit
fi
else
#<PORT IS NOT A LISTEN. MOVE PORT FROM CLEAR.LIST TO WASTE.LIST>#
/bin/echo " "$clear_vm_port" is NOT LISTEN. REMOVE PORT FROM CLEAR.LIST"
/usr/bin/sed -i "/$clear_vm_port/d" $SRV_TMP_DIR/clear.list
/usr/bin/echo $clear_vm_port >> $SRV_TMP_DIR/waste.list
make_housekeeper
fi
done
fi
}
make_housekeeper() {
/usr/bin/echo "=Execute housekeeper="
/usr/bin/cat $SRV_TMP_DIR/waste.list |while read line
do
/usr/bin/echo "$line"
if /usr/bin/netstat -lnt |/usr/bin/grep ":$line" > /dev/null
then
/bin/echo "port_alive, vm is running"
if /usr/bin/netstat -nt |/usr/bin/grep ":$line"
|/usr/bin/grep "ESTABLISHED" > /dev/null
then
/bin/echo "port_in_use can't delete vm!!!"
else
/bin/echo "port_not in use. Deleting vm"
/usr/bin/sed -i "/$line/d" $SRV_TMP_DIR/waste.list
/usr/bin/echo $line >> $SRV_TMP_DIR/recycle.list
$SRV_SCRIPTS_DIR/vm_delete.sh $line
fi
else
/usr/bin/echo "posible vm is already off. Deleting vm"
/usr/bin/echo "MOVE VM IN OFF STATE $line FROM WASTE.LIST TO"
"RECYCLE.LIST AND DELETE VM"
/usr/bin/sed -i "/$line/d" $SRV_TMP_DIR/waste.list
/usr/bin/echo $line >> $SRV_TMP_DIR/recycle.list
$SRV_SCRIPTS_DIR/vm_delete.sh "$line"
fi
done
create_clear_vm
}
create_clear_vm() {
/usr/bin/echo "=Create new VM="
while [ $SRV_POOL_SIZE -gt 0 ]
do
new_vm_port=$(($SRV_START_PORT_POOL+$SRV_POOL_SIZE))
/usr/bin/echo "new_vm_port=$new_vm_port"
if /usr/bin/grep "$new_vm_port" $SRV_TMP_DIR/clear.list > /dev/null
then
/usr/bin/echo "$new_vm_port port is already defined in clear.list"
else
if /usr/bin/grep "$new_vm_port" $SRV_TMP_DIR/waste.list > /dev/null
then
/usr/bin/echo "$new_vm_port port is already defined in waste.list"
else
if /usr/bin/grep "$new_vm_port" $SRV_TMP_DIR/recycle.list > /dev/null
then
/usr/bin/echo "$new_vm_port PORT IS ALREADY DEFINED IN RECYCLE LIST"
else
if /usr/bin/grep "$new_vm_port" $SRV_TMP_DIR/conn_wait.list > /dev/null
then
/usr/bin/echo "$new_vm_port PORT IS ALREADY DEFINED IN CONN_WAIT LIST"
else
/usr/bin/echo "PORT IN NOT DEFINED IN NO ONE LIST WILL CREATE"
"VM ON PORT $new_vm_port"
/usr/bin/echo $new_vm_port >> $SRV_TMP_DIR/recycle.list
$SRV_SCRIPTS_DIR/vm_create.sh $new_vm_port
fi
fi
fi
fi
SRV_POOL_SIZE=$(($SRV_POOL_SIZE-1))
done
/usr/bin/echo "# $date STOP EXECUTE VM_MANAGER.SH #"
}
make_connect_to_vm |/usr/bin/tee -a /var/log/vm_manager.log
/etc/vm_manager.confsrv_scripts_dir=/home/admin/scripts_vdi_new
srv_pool_size=4
srv_start_port_pool=5920
srv_tmp_dir=/tmp/vm_state
základný_hostiteľ=win10_2
input_iface=enp5s0
vdi_spice_port=5906
count_conn_tryes=10
Popis premenných v konfiguračnom súbore vm_manager.conf
srv_scripts_dir — priečinok, v ktorom sa nachádzajú skripty vm_manager.sh, vm_connect.sh, vm_delete.sh, vm_create.sh, vm_clear.sh
srv_pool_size — veľkosť oblasti Vm
srv_start_port_pool - počiatočný port, po ktorom sa začne umiestňovanie portov korenia pre konzoly virtuálnych strojov
srv_tmp_dir - priečinok na ukladanie dočasných súborov
base_host — základný Vm (zlatý obrázok), z ktorého sa vyrobia klony Vm do fondu
input_iface — sieťové rozhranie servera oproti klientskym staniciam
vdi_spice_port — sieťový port servera, z ktorého bude požiadavka na pripojenie od klienta vzdialeného prehliadača presmerovaná na port korenia vyhradeného Vm
count_conn_tryes — časovač čakania, po ktorom sa má za to, že nenastalo žiadne pripojenie k Vm (podrobnosti nájdete v vm_connect.sh)
Skript vm_manager.sh načíta konfiguračný súbor zo súboru vm_manager.conf a vyhodnotí stav virtuálnych počítačov v oblasti na základe niekoľkých parametrov, konkrétne: koľko virtuálnych počítačov je nasadených, či existujú voľné čisté virtuálne počítače. Na tento účel načíta súbor clear.list, ktorý obsahuje čísla portov „spice_console“ „čerstvo vytvorených“ (pozri nižšie cyklus vytvárania virtuálnych počítačov) virtuálnych počítačov a skontroluje nadviazané spojenie s nimi. Keď sa zistí port s nadviazaným sieťovým pripojením (čo by rozhodne nemalo byť), zobrazí sa varovanie a port sa prenesie do waste.list Keď sa zistí prvý port zo súboru clear.list, s ktorým momentálne nie je spojenie , vm_manager.sh zavolá skript vm_connect.sh a odošle mu ako parameter číslo tohto portu.
/home/admin/scripts_vdi_new/vm_connect.sh
#!/bin/sh
date=$(/usr/bin/date)
/usr/bin/echo "#" "$date" "START EXECUTE VM_CONNECT.SH#"
#<SET LOCAL VARIABLES FOR SCRIPT>#
free_port="$1"
input_iface=$(/usr/bin/cat /etc/vm_manager.conf |/usr/bin/grep "input_iface"
|/usr/bin/cut -d "=" -f2)
/usr/bin/echo "input_iface=$input_iface"
vdi_spice_port=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "vdi_spice_port" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo "vdi_spice_port=$vdi_spice_port"
count_conn_tryes=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "count_conn_tryes" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo "count_conn_tryes=$count_conn_tryes"
#</SET LOCAL VARIABLES FOR SCRIPT>#
#<CREATE IPTABLES RULES AND SEND SIGNAL TO CONNECT>#
/usr/bin/echo "create rule for port" $free_port
/usr/sbin/iptables -I INPUT -i $input_iface -p tcp -m tcp --dport
$free_port -j ACCEPT
/usr/sbin/iptables -I OUTPUT -o $input_iface -p tcp -m tcp --sport
$free_port -j ACCEPT
/usr/sbin/iptables -t nat -I PREROUTING -p tcp -i $input_iface --dport
$vdi_spice_port -j DNAT --to-destination 127.0.0.1:$free_port
/usr/bin/echo "RULE ADDED, CONNECT NOW!"
#</CREATE IPTABLES RULES AND SEND SIGNAL TO CONNECT>#
#<WAIT CONNECT ESTABLISHED AND ACTIVATE CONNECT TIMER>#
while [ $count_conn_tryes -gt 0 ]
do
if /usr/bin/netstat -nt |/usr/bin/grep ":$free_port"
|/usr/bin/grep "ESTABLISHED" > /dev/null
then
/bin/echo "$free_port NOW in use!!!"
/usr/bin/sleep 1s
/usr/sbin/iptables -t nat -D PREROUTING -p tcp -i $input_iface --dport
$vdi_spice_port -j DNAT --to-destination 127.0.0.1:$free_port
/usr/sbin/iptables -D INPUT -i $input_iface -p tcp -m tcp --dport
$free_port -j ACCEPT
/usr/sbin/iptables -D OUTPUT -o $input_iface -p tcp -m tcp --sport
$free_port -j ACCEPT
/usr/bin/sed -i "/$free_port/d" $SRV_TMP_DIR/conn_wait.list
/usr/bin/echo $free_port >> $SRV_TMP_DIR/waste.list
return
else
/usr/bin/echo "$free_port NOT IN USE"
/usr/bin/echo "RULE ADDED, CONNECT NOW!"
/usr/bin/sleep 1s
fi
count_conn_tryes=$((count_conn_tryes-1))
done
#</WAIT CONNECT ESTABLISED AND ACTIVATE CONNECT TIMER>#
#<IF COUNT HAS EXPIRED. REMOVE IPTABLES RULE AND REVERT
# VM TO CLEAR.LIST>#
/usr/bin/echo "REVERT IPTABLES RULE AND REVERT VM TO CLEAN
LIST $free_port"
/usr/sbin/iptables -t nat -D PREROUTING -p tcp -i $input_iface --dport
$vdi_spice_port -j DNAT --to-destination 127.0.0.1:$free_port
/usr/sbin/iptables -D INPUT -i $input_iface -p tcp -m tcp --dport $free_port
-j ACCEPT
/usr/sbin/iptables -D OUTPUT -o $input_iface -p tcp -m tcp --sport
$free_port -j ACCEPT
/usr/bin/sed -i "/$free_port/d" $SRV_TMP_DIR/conn_wait.list
/usr/bin/echo $free_port >> $SRV_TMP_DIR/clear.list
#</COUNT HAS EXPIRED. REMOVE IPTABLES RULE AND REVERT VM
#TO CLEAR.LIST>#
/usr/bin/echo "#" "$date" "END EXECUTE VM_CONNECT.SH#"
# Attention! Must Be! sysctl net.ipv4.conf.all.route_localnet=1
Skript vm_connect.sh zavádza pravidlá brány firewall, ktoré vytvárajú presmerovanie serverového portu „vdi_spice_port“ rozhrania enp5s0 na „port konzoly korenia“ virtuálneho počítača umiestneného na rozhraní servera lo0, ktorý je odovzdaný ako spúšťací parameter. Port sa prenesie do conn_wait.list, virtuálny počítač sa považuje za čakajúci na pripojenie. Reťazec „RULE ADDED, CONNECT NOW“ sa odošle do relácie klientskej stanice na „signálovom“ porte servera, ktorý očakáva skript remote.sh na ňom spustený. Cyklus čakania na pripojenie začína počtom pokusov určeným hodnotou premennej „count_conn_tryes“ z konfiguračného súboru. Každú sekundu sa do relácie nc odošle reťazec „RULE ADDED, CONNECT NOW“ a skontroluje sa prítomnosť vytvoreného pripojenia k portu „spice_console“.
Ak po nastavený počet pokusov nedôjde k žiadnemu spojeniu, port „spice_console“ sa prenesie späť do clear.list Vykonávanie vm_connect.sh sa ukončí, vykonávanie vm_manager.sh sa obnoví, čím sa spustí cyklus čistenia.
Ak sa zistí pripojenie klientskej stanice k portu „spice_console“ na rozhraní lo0, pravidlá brány firewall, ktoré vytvárajú presmerovanie medzi portom „spice“ servera a portom „spice_console“, sa vymažú a spojenie sa ďalej udržiava pomocou stavu brány firewall. detekčný mechanizmus. Ak je spojenie prerušené, nebude možné obnoviť spojenie s portom „spice_console“. Port „spice_console“ sa presunie do waste.list, virtuálny počítač sa považuje za „špinavý“ a nebude sa môcť vrátiť do fondu „čistých“ virtuálnych počítačov bez toho, aby prešiel čistením. Vykonávanie vm_connect.sh sa skončí a vykonávanie vm_manager.sh sa obnoví, čím sa spustí cyklus čistenia.
Cyklus čistenia začína prezretím súboru waste.list, do ktorého sa prenesú čísla portov „spice_console“ virtuálnych strojov, ku ktorým bolo vytvorené spojenie. Prítomnosť aktívneho pripojenia sa určuje na každom porte „spice_console“ zo zoznamu. Ak nie je pripojenie, predpokladá sa, že virtuálny stroj sa už nepoužíva a port sa presunie do recycle.list a spustí sa proces vymazania virtuálneho stroja (pozri nižšie), ku ktorému tento port patril. Ak sa na porte zistí aktívne sieťové pripojenie, virtuálny počítač sa považuje za používaný a nevykoná sa na ňom žiadna akcia. Ak port nepočúva, VM sa považuje za vypnutý a už nie je potrebný. Port sa prenesie do recycle.list a spustí sa proces vymazania virtuálneho počítača. Na tento účel sa zavolá skript vm_delete.sh, ktorému sa číslo „spice_console“ odovzdá ako parameter portu virtuálneho počítača, ktorý je potrebné odstrániť.
/home/admin/scripts_vdi_new/vm_delete.sh
#!/bin/sh
#<Set local VARIABLES>#
port_to_delete="$1"
date=$(/usr/bin/date)
#</Set local VARIABLES>#
/usr/bin/echo "# $date START EXECUTE VM_DELETE.SH#"
/usr/bin/echo "TRY DELETE VM ON PORT: $vm_port"
#<VM NAME SETUP>#
vm_name_part1=$(/usr/bin/cat /etc/vm_manager.conf |/usr/bin/grep 'base_host'
|/usr/bin/cut -d'=' -f2)
vm_name=$(/usr/bin/echo "$vm_name_part1""-""$port_to_delete")
#</VM NAME SETUP>#
#<SHUTDOWN AND DELETE VM>#
/usr/bin/virsh destroy $vm_name
/usr/bin/virsh undefine $vm_name
/usr/bin/rm -f /var/lib/libvirt/images_write/$vm_name.qcow2
/usr/bin/sed -i "/$port_to_delete/d" $SRV_TMP_DIR/recycle.list
#</SHUTDOWN AND DELETE VM>#
/usr/bin/echo "VM ON PORT $vm_port HAS BEEN DELETE AND REMOVE"
"FROM RECYCLE.LIST. EXIT FROM VM_DELETE.SH"
/usr/bin/echo "# $date STOP EXECUTE VM_DELETE.SH#"
exit
Odstránenie virtuálneho stroja je pomerne triviálna operácia, skript vm_delete.sh určuje názov virtuálneho stroja, ktorý vlastní port odovzdaný ako spúšťací parameter. Virtuálny počítač je nútený zastaviť, virtuálny počítač je odstránený z hypervízora a virtuálny pevný disk tohto virtuálneho počítača je odstránený. Port "spice_console" je odstránený z recycle.list. Vykonávanie vm_delete.sh sa končí, vykonávanie vm_manager.sh sa obnoví
Skript vm_manager.sh po dokončení operácií na vyčistenie nepotrebných virtuálnych strojov zo zoznamu waste.list začne cyklus vytvárania virtuálnych strojov v oblasti.
Proces začína identifikáciou portov „spice_console“ dostupných na umiestnenie. Aby ste to dosiahli, na základe parametra konfiguračného súboru „srv_start_port_pool“, ktorý nastavuje počiatočný port pre oblasť „spice_console“ virtuálnych strojov, a parametra „srv_pool_size“, ktorý určuje maximálny počet virtuálnych strojov, sú všetky možné možnosti portu postupne vyhľadávané. Pre každý konkrétny port sa hľadá v clear.list, waste.list, conn_wait.list, recycle.list. Ak sa v niektorom z týchto súborov nájde port, považuje sa port za zaneprázdnený a preskočí sa. Ak sa port nenájde v zadaných súboroch, pridá sa do súboru recycle.list a začne sa proces vytvárania nového virtuálneho počítača. Na tento účel sa zavolá skript vm_create.sh, ktorému sa ako parameter odovzdá číslo portu „spice_console“, pre ktorý je potrebné vytvoriť VM.
/home/admin/scripts_vdi_new/vm_create.sh
#!/bin/sh
/usr/bin/echo "#" "$date" "START RUNNING VM_CREATE.SH#"
new_vm_port=$1
date=$(/usr/bin/date)
a=0
/usr/bin/echo SRV_TMP_DIR=$SRV_TMP_DIR
#<SET LOCAL VARIABLES FOR SCRIPT>#
base_host=$(/usr/bin/cat /etc/vm_manager.conf |/usr/bin/grep "base_host"
|/usr/bin/cut -d "=" -f2)
/usr/bin/echo "base_host=$base_host"
#</SET LOCAL VARIABLES FOR SCRIPT>#
hdd_image_locate() {
/bin/echo "Run STEP 1 - hdd_image_locate"
hdd_base_image=$(/usr/bin/virsh dumpxml $base_host
|/usr/bin/grep "source file" |/usr/bin/grep "qcow2" |/usr/bin/head -n 1
|/usr/bin/cut -d "'" -f2)
if [ -z "$hdd_base_image" ]
then
/bin/echo "base hdd image not found!"
else
/usr/bin/echo "hdd_base_image found is a $hdd_base_image. Run next step 2"
#< CHECK FOR SNAPSHOT ON BASE HDD >#
if [ 0 -eq `/usr/bin/qemu-img info "$hdd_base_image" | /usr/bin/grep -c "Snapshot"` ]
then
/usr/bin/echo "base image haven't snapshot, run NEXT STEP 3"
else
/usr/bin/echo "base hdd image have a snapshot, can't use this image"
exit
fi
#</ CHECK FOR SNAPSHOT ON BASE HDD >#
#< CHECK FOR HDD IMAGE IS LINK CLONE >#
if [ 0 -eq `/usr/bin/qemu-img info "$hdd_base_image" |/usr/bin/grep -c "backing file"
then
/usr/bin/echo "base image is not a linked clone, NEXT STEP 4"
/usr/bin/echo "Base image check complete!"
else
/usr/bin/echo "base hdd image is a linked clone, can't use this image"
exit
fi
fi
#</ CHECK FOR HDD IMAGE IS LINK CLONE >#
cloning
}
cloning() {
# <Step_1 turn the base VM off >#
/usr/bin/virsh shutdown $base_host > /dev/null 2>&1
# </Step_1 turn the base VM off >#
#<Create_vm_config>#
/usr/bin/echo "Free port for Spice VM is $new_vm_port"
#<Setup_name_for_new_VM>#
new_vm_name=$(/bin/echo $base_host"-"$new_vm_port)
#</Setup_name_for_new_VM>#
#<Make_base_config_as_clone_base_VM>#
/usr/bin/virsh dumpxml $base_host > $SRV_TMP_DIR/$new_vm_name.xml
#<Make_base_config_as_clone_base_VM>#
##<Setup_New_VM_Name_in_config>##
/usr/bin/sed -i "s%<name>$base_host</name>%<name>$new_vm_name</name>%g" $SRV_TMP_DIR/$new_vm_name.xml
#</Setup_New_VM_Name_in_config>#
#<UUID Changing>#
old_uuid=$(/usr/bin/cat $SRV_TMP_DIR/$new_vm_name.xml |/usr/bin/grep "<uuid>")
/usr/bin/echo old UUID $old_uuid
new_uuid_part1=$(/usr/bin/echo "$old_uuid" |/usr/bin/cut -d "-" -f 1,2)
new_uuid_part2=$(/usr/bin/echo "$old_uuid" |/usr/bin/cut -d "-" -f 4,5)
new_uuid=$(/bin/echo $new_uuid_part1"-"$new_vm_port"-"$new_uuid_part2)
/usr/bin/echo $new_uuid
/usr/bin/sed -i "s%$old_uuid%$new_uuid%g" $SRV_TMP_DIR/$new_vm_name.xml
#</UUID Changing>#
#<Spice port replace>#
old_spice_port=$(/usr/bin/cat $SRV_TMP_DIR/$new_vm_name.xml
|/usr/bin/grep "graphics type='spice' port=")
/bin/echo old spice port $old_spice_port
new_spice_port=$(/usr/bin/echo "<graphics type='spice' port='$new_vm_port' autoport='no' listen='127.0.0.1'>")
/bin/echo $new_spice_port
/usr/bin/sed -i "s%$old_spice_port%$new_spice_port%g" $SRV_TMP_DIR/$new_vm_name.xml
#</Spice port replace>#
#<MAC_ADDR_GENERATE>#
mac_new=$(/usr/bin/hexdump -n6 -e '/1 ":%02X"' /dev/random|/usr/bin/sed s/^://g)
/usr/bin/echo New Mac is $mac_new
#</MAC_ADDR_GENERATE>#
#<GET OLD MAC AND REPLACE>#
mac_old=$(/usr/bin/cat $SRV_TMP_DIR/$new_vm_name.xml |/usr/bin/grep "mac address=")
/usr/bin/echo old mac is $mac_old
/usr/bin/sed -i "s%$mac_old%$mac_new%g" $SRV_TMP_DIR/$new_vm_name.xml
#<GET OLD MAC AND REPLACE>#
#<new_disk_create>#
/usr/bin/qemu-img create -f qcow2 -b $hdd_base_image /var/lib/libvirt/images_write/$new_vm_name.qcow2
#</new_disk_create>#
#<attach_new_disk_in_confiig>#
/usr/bin/echo hdd base image is $hdd_base_image
/usr/bin/sed -i "s%<source file='$hdd_base_image'/>%<source file='/var/lib/libvirt/images_write/$new_vm_name.qcow2'/>%g" $SRV_TMP_DIR/$new_vm_name.xml
#</attach_new_disk_in_confiig>#
starting_vm
#</Create_vm config>#
}
starting_vm() {
/usr/bin/virsh define $SRV_TMP_DIR/$new_vm_name.xml
/usr/bin/virsh start $new_vm_name
while [ $a -ne 1 ]
do
if /usr/bin/virsh list --all |/usr/bin/grep "$new_vm_name" |/usr/bin/grep "running" > /dev/null 2>&1
then
a=1
/usr/bin/sed -i "/$new_vm_port/d" $SRV_TMP_DIR/recycle.list
/usr/bin/echo $new_vm_port >> $SRV_TMP_DIR/clear.list
/usr/bin/echo "#" "$date" "VM $new_vm_name IS STARTED #"
else
/usr/bin/echo "#VM $new_vm_name is not ready#"
a=0
/usr/bin/sleep 2s
fi
done
/usr/bin/echo "#$date EXIT FROM VM_CREATE.SH#"
exit
}
hdd_image_locate
Proces vytvárania nového virtuálneho počítača
Skript vm_create.sh načíta hodnotu premennej „base_host“ z konfiguračného súboru, ktorá určí vzorový virtuálny stroj, na základe ktorého sa vytvorí klon. Stiahne xml konfiguráciu VM z databázy hypervízora, vykoná sériu kontrol qcow na obraze disku VM a po úspešnom dokončení vytvorí xml konfiguračný súbor pre nový VM a obraz disku „prepojeného klonu“ nového VM. Potom sa konfigurácia xml nového virtuálneho počítača načíta do databázy hypervízora a virtuálny počítač sa spustí. Port "spice_console" sa presunie z recycle.list do clear.list. Vykonávanie vm_create.sh sa končí a vykonávanie vm_manager.sh končí.
Keď sa nabudúce pripojíte, všetko začne od začiatku.
V prípade núdze súprava obsahuje skript vm_clear.sh, ktorý násilne prebehne cez všetky virtuálne počítače z fondu a odstráni ich, čím vynuluje hodnoty zoznamu. Jeho volanie počas bootovacej fázy vám umožní spustiť (pod)VDI s čistým štítom.
/home/admin/scripts_vdi_new/vm_clear.sh
#!/usr/bin/sh
#set VARIABLES#
SRV_SCRIPTS_DIR=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "srv_scripts_dir" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo "SRV_SCRIPTS_DIR=$SRV_SCRIPTS_DIR"
export SRV_SCRIPTS_DIR=$SRV_SCRIPTS_DIR
SRV_TMP_DIR=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "srv_tmp_dir" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo "SRV_TMP_DIR=$SRV_TMP_DIR"
export SRV_TMP_DIR=$SRV_TMP_DIR
SRV_POOL_SIZE=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "srv_pool_size" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo "SRV_POOL_SIZE=$SRV_POOL_SIZE"
SRV_START_PORT_POOL=$(/usr/bin/cat /etc/vm_manager.conf
|/usr/bin/grep "srv_start_port_pool" |/usr/bin/cut -d "=" -f2)
/usr/bin/echo SRV_START_PORT_POOL=$SRV_START_PORT_POOL
#Set VARIABLES#
/usr/bin/echo "= Cleanup ALL VM="
/usr/bin/mkdir $SRV_TMP_DIR
/usr/sbin/service iptables restart
/usr/bin/cat /dev/null > $SRV_TMP_DIR/clear.list
/usr/bin/cat /dev/null > $SRV_TMP_DIR/waste.list
/usr/bin/cat /dev/null > $SRV_TMP_DIR/recycle.list
/usr/bin/cat /dev/null > $SRV_TMP_DIR/conn_wait.list
port_to_delete=$(($SRV_START_PORT_POOL+$SRV_POOL_SIZE))
while [ "$port_to_delete" -gt "$SRV_START_PORT_POOL" ]
do
$SRV_SCRIPTS_DIR/vm_delete.sh $port_to_delete
port_to_delete=$(($port_to_delete-1))
done
/usr/bin/echo "= EXIT FROM VM_CLEAR.SH="
Týmto by som rád ukončil prvú časť môjho príbehu. Vyššie uvedené by malo správcom systému stačiť na vyskúšanie underVDI v akcii. Ak bude táto téma pre komunitu zaujímavá, v druhej časti budem hovoriť o úprave livecd Fedory a jej premene na kiosk.
Zdroj: hab.com
