KVM (ühekas)vDI ühekordsete virtuaalmasinate kasutamine bashiga

Kelle see artikkel on mõeldud

See artikkel võib huvi pakkuda süsteemiadministraatoritele, kelle ees seisis ülesanne luua "ühekordsed" tööjaamad.

Proloog

IT-osakonda noorest, dünaamiliselt arenevast ettevõttest, millest on väike regionaalne võrgustik, pöörduti palvega luua "iseenesest teenindamise jaamad" nende välishoone klientide kasutamiseks. Nendes jaamades on ette nähtud kasutada registreerimist ettevõtte välistel portaalidel, andmete üleslaadimist välistelt seadmetelt ja töötamist riiklike portaalidega.

Oluline aspekt oli see, et enamus tarkvarast on "suitsetatud" MS Windowsile (näiteks "Deklaratsioon"), ja hoolimata liikumisest avatud formaatide suunas, jääb MS Office domineerivaks standardiks elektrooniliste dokumentide vahetamisel. Seega ei saanud me selle ülesande lahendamisel MS Windowsist loobuda.

Peamine probleem nähti kasutajaseansside erinevate andmete kogunemise võimaluses, mis võiks viia nende lekkimiseni kolmandatele isikutele. See olukord on juba varjanud MFC-d. Kuid erinevalt kvasi-riigilisest (riiklikust autonoomsest asutusest) MFC-st, karistatakse mittetulunduslikke organisatsioone sarnaste puuduste eest palju rangemalt. Järgmise kriitilise probleemina oli nõudmine, et töötada koos välistelt andmekandjatelt, millel on kindlasti palju kurjategijate pahavara. Pahavara oht interneti kaudu toimetatakse, peeti vähem tõenäoliseks, kuna interneti juurdepääs on piiratud lubatud aadresside valiku kaudu. Nõuete väljatöötamisse kaasati teiste osakondade töötajad, kes esitasid oma nõudmisi ja soove, lõpp-nõuded nägid välja järgmised:

IB nõuded

  • Pärast kasutamist peavad kõik kasutajaandmed (sealhulgas ajutised failid ja registrivõtmed) olema kustutatud.
  • Kõik kasutaja poolt käivitatud protsessid peavad oma töö lõppedes lõpetama.
  • Internetti pääs lubatud aadresside nimekirja kaudu.
  • Piirangud kolmanda-poolse koodi käivitamiseks.
  • Kui seanss seisab rohkem kui 5 minutit, peab seanss automaatselt lõpetama ja jaam peab teostama puhastuse.

Tellija nõuded

  • Klientide jaamade arv harukontoris – mitte rohkem kui 4.
  • Minimaalne ooteaeg süsteemi valmidusest, hetkest, mil sa istud toolile, kuni klienditarkvaraga töötamise algus.
  • Perifeersete seadmete (skännerid, mälupulgad) ühendamise võimalus otse «ise teenindamise jaama» paigalduskohtade kaudu.
  • Kliendi soovingud
  • Reklaammaterjalide (piltide) demonstreerimine, kui kompleks on väljaspool kasutust.

Loomevaev

Pärast soovide rahuldamist Windowsi livecd-dega jõudsime ühisele järeldusele, et saadud lahendus ei rahulda vähemalt kolme kriitilist punkti. Nad kas laadivad pika aja või ei ole päris live, või nende kohandamine on seotud suurte kannatustega. Võib-olla ei otsinud me piisavalt ja saate soovitada mõnda tööriistade komplekti, oleksin tänulik.

Edasi hakkasime vaatama VDI suunas, kuid enamus lahendusi on selle ülesande jaoks kas liiga kallid või nõuavad suurt tähelepanu. Soovisime lihtsat tööriista, millel oleks minimaalne maagia, ja enamus probleeme saaks lahendada lihtsa taaskäivitamise / teenuse uuesti käivitamisega. Õnneks oli meil serverivarustus, madalama klassi aparaadid filiaalides, mis tulid välja kasutuselt eemaldatud teenusest, mida saime kasutada tehnoloogilise aluse jaoks.

Kuidas olukord lõppes? Kuidas lõppes? Kahjuks ei saa ma teile rääkida, sest NDA, kuid otsingute käigus töötasime välja huvitava skeemi, mis osutus laboratoorsetes katsetustes heaks, kuigi ei läinud seeriatootmisse.

Mõned disklaimerid: autor ei pretendeeri sellele, et pakutud lahendus lahendab täielikult kõik esitatud ülesanded ja teeb seda vabatahtlikult ja lauldes. Autor on eelnevalt nõus väitega, et Sein Englishe sprache is zehr schlecht. Kuna lahendus enam ei arene, ei tasu kukkuda bugide parandamise ega funktsionaalsuse muutmise lootustes, kõik on teie kätes. Autor arvab, et olete vähemalt veidi tuttav KVM-iga ja olete lugenud ülevaateartiklit Spice protokolli kohta ning töötanud veidi Centos või muu GNU Linuxi distributsiooniga.

Selles artiklis sooviksin käsitleda saadud lahenduse selgroogu, nimelt kliendi ja serveri vahelist suhtlemist ning virtuaalmasinate elutsükli protsesside olemust antud lahenduses. Kui artikkel osutub publikule huvitavaks, kirjeldan live-piltide rakendamise üksikasju, et luua õhukesed kliendid Fedora põhjal, ning räägin virtuaalmasinate seadistamise detailidest ja KVM serverid soorituse ja turvalisuse optimeerimiseks.

Kui võtta värvilist paberit,
Värvid, pintslid ja liim,
Ja veel natuke oskusi…
Saame 100 eurot!

Testseina skeem ja kirjeldus

KVM (ühekas)vDI ühekordsete virtuaalmasinate kasutamine bashiga

Kõik seadmed asuvad filiaali sisevõrgus, ainult interneti kanal väljub. Proxiserver oli ajalooliselt olemas, midagi erakordset ta endas ei kanna. Kuid just seal, muu hulgas, toimub virtuaalmasinate (edaspidi lühendatult VMs) liikluse filtreerimine. Miski ei takista selle teenuse paigutamist KVM serverisse, ainus asi, millele tuleb tähelepanu pöörata, on see, kuidas koormus diskisüsteemile muutub.

Kliendi jaama – tegelikult «ise teenindavad jaamad», meie teenuse «frontend». Need on Lenovo IdeaCentre nettopid. Miks on see seade hea? Peaaegu kõigi omaduste tõttu, eriti rõõmustab suur USB-portide arv ja eesmine kaardilugeja. Meie skeemis on kaardilugejasse sisestatud SD kaart, millel on aktiivne kirjutamise kaitse ja millele on salvestatud modifitseeritud live-pilt Fedora 28-st. Loomulikult on nettopiga ühendatud monitor, klaviatuur ja hiir.

Lüliti – tavaline teise taseme riistvaralüliti, seisab serveriruumis ja vilgub tulesid. Ei ole ühendatud ühegi võrgu, välja arvatud «ise teenindavate jaamade» võrk.

KVM_Server – skeemi süda, labori katsedes Core 2 Quad Q9650 koos 8 GB mäluga tõmbas usaldusväärselt 3 virtuaalmasinat Windows 10-ga. Diskisüsteem - adaptec 3405, 2 ketast Raid 1 + SSD. Rikkalikes testides Xeon 1220 tõsisem LSI 9260 + SSD vedasid kergesti 5-6 VMs. Serverid saime eelmise teenuse jääkidest, kapitalikulusid pole palju. Selle(serveri) peale on üles seatud KVM virtualiseerimissüsteem koos virtuaalmasinate puuli pool_Vm.

Vm – virtuaalmasin, meie teenuse tagumisel küljel. Seal toimub kasutaja töö.

Enp5s0 – võrguliides, mis suunab iseemakeerimise jaama võrku, kus elavad dhcpd, ntpd, httpd ja xinetd kuulab „signal” sadamat.

Lo0 – pöördfaili pseudo-liides. Standardne.

Spice_console – väga huvitav asi, sest erinevalt klassikalisest RDP-st, KVM + Spice protokolli kasutamisel, tekib täiendav entiteet – virtuaalmasina konsooli port. Põhimõtteliselt, ühendades selle TCP pordi kaudu, saame VM konsooli, ilma et oleks vaja ühendust võtta VM-iga läbi selle võrguliidese. Kõik suhtlemine VM-iga signaalide edastamise osas toimub serveri kaudu. Kõige lähem analoog funktsiooni poolest on IPKVM. See tähendab, et sellele pordile edastatakse VM-i ekraanipilt, sellele kantakse ka hiire liikumise andmed ja (mis kõige tähtsam) interaktsioon Spice protokolli kaudu võimaldab sujuvalt suunata USB-seadmeid virtuaalmasinasse, justkui see seade oleks otse VM-iga ühendatud. Kontrollitud välkmälu, skannerite, veebikaamerate puhul.

Vnet0, virbr0 ja virtuaalsed VM-i võrgukaardid moodustavad virtuaalsete masinate võrgu.

Kuidas SEE töötab

Klientjaama poolt

Klientjaam käivitub graafilises režiimis muudetud Fedora 28 live-imažilt, saab dhcp kaudu IP-aadressi aadressiruumi 169.254.24.0/24. Käivitumise käigus luuakse tulemüürireeglid, mis võimaldavad ühendusi serveri „signal” ja „spice” sadamatega. Pärast käivitamist ootab jaam kasutaja „Client” autentimist. Pärast kasutaja autentimist käivitub töölaudade haldur „openbox” ja täidetakse autostardi skript autostart autenditud kasutaja nimel. Kõigi muu hulgas 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

client.conf faili muutuja kirjeldus
server_ip — KVM_Serveri aadress
vdi_signal_port — KVM_Serveri sadam, kus xinetd töötab
vdi_spice_port — KVM_Serveri võrgupord, mille kaudu edastatakse remote-viewer kliendi ühendumistaotlused virtuaalmaja spice porti (detailid allpool)
animation_folder — kaust, kust saadakse pildid bullshit animatsiooni näitamiseks
background_folder — kaust, kust saadakse pildid taustapiltide esitamiseks ooterežiimis. Rohkem animatsioonist artikli järgmises osas.

Skripti remote.sh võtab konfiguratsioonifailist /etc/client.conf seaded ja loodi nc abil ühendus KVM serveri "vdi_signal_port" porti, et saada serverist andmevoog, milles oodatakse rida "RULE ADDED, CONNECT NOW". Kui otsitud rida on saadud, käivitatakse kioskirežiimis remote-viewer, luues ühenduse serveri "vdi_spice_port" portiga. Skripti täitmine peatatakse, kuni remote-viewer protsess on lõppenud.

Remote-viewer, ühendudes "vdi_spice_port" portiga, jõuab serveri küljest redirectimise tõttu "spice_console" porti, mis on seotud liidese lo0, s.t. virtuaalmasina konsoolisse ning toimub, otseselt, kasutaja töö. Ühenduse ootamise protsessis kuvatakse kasutajale BS animatsioon, mis on jpeg-failide slaidiesitlus, kus pildi katalooge määrab konfiguratsioonifaili animation_folder muutuja väärtus.

Kui virtuaalmasina "spice_console" port kaob ühendus, mis signaalib virtuaalmasina väljalülitamist/taaskäivitamist (s.t. kasutaja sessiooni tegelikku lõppu), lõpetatakse kõik autoriseeritud kasutaja nimel käivitatud protsessid, mis põhjustab lightdm taaskäivitamise ja tagastamise autentimise ekraanile.

KVM serveri poolt

Enp5s0 võrguadapteri "signal" port ootab xinetd ühendust. Pärast "signal" porti ühendust käivitab xinetd skripti vm_manager.sh, edastamata sellele mingeid sisendparameetreid, ja suunab skripti täitmise tulemuse klientjaama nc sessioonile.

/etc/xinetd.d/test-server

teenus 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 — vm_manager.sh, vm_connect.sh, vm_delete.sh, vm_create.sh, vm_clear.sh skriptide asukoha kaust
srv_pool_size — VM basseini suurus
srv_start_port_pool — algne port, kust alates hakkavad virtuaalmasina spice konsoolide portid paiknema
srv_tmp_dir — kaust ajutiste failide jaoks
base_host — baas VM (kuldpilt), millest tehakse VM koopiaid basseini
input_iface — serveri võrgu liides, mis vaatab Client Stations poole
vdi_spice_port — serveri võrgu port, kust toimub remote-vieweri kliendi ühendusküsimuse suunamine virtuaalmasina spice porti
count_conn_tryes — ooteaeg, pärast mille kulgu arvatakse, et ühendus Vm-iga ei ole toimunud (töö üksikasjade jaoks vaata vm_connect.sh)

Skript vm_manager.sh loeb konfiguratsioonifaili vm_manager.conf, hindab virtuaalmasinate olekut grupis mitme parameetri põhjal, nimelt: kui palju VM-e on kasutusele võetud, kas on vabu puhtaid VM-e. Selleks loeb ta faili clear.list, milles on «spice_console» portide numbrid «värskelt loodud» (vt allpool VM-i loomise tsüklit) virtuaalmasinate kohta ja kontrollib nende ühenduse olemasolu. Kui leitakse port, millel on kehtiv võrguühendus (mida ei peaks kindlasti olema), kuvatakse hoiatusteade ja port kantakse waste.listi. Kui leiate esimest porti failist clear.list, millega praegu ei ole ühendust, kutsub vm_manager.sh esile skripti vm_connect.sh ja edastab sellele määramisena selle porti numbri.

/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üürireeglid, mis loovad „vdi_spice_port” serveri enp5s0 liidese portide suunamise VM-i „spice console” porti, mis asub serveri lo0 liideses ja mis edastatakse käivitamisel parameetrina. Port kantakse conn_wait.listi, VM loetakse ühenduse ootamiseks. Client Station'i seansis edastatakse serveris «signal» porti rida «RULE ADDED, CONNECT NOW», mida oodatakse käivitatud skriptist remote.sh. Algab ühenduse ootamise tsükkel, mille katsete arv on määratud konfiguratsioonifaili muutujaga «count_conn_tryes». Iga sekundi järel antakse nc seansis välja rida «RULE ADDED, CONNECT NOW» ja kontrollitakse, kas „spice_console” port on kehtiva ühendusega.

Kui määratud katsete arvu jooksul ühendust ei toimunud, kantakse „spice_console” port tagasi clear.listi. vm_connect.sh täitmine lõpeb, jätkatakse vm_manager.sh täitmist, mis käivitab puhastustsükli.

Kui Client Station ühendub lo0 liidese «spice_console» pordiga, eemaldatakse tulemüürireeglid, mis loovad ümbersuunamise «spice» serveri ja «spice_console» pordi vahel, ning edasine ühenduse säilitamine toimub tulemüüri oleku määramise mehhanismi kaudu. Ühenduse katkedes ei õnnestu «spice_console» pordiga uuesti ühendust luua. «spice_console» port kantakse waste.list faili, VM loetakse „räpaseks“ ja ta ei saa naasta „puhtate“ virtuaalmasinate punkti ilma puhastamiseta. vm_connect.sh skripti täitmine lõppeb, jätkab vm_manager.sh täitmine, mis käivitab puhastusprotsessi.

Puhastusprotsess algab waste.list faili vaatamisest, kuhu kantakse virtuaalmasinate «spice_console» portide numbrid, kellega ühendust loodi. Iga loendis oleva «spice_console» pordi puhul määratakse kindlaks, kas aktiivne ühendus on olemas. Kui ühendust pole, arvatakse, et virtuaalmasinat ei kasutata enam ja port kantakse recycle.list, alustatakse virtuaalmasina eemaldamise protsessi (vt allpool), millele see port kuulus. Kui pordil on aktiivne võrguühendus, arvatakse, et virtuaalmasinat kasutatakse ning tema suhtes ei tehta mingeid toiminguid. Kui porti ei kuulata, arvatakse, et VM on välja lülitatud ja enam ei vajata. Port kantakse recycle.list ja käivitatakse virtuaalmasina eemaldamise protsess. Selleks kutsutakse esile vm_delete.sh skript, millele edastatakse VM «spice_console» pordi number, mille soovitakse eemaldada.

/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

Virtuaalmasina eemaldamine on piisavalt triviaalne operatsioon, skript vm_delete.sh määrab ära virtuaalmasina nime, mille port on edastatud käivitusparameetrina. VM sunnitakse peatuma, VM eemaldatakse hüperviisorist ning eemaldatakse selle VM virtuaalne kõvaketas. «spice_console» port kantakse recycle.list failist. vm_delete.sh skripti täitmine lõppeb, jätkub vm_manager.sh täitmine.

Skript vm_manager.sh, lõpetades üleliigsete virtuaalmasinate eemaldamise operatsioonid waste.list failist, alustab virtuaalmasinate loomise tsüklit puuli.

Protsess algab sellega, et määratakse kõik saadaval olevad "spice_console" sadamad. Selleks tehtakse konfiguratsioonifaili parameetri "srv_start_port_pool" põhjal, mis määrab algsadama "spice_console" virtuaalmasinate puule, ja parameetri "srv_pool_size", mis määrab virtuaalmasinate maksimaalse arvu, järjestikune ülekäik kõigist võimalikest sadamavalikutest. Iga kindla sadama jaoks otsitakse selle olemasolu clear.list, waste.list, conn_wait.list, recycle.list failides. Kui sadam tuvastatakse mõnes eespool nimetatud failis, peetakse seda hõivatud ja see jäetakse vahele. Kui sadamat nendest failidest ei leita, kantakse see recycle.list faili ja alustatakse uue virtuaalmasina loomise protsessi. Selleks käivitatakse skript vm_create.sh, millele antakse parameetrina "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äärab virtuaalmasina malli, mille põhjal luuakse kloon. See väljastab virtuaalmasina XML konfiguratsiooni hüperviisori andmebaasist, teostab rea kontrollimisi VM-i qcow ketta kujutise kohta ja eduka lõpetamise järel loob XML konfiguratsioonifaili uue VM-i jaoks ning "linked clone" ketta kujutise uue VM-i jaoks. Pärast seda laaditakse uue VM-i XML konfigureerimine hüperviisori andmebaasi, ja VM käivitatakse. "spice_console" port kantakse recycle.list failist clear.list faili. Skripti vm_create.sh täitmine lõpeb ja vm_manager.sh täitmine lõpetatakse.
Järgmise ühenduse korral algab kõik taas algusest.

Hädajuhtumite jaoks on kaasas skript vm_clear.sh, mis sunniviisiliselt käib läbi kõik VM-d puulus ja kustutab need, lähtestades nimekirjade väärtused. Selle väljakutsumine laadimisfaasis võimaldab (alustada) VDI tööd puhta lehena.

/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 soovin lõpetada oma jutustuse esimese osa. Esitatud teave peaks olema piisav süsteemiadministraatoritele, et proovida VDI-d tegutsemas. Kui kogukond peab selle teema huvitavaks, räägin teises osas Fedora livecd modifitseerimisest ja selle muutmisest kioskiks.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster