Skip to main content

Posts

Showing posts from 2025

Đọc code Python xem Ansible group priority thay đổi thứ tự gộp group vars

Ansible group dùng để nhóm các máy lại thành từng nhóm trong kho inventory. Khi một máy nằm trong nhiều group, các group vars sẽ được gộp lại, theo thứ tự children sẽ ghi đè parent, group sau sẽ ghi đè group trước . Sau và trước mặc định dựa theo tên group theo thứ tự bảng chữ cái. Trong Ansible inventory có thể cấu hình group priority cho group, khi không set có giá trị mặc định là 1 , giá trị priority có kiểu int, có thể là số âm. # lib/ansible/inventory/group.py class Group: """A group of ansible hosts.""" def __init__(self, name: str) -> None: name = helpers.remove_trust(name) self.depth: int = 0 self.name: str = to_safe_group_name(name) self.hosts: list[Host] = [] self._hosts: set[str] | None = None self.vars: dict[str, t.Any] = {} self.child_groups: list[Group] = [] self.parent_groups: list[Group] = [] self._hosts_cache: list[Host] | None = None self.pri...

Thẻ HTML link rel=alternate

Trong HTML, thẻ <link> thường dùng để liên kết các file file CSS hay favicon: <link rel="stylesheet" type="text/css" href="./theme/css/custom.css" media="screen"> <link rel="icon" href="favicon.ico" /> The <link> HTML element specifies relationships between the current document and an external resource. This element is most commonly used to link to stylesheets, but is also used to establish site icons (both "favicon" style icons and icons for the home screen and apps on mobile devices) among other things. https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link Ngoài hai giá trị rel (relation) stylesheet , icon nói trên, còn nhiều giá trị khác, trong đó đáng chú ý là alternate The rel attribute defines the relationship between a linked resource and the current document Alternate representations of the current document. rel="alternate" dùng để liên kế...

Ansible không ưu tiên CLI option --user cao bằng inventory

99% các chương trình có giao diện dòng lệnh CLI đều ưu tiên option được người dùng chỉ định mức ưu tiên cao nhất. Ansible đặc biệt, vì nó nằm trong 1% còn lại. Mặc định, ansible sử dụng user của người dùng gõ lệnh $USER để ssh vào máy cần quản lý. Người dùng có thể thay đổi giá trị này với option --user REMOTE_USER . Nhưng khi trong inventory có chỉ định ansible_user thì khác: all: hosts: vm1: ansible_host: 127.0.0.1 ansible_user: inventory_user Chạy: $ ansible-playbook -i inventory.yml order.yml --user cli_user PLAY [all] ************************************************************************** TASK [Gathering Facts] ************************************************************** [ERROR]: Task failed: Failed to connect to the host via ssh: inventory_user@127.0.0.1: Permission denied (publickey,password). fatal: [vm1]: UNREACHABLE! => {"changed": false, "msg": "Task failed: Failed to connect to the host via ssh: inventory_user@127....

Ansible role luôn chạy trước task

Ansible là công cụ tự động hóa "đơn giản", "dễ dùng". Trong một ansible play, có thể dùng tasks, hoặc roles, hoặc cả hai. Thứ tự chạy của chúng có chút bất ngờ . Thứ tự role và task khi trong cùng play Playbook order.yml - hosts: all tasks: - name: task1 debug: msg: "This is task1" roles: - role: pika Role pika: roles/pika/tasks/main.yml : - name: task in role debug: msg: this is task in a role Output: $ uvx --from 'ansible-core>2.19' ansible-playbook -K -i localhost, order.yml BECOME password: PLAY [all] ************************************************************************** ... TASK [pika : task in role] ********************************************************** ok: [localhost] => { "msg": "this is task in a role" } TASK [task1] ************************************************************************ ok: [localhost] => { "msg": "This is task1" ...

[Python] Tính toán IP trong mạng

Python từ 3.3 có sẵn thư viện ipaddress rất tiện lợi để tính toán IP trong mạng. Thư viện ipaddress $ podman run -it python:3.10-alpine ... Python 3.10.19 (main, Oct 9 2025, 22:43:20) [GCC 14.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import ipaddress >>> print(ipaddress.__doc__) A fast, lightweight IPv4/IPv6 manipulation library in Python. This library is used to create/poke/manipulate IPv4 and IPv6 addresses and networks. >>> ipaddress. ipaddress.AddressValueError( ipaddress.IPv4Network( ipaddress.collapse_addresses( ipaddress.ip_network( ipaddress.IPV4LENGTH ipaddress.IPv6Address( ipaddress.functools ipaddress.summarize_address_range( ipaddress.IPV6LENGTH ipaddress.IPv6Interface( ipaddress.get_mixed_type_key( ipaddress.v4_int_to_packed( ipaddress.IPv4Address( ...

[TIL] requests đoán "có giáo dục" encoding và có thể sai

requests là thư viện HTTP client phổ biến nhất của Python, nó phổ biến vì dễ dùng, chỉ cần import requests; requests.get là xong. Trông dễ như vậy bởi requests đã cấu hình mặc định hết rất nhiều thứ như: connection, headers, adapter, session, encoding, ... mà mặc định thì nhiều khi đúng, đôi khi sai. Encoding Vì Python mặc định encoding trên Linux là utf-8 , người dùng dễ mặc định là requests cũng vậy, nhưng thực tế thì: Tài liệu viết: When you make a request, Requests makes educated guesses about the encoding of the response based on the HTTP headers. The text encoding guessed by Requests is used when you access r.text. You can find out what encoding Requests is using, and change it, using the r.encoding property: r.encoding 'utf-8' r.encoding = 'ISO-8859-1' If you change the encoding, Requests will use the new value of r.encoding whenever you call r.text. You might want to do this in any situation where you can apply special logic to work out what the en...

[TIL] Docker trên MacOS share toàn bộ thư mục $HOME /Users/you với Docker Machine

Docker chạy được trên các hệ điều hành không phải Linux là 1 điều kỳ diệu. Điều kỳ diệu ấy nhờ việc các hệ điều hành tạo ra một máy ảo Linux rồi chạy container trên đó. Máy ảo này thường gọi là Docker machine, Podman machine, hay cái gì đó machine. Nhưng làm thế nào khi bind mount: -v $PWD:/app , thư mục hiện tại trên MacOS, ví dụ /Users/pikachu/fml lại xuất hiện trong container? Share /Users cho máy ảo Hầu hết người dùng đều mount từ 1 thư mục nào đó trong "$HOME" của user vào container, vậy nên mặc định Docker machine share sẵn thư mục này, bao gồm tất cả mọi thứ, kể cả .bashrc hay .ssh, ... Virtual file shares By default the /Users, /Volumes, /private, /tmp and /var/folders directory are shared. If your project is outside this directory then it must be added to the list, otherwise you may get Mounts denied or cannot start service errors at runtime. https://docs.docker.com/desktop/settings-and-maintenance/settings/#virtual-file-shares Vì thư mục được mount nằm tron...

Đọc code Go Traefik xem router ưu tiên match theo độ dài rule

Traefik là gì Traefik (pronounced traffic) is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy. Traefik integrates with your existing infrastructure components (Docker, Swarm mode, Kubernetes, Consul, Etcd, Rancher v2, Amazon ECS, ...) and configures itself automatically and dynamically. Pointing Traefik at your orchestrator should be the only configuration step you need. Traefik là một HTTP reverse proxy và load balancer giúp triển khai microservices dễ dàng. Traefik có tính năng tương tự NGINX, với điểm mạnh lớn nhất là khả năng tích hợp, cấu hình tự động với hệ thống đã chạy như Kubernetes, Docker, ... Traefik được viết bằng Go, về hiệu năng chưa có gì vượt trội so với NGINX, nhưng có nhiều tính năng hiện đại như: tích hợp HTTPS dễ dàng, hỗ trợ sẵn dashboard, metrics, rate limit,... Build Traefik từ source Tạo file build.sh git clone https://github.com/traefik/traefik --depth 1 --branch v3.5 cd traefik touch webui/static/index.html make ...

[TIL] Tên group trong inventory của Ansible là duy nhất

Nếu cho 1 file inventory có: host1 trong group linux , thuộc về group zone1 . host3 trong group linux , thuộc về group zone2 . Hỏi: host1 nằm trong những group nào? File hosts.yml zone1: children: linux: hosts: host1: windows: hosts: host2: zone2: children: linux: hosts: host3: windows: hosts: host4: Dù cấu trúc biểu diễn trong file YAML ở trên trông như host1 thuộc về zone1 và không liên quan tới zone2 , thì kết quả lại đáng ngạc nhiên: $ uvx --from ansible-core ansible -i hosts.yml host1 -m debug -a 'msg={{group_names}}' Installed 9 packages in 15ms host1 | SUCCESS => { "msg": [ "linux", "zone1", "zone2" ] } Giải thích: host1 trong linux group, linux group thuộc children của zone1 group, VÀ linux group cũng thuộc children của zone2 group, nên kết quả: host1 nằm trong cả group zone1 lẫn zone2 . Thực hiệ...

Cài đặt Raspberry Pi OS Bookworm trên Raspberry Pi Zero W với rpi-imager hỏng

Gã nhẹ nhàng mở nắp chiếc hộp nhựa, nó đã theo gã đi về tương lai 2 múi giờ suốt 1 năm trời rồi lại quay trở về, vẫn chỉ nằm im trong đó. Lớp kim loại sáng bóng khi xưa nay đã lốm đốm đen như làn da của những bạn trẻ U40. Rút chiếc thẻ nhớ, cắm vào khe đọc. Bật nautilus , kết nối thành công. Sửa password wifi trong /etc/wpa_supplicant/wpa_supplicant.conf rồi cắm trở lại. Một đầu kết nối cổng USB-A, đầu kia cắm vào cổng micro USB power, đèn xanh nháy liên tục rồi sáng hẳn, nó còn sống. Nó là chiếc Raspberry Pi Zero W(ireless) mua từ 2018 . Upgrade từ Buster lên Bookworm không thành Chiếc Raspberry Pi vẫn chạy "ngon", vì "ngon" là do người ăn đánh giá. Nhưng phần mềm lẫn hệ điều hành đều đã cũ, bản Raspbian Buster hết hạn vào tháng 6 năm 2024 . Hệ điều hành mặc định cho Raspberry Pi từng có tên là Raspbian, phát triển dựa trên Debian. Năm 2020, hệ điều hành chính thức của Raspberry Pi có tên là Raspberry Pi OS hay gọi tắt là raspios . Tiếp tục dựa trên Debian, r...

Tìm hiểu password hashing trong /etc/shadow trên Linux

Các hệ điều hành Linux sử dụng file /etc/passwd để chứa thông tin các user của hệ thống và /etc/shadow để chứa thông tin về password tương ứng của các user này. Mọi tài khoản đều có thể xem /etc/passwd , nhưng file /etc/shadow được bảo mật, chỉ có root và các user trong group shadow mới xem được: # ls -l /etc/passwd /etc/shadow -rw-r--r-- 1 root root 3443 Jul 25 21:02 /etc/passwd -rw-r----- 1 root shadow 1855 Jul 25 20:52 /etc/shadow Admin không chỉnh sửa trực tiếp nội dung file /etc/shadow mà dùng các công cụ quản lý user trên hệ thống như useradd , usermod , passwd . Ví dụ nội dung /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin pika:x:1000:1000::/home/pika:/bin/bash Mỗi dòng trong /etc/passwd chứa login-name:x:uid:gid:username-or-comment:home:shell . # cat /etc/shadow root:$6$rounds=100000$iA2WWPgA5y...

[TIL] Lấy memory page size với CLI, Python, Rust, C

page size là gì? $ apropos pagesize getpagesize (2) - get memory page size $ man 2 getpagesize getpagesize - get memory page size SYNOPSIS #include <unistd.h> int getpagesize(void); .. DESCRIPTION The function getpagesize() returns the number of bytes in a memory page, where "page" is a fixed-length block, the unit for memory allocation and file mapping performed by mmap(2). C function getpagesize trả về số bytes trong một memory page , trong đó page là một block có độ dài cố định, là đơn vị để cấp phát bộ nhớ (memory allocation). Lấy page size bằng CLI, Python, Rust, C CLI $ whatis getconf getconf (1) - Query system configuration variables getconf (1posix) - get configuration values $ getconf PAGESIZE 4096 Python $ python3 -c 'import resource; print(resource.getpagesize())' 4096 Code C của lib resource : #include <unistd.h> // getpagesize() ... static int res...

[TIL] GitHub Action actions/checkout mặc định checkout merge commit với pull_request

GitHub Action @actions/checkout xuất hiện ở gần như mọi GitHub Action workflow. Khi người dùng tạo Repository, GitHub sẽ gợi ý bằng 1 nút bấm trên giao diện để add GitHub action phù hợp với ngôn ngữ lập trình dùng chính trong repo. Ví dụ Python https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python # This workflow will install Python dependencies, run tests and lint with a single version of Python # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python name: Python application on: push: branches: [ "main" ] pull_request: branches: [ "main" ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # ... Nó có vẻ làm những gì người dùng mong đợi: chứa các file code ở branch đã push lên, vì vậy, không mấy ai thực sự xem doc/code hay biết nó thực sự làm gì. Thậm chí bấm vào GitHub repo https://github.com/actions/checkout ...

[TIL] Tạo alias trong fish shell với funcsave

Fish shell sử dụng cú pháp khác với các shell truyền thống như bash zsh whatis fish fish (1) - the friendly interactive shell Cấu hình Fish không đọc cấu hình từ file .profile hay .*rc mà cấu hình nằm trong thư mục ~/.config/fish $ find ~/.config/fish/ /home/me/.config/fish/ /home/me/.config/fish/conf.d /home/me/.config/fish/completions /home/me/.config/fish/fish_variables /home/me/.config/fish/functions /home/me/.config/fish/functions/sshaa.fish /home/me/.config/fish/functions/gtus.fish /home/me/.config/fish/functions/gco.fish /home/me/.config/fish/functions/gd.fish /home/me/.config/fish/functions/gpo.fish /home/me/.config/fish/config.fish alias là function alias is a simple wrapper for the function builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell alias. For other uses, it is recommended to define a function. Để tạo 1 alias mới, viết alias la='ls -la' Để "save" alias này, gõ funcsave la sẽ tạo ra 1...

Tìm kiếm công cụ xử lý JSON, YAML xịn nhất: jq, yq, jmes... nushell

Ngành IT ngày nay ngập tràn JSON và YAML, 2 định dạng này ở khắp mọi nơi. Việc sử dụng các CLI tool truyền thống (ví dụ: grep) không hiệu quả khiến người dùng phải tìm kiếm những công cụ mới. Hàng trăm công cụ được sinh ra để truy cập/xử lý dữ liệu từ 1 JSON object, và cộng đồng khá ưa chuộng jq . Nhưng đây đã phải là lựa chọn tốt nhất để "xem và xử lý" JSON, YAML...? Thử các công cụ này để tìm ra giải pháp xịn nhất. JMESPath JMESPath không phổ biến khi xử lý JSON tùy ý, nhưng là cú pháp có sẵn khi dùng aws cli --query . JMESPath cũng có câu lệnh cli là jp https://github.com/jmespath/jp nhưng ít người biết. Cú pháp JMESPath https://jmespath.org/ trông hơi giống jq nhưng không phải, và tính năng cũng kém hơn: aws --region ap-southeast-1 lambda list-functions --query 'Functions[?LastModified > `2023-01-02`].[FunctionName,LastModified]' --output table ------------------------------------------------- | ListFunctions | +-------...

Tặng mã giảm giá khóa học online "Học kubernetes, helm, fluxcd trên máy với k3s"

  Tác giả FAMILUG mới public khóa học online Học kubernetes, helm, fluxcd trên máy với k3s trên Udemy Thân gửi tặng bạn đọc mã giảm giá FAMILUGK3S2504 Mã sẽ hết hạn ngày 15/5/2025.

[TIL] Libvirt QEMU://session has limited network funtions

https://wiki.libvirt.org/FAQ.html#what-is-the-difference-between-qemu-system-and-qemu-session-which-one-should-i-use What is the difference between qemu:///system and qemu:///session? Which one should I use? All 'system' URIs (be it qemu, lxc, uml, ...) connect to the libvirtd daemon running as root which is launched at system startup. Virtual machines created and run using 'system' are usually launched as root, unless configured otherwise (for example in /etc/libvirt/qemu.conf). All 'session' URIs launch a libvirtd instance as your local user, and all VMs are run with local user permissions. You will definitely want to use qemu:///system if your VMs are acting as servers. VM autostart on host boot only works for 'system', and the root libvirtd instance has necessary permissions to use proper networkings via bridges or virtual networks. qemu:///system is generally what tools like virt-manager default to. qemu:///session has a serious drawback: sin...

AWS SDK không tự chuyển tới S3 bucket khác region

AWS cloud hỗ trợ tới hơn 10 ngôn ngữ lập trình khác nhau với bộ SDK cho riêng từng ngôn ngữ. AWS SDK cho mỗi language có nhiều điểm khác nhau về các hoạt động có thể gây bất ngờ. Bài này bàn về sự khác biệt của Java SDK v2 so với Python SDK boto3 khi truy cập 1 bucket ở khác region. S3 là dịch vụ toàn cầu, nhưng dữ liệu nằm ở 1 region cố định S3 là dịch vụ toàn cầu, cụ thể là không tồn tại 2 bucket cùng tên, mỗi tên bucket là duy nhất. Thế nhưng dữ liệu S3 bucket thì lại nằm ở 1 region cụ thể khi nó được tạo. Nếu bucket tạo ở us-east-1 , dữ liệu sẽ nằm ở us-east-1 , khi code chạy ở region ap-southeast-1 , mặc định code sẽ truy cập tới bucket ở region ap-southeast-1 , và nhận được HTTP status code 301. Python Boto3 tự chuyển tới region khác Một ví dụ nhặt ở trên mạng: 2022-09-30 15:51:09,844 botocore.utils [DEBUG] S3 client configured for region us-east-1 but the bucket testbucket2ffd929fin is in region us-west-2; Please configure the proper region to avoid multiple unnecessary ...

[TIL] RFC cho định dạng CSV chỉ có 7 dòng

RFC mô tả các tài tiêu chuẩn kỹ thuật trên internet. RFC - Requests for Comments. They describe the Internet's technical foundations, such as addressing, routing, and transport technologies. RFCs also specify protocols like TLS 1.3, QUIC, and WebRTC that are used to deliver services used by billions of people every day, such as real-time collaboration, email, and the domain name system. https://www.ietf.org/process/rfcs/ RFC thường dài, chi tiết và khô khan khó đọc (như RFC cho HTTP1.1 https://www.rfc-editor.org/rfc/rfc2616 gần 180 pages), nhưng RFC cho CSV (không) ngạc nhiên ngắn gọn đơn giản trong 7 dòng: https://www.rfc-editor.org/rfc/rfc4180#section-2 1. Each record is located on a separate line, delimited by a line break (CRLF). For example: aaa,bbb,ccc CRLF zzz,yyy,xxx CRLF 2. The last record in the file may or may not have an ending line break. For example: aaa,bbb,ccc CRLF zzz,yyy,xxx 3. There maybe an option...

Điều gì tệ hơn "mất bò mới lo làm chuồng"

Nửa tháng sau khi GitHub action tj-actions/changed-file bị hack , thế giới có gì thay đổi? Xưa các cụ có câu "mất bò mới lo làm chuồng", nhằm phê phán việc không quan tâm đến chuồng của con bò. Nhưng điều tệ hơn là gì? mất bò xong vẫn không làm chuồng Trong ngành IT (hay việc gì cũng thế), thất bại là chỗ người ta rút kinh nhiệm để tiến bộ hơn, phát triển hơn hôm qua. Thôi thì qua đã mất bò thì làm chuồng để mai không mất nữa. Nhưng như mọi "kinh nghiệm", nó không được học qua "chuyện kể"/"lời khuyên" mà chỉ thực sự thấm nếu đã phải trả giá. Internet vẫn tiếp tục dùng GitHub action không pinning tới SHA1 commit hash... Blog FAMILUG do 1 phút lười biếng cũng dùng GHA nelsonjchen/gh-pages-pelican-action@master , để rồi hôm nay trả giá 30 phút gỡ bỏ GHA này. GHA build blog FAMILUG giờ chỉ còn dùng action chính thức của GitHub. Mà nếu GitHub bị hack... thì mọi lo lắng khác đều không có nghĩa lý gì khi blog familug.github.io chạy trên GitHub pag...

Rust tuple, array, slice và compile time size

Hay làm thế nào để "stack overflow" trong Rust. Tuple và array là 2 kiểu dữ liệu primitive compound trong Rust. Compound types can group multiple values into one type. Compound type có thể gộp nhiều giá trị vào 1 kiểu. Xem code online và làm theo tại playground . Tuple Tuple là 1 cách để gộp nhiều giá trị có kiểu khác nhau vào 1 kiểu compound (kiểu gộp?). Các phần tử của tuple nằm trong cặp () , phân cách nhau bằng dấu phẩy , . Tuple hỗ trợ phép destructuring , để tách 1 tuple thành nhiều phần (tương tự Python unpacking). Truy cập từng phần tử theo thứ tự bằng cú pháp T.0 T.1 T.2 ... fn main() { let tup = ("Pika", 42); // type (&str, i32) let (name, number) = tup; println!("Name: {name}: number {number}"); println!("Name: {}", tup.0); } // Name: Pika: number 42 // Name: Pika Tuple không chứa phần tử nào gọi là 1 unit () . Các biểu thức không trả về gì sẽ tự động return unit () . Array An array is a fixed-size s...

Popular posts from this blog

Tài liệu và hướng dẫn học Python

Để tiết kiệm thời gian, tốt nhất là đi học PyMI Updated: 130617 Sau đây là các tài liệu khuyên dùng: Vì nhiều lý do, nên học python2.7 tại thời điểm hiện tại (giờ là tháng 6/2013 - muốn biết tại sao thì tự tìm hiểu) python 3.5+ (giờ là tháng 2/2017) Chuẩn bị: 1. biết bật tắt máy 2. biết cài python 3. tập gõ 10 ngón - gõ 2 ngón hay 1 ngón cũng không sao, nhưng 10 ngón là cách dễ nhất để gõ nhanh nhất. Tài liệu - Nên dùng tài liệu tại trang chủ của Python làm chính, tham khảo thêm các tài liệu khác tại http://www.familug.org/2016/12/free-ebook.html Căn bản, mới học 1.1 Python PyMI.vn https://pymi.vn/tutorial/ 1.2. Python offical tutorial kết hợp làm bài tập trên HackerRank  (đề bài bằng tiếng Anh, nhưng Google translate 1 lúc cũng ra vì có nhiều ví dụ mẫu đi kèm). Học viên của Pymi.vn có rất nhiều học viên đã tự học với Learn Python the hard way nhưng chưa thấy ai thành công cả. Hai link dưới nên đọc sau khi đã nắm được những phần cơ bản của ngôn ngữ pytho...

The PyMiers

New FAMILUG