A word on this blog.
A word on this blog.
Witam 👋 This is my personal corner of the internet — a collection of technical notes, experiments, projects, and things I don’t want to rediscover twice. It started as a pile of private notes. Over time, I moved them to Markdown so they could be searchable, version-controlled, and, when useful, published here. The site is built with Hugo, the HB Framework, and deployed with GitHub Pages.
📻 Building My Self-Hosted RSS Reader
🔔 Customize RSS Feed in Hugo
✨ How to Write a Hugo Shortcode
💫 Podman as a service
💫 Podman as a service
Run rootless Podman containers as persistent systemd services, without introducing Kubernetes.
🎺 How to Create a Widget for Hugo.
🔭 My New Blog
🔭 My New Blog
Sometimes in life, you need to upgrade. This article walks through the new version of my blog and the discoveries that came with it.
⚡ Hugo
⚡ Hugo
What is Hugo Hugo is a fast static site generator, written in Go. It turns Markdown + templates + config into a static website. Install Use the extended build if you process SCSS (this theme does): 1# binary 2curl -L https://github.com/gohugoio/hugo/releases/download/v0.154.3/hugo_extended_0.154.3_linux-amd64.tar.gz | tar -xz 3sudo mv hugo /usr/local/bin/hugo 4 5# or snap 6sudo snap install hugo You also need Dart Sass and Node/npm for SCSS + PostCSS. New site 1hugo new site myblog 2cd myblog Content 1hugo new posts/first-post.md # draft: true by default Serve / Build 1hugo server -D # dev server, include drafts 2hugo # build into public/ 3hugo --gc # build + garbage-collect cache 4hugo --minify -e production # production build Layout 1content/ source markdown 2layouts/ templates (override the theme) 3static/ files copied as-is (images, favicons) 4data/ site data (.yaml/.json/.toml) 5config/ configuration (hugo.yaml, params, menus) 6public/ generated site (gitignored) Front matter 1--- 2title: "First Post" 3date: 2026-01-01T00:00:00+02:00 4draft: true 5--- 6 7Content. Templates & partials layouts/_default/single.html, list.html, baseof.html Override anything from the theme by mirroring the path in layouts/. Partials: {{ partial "name" . }} Useful functions 1{{ .Title }} {{ .Content }} {{ .Params.custom }} 2{{ range ... }} {{ if ... }} {{ with ... }} 3{{ resources.Get "x" | minify | fingerprint }} Modules 1hugo mod get -u ./... # update modules 2hugo mod tidy 3hugo mod graph # list the module graph Key notes _index.md = section page; index.md = leaf bundle page. draft: true pages only appear with hugo server -D. The ./-relative image paths resolve against static/, not the content bundle.
🐶 GoDog
🐶 GoDog
What is GoDog GoDog is the Cucumber implementation for Go: Behaviour-Driven Development (BDD). You write scenarios in Gherkin (.feature files), then implement the steps in Go. go test runs the scenarios as normal tests. Install 1go get github.com/cucumber/godog/cmd/godog@latest In practice it is a test dependency added to your go.mod. Example 1. Feature file features/calculator.feature: 1Feature: Calculator 2 3 Scenario: add two numbers 4 Given I have a calculator 5 When I add 3 and 5 6 Then the result should be 8 2. Step definitions main_test.go:
🐹 Golang
🐹 Golang
Installation Install Go: 1GO_VERSION="1.21.0" 2 3wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz 4sudo rm -rf /usr/local/go 5sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz 6 7export PATH="/usr/local/go/bin:$PATH" 8 9go version To keep Go available after reboot: 1echo 'export PATH="/usr/local/go/bin:$PATH"' >> ~/.bashrc 2source ~/.bashrc Create a project 1mkdir myapp 2cd myapp 3 4go mod init myapp A go.mod file is created: 1myapp/ 2└── go.mod It describes the Go module and its dependencies. Hello World Create main.go: 1package main 2 3import "fmt" 4 5func main() { 6 fmt.Println("Hello World") 7} 1go run . 2go build This creates a binary: ./myapp
Projects
Projects
Just a short list of personnal projects, I am currently working on.
🎉 The Beauty of WSL
🎉 The Beauty of WSL
WSL stands for Windows Subsystem for Linux. It allows us to get the best of both the Linux and Windows worlds...
🚩 Firewalld
🚩 Firewalld
Basic Troubleshooting 1# Get the state 2firewall-cmd --state 3systemctl status firewalld 4 5# Get infos 6firewall-cmd --get-default-zone 7firewall-cmd --get-active-zones 8firewall-cmd --get-zones 9firewall-cmd --set-default-zone=home 10 11firewall-cmd --permanent --zone=FedoraWorkstation --add-source=00:FF:B0:CB:30:0A 12firewall-cmd --permanent --zone=FedoraWorkstation --add-service=ssh 13 14firewall-cmd --get-log-denied 15firewall-cmd --set-log-denied=<all, unicast, broadcast, multicast, or off> Add/Remove/List Services 1#Remove 2firewall-cmd --zone=public --add-service=ftp --permanent 3firewall-cmd --zone=public --remove-service=ftp --permanent 4firewall-cmd --zone=public --remove-port=53/tcp --permanent 5firewall-cmd --zone=public --list-services 6 7# Add 8firewall-cmd --zone=public --new-service=portal --permanent 9firewall-cmd --zone=public --service=portal --add-port=8080/tcp --permanent 10firewall-cmd --zone=public --service=portal --add-port=8443/tcp --permanent 11firewall-cmd --zone=public --add-service=portal --permanent 12firewall-cmd --reload 13 14firewall-cmd --zone=public --new-service=k3s-server --permanent 15firewall-cmd --zone=public --service=k3s-server --add-port=443/tcp --permanent 16firewall-cmd --zone=public --service=k3s-server --add-port=6443/tcp --permanent 17firewall-cmd --zone=public --service=k3s-server --add-port=8472/udp --permanent 18firewall-cmd --zone=public --service=k3s-server --add-port=10250/tcp --permanent 19firewall-cmd --zone=public --add-service=k3s-server --permanent 20firewall-cmd --reload 21 22firewall-cmd --zone=public --new-service=quay --permanent 23firewall-cmd --zone=public --service=quay --add-port=8443/tcp --permanent 24firewall-cmd --zone=public --add-service=quay --permanent 25firewall-cmd --reload 26 27firewall-cmd --get-services # It's also possible to add a service from list 28firewall-cmd --runtime-to-permanent Checks and Get infos list open port by services 1for s in `firewall-cmd --list-services`; do echo $s; firewall-cmd --permanent --service "$s" --get-ports; done; 2 3sudo sh -c 'for s in `firewall-cmd --list-services`; do echo $s; firewall-cmd --permanent --service "$s" --get-ports; done;' 4ssh 522/tcp 6dhcpv6-client 7546/udp Check one service 1firewall-cmd --info-service cfrm-IC 2cfrm-IC 3 ports: 7780/tcp 8440/tcp 8443/tcp 4 protocols: 5 source-ports: 6 modules: 7 destination: List zones and services associated 1firewall-cmd --list-all 2public (active) 3 target: default 4 icmp-block-inversion: no 5 interfaces: ens192 6 sources: 7 services: ssh dhcpv6-client https Oracle nimsoft 8 ports: 10050/tcp 1521/tcp 9 protocols: 10 masquerade: no 11 forward-ports: 12 source-ports: 13 icmp-blocks: 14 rich rules: 1firewall-cmd --zone=backup --list-all Get active zones 1firewall-cmd --get-active-zones 2backup 3 interfaces: ens224 4public 5 interfaces: ens192 Tree folder 1ls /etc/firewalld/ 2firewalld.conf helpers/ icmptypes/ ipsets/ lockdown-whitelist.xml services/ zones/ IPSET 1firewall-cmd --get-ipset-types 2firewall-cmd --permanent --get-ipsets 3firewall-cmd --permanent --info-ipset=integration 4firewall-cmd --ipset=integration --get-entries 5 6firewall-cmd --permanent --new-ipset=test --type=hash:net 7firewall-cmd --ipset=local-blocklist --add-entry=103.133.104.0/23
⚙️ Systemd
⚙️ Systemd
systemd replaces the SysV init system: services are managed with systemctl, and runlevels map to targets. 1systemctl status <unit> # status of a service. 2systemctl start|stop|restart <unit> # run / stop / restart. 3systemctl enable|disable <unit> # start at boot (or not). 4systemctl isolate multi-user.target # equivalent of runlevel 3. 5systemctl set-default multi-user.target # change the default target. 6systemctl get-default See the Runlevels & Shutdown page for the classic runlevel table.
👺 The Bad, the Good and the Ugly Git
👢 Boot
👢 Boot
The Boot - starting process - The BIOS is started automatically and detects the peripherals. - Loads the boot routine from the MBR (Master Boot Record) - it is the boot disk, located on the first sector of the hard disk. - The MBR contains a loader that loads the "second stage loader": this is the "boot loader" specific to the system being loaded. -> Linux uses LILO (Linux Loader) or GRUB (Grand Unified Bootloader). - LILO loads the kernel into memory, decompresses it, and passes it the parameters. - The kernel mounts the `/` filesystem (from there, the commands in `/sbin` and `/bin` are available). - The kernel runs its first process: `init`. LILO is a legacy bootloader (obsolete), superseded by GRUB and now GRUB2. The LILO section below is kept for historical reference. LILO configuration LILO can offer several kernels as choices. The default choice: “Linux”. /etc/lilo.conf : configuration of the kernel parameters. /sbin/lilo : to write the new parameters to disk. -> creates the /boot/map file, which contains the physical blocks where the boot program is located.
🔄 Data Guard
🔄 Data Guard
Synchronisation mechanism between two databases in Active/Passive. Switchover 1dgmgrl sys@orcl 2DGMGRL> switchover to 'orcl'; Check primary / standby 1echo -e "set heading off;\n select database_role FROM v\$database;" | sqlplus -S / as sysdba 2# PHYSICAL STANDBY (or PRIMARY) 3 4echo -e "set heading off;\n select open_mode FROM v\$database;" | sqlplus -S / as sysdba 5# MOUNTED (a standby is mounted, not open) PRIMARY + READ WRITE → primary. PHYSICAL STANDBY + MOUNTED → standby.
🕵️ Auditing
🕵️ Auditing
Enable auditing 1ALTER SYSTEM SET audit_trail = DB, EXTENDED SCOPE = SPFILE; -- detailed user actions. 2SHOW PARAMETER audit_trail; -- default NONE → set it to EXTENDED where possible. 3SHOW PARAMETER audit; -- the full audit configuration. Audit users 1AUDIT SELECT TABLE, UPDATE TABLE, INSERT TABLE BY hr BY SESSION; 2AUDIT SELECT TABLE, UPDATE TABLE, INSERT TABLE BY hr BY SESSION WHENEVER SUCCESSFUL; 3AUDIT SELECT TABLE, UPDATE TABLE, INSERT TABLE BY hr BY SESSION WHENEVER NOT SUCCESSFUL; 4AUDIT SELECT TABLE, UPDATE TABLE, INSERT TABLE BY hr BY ACCESS; 5AUDIT SELECT TABLE, UPDATE TABLE, INSERT TABLE BY hr BY ACCESS WHENEVER SUCCESSFUL; 6AUDIT SELECT TABLE, UPDATE TABLE, INSERT TABLE BY hr BY ACCESS WHENEVER NOT SUCCESSFUL; 7 8AUDIT ALL BY ACCESS; -- alternatively, audit everything. Audit tables 1AUDIT SELECT, INSERT, UPDATE ON hr.employees BY SESSION; 2AUDIT SELECT, INSERT, UPDATE ON hr.employees BY SESSION WHENEVER SUCCESSFUL; 3AUDIT SELECT, INSERT, UPDATE ON hr.employees BY SESSION WHENEVER NOT SUCCESSFUL; 4AUDIT SELECT, INSERT, UPDATE ON hr.employees BY ACCESS; 5AUDIT SELECT, INSERT, UPDATE ON hr.employees BY ACCESS WHENEVER SUCCESSFUL; 6AUDIT SELECT, INSERT, UPDATE ON hr.employees BY ACCESS WHENEVER NOT SUCCESSFUL; View the audit trail 1SELECT * FROM dba_audit_trail WHERE username = 'HR'; -- the audited actions of a user. 2SELECT * FROM dba_stmt_audit_opts; -- the user-level audits enabled. 3SELECT * FROM dba_obj_audit_opts; -- the object-level audits enabled.
💾 Backup & Recovery (RMAN)
💾 Backup & Recovery (RMAN)
Connect 1rman 2RMAN> connect target 1rman target / With a recovery catalog: 1rman target sys/<pwd>@orcl catalog repo/<pwd>@rmancat 1RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON; -- enables restoring the CONTROLFILE. 2RMAN> SHOW ALL; -- the whole RMAN configuration. Backup 1RMAN> BACKUP DATABASE; -- full backup. 2RMAN> BACKUP DATABASE PLUS ARCHIVELOG; -- full + archived logs. 3RMAN> BACKUP INCREMENTAL LEVEL 0 DATABASE; -- level 0 = baseline. 4RMAN> BACKUP INCREMENTAL LEVEL 1 DATABASE; -- level 1 = incremental. 5RMAN> BACKUP CUMULATIVE INCREMENTAL LEVEL 1 DATABASE; -- cumulative increments. 6RMAN> BACKUP AS COMPRESSED BACKUPSET DATABASE; -- compressed full backup. 7RMAN> BACKUP ARCHIVELOG UNTIL TIME 'sysdate - 1/24' ALL DELETE INPUT; Run a script:
🔁 Redo Log & Archivelog
🔁 Redo Log & Archivelog
Redo log principles The redo log files keep a trace of every data alteration, so that after a crash they can replay the changes. You need at least two, and they deserve careful attention for both backup and access optimisation. In ARCHIVELOG mode the redo logs are archived — keeping a full trace of all changes, not just what fits within the redo log file size. The redo buffer is flushed to disk when it is full, so the redo log files should be at least as large as the redo log buffer (log_buffer).
⚙️ SPFILE & PFILE
⚙️ SPFILE & PFILE
Configuration via init.ora (PFILE) init.<SID>.ora was the way to configure Oracle 8/9. It is the database parameter file — without it the database cannot start. Default location: $ORACLE_HOME/dbs (UNIX) or %ORACLE_HOME%\database (Windows). Sometimes a system stays on `init..ora` even on 11g/12c, because the instance was upgraded from an old version. Examples of parameters:
🚚 Move / Clone a Database
🚚 Move / Clone a Database
Copy the source database oraprd into a target test database oratest (created beforehand). The copy stops oratest and replaces its files with oraprd’s, then makes them take effect. 1. Generate the control-file script 1ALTER DATABASE BACKUP CONTROLFILE TO TRACE; This writes a trace file into user_dump_dest. The relevant part looks like: 1STARTUP NOMOUNT 2CREATE CONTROLFILE REUSE DATABASE "oraprd" NORESETLOGS ARCHIVELOG 3MAXLOGFILES 5 4MAXLOGMEMBERS 3 5MAXDATAFILES 100 6MAXINSTANCES 1 7MAXLOGHISTORY 908 8LOGFILE 9 GROUP 1 'G:\ORACLE\ORADATA\oraprd\REDO01.LOG' SIZE 10M, 10 GROUP 1 'G:\ORACLE\ORADATA\oraprd\REDO02.LOG' SIZE 10M, 11 GROUP 2 'F:\ORACLE\ORADATA\oraprd\REDO03.LOG' SIZE 10M, 12 GROUP 2 'F:\ORACLE\ORADATA\oraprd\REDO04.LOG' SIZE 10M 13DATAFILE 14 'F:\ORACLE\ORADATA\oraprd\SYSTEM01.DBF', 15 'F:\ORACLE\ORADATA\oraprd\CWMLITE01.DBF', 16 'F:\ORACLE\ORADATA\oraprd\DATA\DATPRD.DBF', 17 ... (the whole list of datafiles) 18CHARACTER SET WE8MSWIN1252 19; 20 21RECOVER DATABASE 22ALTER SYSTEM ARCHIVE LOG ALL; 23ALTER DATABASE OPEN; 24ALTER TABLESPACE TEMP ADD TEMPFILE 'G:\ORACLE\ORADATA\oraprd\TEMP02.DBF' SIZE 2000M REUSE AUTOEXTEND OFF; 2. Adapt the generated script The source database must be shut down so that all files are synchronized. Once oraprd’s files are copied over oratest, adapt the control-file script to the new paths (e.g. F:\ORACLE\ORADATA\oraprd and G:\... → D:\ORACLE\ORADATA\oratest), and change the database name:
🧪 Invalid Objects
🧪 Invalid Objects
Find invalid objects 1COL owner FOR a20 2COL object_name FOR a50 3COL subobject_name FOR a30 4 5SELECT owner, object_name, subobject_name, object_type, created 6FROM dba_objects WHERE status <> 'VALID' ORDER BY 2; Recompile — good practice after an import 1SELECT COUNT(*) FROM dba_objects WHERE status = 'INVALID'; 2-- 61 3 4@?/rdbms/admin/utlrp 5 6SELECT COUNT(*) FROM dba_objects WHERE status = 'INVALID'; 7-- 40 Recompile with a PL/SQL cursor 1SET TERMOUT ON 2SET SERVEROUTPUT ON 3DECLARE 4 CURSOR cur_invalid_objects IS 5 SELECT object_name, object_type FROM user_objects 6 WHERE object_type IN ('PROCEDURE','FUNCTION','TRIGGER','SYNONYM','VIEW', 7 'MATERIALIZED VIEW','PACKAGE','PACKAGE BODY') 8 AND status = 'INVALID'; 9 rec_columns cur_invalid_objects%ROWTYPE; 10 err_status NUMBER; 11BEGIN 12 dbms_output.enable(10000); 13 OPEN cur_invalid_objects; 14 LOOP 15 FETCH cur_invalid_objects INTO rec_columns; 16 EXIT WHEN cur_invalid_objects%NOTFOUND; 17 BEGIN 18 IF rec_columns.object_type IN ('VIEW','SYNONYM','MATERIALIZED VIEW','PACKAGE') THEN 19 dbms_output.put_line('Recompiling ' || rec_columns.object_type || ' ' || rec_columns.object_name); 20 EXECUTE IMMEDIATE 'ALTER ' || rec_columns.object_type || ' "' || rec_columns.object_name || '" COMPILE'; 21 ELSIF rec_columns.object_type = 'PACKAGE BODY' THEN 22 dbms_output.put_line('Recompiling ' || rec_columns.object_type || ' ' || rec_columns.object_name); 23 EXECUTE IMMEDIATE 'ALTER PACKAGE "' || rec_columns.object_name || '" COMPILE BODY'; 24 ELSE 25 dbms_output.put_line('Recompiling ' || rec_columns.object_type || ' ' || rec_columns.object_name); 26 dbms_ddl.alter_compile(rec_columns.object_type, NULL, rec_columns.object_name); 27 END IF; 28 EXCEPTION WHEN OTHERS THEN 29 err_status := SQLCODE; 30 dbms_output.put_line('Recompilation failed: ' || SQLERRM(err_status)); 31 END; 32 END LOOP; 33 CLOSE cur_invalid_objects; 34END; 35/ Drop invalid objects 1SET SERVEROUTPUT ON 2DECLARE 3 CURSOR cur_invalid_objects IS 4 SELECT object_name, object_type FROM user_objects 5 WHERE object_type IN ('PROCEDURE','FUNCTION','TRIGGER','SYNONYM','VIEW', 6 'MATERIALIZED VIEW','PACKAGE','PACKAGE BODY') 7 AND status = 'INVALID'; 8 rec_columns cur_invalid_objects%ROWTYPE; 9BEGIN 10 dbms_output.enable(10000); 11 OPEN cur_invalid_objects; 12 LOOP 13 FETCH cur_invalid_objects INTO rec_columns; 14 EXIT WHEN cur_invalid_objects%NOTFOUND; 15 dbms_output.put_line('DROP ' || rec_columns.object_type || ' ' || rec_columns.object_name); 16 EXECUTE IMMEDIATE 'DROP ' || rec_columns.object_type || ' ' || rec_columns.object_name; 17 END LOOP; 18 CLOSE cur_invalid_objects; 19END; 20/ `DROP ` does not map one-to-one for every object type (e.g. there is no `DROP PACKAGE BODY`, and `SYNONYM`/`TRIGGER` need care). Prefer recompiling; drop only objects you are sure you no longer need.
👥 Users, Roles & Privileges
👥 Users, Roles & Privileges
Managing users Four main concepts: USERS — with the granted PRIVILEGES. ROLES — a pack of privileges. PROFILES — a pack of limitations. Note: an unquoted SQL name is uppercase; a quoted name keeps its case as written. Creation / deletion: 1-- all users, with account status, expiry, profile, etc. 2SELECT username, profile, account_status, expiry_date, lock_date 3FROM dba_users WHERE oracle_maintained = 'N'; 4 5CREATE USER my_user IDENTIFIED BY my_password; -- create a user. 6DROP USER my_user; -- drop a user. 7DROP USER my_user CASCADE; -- drop a user and all its tables. Privileges 1SELECT * FROM dba_sys_privs; -- all possible privileges. 2SELECT * FROM dba_sys_privs WHERE grantee = 'MY_USER'; -- one user's privileges. 3 4GRANT create session, alter session, drop any index TO my_user; 5REVOKE alter session FROM my_user; Roles 1CREATE ROLE my_role; -- create a role. 2GRANT create session, alter session, drop tablespace, delete any table TO my_role; -- grant to a role. 3GRANT my_role TO my_user, hr; -- grant a role to users. 4REVOKE alter session FROM my_role; 5 6SELECT * FROM dba_roles; 7SELECT * FROM dba_role_privs WHERE grantee = 'MY_USER'; -- roles of one user. 8SELECT grantee, granted_role, admin_option, default_role FROM dba_role_privs ORDER BY 1,2; 9SELECT * FROM dba_sys_privs WHERE grantee = 'MY_ROLE'; 10SELECT * FROM dba_tab_privs WHERE grantee = 'MY_ROLE'; Profiles 1SELECT * FROM dba_profiles; -- all profiles. 2SELECT * FROM dba_profiles WHERE profile = 'MY_PROFILE'; -- one profile's limits. 3 4CREATE PROFILE my_profile LIMIT idle_time 15 connect_time 20 failed_login_attempts 50; 5ALTER USER my_user PROFILE my_profile; Account management 1ALTER USER my_user IDENTIFIED BY new_password; -- change the password. 2ALTER USER my_user ACCOUNT UNLOCK; -- unlock a user. sys / system 1ALTER USER sys IDENTIFIED BY '<password>'; 2ALTER USER system IDENTIFIED BY '<password>'; If the DB password is changed, you must also regenerate the password file (orapwd), which controls remote SYSDBA access:
💻 Oracle Clients
💻 Oracle Clients
Listener / Tnsname.ora 1# Check if listner is present 2ps -edf | grep lsn 3 4# Prompt Listner 5lsnrctl 6LSNRCTL> help 7The following operations are available 8An asterisk (*) denotes a modifier or extended command: 9 10start stop status services 11version reload save_config trace 12spawn quit exit set* 13show* 14 15lsnrctl status 16lsnrctl start 17 18# Logs 19less /opt/oracle/product/12c/db/network/admin/listener.ora Local Listner 1# in Oracle prompt 2show parameter listener; 3NAME TYPE VALUE 4------------------------------------ ----------- ------------------------------ 5listener_networks string 6local_listener string LISTENER_TOTO 7remote_listener string First LISTENER_TOTO must be defined in the tnsnames.ora. 1# in Oracle prompt 2alter system set local_listener='LISTENER_TOTO' scope=both; 3alter system register; 1lsnrctl status 2 3LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 29-APR-2021 18:58:48 4Copyright (c) 1991, 2016, Oracle. All rights reserved. 5Connecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521)) 6STATUS of the LISTENER 7------------------------ 8Alias LISTENER 9Version TNSLSNR for Linux: Version 12.2.0.1.0 - Production 10Start Date 29-APR-2021 18:11:13 11Uptime 0 days 0 hr. 47 min. 34 sec 12Trace Level off 13Security ON: Local OS Authentication 14SNMP OFF 15Listener Log File /u01/oracle/base/diag/tnslsnr/myhost/listener/alert/log.xml 16Listening Endpoints Summary... 17 (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=myhost.example.com)(PORT=1521))) 18Services Summary... 19Service "+ASM" has 1 instance(s). 20 Instance "+ASM", status READY, has 1 handler(s) for this service... 21Service "+ASM_DATA" has 1 instance(s). 22 Instance "+ASM", status READY, has 1 handler(s) for this service... 23Service "+ASM_FRA" has 1 instance(s). 24 Instance "+ASM", status READY, has 1 handler(s) for this service... 25Service "ORCL" has 1 instance(s). 26 Instance "ORCL", status READY, has 1 handler(s) for this service... 27Service "ORCLXDB" has 1 instance(s). 28 Instance "ORCL", status READY, has 1 handler(s) for this service... 29The command completed successfully Static Listner: TNSnames.ORA Services have to be listed in tnsnames.ora of client hosts.
💽 Disks ASM
💽 Disks ASM
Basics Start ASM - The old way: 1. oraenv # ora SID = +ASM1 (if second nodes +ASM2 ) 2sqlplus / as sysasm 3startup Start ASM - The new method: 1srvctl start asm -n ora-node1-hostname Check ASM volumes 1srvctl status asm 2asmcmd lsdsk 3asmcmd lsdsk -G DATA 4srvctl status diskgroup -g DATA Check clients connected to ASM volume 1# List clients 2asmcmd lsct 3 4DB_Name Status Software_Version Compatible_version Instance_Name Disk_Group 5+ASM CONNECTED 19.0.0.0.0 19.0.0.0.0 +ASM DATA 6+ASM CONNECTED 19.0.0.0.0 19.0.0.0.0 +ASM FRA 7ORCL CONNECTED 12.2.0.1.0 12.2.0.0.0 ORCL DATA 8ORCL CONNECTED 12.2.0.1.0 12.2.0.0.0 ORCL FRA 9MYDB CONNECTED 12.2.0.1.0 12.2.0.0.0 MYDB DATA 10MYDB CONNECTED 12.2.0.1.0 12.2.0.0.0 MYDB FRA 11 12# Files Open 13asmcmd lsof 14 15DB_Name Instance_Name Path 16ORCL ORCL +DATA/ORCL/DATAFILE/blob.268.1045299983 17ORCL ORCL +DATA/ORCL/DATAFILE/data.270.1045299981 18ORCL ORCL +DATA/ORCL/DATAFILE/indx.269.1045299983 19ORCL ORCL +DATA/ORCL/control01.ctl 20ORCL ORCL +DATA/ORCL/redo01a.log 21ORCL ORCL +DATA/ORCL/redo02a.log 22ORCL ORCL +DATA/ORCL/redo03a.log 23ORCL ORCL +DATA/ORCL/redo04a.log 24ORCL ORCL +DATA/ORCL/sysaux01.dbf 25[...] Connect to ASM prompt 1. oraenv # ora SID = +ASM 2asmcmd ASMlib ASMlib - provide oracleasm command: 1# list 2oracleasm listdisks 3DATA2 4FRA1 5 6# check 7oracleasm status 8Checking if ASM is loaded: yes 9Checking if /dev/oracleasm is mounted: yes 10 11# check one ASM volume 12oracleasm querydisk -d DATA2 13Disk "DATA2" is a valid ASM disk on device [8,49] 14 15# scan 16oracleasm scandisks 17Reloading disk partitions: done 18Cleaning any stale ASM disks... 19Scanning system for ASM disks... 20Instantiating disk "DATA3" 21 22# Create, delete, rename 23oracleasm createdisk DATA3 /dev/sdf1 24oracleasm deletedisk 25oracleasm renamedisk custom script to list disks handle for ASM (not relevant anymore): 1cat asmliblist.sh 2#!/bin/bash 3for asmlibdisk in `ls /dev/oracleasm/disks/*` 4 do 5 echo "ASMLIB disk name: $asmlibdisk" 6 asmdisk=`kfed read $asmlibdisk | grep dskname | tr -s ' '| cut -f2 -d' '` 7 echo "ASM disk name: $asmdisk" 8 majorminor=`ls -l $asmlibdisk | tr -s ' ' | cut -f5,6 -d' '` 9 device=`ls -l /dev | tr -s ' ' | grep -w "$majorminor" | cut -f10 -d' '` 10 echo "Device path: /dev/$device" 11 done Disks Group Disk Group : all disks in teh same DG should have same size. Different type of DG, external means that LUN replication is on storage side. When a disk is added to DG wait for rebalancing before continuing operations.
📋 Procedures
📋 Procedures
Basics find a procedures 1SELECT * 2 FROM USER_OBJECTS 3 WHERE object_type = 'PROCEDURE' 4 AND object_name = 'grant_RW' Example which give SELECT right on one schema to the role 1CREATE OR REPLACE PROCEDURE grant_RO_to_schema( 2 username VARCHAR2, 3 grantee VARCHAR2) 4AS 5BEGIN 6 FOR r IN ( 7 SELECT owner, table_name 8 FROM all_tables 9 WHERE owner = username 10 ) 11 LOOP 12 EXECUTE IMMEDIATE 13 'GRANT SELECT ON '||r.owner||'.'||r.table_name||' to ' || grantee; 14 END LOOP; 15END; 16/ 17 18-- See if procedure is ok -- 19SHOW ERRORS 20 21CREATE ROLE '${ROLE_NAME}' NOT IDENTIFIED; 22GRANT CONNECT TO '${ROLE_NAME}'; 23GRANT SELECT ANY SEQUENCE TO '${ROLE_NAME}'; 24GRANT CREATE ANY TABLE TO '${ROLE_NAME}'; 25 26-- Play the Procedure -- 27EXEC grant_RO_to_schema('${SCHEMA}','${ROLE_NAME}') Procedure which give Read/Write right to one schema: 1su - oracle -c ' 2export SQLPLUS="sqlplus -S / as sysdba" 3export ORAENV_ASK=NO; 4export ORACLE_SID='${SID}'; 5. oraenv | grep -v "remains"; 6 7${SQLPLUS} <<EOF2 8set lines 200 pages 2000; 9CREATE OR REPLACE PROCEDURE grant_RW_to_schema( 10 username VARCHAR2, 11 grantee VARCHAR2) 12AS 13BEGIN 14 FOR r IN ( 15 SELECT owner, table_name 16 FROM all_tables 17 WHERE owner = username 18 ) 19 LOOP 20 EXECUTE IMMEDIATE 21 '\''GRANT SELECT,DELETE,UPDATE,INSERT,ALTER ON '\''||r.owner||'\''.'\''||r.table_name||'\'' to '\'' || grantee; 22 END LOOP; 23END; 24/ 25CREATE ROLE '${ROLE_NAME}' NOT IDENTIFIED; 26GRANT CONNECT TO '${ROLE_NAME}'; 27GRANT SELECT ANY SEQUENCE TO '${ROLE_NAME}'; 28GRANT CREATE ANY TABLE TO '${ROLE_NAME}'; 29GRANT CREATE ANY INDEX TO '${ROLE_NAME}'; 30EXEC grant_RW_to_schema('\'''${SCHEMA}''\'','\'''${ROLE_NAME}''\'') 31exit; 32EOF2 33unset ORAENV_ASK; 34' 1-- This one is working better : 2CREATE OR REPLACE PROCEDURE grant_RW_to_schema( 3myschema VARCHAR2, 4myrole VARCHAR2) 5AS 6BEGIN 7for t in (select owner,object_name,object_type from all_objects where owner=myschema and object_type in ('TABLE','VIEW','PROCEDURE','FUNCTION','PACKAGE')) loop 8if t.object_type in ('TABLE','VIEW') then 9EXECUTE immediate 'GRANT SELECT, UPDATE, INSERT, DELETE ON '||t.owner||'.'||t.object_name||' TO '|| myrole; 10elsif t.object_type in ('PROCEDURE','FUNCTION','PACKAGE') then 11EXECUTE immediate 'GRANT EXECUTE ON '||t.owner||'.'||t.object_name||' TO '|| myrole; 12end if; 13end loop; 14end; 15/