Кому предназначена данная статья
Данная статья может быть интересна системным администраторам, перед которыми вставала задача создать сервис «одноразовых» рабочих мест.
Proloog
В отдел ИТ сопровождения молодой динамично развивающейся компании с небольшой региональной сетью, обратились с просьбой организовать «станции самообслуживания» для использования их внешними клиентами. Данные станции предполагалось использовать для регистрации на внешних порталах компании, загрузки данных с внешних устройств, работы с государственными порталами.
Важным аспектом являлся тот факт, что большая часть программного обеспечения «заточена» под MS Windows (например, «Декларация»), а несмотря на движение в сторону открытых форматов, MS Office остается доминирующим стандартом при обмене электронными документами. Таким образом, отказаться от MS Windows при решении данной задачи мы не могли.
Основной проблемой виделось возможность накопления различных данных пользовательских сеансов, которые могли бы привести к их утечке третьим лицам. . Kuid erinevalt kvasi-riigiasutusest (riigi autonoomne asutus) MFЦ, saavad hindamatud organisatsioonid selle eest palju rangemaid karistusi. Järgmine kriitilisema probleemina tõstatus nõue töötada väliste andmehoidlatega, milles kahtlemata on hulgaliselt pahavara. Interneti kaudu pahavara sisseviimise tõenäosus peeti vähem tõenäoliseks, kuna interneti juurdepääs on piiratult lubatud valge nimekiri aadressidest. Nõuete väljatöötamisele kaasati teiste osakondade töötajad, kes esitasid oma nõuded ja soovid, ning lõplikud nõuded nägid välja järgmiselt:
IB nõuded
- Pärast kasutamist peavad kõik kasutaja andmed (sealhulgas ajutised failid ja registervõtmed) olema kustutatud.
- Kõik kasutaja poolt käivitunud protsessid peavad töö lõppedes lõpetama.
- Internetis juurdepääs valge nimekiri aadressidest.
- Piirangud kolmanda osapoole koodi käivitamise võimalusele.
- Kui sessioon jääb seisma kauem kui 5 minutit, peab sessioon automaatselt lõppema ja jaam peab puhastuse tegema.
Kliendi nõuded
- Filiaali klienditeenindaja jaotus – maksimaalselt 4.
- Minimaalne ooteaeg süsteemi valmimiseni, alates hetkest, kui 'istud toolile', kuni klientide tarkvara kasutamise alustamiseni.
- Võimalus ühendada perifeerseadmeid (skannerid, USB-mälud) otse 'isehooldusteenuse jaama' paigaldamiskohtadest.
- Kliendi soovid
- Reklaammaterjalide (piltide) demonstreerimine komplekside seiskamise ajal.
Loomehädad
Pärast pikka mängimist Windowsi livecd-idega oleme jõudnud üksmeelsele järeldusele, et saadud lahendus ei rahulda vähemalt 3 kriitilist punkti. Need kas laadivad pikalt, ei ole tõeliselt live, või nende kohandamine oli seotud erakordsete probleemidega. Võib-olla otsisime halvasti ja te oskate soovitada mõnda tööriistade komplekti, oleksin tänulik.
Jätkusoone vaatamise asemel suundusime VDI suunas, kuid enamik lahendusi kas on liiga kallid või vajavad suurt tähelepanu. Soovisime lihtsat tööriista, millel on minimaalselt „maagiat”, ja enamiku probleemide lahendamine oleks võimalik lihtsalt teenuse taaskäivitamisega. Õnneks oli meil olemas serveritehnika, madalama klassi seadmed filiaalides, mille saime kasutada tehnoloogilise aluse loomiseks, mis oli saadud vananenud teenusest.
Mis lõpuks välja tuli? Kuidas lõpuks läks, seda ma teile rääkida ei saa, sest NDA, kuid otsingute käigus töötasime välja huvitava skeemi, mis näitas laborikatsetes head tulemust, kuigi seeriatootmisse see ei läinud.
Mõned tähelepanekud: autor ei väida, et pakutud lahendus lahendab täielikult kõik esitatud ülesanded ja teeb seda vabatahtlikult ning lauldes. Autor nõustub eelnevalt väitega, et Sein Englishe sprache is zehr schlecht. Kuna lahendus enam ei arene, ei tasu loota bugide parandamisele või funktsionaalsuse muutmisele, kõik on teie kätes. Autor eeldab, et teil on vähemalt vähegi teadmisi KVM-ist ja olete lugenud ülevaateartiklit Spice protokolli kohta ning veidi töötanud Centos või mõne muu GNU Linuxi distributsiooniga.
Selles artiklis sooviksin analüüsida saavutatud lahenduse põhialuseid, nimelt kliendi ja serveri vahekorra ning virtuaalmasinate elu tsükli protsesside olemust seoses käsitletava lahendusega. Kui artikkel osutub publikule huvitavaks, kirjeldan live-piltide rakendamise üksikasju peenete klientide loomiseks Fedora põhjal ja räägin virtuaalmasinate seadmise detailidest. KVM server tõhususe ja turvalisuse optimeerimiseks.
Kui võtta värviline paber,
Värvid, pintslid ja liim,
Ja veel veidi osavust…
Saab teha sada rubla!
Katse seadmise skeem ja kirjeldus

Kogu varustus asub filiaali võrgus, väljapoole suundub ainult internetiühendus. Proxy-server on ajalooliselt juba olemas olnud, midagi erakordset ta endast ei esinda. Just sellel serveril toimub muu hulgas ka virtuaalmasinate (edasi teksis VMs) liikluse filtreerimine. Miski ei takista selle teenuse tootmist KVM-serveris, ainsana tuleb jälgida, kuidas see mõju avaldab diskialusele koormusele.
Client Station – meie teenuse „eneseabi“ ja „front-end“. Need on Lenovo IdeaCentre nettopsid. Miks on see seade hea? Peaaegu kõiges, eriti rõõmustab suur USB-portide arv ja Kaardilugeja esipaneelil. Meie süsteemis on kaardilugejas SD kaart, millel on lubatud kirjutamise kaitse ja millele on salvestatud kohandatud live pilt Fedora 28. Muidugi on nettopsi külge ühendatud ka monitor, klaviatuur ja hiir.
Switch – täiesti tavaline teise taseme riistvaraswitch, mis asub serveritoas ja vilgub valgustega. Ei ole ühendatud ükskõik milliste võrkudega peale „eneseabi“ jaamade.
KVM_Server – põhijoonis, mille testimisel Core 2 Quad Q9650 ja 8 GB RAM suudab tõhusalt töödelda kolm Windows 10 virtuaalmasinat. Kõvakettasüsteem – adaptec 3405 kahel kettal Raid 1 + SSD. Välikatsetel Xeon 1220 tõsisem LSI 9260 + SSD suudab hõlpsasti hallata 5-6 VM-i. Serverid saime me varisemise tagajärjel teenusest, kapitalikulud oleksid olnud minimaalsed. Sellel serveril (serveritel) on välja töötatud KVM virtualiseerimissüsteem koos virtuaalmasinate puulega pool_Vm.
VM – virtuaalmasin, meie teenuse taust. Siin toimub kasutaja töö.
Enp5s0 – võrgu liides, mis suhestub enese teenindamise „jaamade“ võrguga, kus resideeruvad dhcpd, ntpd, httpd ja xinetd kuulab „signaali“ porti.
Lo0 – pseudo-liides ringpöörde. Standardne.
Spice_console – Väga huvitav asi, fakt on selles, et erinevalt klassikalisest RDP-st, kui käivitatakse KVM+Spice protokolli kombinatsioon, tekib täiendav element – virtuaalmasina konsoolipord. Ühendudes sellele TCP-pordile, saame me virtuaalmasina konsooli, ilma et oleks vaja ühendada virtuaalmasinaga läbi selle võrgu liidese. Kõik interaktsioonid virtuaalmasinaga signaalide edastamise osas võtab server enda peale. lähim sarnane funktsioon on IPKVM. See tähendab, et sellel pordil edastatakse virtuaalmasina monitori pilt, sellele saadetakse ka hiirekursori liikumise andmed ja (mis kõige tähtsam) Spice protokolli kaudu on võimalik sujuvalt suunata USB seadmeid virtuaalmasinasse, justkui see seade oleks ühendatud ise virtuaalmasinaga. Kontrollitud flash-mälupulkade, skannerite ja veebikaameratega.
Vnet0, virbr0 ja virtuaalsed VM-i võrkaartid loovad virtuaalmasinate võrgu.
Kuidas SEE töötab
Kliendi jaama poolt
Kliendi tööjaam käivitub graafilises režiimis modifitseeritud Fedora 28 live-pildilt, saab DHCP kaudu IP-aadressi aadressivahemikust 169.254.24.0/24. Käivitamise protsessis luuakse tulemüüri reeglid, mis võimaldavad ühendusi serveri «signal» ja «spice» portidele. Pärast laadimist ootab tööjaam kasutaja «Client» autoriseerimist. Pärast kasutaja autoriseerimist alustatakse töölaua halduri «openbox» käivitamist ja autoriseeritud kasutaja nimel käivitatakse autostardi skript autostart. Muuhulgas käivitab autostardi skript skripti 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
Muutujate kirjeldus failis client.conf
server_ip — KVM_Serveri aadress
vdi_signal_port — KVM_Serveri port, kus asub xinetd
vdi_spice_port — KVM_Serveri võrgupord, mille kaudu toimub remote-viewer kliendi ühendumise päringu suunamine spetsiaalse VM spice porti (täiendavad üksikasjad allpool)
animation_folder — kaust, kust võetakse pilte bullshit animatsiooni näitamiseks
background_folder — kaust, kust saadetakse pilte esitluste ekraanil ooterežiimis. Lisateave animatsiooni kohta artikli järgmises osas.
Skript remote.sh võtab seaded failist konfiguratsioonist /etc/client.conf ja loob nc abil ühenduse KVM serveri „vdi_signal_port” sadamasse, saades serverilt andmevoo, milles oodatakse rea „RULE ADDED, CONNECT NOW”. Kui otsitud rida saabub, käivitub kioskirežiimis remote-viewer, luues ühenduse serveri „vdi_spice_port” sadamaga. Skripti täitmine peatatakse kuni remote-viewer'i täitmise lõpetamiseni.
Remote-viewer, ühendudes „vdi_spice_port” sadamasse, juhtimisredirekteerimise kaudu serveri pool, jõuab lo0 liidese „spice_console” sadamasse, st virtuaalmasina konsooli ja toimub kasutaja töö. Ühenduse ootamise ajal näidatakse kasutajale bullshit animatsiooni, mis on slaidiasjade keeris jpeg failidest, pildi kaustateed määrab konfiguratsioonifaili muutuja animation_folder.
Kui ühendus 'spice_console' portiga kaob, mis näitab virtuaalmasina väljalülitamist/taaskäivitamist (st kasutaja seansi tegelikku lõppu), lõpetatakse kõik autoriseeritud kasutaja nimel jooksnud protsessid, mis viib lightdm taaskäivitamiseni ja tagastab autoriseerimisekraanile.
KVM Serveri küljelt
‘signal’ port enp5s0 võrgukaardil ootab xinetd jaoks ühendust. Pärast ühendust ‘signal’ port xinetd käivitab skripti vm_manager.sh, edastamata sealjuures mingeid sisendparameetreid, ning suunab skripti väljundi nc seanssi Client Station.
/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
base_host=win10_2
input_iface=enp5s0
vdi_spice_port=5906
count_conn_tryes=10
vm_manager.conf konfiguratsioonifaili muutujate kirjeldus
srv_scripts_dir — kaust, kus asuvad skriptid vm_manager.sh, vm_connect.sh, vm_delete.sh, vm_create.sh, vm_clear.sh
srv_pool_size — Vm-i puhuti suurus
srv_start_port_pool — algusport, millest alates hakkavad asuma virtuaalmasinate spice konsoolide portid
srv_tmp_dir — kaust ajutiste failide jaoks
base_host — põhivm (kuldne mudel), mille alusel luuakse Vm klone basseiniks
input_iface — serveri võrgu liides, mis suunab Klientjaamade poole
vdi_spice_port — serveri võrgupord, mille kaudu suunatakse remote-viewer kliendi ühendusipäring spice pordi suunatud Vm-ile
count_conn_tryes — ooteaeg, mille möödudes loetakse, et ühendust Vm-iga ei toimunud (tööpõhimõtte kohta vaata vm_connect.sh)
Skript vm_manager.sh loeb konfiguratsioonifaili failist vm_manager.conf, hindab virtuaalmasinate olekut basseinist mitmete parameetrite alusel, nimelt: kui palju VM-e on juurutatud, kas on vabade puhaste VM-e. Selleks loeb ta faili clear.list, milles on „freshly created” (vt allpool VM-i loomise tsükkel) virtuaalmasinate „spice_console” portide numbrid, ning kontrollib nendele loodud ühenduse olemasolu. Kui leitakse port, millel on aktiivne võrguühendus (mida ei tohiks ilmtingimata juhtuda), antakse hoiatusteade ja port kantakse waste.list. Kui leiate esimese porta failist clear.list, millega hetkel pole ühendust, kutsub vm_manager.sh välja skripti vm_connect.sh ja edastab sellele selle porta numbri parameetrina.
/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 lisab tulemüüri reeglid, mis suunavad serveri enp5s0 liidese "vdi_spice_port" porti "spice console port" VM-ile, mis asub serveri lo0 liidesel ja edastatakse käivitamisparameetrina. Port kantakse üle conn_wait.list'i, VM loetakse ühenduse ootamiseks. Client Stationi seansis edastatakse serveri "signal" pordile string "RULE ADDED, CONNECT NOW", mida ootab käivitatud skript remote.sh. Algab ootetsükkel ühenduse loomisega, mille katsete arv määratakse konfiguratsioonifaili muutujaga "count_conn_tryes". Iga sekundi järel edastatakse nc seansis string "RULE ADDED, CONNECT NOW" ja kontrollitakse, kas "spice_console" porti on ühendus loodud.
Kui ettenähtud katsete arv on möödunud ja ühendust ei ole loodud, kantakse "spice_console" port tagasi clear.list'i. Skripti vm_connect.sh täitmine lõpetatakse ja jätkatakse vm_manager.sh täitmist, mis käivitab puhastuskupli.
Kui kliendi jaama ühendust loetakse lo0 liidese "spice_console" pordiga, eemaldatakse tulemüürireeglid, mis loovad ümbersuunamise serveri "spice" pordi ja "spice_console" pordi vahel, ning ühenduse säilitamine toimub tulemüüri oleku määramise mehhanismi kaudu. Kui ühendus katke, ei saa uuesti "spice_console" pordiga ühendust luua. "Spice_console" port kantakse waste.list'i, VM peab olema "räpane" ja ta ei saa naasta "puhtasse" virtuaalmasinate basseinile ilma puhastusprotsessita. vm_connect.sh täitmine lõpeb, jätkub vm_manager.sh täitmine, mis käivitab puhastusringi.
Puhastusprotsess algab failiga waste.list, kuhu kantakse virtuaalmasinate "spice_console" portide numbrid, millega on loodud ühendus. Kontrollitakse, kas iga "spice_console" porta suhtes on aktiivne ühendus. Kui ühendust ei ole, loetakse, et virtuaalmasinat ei kasutata enam, ning port kantakse recycle.list'i, ja käivitatakse virtuaalmasina (vt allpool) kustamise protsess, millele see port kuulus. Kui tõrget ei avastata ning port on aktiivne, peetakse virtuaalmasinat kasutatuks ning mingeid toiminguid tema suhtes ei tehta. Kui port ei kuule, loetakse, et VM on välja lülitatud ja enam ei vajata. Port kantakse recycle.list'i ja käivitatakse virtuaalmasina kustamise protsess. Selleks käivitatakse skript vm_delete.sh, millele antakse parameetrina virtuaalmasina "spice_console" porti number, mille tuleb kustutada.
/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
Virtuaalse masina eemaldamine on piisavalt lihtne toiming, skript vm_delete.sh tuvastab virtuaalse masina nime, mille port on antud käivitamisparameetrina. Teostatakse VM-a sundseisak, eemaldatakse VM hüperviisorist ja kustutatakse selle virtuaalne kõvaketas. Port "spice_console" eemaldatakse recycle.listist. Skripti vm_delete.sh täitmine lõppeb ning jätkub vm_manager.sh täitmine.
Skripti vm_manager.sh lõppedes, pärast tarbetute virtuaalsete masinate eemaldamise toimingute lõpuleviimist waste.listist, alustab see virtuaalsete masinate loomise tsüklit basseinist.
Protsess algab selle määratlemisega, millised "spice_console" sadamad on saadaval. Selleks, lähtudes konfiguratsioonifaili parameetrist "srv_start_port_pool", mis määrab algsadama virtuaalmasinate "spice_console" basseinis, ja parameetrist "srv_pool_size", mis määrab maksimaalse virtuaalmasinate arvu, toimub kõikide sadamate järjestikune kontrollimine. Iga määratletud sadama puhul otsitakse seda failidest clear.list, waste.list, conn_wait.list, recycle.list. Kui sadam leitakse mõnes neist failidest, loetakse sadam hõivatuks ja jäetakse vahele. Kui sadamat nimetatud failides ei leita, lisatakse see faili recycle.list ja algab uue virtuaalmasina loomise protsess. Selleks kutsutakse välja skript vm_create.sh, millele edastatakse parameetri "spice_console" sadama number, mille jaoks tuleb VM luua.
/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
Uue virtuaalmasina loomise protsess
Skript vm_create.sh loeb konfiguratsioonifailist muutuja «base_host» väärtuse, mis määratleb virtuaalmasina malli, mille põhjal luuakse kloon. See tõmbab välja VM-i XML-konfiguratsiooni hypervisorist, teeb mitmeid kontrolli QCOW ketta pildi kohta ja, kui need on edukad, loob uue VM-i XML-konfiguratsioonifaili ja «linked clone» ketta pildi uuele VM-ile. Pärast seda laaditakse uue VM-i XML-konfiguratsioon hypervisorisse ja VM käivitatakse. Port «spice_console» kantakse recycle.list failist clear.list faili. vm_create.sh täitmine lõppeb ja vm_manager.sh täitmine lõpetatakse.
Järgmise ühenduse korral algab kõik algusest.
Hädaolukordade jaoks on komplektis skript vm_clear.sh, mis sundkorras läbib kõik VM-id grupis ja kustutab need, nullides listide väärtused. Selle kutsumine laadimise etapis võimaldab (ühe)VDI-d alustada puhtalt lehelt.
/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="
Sellega lõpetan oma jutu esimese osa. Esitatud teave peaks olema piisav, et süsteemiadministraatorid saaksid proovida (under)VDI-t praktikas. Kui kogukond leiab selle teema huvitavana, tutvustan teises osas Fedora livecd modifikatsiooni ja selle muutmist kiosksüsteemiks.
Allikas: habr.com
