Bagaimana Ansible berbeda dari hanya menjalankan cangkang pesta penyediaan di Vagrant?


39

Sebuah tim sysadmin IT yang memiliki pengalaman menggunakan skrip shell untuk menyelesaikan masalah mereka, sedang mempertimbangkan untuk mulai menggunakan Ansible sebagai gantinya.

Apakah ada perbedaan substansial dan alasan yang baik untuk mulai menggunakan Ansible vs. untuk terus menulis skrip shell?

Jawaban:


29

Saya tidak pernah menggunakan Ansible tetapi sejak beberapa minggu, saya mencoba mencari tahu apa yang bisa dilakukan Ansible dibandingkan dengan skrip shell - Yang membuktikan, setidaknya dalam kasus saya, bahwa kampanye iklan menghantui yang mereka jalankan efektif! Setelah banyak usaha yang gagal - yang membuktikan bagaimana dokumentasi mereka gagal menjawab salah satu pertanyaan yang paling jelas - saya pikir saya akhirnya mendapatkannya:

Sekarang, mari kita tonton video pendahuluan dan secara acak sebagai pengguna baru yang potensial melalui materi pendahuluan untuk ansible ans, mari kita bandingkan dengan apa yang dapat dihasilkan oleh programmer shell yang ahli.

Kesimpulan saya adalah bahwa lebih dari scripting shell, Ansible pada dasarnya menawarkan 1. Kemungkinan memeriksa bahwa suatu sistem setuju dengan keadaan yang diinginkan, 2. kemampuan untuk berintegrasi dengan Ansible Tower, yang merupakan sistem pembayaran yang tampaknya mencakup kemampuan pemantauan. Dalam beberapa kasus penting, seperti ketika menerapkan pola server yang tidak dapat diubah, poin 1 mungkin tidak terlalu berguna, jadi daftarnya, agak tipis.

Kesimpulan saya adalah bahwa manfaat yang ditawarkan oleh Ansible lebih dari scripting shell, seperti yang disajikan oleh dokumentasi, dapat masuk akal dalam beberapa kasus optimis yang tercakup dengan baik oleh modul yang tersedia tetapi kecil atau bahkan hipotetis dalam kasus umum. Bagi seorang programmer shell yang terampil, manfaat ini kemungkinan besar diimbangi oleh aspek trade-off lainnya.

Tapi ini mungkin hanya membuktikan betapa buruknya materi pengantar!

Video mulai cepat:

Ada video mulai cepat . Ini dimulai dengan halaman yang mengklaim bahwa ... yah ini bukan benar-benar klaim, ini adalah daftar peluru, artefak yang biasa digunakan untuk menunda penilaian kritis dalam presentasi (karena logika tidak ditampilkan, tidak dapat dikritik!)

1. Ansible sederhana:

1.1 Otomatisasi yang dapat dibaca manusia - Spesifikasi adalah dokumen teknis, bagaimana mungkin

  name: upgrade all packages
  yum:
    name: '*'
    state: latest

lebih mudah dibaca daripada doa yum terkait yang ditemukan dalam skrip shell? Selain itu, siapa pun yang memiliki kontak dengan AppleScript mati tertawa ketika mereka membaca "otomatisasi yang dapat dibaca manusia".

1.2 Tidak diperlukan keahlian pengkodean khusus - Apa itu pengkodean jika tidak menulis spesifikasi formal? Mereka memiliki kondisional, variabel, jadi, bagaimana itu bukan pengkodean? Dan mengapa saya membutuhkan sesuatu yang tidak dapat saya programkan, yang selanjutnya akan menjadi tidak fleksibel? Pernyataan itu sangat tidak akurat!

1.3 Tugas dieksekusi secara berurutan - Ya, mungkin beberapa penggemar codegolf mengetahui bahasa yang mengeksekusi tugas-tugas dalam kekacauan, tetapi menjalankan tugas-tugas dalam urutan hampir tidak terlihat luar biasa.

1.4 Dapatkan produktif dengan cepat - Pemrogram shell yang terampil sekarang produktif. Argumen tandingan ini sama seriusnya dengan argumen awal.

2. Ansible sangat kuat

Trik penjual yang populer untuk menjual artefak adalah membodohi orang agar percaya bahwa mereka akan mendapatkan "kekuatan" artefak ini. Sejarah iklan untuk mobil atau minuman isotonik harus menyediakan daftar contoh yang meyakinkan.

Di sini Ansible dapat melakukan "penyebaran aplikasi" - tetapi skrip shell tentu saja melakukannya, "manajemen konfigurasi" tetapi ini hanyalah pernyataan tujuan dari alat tersebut, bukan fitur, dan "alur kerja orkestrasi" yang terlihat agak megah tetapi tidak ada contoh yang berlaku melampaui apa yang bisa dilakukan GNU Parallel .

3. Ansible tidak agen

Untuk mengisi kolom, mereka menulis dalam tiga cara yang berbeda bahwa ini hanya perlu ssh, yang, karena semua orang tahu adalah daemon dan tidak ada hubungannya dengan agen - agen ini yang meliputi manajemen konfigurasi dunia!

Sisa video

Sisa video memperkenalkan inventaris, yang merupakan daftar sumber daya statis (seperti server) dan menunjukkan cara menggunakan Apache di tiga server secara bersamaan. Ini benar-benar tidak sesuai dengan cara saya bekerja, di mana sumber daya sangat dinamis dan dapat dihitung dengan tool-line perintah yang disediakan oleh penyedia cloud saya, dan dikonsumsi oleh fungsi shell saya menggunakan |operator pipa . Juga, saya tidak menggunakan Apache pada tiga server secara bersamaan, melainkan, saya membangun gambar contoh master yang kemudian saya gunakan untuk memulai 3 contoh yang merupakan replika yang tepat dari yang lain. Jadi bagian “mengatur” argumentasi tidak terlihat sangat relevan.

Dokumentasi acak langkah 1: Integrasi dengan EC2

EC2 adalah layanan komputasi dari Amazon, berinteraksi dengannya didukung oleh beberapa modul Ansible . (Penyedia komputasi awan populer lainnya juga disediakan):

# demo_setup.yml

- hosts: localhost
  connection: local
  gather_facts: False

  tasks:

    - name: Provision a set of instances
      ec2:
         key_name: my_key
         group: test
         instance_type: t2.micro
         image: "{{ ami_id }}"
         wait: true
         exact_count: 5
         count_tag:
            Name: Demo
         instance_tags:
            Name: Demo
      register: ec2

Shell-script yang sesuai pada dasarnya akan identik dengan YAML digantikan oleh JSON:

provision_a_set_of_instances()
{
  aws --output=text ec2 run-instances --image-id …   
}

atau versi JSON

provision_a_set_of_instances()
{
  aws --output=text ec2 run-instances --cli-input-json "$(provision_a_set_of_instances__json)"  
}

provision_a_set_of_instances__json()
{
  cat <<EOF
{
    "ImageId": … 
}
EOF
}

Kedua versi pada dasarnya identik, sebagian besar payload adalah enumerasi nilai inisialisasi dalam struktur YAML atau JSON.

Dokumentasi acak langkah 2: Pengiriman Berkelanjutan dan Peningkatan Kemampuan

Bagian terbesar dari panduan ini tidak menampilkan fitur yang benar-benar menarik: ia memperkenalkan variabel (IIRC, skrip shell juga memiliki variabel) !, dan modul Ansible menangani mysql, sehingga jika alih-alih mencari setelah "bagaimana cara membuat pengguna mysql dengan hak istimewa di XY ”dan diakhiri dengan sesuatu seperti

# Create Application DB User
mysql --host "${mysql_host}" --user "${mysql_user}" --password "${mysql_password}" "${mysql_table}" <<EOF
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';
EOF

Anda mencari setelah "bagaimana cara membuat pengguna mysql dengan hak istimewa di XY tidak mungkin " dan berakhir dengan

- name: Create Application DB User
  mysql_user: name={{ dbuser }} password={{ upassword }}
              priv=*.*:ALL host='%' state=present

Perbedaannya mungkin masih tidak terlalu berarti. Pada halaman itu kami juga menemukan bahwa Ansible memiliki bahasa pemrograman-meta templat

{% for host in groups['monitoring'] %}
-A INPUT -p tcp -s {{ hostvars[host].ansible_default_ipv4.address }} --dport 5666 -j ACCEPT
{% endfor %}

Ketika saya melihat ini, saya benar-benar berada di zona nyaman saya. Jenis meta-pemrograman sederhana untuk bahasa-bahasa deklaratif ini persis dengan paradigma teoretis yang sama dengan Makefiles BSD! Yang kebetulan telah saya programkan secara luas. Kutipan ini menunjukkan kepada kita bahwa janji untuk bekerja dengan file YAML rusak (jadi saya tidak bisa menjalankan buku pedoman saya melalui parser YAML, misalnya ). Ini juga menunjukkan kepada kita bahwa Ansible harus membahas seni halus dari urutan evaluasi: kita harus memutuskan apakah variabel diperluas pada "bagian deklaratif" bahasa atau pada meta-bagian "imperatif" bahasa. Di sini pemrograman shell lebih sederhana, tidak ada meta-pemrograman, selain dari sumber skrip eksplisit eval atau eksternal. Kutipan shell ekuivalen hipotetis akan menjadi

enumerate_group 'monitoring' | {
  while read host; do
    …
  done
}

yang kompleksitasnya dibandingkan dengan varian Ansible mungkin dapat ditoleransi: itu hanya menggunakan konstruksi sederhana, teratur, membosankan dari bahasa.

Dokumentasi acak langkah 3: Strategi pengujian

Terakhir, kami bertemu dengan apa yang ternyata menjadi fitur menarik pertama dari Ansible: “Sumber daya yang memungkinkan adalah model dari keadaan yang diinginkan. Dengan demikian, tidak perlu menguji apakah layanan dimulai, paket diinstal, atau hal-hal lain semacam itu. Ansible adalah sistem yang akan memastikan hal-hal ini benar secara deklaratif. Alih-alih, tegaskan hal-hal ini di buku pedoman Anda. ”Sekarang mulai sedikit menarik, tetapi:

  1. Selain beberapa situasi standar yang mudah diimplementasikan oleh modul yang tersedia, saya harus memberi makan bit mengimplementasikan tes sendiri, yang kemungkinan besar akan melibatkan beberapa perintah shell.

  2. Memeriksa kesesuaian instalasi mungkin tidak terlalu relevan dalam konteks di mana pola server yang tidak dapat diimplementasikan: di mana semua sistem yang berjalan biasanya muncul dari gambar master (misalnya gambar atau gambar buruh pelabuhan misalnya) dan tidak pernah diperbarui - mereka diganti oleh baru sebagai gantinya.

Kekhawatiran yang belum terselesaikan: pemeliharaan

Materi pengantar dari Ansible mengabaikan pertanyaan tentang rawatan. Dengan dasarnya tidak ada sistem tipe, skrip shell memiliki kemudahan pemeliharaan JavaScript, Lisp atau Python: refactoring luas hanya dapat dicapai dengan sukses dengan bantuan testuite otomatis yang luas - atau setidaknya desain yang memungkinkan pengujian interaktif mudah. Yang mengatakan, sementara skrip shell adalah lingua franca dari konfigurasi dan pemeliharaan sistem, hampir setiap bahasa pemrograman memiliki antarmuka ke shell. Oleh karena itu benar-benar layak untuk memanfaatkan keunggulan rawat-kesehatan dari bahasa-bahasa maju, dengan menggunakannya untuk merekatkan bersama berbagai bit dari bit konfigurasi shell. Untuk OCaml, saya menulis Rashell yang pada dasarnya menyediakan pola interaksi umum untuk subproses, yang membuat terjemahan skrip konfigurasi ke OCaml pada dasarnya sepele.

Di sisi dari Ansible, struktur buku pedoman yang sangat lemah dan keberadaan fitur meta-pemrograman membuat situasi pada dasarnya seburuk itu untuk skrip shell, dengan poin minus yang tidak jelas bagaimana menulis unit test untuk Ansible , dan argumen untuk memperkenalkan ad-hoc bahasa tingkat yang lebih tinggi tidak dapat ditiru.

Idempotensi langkah konfigurasi

Dokumentasi Ansible menarik perhatian pada perlunya menulis langkah konfigurasi idempoten. Lebih tepatnya, langkah-langkah konfigurasi harus ditulis sehingga urutan langkah aba dapat disederhanakan menjadi ab , yaitu kita tidak perlu mengulangi langkah konfigurasi. Ini adalah kondisi yang lebih kuat daripada idempotensi. Karena Ansible memungkinkan playbook untuk menggunakan perintah shell sewenang-wenang, Ansible sendiri tidak dapat menjamin bahwa kondisi yang lebih kuat ini dihormati. Ini hanya bergantung pada disiplin programmer.


Ini sepertinya manual ... mengesankan!
Pierre.Vriens

4
Saya sangat setuju. Kami menggunakan Ansible selama lebih dari 1 tahun sekarang dan sekarang menggunakan wadah Docker, dibuat dengan skrip bash tua yang bagus dan sederhana. Mendefinisikan status juga menurut saya sejauh ini merupakan fitur yang paling menarik, tetapi seperti yang Anda sebutkan tadi - ada begitu banyak layanan yang tidak memiliki modul Ansible yang sesuai, jadi Anda selalu harus mundur ke perintah bash. Dan ya, kami juga hanya menggunakan kontainer yang tidak dapat diubah ke server, jadi mendefinisikan keadaan sebenarnya tidak ada manfaatnya dalam kasus ini.
Andreas

1
Setelah menggunakan ansible secara menyeluruh, saya dapat mengkonfirmasi semua poin yang saya buat apriori. Idempotensi dimungkinkan tetapi tidak ditegakkan oleh ansible (lihat modul vmware_guest untuk warga negara yang buruk), bekerja dengan sistem makro mereka sangat menyusahkan dan sangat sulit untuk melakukan bahkan perawatan paling dasar pada data terstruktur, beberapa hal dasar melakukan kesalahan (format playbook tidak dapat memakan mode file Unix tanpa terapi) dan satu-satunya hal yang baik adalah memuat fungsi berguna yang ditulis untuk memungkinkan. Jadi kalau bukan karena Red Hat mendorong produk itu, saya tidak bisa memahami adopsi luas.
Michael Le Barbier Grünewald

1
@Andreas Saya setuju Anda masih memiliki banyak kasus di mana Anda harus kembali ke modul shell atau perintah yang tidak berarti permainan yang Anda lakukan tidak dapat idempoten. Modul inti sendiri mempertahankan idempotensi dengan hanya memeriksa apakah tindakan harus dilakukan. Anda dapat melakukan hal yang sama dengan modul shell atau perintah dengan terlebih dahulu menjalankan tugas yang memeriksa apakah sesuatu harus dilakukan dan mendaftarkan hasilnya, kemudian melakukan persyaratan pada tugas kedua berdasarkan pada output dari tugas pertama.
Levi

1
@ MichaelLeBarbierGrünewald, saya harus setuju secara keseluruhan, ketika saya bekerja dengan Ansible, itu sangat menyebalkan untuk bisa berjalan dan pekerjaannya yang membutuhkan waktu berminggu-minggu untuk mendapatkan buku pedoman bersama untuk terhubung ke infrastruktur di mantan perusahaan berbasis cloud saya, menyediakan linux distro, instal LAMP / LEMP atau apa pun. Setelah selesai, itu menghemat waktu kita, tetapi butuh waktu sebulan hanya untuk bangun dan berjalan. Tak satu pun dari kami yang menguasai skrip bash sehingga itu bukan alternatif.
Daniel

22

Ketika Anda mengatakannya dengan cara ini, bahkan jika Ansible memiliki beberapa keuntungan yang melekat, manfaat menggunakan alat yang dikenal (dalam hal ini skrip shell) harus melebihi. Saya tidak berpikir ada jawaban yang jelas untuk itu.

Jika tim dapat mencapai hal-hal yang mungkin dilakukan dengan shell:

  1. Manajemen konfigurasi deklaratif dan idempoten
  2. Akses ke cuplikan yang dapat digunakan kembali (yaitu, buku pedoman) untuk layanan populer industri.
  3. Manajemen yang dapat diandalkan dari eksekusi jarak jauh, dengan mencoba ulang, logika bergulir, dll.

maka mereka mungkin bisa tetap dengan apa yang mereka ketahui.

Lagi pula, Anda dapat menerapkan "penjaga" di BASH. Anda dapat menemukan banyak pekerjaan BASH yang ada di luar sana untuk menyelesaikan berbagai tugas konfigurasi server (pada dasarnya setiap Dockerfile di luar sana adalah kode instalasi bash 90%). Anda bisa mendekati apa yang ditawarkan Ansible / Salt / Chef-Zero, tanpa harus mem-porting seluruh solusi yang ada ke alat-alat tersebut.

Ini adalah tindakan penyeimbang antara kecenderungan NIH (tidak ditemukan di sini), dan membuang skrip yang baik dan mapan demi solusi yang lebih kuat.

Satu pertimbangan terakhir yang perlu diingat: bagaimana tumpukan teknologi Anda mengukur ketika Anda mencoba merekrut lebih banyak orang ke tim. Menemukan orang yang memiliki pengalaman yang memungkinkan jauh lebih mudah daripada menemukan orang yang memiliki pengalaman dalam alat CM scripting khusus rumah Anda. Ini bukan semata-mata pertimbangan teknis, lebih merupakan pertimbangan budaya. Apakah Anda ingin menjadi org aneh yang menciptakan Ansible sendiri, atau Anda ingin menjadi org wajar yang menemukan alat yang tepat untuk pekerjaan itu? Keputusan itu memengaruhi kemampuan Anda untuk menarik bakat.


4
Menyukai jawaban Anda; Saya juga akan menyebutkan bahwa, jika tim bash akan melakukan idempotensi, manajemen eksekusi, dan penggunaan kembali, pada dasarnya menulis kerangka kerja manajemen konfigurasi mereka sendiri, ada biaya yang terlibat, dan kita semua tahu bahwa itu bisa sangat buruk untuk proyek-proyek in-house .
ᴳᵁᴵᴰᴼ

Saya juga berlangganan jawaban Anda, terutama setelah memasukkan pengalaman yang tersedia dalam keseimbangan. Saya memiliki dua kritik kecil: pertama adalah idempotensi. Ini tentu saja merupakan aspek penting dari sistem konfigurasi, tetapi karena dimungkinkan untuk menggunakan perintah shell yang mungkin dalam buku pedoman yang dimungkinkan, sistem ini dapat mendorong untuk menggunakan idempotensi. (Kami benar-benar menginginkan sesuatu yang lebih kuat yang idempotensi aba = ab .) Kedua manajemen yang dapat diandalkan dari eksekusi jarak jauh mungkin sama sekali tidak relevan dalam beberapa kasus penting, misalnya ketika menerapkan pola server yang tidak dapat diubah menggunakan contoh gambar.
Michael Le Barbier Grünewald

13

Jawaban di atas mencakup sebagian tetapi melewatkan salah satu elemen penting: desain konvergen. Saya menulis beberapa kata beberapa waktu lalu tentang ini dalam konteks Chef di https://coderanger.net/thinking/ tetapi versi singkatnya adalah bahwa bash script adalah sekumpulan instruksi, sementara buku pedoman Ansible (atau resep Chef, Salt state, dll) adalah deskripsi dari state yang diinginkan. Dengan mendokumentasikan keadaan yang Anda inginkan daripada langkah-langkah yang ingin Anda ambil untuk sampai ke sana, Anda dapat mengatasi lebih banyak keadaan awal. Ini adalah jantung dari Teori Janji seperti yang diuraikan dalam CFEngine sejak lama, dan desain yang kita (semua perangkat konfigurasi konfigurasi) telah salin sejak itu.

tl; dr Kode yang memungkinkan mengatakan apa yang Anda inginkan, kode bash mengatakan bagaimana melakukan sesuatu.


2
Bisakah Anda juga menambahkan beberapa referensi ke "teori janji", seperti buku atau artikel, dan materi berharga lainnya jika seseorang ingin mempelajarinya?
Evgeny

1
Itu sebenarnya yang saya singgung ketika saya mengatakan bahwa Anda dapat menulis kode bash idempoten (yaitu yang dapat mulai kapan saja, dijalankan beberapa kali, dan konvergen ke keadaan yang diinginkan). Tetapi jawaban Anda membuatnya lebih jelas.
Assaf Lavie

Ya, idempotensi adalah properti penting dari sistem konvergen tetapi keduanya tidak selalu terhubung langsung :) adapun materi tentang Teori Janji, Mark Burgess (pencipta CFEngine) memiliki beberapa buku, saya dapat menemukan tautan ketika saya kembali ke sebuah laptop
coderanger


3

Satu hal yang patut dicatat adalah Anda akan memiliki lebih sedikit masalah dalam menjalankan buku pedoman yang mungkin di host jarak jauh juga. Karena itu alasan utama untuk menjalankan ansible. Saat Anda menggunakan skrip shell, Anda masih harus memiliki cara untuk skrip scp'ing ke host jarak jauh.


Bukankah Ansible hanya pembungkus ssh dalam pengertian ini?
Evgeny

Intinya ya. Itu ssh, menyalin skrip python jarak jauh, dan menjalankannya. Itu artinya, btw, bahwa jika modul yang memungkinkan Anda bergantung pada beberapa pustaka python, pustaka ini harus ada pada mesin jarak jauh, dalam kondisi tertentu.
Assaf Lavie

1
Dan jika Anda mengacaukan konfigurasi ssh, Anda dikunci dari mesin Anda, kelemahan push dan pull yang biasa.
Tensibai

1

Ini tahun 2019 dan saya baru saja menghabiskan beberapa hari pada kurva pembelajaran yang memungkinkan dan inilah kebenaran absolutnya: Ansible tidak sebanding dengan masalahnya.

belum selesai, tidak berjalan di windows dan kombinasi konfigurasi YAML dan pesan kesalahan yang menyesatkan akan membuat mata Anda berdarah. Tampaknya hampir sengaja mengerikan dan maksud saya serius. Ini jelas produk dari proyek sisi pengembang frustrasi sysadmin redhat. Mungkin seorang hipster.

Jika Anda tidak memerlukan apa pun. Fitur-fiturnya di luar ketentuan, dan Anda hanya penyediaan pada satu OS tertentu. Sayangnya, tuliskan shell.script yang layak.

Sampai sekarang, seluruh proyek mengingatkan saya pada forum linux awal di mana noobs diberitahu kepada RTFM dan diejek karena bertanya mengapa seseorang tidak bisa menulis GUI untuk mengonfigurasi pengaturan grafis. Anda hanya tidak mengerti, kan? Anda harus tetap berpegang pada windows ... mungkin saya akan sobat .. senang VI-ing.

Gunakan Docker. Lebih suka apa pun. Docker luar biasa sederhana dan kuat.

Tetapi bagaimana jika Anda benar-benar harus menyediakan timah yang sudah ada? Apa alternatif nyata?

Yah ... belum ada. Tapi saya akan berjanji kepada Anda ini, kecuali jika menjadi lebih baik, akan ada segera. Karena sekeras apa pun fanboy mendorongnya, dan maafkan itu gagal ... itu adalah 5 dari 10 upaya.

Buat skrip bash, dan selamatkan diri Anda dari masalah.


Pertama itu berfungsi di windows melalui Win_RM atau SSH. Kedua sintaks yaml sangat bagus dan dapat dihasilkan secara pemrograman dan sementara beberapa kesalahan dapat menyesatkan tidak ada bedanya dengan Java atau Python memuntahkan nyali selama pengecualian. Ketiga gagasan hanya SCPing script ke server tidak berlaku di lingkungan cloud yang sangat dinamis. Server yang mana? Server bisa berubah setiap hari. Ansible memungkinkan plugin inventaris yang mudah dikonfigurasi dengan cara mudah untuk mengelompokkan server dan memberikan variabel padanya. Saya rasa Ansible tidak sepadan. Saya pikir ini berlebihan bagi lingkungan Anda.
Levi

@ Lewi ya. Ini semua salah saya yang mungkin tidak berjalan di windows, memiliki konfigurasi yang tidak memiliki skema, dan, memiliki kurva belajar yang lebih lama dan biaya perawatan yang lebih tinggi daripada metode dipesan lebih dahulu untuk mencapai tugas yang sama.
Richard

Untuk lingkungan cloud ada pendekatan lain untuk jenis perusahaan skala besar yang mungkin membenarkan kurva belajar. Saya mengerti apa yang dilakukan oleh ansible. Saya hanya tidak melihat ceruknya.
Richard

Ceruk adalah kerangka kerja otomatisasi yang mudah digunakan untuk banyak mesin. Ini tidak sebagus untuk Windows seperti halnya untuk Linux. Juga tidak bagus untuk msdos dan netware. Ini 2019, windows server adalah ceruk kecil yang tidak berguna hari ini.
dyasny
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.