Do-it-yourself Bare-Metal Provisioning, atanapi Nyiapkeun otomatis server ti mimiti

Halo, kuring Denis sareng salah sahiji kagiatan kuring nyaéta pamekaran solusi infrastruktur di X5. Dinten abdi hoyong bagikeun sareng anjeun kumaha anjeun tiasa nyebarkeun sistem persiapan server otomatis dumasar kana alat anu sayogi umum. Dina pamanggih kuring, ieu mangrupikeun solusi anu pikaresepeun, sederhana sareng fleksibel.

Do-it-yourself Bare-Metal Provisioning, atanapi Nyiapkeun otomatis server ti mimiti

Ku préparasi kami hartosna: ngahurungkeun server anyar out of the box kana server pinuh ngonpigurasi kalawan OS. Linux atanapi nganggo hypervisor ESXi (panyebaran server Windows henteu dibahas dina tulisan ieu).

istilah:

  • server - server nu kudu ngonpigurasi.
  • server instalasi teh server utama nu nyadiakeun sakabéh prosés persiapan ngaliwatan jaringan.

Naha automation diperlukeun?

Hayu urang nyebutkeun aya tugas: nyiapkeun server massively ti scratch, dina puncak - 30 per poé. Server pabrik sareng modél anu béda, sistem operasi anu béda tiasa dipasang dina éta, sareng tiasa atanapi henteu gaduh hypervisor.

Operasi naon anu kalebet dina prosés pangaturan (tanpa otomatis):

  • nyambungkeun keyboard, mouse, monitor ka server;
  • ngonpigurasikeun mios, razia, IPMI;
  • update firmware komponén;
  • nyebarkeun gambar sistem file (atanapi pasang hypervisor sareng nyalin mesin virtual);

Catetan. Alternatipna, panyebaran OS tiasa dilakukeun ku pamasangan sareng file réspon otomatis. Tapi ieu moal dibahas dina artikel. Sanajan anjeun bakal nempo handap yén nambahkeun pungsi ieu teu hese.

  • ngonpigurasikeun parameter OS (hostname, IP, jsb).

Kalayan pendekatan ieu, setélan anu sami dilakukeun sacara berurutan dina unggal server. Éféktivitas karya sapertos ieu pisan low.

Hakekat automation nyaéta ngaleungitkeun partisipasi manusa tina prosés persiapan server. Sabisa-bisa.

Automation ngurangan downtime antara operasi sarta ngamungkinkeun pikeun nyadiakeun sababaraha server sakaligus. Kamungkinan kasalahan kusabab faktor manusa ogé dikirangan pisan.

Do-it-yourself Bare-Metal Provisioning, atanapi Nyiapkeun otomatis server ti mimiti

Kumaha server otomatis ngonpigurasi?

Hayu urang analisa sadayana tahapan sacara rinci.

Anjeun gaduh server Linux anu anjeun pake salaku server instalasi PXE. Jasa dipasang sareng dikonpigurasikeun: DHCP, TFTP.

Janten, urang boot server (anu kedah dikonpigurasi) via PXE. Hayu urang apal kumaha gawéna:

  • Boot jaringan dipilih dina server.
  • Server ngamuat PXE-ROM tina kartu jaringan sareng ngahubungi server instalasi via DHCP pikeun kéngingkeun alamat jaringan.
  • Pangladén pamasangan DHCP ngaluarkeun alamat, kitu ogé paréntah pikeun diunduh satuluyna via PXE.
  • Server beban bootloader jaringan tina server instalasi via PXE, loading salajengna lumangsung nurutkeun file konfigurasi PXE.
  • Boot lumangsung dumasar kana parameter narima (kernel, initramfs, titik Gunung, gambar squashfs, jsb).

Catetan. Artikel ngajelaskeun booting via PXE via mode BIOS. Ayeuna, produsén aktip ngalaksanakeun bootmode UEFI. Pikeun PXE, bédana bakal aya dina konfigurasi server DHCP sareng ayana bootloader tambahan.

Hayu urang tingali conto konfigurasi server PXE (menu pxelinux).

File pxelinux.cfg/default:

default menu.c32
prompt 0
timeout 100
menu title X5 PXE Boot Menu
LABEL InstallServer Menu
	MENU LABEL InstallServer
	KERNEL menu.c32
	APPEND pxelinux.cfg/installserver
LABEL VMware Menu
	MENU LABEL VMware ESXi Install
	KERNEL menu.c32
	APPEND pxelinux.cfg/vmware
LABEL toolkit // меню по умолчанию
	MENU LABEL Linux Scripting Toolkits
	MENU default
	KERNEL menu.c32
	APPEND pxelinux.cfg/toolkit // переход на следующее меню

File pxelinux.cfg/toolkit:

prompt 0
timeout 100
menu title X5 PXE Boot Menu
label mainmenu
    menu label ^Return to Main Menu
    kernel menu.c32
    append pxelinux.cfg/default
label x5toolkit-auto // по умолчанию — автоматический режим
        menu label x5 toolkit autoinstall
        menu default
        kernel toolkit/tkcustom-kernel
        append initrd=toolkit/tk-initramfs.gz quiet net.ifnames=0 biosdevname=0 nfs_toolkit_ip=192.168.200.1 nfs_toolkit_path=tftpboot/toolkit nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh CMDIS2=”…”
label x5toolkit-shell // для отладки - консоль
        menu label x5 toolkit shell
        kernel toolkit/tkcustom-kernel
        append initrd=toolkit/tkcustom-initramfs.gz quiet net.ifnames=0 biosdevname=0 nfs_toolkit_ip=192.168.200.1 nfs_toolkit_path=tftpboot/toolkit nfs_toolkit_script=scripts/mount.sh script_cmd=/bin/bash CMDIS2=”…”

Kernel sareng initramfs dina tahap ieu mangrupikeun gambar Linux perantara, kalayan bantosan persiapan utama sareng konfigurasi server bakal dilaksanakeun.

Sakumaha anjeun tiasa tingali, bootloader ngalangkungan seueur parameter kana kernel. Sababaraha parameter ieu dianggo ku kernel sorangan. Sareng urang tiasa nganggo sababaraha pikeun tujuan urang sorangan. Ieu bakal dibahas engké, tapi pikeun ayeuna anjeun ngan bisa inget yen sakabeh parameter lulus bakal sadia dina gambar Linux Ubuntu panengah via /proc/cmdline.

Dimana kuring tiasa kéngingkeun, kernel sareng initramfs?
Salaku dasar, anjeun tiasa milih distribusi Linux mana waé. Naon anu urang perhatikeun nalika milih:

  • gambar boot kedah universal (kasadiaan drivers, kamampuhan pikeun masang utiliti tambahan);
  • Paling dipikaresep, anjeun bakal kudu ngaluyukeun initramfs.

Kumaha ieu dilakukeun dina solusi kami pikeun X5? CentOS 7 dipilih salaku dadasar. Hayu urang coba trik handap: nyiapkeun struktur gambar hareup, pak kana arsip tur jieun hiji initramfs, di jerona bakal aya arsip Sistim file urang. Nalika ngamuat gambar, arsip bakal dilegakeun kana partisi tmpfs anu diciptakeun. Ku cara kieu urang bakal meunang gambar linux hirup minimal, acan full-fledged kalawan sagala utiliti diperlukeun, diwangun ku ukur dua file: vmkernel na initramfs.

#создаем директории: 

mkdir -p /tftpboot/toolkit/CustomTK/rootfs /tftpboot/toolkit/CustomTK/initramfs/bin

#подготавливаем структуру:

yum groups -y install "Minimal Install" --installroot=/tftpboot/toolkit/CustomTK/rootfs/
yum -y install nfs-utils mariadb ntpdate mtools syslinux mdadm tbb libgomp efibootmgr dosfstools net-tools pciutils openssl make ipmitool OpenIPMI-modalias rng-tools --installroot=/tftpboot/toolkit/CustomTK/rootfs/
yum -y remove biosdevname --installroot=/tftpboot/toolkit/CustomTK/rootfs/

# подготавливаем initramfs:

wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64 -O /tftpboot/toolkit/CustomTK/initramfs/bin/busybox
chmod a+x /tftpboot/toolkit/CustomTK/initramfs/bin/busybox
cp /tftpboot/toolkit/CustomTK/rootfs/boot/vmlinuz-3.10.0-957.el7.x86_64 /tftpboot/toolkit/tkcustom-kernel

# создаем /tftpboot/toolkit/CustomTK/initramfs/init (ниже содержание скрипта):

#!/bin/busybox sh
/bin/busybox --install /bin
mkdir -p /dev /proc /sys /var/run /newroot
mount -t proc proc /proc
mount -o mode=0755 -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts /dev/shm /dev/mapper /dev/vc
mount -t devpts -o gid=5,mode=620 devpts /dev/pts
mount -t sysfs sysfs /sys
mount -t tmpfs -o size=4000m tmpfs /newroot
echo -n "Extracting rootfs... "
xz -d -c -f rootfs.tar.xz | tar -x -f - -C /newroot
echo "done"
mkdir -p /newroot/dev /newroot/proc /newroot/sys
mount --move /sys  /newroot/sys
mount --move /proc /newroot/proc
mount --move /dev  /newroot/dev
exec switch_root /newroot /sbin/init

# упаковываем rootfs и initramfs:

cd /tftpboot/toolkit/CustomTK/rootfs
tar cJf /tftpboot/toolkit/CustomTK/initramfs/rootfs.tar.xz --exclude ./proc --exclude ./sys --exclude ./dev .
cd /tftpboot/toolkit/CustomTK/initramfs
find . -print0 | cpio --null -ov --format=newc | gzip -9 > /tftpboot/toolkit/tkcustom-initramfs-new.gz

Janten kami parantos netepkeun kernel sareng initramfs anu kedah dimuat. Hasilna, dina tahap ieu, ku ngamuat gambar linux panengah via PXE, urang bakal nampi konsol OS.

Hébat, tapi ayeuna urang kedah nransferkeun kontrol ka "otomatisasi" urang.

Éta tiasa dilakukeun sapertos kieu.

Hayu urang nganggap yén saatos ngamuat gambar, urang ngarencanakeun mindahkeun kontrol kana naskah mount.sh.
Hayu urang kalebet skrip mount.sh dina autorun. Jang ngalampahkeun ieu anjeun kudu ngarobah initramfs:

  • ngabongkar initramfs (upami kami nganggo pilihan initramfs di luhur, ieu henteu diperyogikeun)
  • kaasup kode dina ngamimitian anu bakal nganalisis parameter ngaliwatan / proc / cmdline sarta mindahkeun kontrol salajengna;
  • pak initramfs.

Catetan. Dina kasus toolkit X5, kontrol loading ditransferkeun ka naskah /opt/x5/toolkit/bin/hook.sh с помощью override.conf в getty tty1 (ExecStart=…)

Janten, gambarna dimuat, dimana naskah mount.sh dimimitian dina autorun. Salajengna, skrip mount.sh nganalisa parameter anu diliwatan (script_cmd=) salami palaksanaan sareng ngaluncurkeun program / naskah anu diperyogikeun.

labél toolkit-otomatis
kernel...
append...nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh

labél toolkit-kerang
kernel...
append...nfs_toolkit_script=scripts/mount.sh script_cmd = / bin / bash

Do-it-yourself Bare-Metal Provisioning, atanapi Nyiapkeun otomatis server ti mimiti

Di dieu di kénca nyaéta menu PXE, di katuhu nyaéta diagram transfer kontrol.

Urang ilahar kaluar mindahkeun kontrol. Gumantung kana pilihan menu PXE, skrip konfigurasi otomatis atanapi konsol debugging diluncurkeun.

Dina kasus konfigurasi otomatis, diréktori anu diperyogikeun dipasang tina pangladén pamasangan, anu ngandung:

  • naskah;
  • disimpen mios / UEFI témplat pikeun sagala rupa server;
  • firmware;
  • Utiliti server;
  • log

Salajengna, skrip mount.sh mindahkeun kontrol ka skrip master-install.sh tina diréktori naskah.

Tangkal naskah (urutan anu diluncurkeun) sapertos kieu:

  • master-install
  • fungsi dibagikeun (fungsi dibagikeun)
  • info (kaluaran informasi)
  • model (nyetél parameter instalasi dumasar kana model server)
  • prepare_utils (pamasangan utilitas anu diperyogikeun)
  • fwupdate (update firmware)
  • diag (diagnosa dasar)
  • biosconf (setélan BIOS/UEFI)
  • clockfix (nyetel waktos dina motherboard)
  • srmconf (konfigurasi panganteur antarbeungeut jauh)
  • raidconf (ngonpigurasikeun volume logis)

salah sahiji:

  • prapasang (mindahkeun kontrol ka OS atanapi pamasang hypervisor, sapertos ESXi)
  • merged-install (mimiti langsung ngabongkar gambar)

Ayeuna urang terang:

  • kumaha boot server via PXE;
  • kumaha cara nransper kontrol kana naskah anjeun sorangan.


Hayu urang neruskeun. Patarosan di handap ieu janten relevan:

  • Kumaha pikeun ngaidentipikasi server anu kami siapkeun?
  • Utiliti naon sareng kumaha ngonpigurasikeun server?
  • Kumaha carana kéngingkeun setélan pikeun server khusus?

Kumaha pikeun ngaidentipikasi server anu kami siapkeun?

Ieu basajan - DMI:

dmidecode –s system-product-name
dmidecode –s system-manufacturer
dmidecode –s system-serial-number

Sadaya anu anjeun peryogikeun aya di dieu: padagang, modél, nomer séri. Upami anjeun henteu yakin yén inpormasi ieu aya dina sadaya server, anjeun tiasa ngaidentipikasi ku alamat MAC na. Atanapi dina dua cara dina waktos anu sami, upami padagang server béda-béda sareng dina sababaraha modél henteu aya inpormasi ngeunaan nomer séri.

Dumasar inpormasi anu ditampi, polder jaringan dipasang tina server pamasangan sareng sadaya anu diperyogikeun dimuat (utilitas, firmware, jsb.).

Utiliti naon sareng kumaha ngonpigurasikeun server?

Kuring bakal nyayogikeun utilitas pikeun Linux pikeun sababaraha pabrik. Sadaya utilitas sayogi dina situs wéb resmi vendor.

Do-it-yourself Bare-Metal Provisioning, atanapi Nyiapkeun otomatis server ti mimiti

Kalawan firmware nu, Jigana sagalana jelas. Biasana aya dina bentuk file laksana anu rangkep. File laksana ngatur prosés update firmware sareng ngalaporkeun kodeu balik.

BIOS sareng IPMI biasana dikonpigurasi ngalangkungan témplat. Upami diperlukeun, témplat tiasa diédit sateuacan diunduh.

Utiliti RAID ti sababaraha padagang ogé tiasa dikonpigurasikeun nganggo citakan. Upami ieu henteu masalahna, maka anjeun kedah nyerat skrip konfigurasi.

Prosedur pikeun nyetél RAID paling sering sapertos kieu:

  • Urang menta konfigurasi ayeuna.
  • Lamun geus aya arrays logis, urang mupus aranjeunna.
  • Hayu urang tingali naon disk fisik anu aya sareng sabaraha jumlahna.
  • Jieun Asép Sunandar Sunarya logis anyar. Urang ngaganggu prosés bisi aya kasalahan.

Kumaha carana kéngingkeun setélan pikeun server khusus?

Hayu urang nganggap yén setélan sadaya server bakal disimpen dina server instalasi. Dina hal ieu, pikeun ngajawab patarosan urang, urang mimitina kudu mutuskeun kumaha nransper setelan ka server instalasi.

Dina awalna, anjeun tiasa meunang ku file téks. (Dina mangsa nu bakal datang, Anjeun meureun hoyong make file téks salaku padika fallback pikeun nransper setelan.)

Anjeun tiasa "ngabagikeun" file téks dina server instalasi. Sareng tambahkeun gunungna kana naskah mount.sh.

Baris baris, contona, kasampak kawas kieu:

<nomer serial> <hostname> <subnet>

Garis ieu bakal dialihkeun kana file ku insinyur tina mesin karyana. Teras, nalika nyetél server, parameter pikeun server khusus bakal dibaca tina file.

Tapi, dina jangka panjang, eta leuwih hade migunakeun database pikeun nyimpen setelan, nagara bagian jeung log pamasangan server.

Tangtosna, pangkalan data waé henteu cekap, sareng anjeun kedah nyiptakeun bagian klien kalayan bantosan setélan anu bakal ditransfer kana pangkalan data. Ieu langkung hese pikeun dilaksanakeun dibandingkeun sareng file téks, tapi kanyataanna, sadayana henteu sesah sigana. Ieu rada mungkin nulis versi minimal tina hiji klien nu saukur bakal mindahkeun data kana database sorangan. Sarta dina mangsa nu bakal datang bakal mungkin pikeun ngaronjatkeun program klien dina mode bébas (laporan, labél percetakan, ngirim bewara, jsb nu datang ka pikiran).

Ku nyieun pamundut husus ka database jeung nangtukeun jumlah serial server, urang bakal nampa parameter diperlukeun pikeun ngonpigurasikeun server.

Tambih Deui, urang moal kedah ngadamel konci pikeun aksés sakaligus, sapertos dina file téks.

Urang tiasa nyerat log konfigurasi kana pangkalan data dina sadaya tahapan sareng ngontrol prosés pamasangan ngalangkungan acara sareng umbul tina tahap persiapan.

Ayeuna urang terang kumaha:

  • boot server via PXE;
  • mindahkeun kadali kana naskah urang;
  • ngaidentipikasi server anu kudu disiapkeun ku nomer serial na;
  • ngonpigurasikeun server ngagunakeun Utiliti luyu;
  • mindahkeun setélan kana database server instalasi ngagunakeun bagian klien.

Kami terang kumaha:

  • server dipasang narima setélan diperlukeun tina database;
  • sagala kamajuan persiapan kacatet dina database (log, acara, umbul panggung).

Kumaha upami tipena béda parangkat lunak anu anjeun pasang? Kumaha cara masang hypervisor, nyalin VM sareng ngonpigurasikeun sadayana?

Dina kasus nyebarkeun gambar sistem file (linux) kana hardware, sadayana saderhana:

  • Saatos nyetél sadaya komponén server, urang nyebarkeun gambar.
  • Pasang grub bootloader.
  • Kami chroot sareng ngonpigurasikeun sadayana anu diperyogikeun.

Kumaha cara nransper kontrol ka installer OS (ngagunakeun ESXi sabagé conto).

  • Kami ngatur transfer kontrol tina skrip kami ka pamasang hypervisor nganggo file réspon otomatis (kickstart):
  • Urang mupus partisi ayeuna dina disk.
  • Jieun partisi kalayan ukuran 500MB.
  • Urang nandaan salaku bootable.
  • Format kana FAT32.
  • Urang nyalin file instalasi ESXi kana akar.
  • Masang syslinux.
  • Salin syslinux.cfg ka /syslinux/

default esxi
prompt 1
timeout 50
label esxi
kernel mboot.c32
append -c boot.cfg

  • Nyalin mboot.c32 ka /syslinux.
  • Boot.cfg kedah gaduh kernelopt=ks=ftp:// /ks_esxi.cfg
  • Urang reboot server.

Saatos server reboots, installer ESXi bakal ngundeur ti hard drive server urang. Sadaya file installer perlu bakal dimuat kana memori lajeng instalasi ESXi bakal dimimitian, nurutkeun file respon otomatis dieusian.

Ieu sababaraha baris ti file autoresponse ks_esxi.cfg:

%firstboot --interpreter=busybox
…
# получаем серийный номер

SYSSN=$(esxcli hardware platform get | grep Serial | awk -F " " '{print $3}')

# получаем IP

IPADDRT=$(esxcli network ip interface ipv4 get | grep vmk0 | awk -F " " '{print $2}')
LAST_OCTET=$(echo $IPADDRT | awk -F'.' '{print $4}')

# подключаем NFS инсталл-сервера

esxcli storage nfs add -H is -s /srv/nfs_share -v nfsshare1

# копируем временные настройки ssh, для использования ssh-клиента

mv /etc/ssh /etc/ssh.tmp
cp -R /vmfs/volumes/nfsshare1/ssh /etc/
chmod go-r /etc/ssh/ssh_host_rsa_key

# копируем ovftool, для развертывания ВМ сейчас, плюс возможно пригодится позже

cp -R /vmfs/volumes/nfsshare1/ovftool /vmfs/volumes/datastore1/

# развертываем ВМ

/vmfs/volumes/datastore1/ovftool/tools/ovftool --acceptAllEulas --noSSLVerify --datastore=datastore1 --name=VM1 /vmfs/volumes/nfsshare1/VM_T/VM1.ova vi://root:[email protected]
/vmfs/volumes/datastore1/ovftool/tools/ovftool --acceptAllEulas --noSSLVerify --datastore=datastore1 --name=VM2 /vmfs/volumes/nfsshare1/VM_T/VM2.ova vi://root:[email protected]

# получаем строку с настройками нашего сервера

ssh root@is "mysql -h'192.168.0.1' -D'servers' -u'user' -p'secretpassword' -e "SELECT ... WHERE servers.serial='$SYSSN'"" | grep -v ^$ | sed 's/NULL//g' > /tmp/servers
...
# генерируем скрипт настройки сети

echo '#!/bin/sh' > /vmfs/volumes/datastore1/netconf.sh
echo "esxcli network ip interface ipv4 set -i=vmk0 -t=static --ipv4=$IPADDR --netmask=$S_SUB || exit 1" >> /vmfs/volumes/datastore1/netconf.sh
echo "esxcli network ip route ipv4 add -g=$S_GW -n=default || exit 1" >> /vmfs/volumes/datastore1/netconf.sh
chmod a+x /vmfs/volumes/datastore1/netconf.sh

# задаем параметр guestinfo.esxihost.id, указываем в нем серийный номер

echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM1/VM1.vmx
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM2/VM2.vmx
...
# обновляем информацию в базе

SYSNAME=$(esxcli hardware platform get | grep Product | sed 's/Product Name://' | sed 's/^ *//')
UUID=$(vim-cmd hostsvc/hostsummary | grep uuid | sed 's/ //g;s/,$//' | sed 's/^uuid="//;s/"$//')
ssh root@is "mysql -D'servers' -u'user' -p'secretpassword' -e "UPDATE servers ... SET ... WHERE servers.serial='$SYSSN'""
ssh root@is "mysql -D'servers' -u'user' -p'secretpassword' -e "INSERT INTO events ...""

# возвращаем настройки SSH

rm -rf /etc/ssh
mv /etc/ssh.tmp /etc/ssh

# настраиваем сеть и перезагружаемся

esxcli system hostname set --fqdn=esx-${G_NICK}.x5.ru
/vmfs/volumes/datastore1/netconf.sh
reboot

Dina tahap ieu, hypervisor dipasang sareng dikonpigurasikeun, sareng mesin virtual disalin.

Kumaha ngonpigurasikeun mesin virtual ayeuna?

Urang curang saeutik: salila instalasi urang nyetel parameter guestinfo.esxihost.id = "$ SYSSN" dina file VM1.vmx sarta dituduhkeun jumlah serial tina server fisik di dinya.

Ayeuna, saatos ngamimitian, mesin virtual (kalayan pakét vmware-tools dipasang) tiasa ngaksés parameter ieu:

ESXI_SN=$(vmtoolsd --cmd "info-get guestinfo.esxihost.id")

Hartina, VM bakal tiasa ngaidentipikasi diri (eta terang nomer séri host fisik), nyuhunkeun pamenta ka database server instalasi sareng nampi parameter anu kedah dikonpigurasikeun. Ieu sadayana disusun kana naskah, anu kedah diluncurkeun sacara otomatis nalika guestos vm dimimitian (tapi sakali: RunOnce).

Ayeuna urang terang kumaha:

  • boot server via PXE;
  • mindahkeun kadali kana naskah urang;
  • ngaidentipikasi server anu kudu disiapkeun ku nomer serial na;
  • ngonpigurasikeun server ngagunakeun Utiliti luyu;
  • mindahkeun setélan kana database server instalasi ngagunakeun bagian klien;
  • ngonpigurasikeun rupa-rupa jenis software, kaasup deploying esxi hypervisor jeung Konfigurasi mesin virtual (sadayana otomatis).

Kami terang kumaha:

  • server dipasang narima setélan diperlukeun tina database;
  • sagala kamajuan persiapan kacatet dina database (log, acara, umbul panggung).


Bottom line:

Kuring yakin yén uniqueness solusi ieu perenahna di kalenturan anak, kesederhanaan, kamampuhan jeung versatility.

Mangga tulis dina komentar naon pikir anjeun.

sumber: www.habr.com

Tambahkeun komentar