Planet Collab

πŸ”’
❌ About FreshRSS
There are new articles available, click to refresh the page.
Before yesterdayYour RSS feeds

Linux – User Management Guide 2 – Groups

December 1st 2022 at 10:11
Linux Groups allow Linux Admins to give access to a group of users rather than individually give access. This simplifies the process and user access management. The last example is giving SSH user access into the server.

brendan@u22s1:~$ sudo useradd -m hugh
brendan@u22s1:~$ ls /home/
brendan  hugh
brendan@u22s1:~$ groups
brendan adm cdrom sudo dip plugdev lxd
brendan@u22s1:~$ groups hugh
hugh : hugh
brendan@u22s1:~$ sudo useradd -r sysuser
brendan@u22s1:~$ groups sysuser
sysuser : sysuser

brendan@u22s1:~$ tail -n 5 /etc/passwd
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
mysql:x:113:118:MySQL Server,,,:/nonexistent:/bin/false
fwupd-refresh:x:114:119:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
hugh:x:1001:1001::/home/hugh:/bin/sh
sysuser:x:998:998::/home/sysuser:/bin/sh
brendan@u22s1:~$ cat /etc/group
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:syslog,brendan
tty:x:5:
[...ommitted]
fwupd-refresh:x:119:
hugh:x:1001:
sysuser:x:998:

brendan@u22s1:~$ tail /etc/group
syslog:x:113:
uuidd:x:114:
tcpdump:x:115:
tss:x:116:
landscape:x:117:
brendan:x:1000:
mysql:x:118:
fwupd-refresh:x:119:
hugh:x:1001:
sysuser:x:998:


Explanation of the group setting
brendan:x:1000:

brendan = group name
:x = group password, nobody uses them, nobody should use them.
:1000 = Group ID (GID)
: = users members of the group


Add and remove groups:
brendan@u22s1:~$ sudo groupadd tadpoles
brendan@u22s1:~$ sudo groupdel tadpoles


Primary vs Supplementary (secondary) groups: How groups are assigned makes the difference, there is no primary or secondary groups, it it is assigned to a user, then it is said a primary group.
brendan@u22s1:~$ cat /etc/group | grep 1000
brendan:x:1000:
brendan@u22s1:~$ cat /etc/group | grep 1001
hugh:x:1001:

How to add a user to a group?
brendan@u22s1:~$ sudo groupadd frogs
brendan@u22s1:~$ tail -n 5 /etc/group
fwupd-refresh:x:119:
hugh:x:1001:
sysuser:x:998:
linux-admins:x:1002:
frogs:x:1003:

Assigning a user to a group. -a = append, -G = Group
brendan@u22s1:~$ sudo usermod -aG frogs hugh
brendan@u22s1:~$ groups hugh
hugh : hugh frogs

You can slao add the user to a group using gpasswd command.
brendan@u22s1:~$ sudo gpasswd -a hugh frogs
Adding user hugh to group frogs


If you want to change the user's primary group, use -g option like this but this is not something Linux Admins usually do.
brendan@u22s1:~$ sudo usermod -g frogs hugh

Log out and log in to start using the newly assigned user group access.
brendan@u22s1:~$ groups
brendan adm cdrom sudo dip plugdev lxd
brendan@u22s1:~$ groups brendan
brendan : brendan adm cdrom sudo dip plugdev lxd frogs


=========================================
One example of using the group is in SSH config file (/etc/ssh/sshd_config).

You can add new line to allow users like this: This works!

AllowUsers brendan hugh leah caitlin sue 

OR, simply use the group. But this works better!

AllowGroups frogs ssh-users

=========================================
How to remove a user from the group?
brendan@u22s1:~$ sudo groupadd dragonfly
brendan@u22s1:~$ sudo usermod -aG dragonfly hugh
brendan@u22s1:~$ groups hugh
hugh : hugh frogs dragonfly
brendan@u22s1:~$ sudo gpasswd -d hugh dragonfly
Removing user hugh from group dragonfly

Linux – User Management Guide 1

November 30th 2022 at 23:01
Add a new user without changing the /etc/default/useradd file.

$ sudo useradd hugh

-----------------------------------------------
This is where the useradd default exist. You can modify it to give default settings to the newly created user.

$ sudo nano /etc/default/useradd

-----------------------------------------------
Add a new user after changing the /etc/default/useradd file.

$ sudo useradd leah

-----------------------------------------------
Now, check the details.

$ tail -n 5 /etc/passwd
landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
bchoi:x:1000:1000:,,,:/home/bchoi:/bin/bash
hugh:x:1001:1001::/home/hugh:/bin/sh
leah:x:1002:1002::/home/leah:/bin/bash

User ID always starts with 1000+ number and increases by 1.
New user settings can be changed using the /etc/defaul/useradd file. Note, sometimes this file may not exists depending on Linux OS.

-----------------------------------------------
Be explicite on Linux when you can.
Remove a user

$ sudo userdel hugh
$ ls -l /home
total 4
drwxr-xr-x 5 bchoi bchoi 4096 Dec  1 08:00 bchoi
$ tail -n 5 /etc/passwd
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
bchoi:x:1000:1000:,,,:/home/bchoi:/bin/bash
leah:x:1002:1002::/home/leah:/bin/bash

-----------------------------------------------
Add the user hugh with the home directory.

$ sudo useradd -m hugh
$ ls -l /home
total 8
drwxr-xr-x 5 bchoi bchoi 4096 Dec  1 08:00 bchoi
drwxr-xr-x 2 hugh  hugh  4096 Dec  1 08:16 hugh

-----------------------------------------------
Removing the user and the home directory.

$ sudo userdel -r hugh
userdel: hugh mail spool (/var/mail/hugh) not found
$ ls -l /home
total 4
drwxr-xr-x 5 bchoi bchoi 4096 Dec  1 08:00 bchoi
$ tail -n 5 /etc/passwd
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
bchoi:x:1000:1000:,,,:/home/bchoi:/bin/bash
leah:x:1002:1002::/home/leah:/bin/bash
-----------------------------------------------
Add user back to the system

$ sudo useradd -m hugh
$ # Setting the password
$ passwd
Changing password for bchoi.
Current password:
passwd: Authentication token manipulation error
passwd: password unchanged
$ passwd
Changing password for bchoi.
Current password:
New password:
Retype new password:
Sorry, passwords do not match.
passwd: Authentication token manipulation error
passwd: password unchanged
$ passwd
Changing password for bchoi.
Current password:
New password:
Retype new password:
passwd: password updated successfully
$ sudo passwd hugh
New password:
Retype new password:
passwd: password updated successfully

-----------------------------------------------
# Create a System User, useful for automation. e.g.) run report weekkly, automate process etc. create a System account

$ sudo useradd -r sysuser
$ cat /etc/passwd | grep sysuser
sysuser:x:999:999::/home/sysuser:/bin/bash

Note,the -r option will assign user below user ID 1000.

-----------------------------------------------
Check the full options in useradd manual.

$ man useradd

-----------------------------------------------
Go over the /etc/passwd file.

$ tail -n 5 /etc/passwd
pollinate:x:111:1::/var/cache/pollinate:/bin/false
bchoi:x:1000:1000:,,,:/home/bchoi:/bin/bash
leah:x:1002:1002::/home/leah:/bin/bash
hugh:x:1003:1003::/home/hugh:/bin/bash
sysuser:x:999:999::/home/sysuser:/bin/bash

-----------------------------------------------
-----------------------------------------------
Break down of /etc/passwd

E.g.) hugh:x:1003:1003::/home/hugh:/bin/bash

hugh = password
:x: = This just indicates that an encrypted password is in use, but this is not used these days, this is just a carry over from old practice. We now use hashed user password, but it is not shown here.
:1003: = UID, User ID
:1003: = GID, Group ID
:: = User information field, "a.k.a. gecos field". Used for first and last name, optional config.
:/home/hugh: = Home directory of the user
:/bin/bash = Shell designated to the user

-----------------------------------------------
If a user has the shell deginated like, this they cannot login. Most of the time, the sysuser is configured for this like landscape user shown below.

landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin = Users cannot login

-----------------------------------------------
Check which shell is in use for your logged in user.

$ echo $SHELL
/bin/bash

-----------------------------------------------
===============================================
The actual user's password gets saved on the /etc/shadow file and it uses the Hashed password.

$ cat /etc/shadow
cat: /etc/shadow: Permission denied
$ sudo cat /etc/shadow
[sudo] password for bchoi:
root:*:18858:0:99999:7:::
daemon:*:18858:0:99999:7:::
bin:*:18858:0:99999:7:::
[...ommitted]
bchoi:$6$6Q0aDO6UlQ2iJJ67$RhL384JQ5hHJZCO2zcl1eFhCR0YEMXnSFFoAbFh8zpCpR1YoCdZ6iC6getj5dS9jqJVJdkyslEvPZmbBN59jq1:19326:0:99999:7:::
leah:!:19326:0:99999:7:::
hugh:$6$Th25rwYyFBBh9pzo$MQa2C1HH8XdDW7IBfSp985Ho7.eUXakwm7Bx.5e55vP.iYpY5vZnwg13SFuVDsF4Uq2Tjm1wc8JKQoYUcbyWK0:19326:0:99999:7:::
sysuser:!:19326::::::

-----------------------------------------------
Break down of the hashed password in the shadow file.

$ sudo cat /etc/shadow | grep hugh
hugh:$6$Th25rwYyFBBh9pzo$MQa2C1HH8XdDW7IBfSp985Ho7.eUXakwm7Bx.5e55vP.iYpY5vZnwg13SFuVDsF4Uq2Tjm1wc8JKQoYUcbyWK0:19326:0:99999:7:::

hugh: = user name
$6$Th25rwYyFBBh9pzo$MZa2C1HH8XdDW7IBfTp985Ho7.eUXakwm7Bx.5e55vP.iYpY5vXnwg13SFuVDsF4Uq2Tjm1wc8JKQoYUcbyWK0 = Hashed password, this is not the actual password
:19326 = Refers to the number of day since Unix epoc, Unix epoc is January 1st 1970.
:0 = How many days need to be passed for the user to change their password again. 0 means at anytime.
:99999 = How many days before the password reset is required? 99999 days since the Unix epoc time, which indicates infinit.
:7 = How many days the user will be reminded to change their password.
: = Until, how many days the user password will be locked.
: = How many days the account is disabled.
: = 

===============================================

MySQL 8 on Ubuntu 22.04 LTS – 3. Import excel file into MySQL using Python Pandas module

November 29th 2022 at 12:54

Follow this instructions to import excel file into MySQL database.

Presumption 1. a database is created following the previous β€œMySQL 8 on Ubuntu 22.04 LTS – 2” method.

Presumption 2. a table called sales_record is created using mysql CLI or HeidiSQL User interface or MySQL Workbench.

Follow the steps below to import the data.

Step 1. Install Python packages
$ pip install pandas xlrd sqlalchemy

Step 2. If using MySQL, install python3-mysqldb.
$ sudo apt install python3-mysqldb

Step 3. Write a simple read code and print the read information to the screen.

import pandas as pd

df = pd.read_excel('NameNumbers.xlsx')
print(df.head())


*** TIP: Use HeidiSQL user interface to manage database and tables

Step 4. Have a backup of the data daily. Use append method when you can. This script will overwrite the existing tables, so use it in the lab environment only.

$ nano importsql.py

import pandas as pd
from sqlalchemy import create_engine

df = pd.read_excel('FileNameHere.xlsx')

engine = create_engine('mysql://CHANGE_USERID:CHANGE_PASSWORD@192.168.0.211/my_table')
df.to_sql('sales_record', con=engine)

4a. Run the script created above. 
$ python importsql.py


Step 5. Append method. Use this method in the production so the records are not overwritten each time.

$ nano importsql_if_exist_append.py

import pandas as pd
from sqlalchemy import create_engine

df = pd.read_excel('FileNameHere.xlsx')

engine = create_engine('mysql://CHANGE_USERID:CHANGE_PASSWORD@192.168.0.211/my_table')
df.to_sql('sales_record', con=engine, if_exists='append')


Step 6. Prevent Pandas putting in its own index numbers. When appending, pandas will put in repeating index. 
Let SQL manage its own index.

import pandas as pd
from sqlalchemy import create_engine

df = pd.read_excel('FileNameHere.xlsx')

engine = create_engine('mysql://CHANGE_USERID:CHANGE_PASSWORD@192.168.0.211/my_table')
df.to_sql('sales_record', con=engine, if_exists='append', index=False)

Step 7. Assign IDs to the first database. 
Manually add Index colum, move it to the top. 
Update it with the following values,
Name=id, Datatype=INT, Default=AUTO_INCREMENT, Primary_Key=YES.

Step 8. Now only insert the new table values.


Reference: https://www.youtube.com/watch?v=oN0koUt3SXQ

Shell Scripting 7/50 – file test operators

November 29th 2022 at 11:48

Check if file or directory exists.

Check if the file is empty or contains some information.

Step 1. Check if file exists.

\c = keep the cursor on the same line
-e = interprete -c as seperator

The shell script:
brendan@LP50C:~/learn_bash$ cat file_test.sh
#! /bin/bash

echo -e "Enter the name of the file : \c"   <<< \c keeps the cursor on the same line
read file_name

if [ -e $file_name ]    <<< -e flag check if the file_name exists or not. Use -f flag to check if normal file. 
then
  echo "$file_name found"
 else
  echo "$file_name not found"
fi

Run the script:
brendan@LP50C:~/learn_bash$ ls
argument.sh  file_test.sh  hw.sh  ifelse.sh  user_inputs.sh  variables.sh
brendan@LP50C:~/learn_bash$ ./file_test.sh
Enter the name of the file : abc.txt
abc.txt not found
brendan@LP50C:~/learn_bash$ ./file_test.sh
Enter the name of the file : hw.sh
hw.sh found


Step 2. Check if a directory exists.

brendan@LP50C:~/learn_bash$ cat dir_test.sh
#! /bin/bash

echo -e "Enter the name of the directory : \c"
read file_name

if [ -d $file_name ]     <<< Use -d to check if it is a directory.
then
  echo "$file_name found"
 else
  echo "$file_name not found"
fi

brendan@LP50C:~/learn_bash$ ./dir_test.sh
Enter the name of the directory : my_dir
my_dir not found
brendan@LP50C:~/learn_bash$ mkdir my_dir
brendan@LP50C:~/learn_bash$ ls
argument.sh  dir_test.sh  file_test.sh  hw.sh  ifelse.sh  my_dir  user_inputs.sh  variables.sh

brendan@LP50C:~/learn_bash$ ls -lh
total 32K
-rwxr-xr-x 1 brendan brendan   80 Nov 22 00:20 argument.sh
-rwxr-xr-x 1 brendan brendan  168 Nov 29 21:26 dir_test.sh
-rwxr-xr-x 1 brendan brendan  163 Nov 29 21:16 file_test.sh
-rwxr-xr-x 1 brendan brendan  141 Nov 21 20:08 hw.sh
-rwxr-xr-x 1 brendan brendan  393 Nov 22 22:51 ifelse.sh
drwxr-xr-x 2 brendan brendan 4.0K Nov 29 21:26 my_dir
-rwxr-xr-x 1 brendan brendan   74 Nov 21 21:17 user_inputs.sh
-rwxr-xr-x 1 brendan brendan  832 Nov 21 20:35 variables.sh

brendan@LP50C:~/learn_bash$ ./dir_test.sh
Enter the name of the directory : my_dir
my_dir found


Step 3. flags to check special files and check whether file is empty or not.

-b = block special files, music, image files
-c = character special files
-s = check if a file is empty or not

-s example: Create two files and keep one empty and append a line to the other.
brendan@LP50C:~/learn_bash$ cp file_test.sh empty_file_test.sh
brendan@LP50C:~/learn_bash$ touch empty_file.txt
brendan@LP50C:~/learn_bash$ touch non_empty_file.txt
brendan@LP50C:~/learn_bash$ echo "I amd learning shell scripting." >> non_empty_file.txt
brendan@LP50C:~/learn_bash$ cat non_empty_file.txt
I amd learning shell scripting.
brendan@LP50C:~/learn_bash$ cat empty_file

brendan@LP50C:~/learn_bash$ ls -l | grep empty
-rw-r--r-- 1 brendan brendan    0 Nov 29 21:33 empty_file.txt
-rwxr-xr-x 1 brendan brendan  169 Nov 29 21:38 empty_file_test.sh
-rw-r--r-- 1 brendan brendan   32 Nov 29 21:37 non_empty_file.txt

Run the new script:

brendan@LP50C:~/learn_bash$ cat empty_file_test.sh
#! /bin/bash

echo -e "Enter the name of the file : \c"
read file_name

if [ -s $file_name ]
then
  echo "$file_name is not empty"
 else
  echo "$file_name is empty"
fi


brendan@LP50C:~/learn_bash$ ./empty_file_test.sh
Enter the name of the file : empty_file.txt
empty_file.txt is empty
brendan@LP50C:~/learn_bash$ ./empty_file_test.sh
Enter the name of the file : non_empty_file.txt
non_empty_file.txt is not empty

Step 4. Other flags
-r = Check read permission
-w = check write permission
-x = check if file has execute permission

MySQL 8 on Ubuntu 22.04 LTS – 2. Replication configuration, Master-Slave & Master-Master

November 28th 2022 at 09:56

Presumption – You have installed mysql 8.0 on both Server 1 and 2.

If you have not installed MySQL yet, use the following command to install it. Refer to my previous blog.

$ apt install mysql-server-8.0

========= MASTER – SLAVE Set up ====================

Step 1. Configure Primary server as below:

brendan@u22s1:~$ sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
brendan@u22s1:~$ cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep bind-address
bind-address            = 0.0.0.0
mysqlx-bind-address     = 127.0.0.1
brendan@u22s1:~$ cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep bind-address
bind-address            = 0.0.0.0
mysqlx-bind-address     = 127.0.0.1
brendan@u22s1:~$ cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep server-id
server-id               = 1
brendan@u22s1:~$ cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep log_bin
log_bin                 = /var/log/mysql/mysql-bin.log



Step 2. Log into mysql as root user and grant the GRANT OPTION.

brendan@u22s1:~$ sudo mysql -u root -p
Enter password:

mysql> CREATE USER 'root'@'%' IDENTIFIED BY 'K0ala!@#$%';
Query OK, 0 rows affected (0.01 sec)

mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)


Step 3. Create repl user with password and grant REPLICATION as SLAVE server.

mysql> CREATE USER 'repl'@'192.168.0.212' IDENTIFIED BY 'K0ala!@#$%';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.0.212';
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW MASTER STATUS \G
*************************** 1. row ***************************
             File: binlog.000110
         Position: 1755
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)


Step 4. Check mysql

brendan@u22s2:~$ systemctl status mysql
● mysql.service - MySQL Community Server
     Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2022-11-29 05:59:42 UTC; 21h left
    Process: 868 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
   Main PID: 951 (mysqld)
     Status: "Server is operational"
      Tasks: 39 (limit: 2238)
     Memory: 424.0M
        CPU: 2.750s
     CGroup: /system.slice/mysql.service
             └─951 /usr/sbin/mysqld

Nov 29 05:59:37 u22s2 systemd[1]: Starting MySQL Community Server...
Nov 29 05:59:42 u22s2 systemd[1]: Started MySQL Community Server.


Step 5. brendan@u22s2:~$ sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
brendan@u22s2:~$ sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

brendan@u22s2:~$ cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep bind-address
bind-address            = 0.0.0.0
mysqlx-bind-address     = 127.0.0.1
brendan@u22s2:~$ cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep server-id
server-id               = 2
brendan@u22s2:~$ cat /etc/mysql/mysql.conf.d/mysqld.cnf | grep log_bin
log_bin                 = /var/log/mysql/mysql-bin.log


Step 6. log into mysql as root and configure replication settings based on the master configs.

brendan@u22s2:~$ sudo mysql -u root -p

mysql> CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.0.211', SOURCE_LOG_FILE='binlog.000110', SOURCE_LOG_POS=1755, SOURCE_SSL=1;

mysql> START REPLICA USER='repl' PASSWORD='K0ala!@#$%';

mysql> SHOW REPLICA STATUS \G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 192.168.0.211
                  Source_User: repl
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: binlog.000110
          Read_Source_Log_Pos: 1755
               Relay_Log_File: u22s2-relay-bin.000002
                Relay_Log_Pos: 323
        Relay_Source_Log_File: binlog.000110
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB:
[...ommitted]


mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.01 sec)


Step 7. Log into the Master server and create a test database.

brendan@u22s1:~$ sudo mysql -u root -p

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydemodb           |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

mysql> CREATE DATABASE testdb01;
Query OK, 1 row affected (0.01 sec)


Step 8. Check the data replication on the slave server.

brendan@u22s2:~$ sudo mysql -u root -p

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb01           |
+--------------------+
5 rows in set (0.00 sec)

If you continue, then this will become master-to-master set-up.

====== MASTER – MASTER Set up ====================

Step 1. Create repl user with password.

brendan@u22s2:~$ sudo mysql -u root -p

mysql> CREATE USER 'repl'@'192.168.0.211' IDENTIFIED BY 'K0ala!@#$%';
Query OK, 0 rows affected (0.02 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.0.211';
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW MASTER STATUS \G
*************************** 1. row ***************************
             File: mysql-bin.000001
         Position: 917
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)

Step 2. On Master 1, change the config.
brendan@u22s1:~$ sudo mysql -u root -p

mysql> CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.0.212', SOURCE_LOG_FILE='mysql-bin.000001', SOURCE_LOG_POS=917, SOURCE_SSL=1;
Query OK, 0 rows affected (0.01 sec)

mysql> START REPLICA USER='repl' PASSWORD='K0ala!@#$%';

mysql> START REPLICA USER='repl' PASSWORD='K0ala!@#$%';
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> SHOW REPLICA STATUS \G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: 192.168.0.212
                  Source_User: repl
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: mysql-bin.000001
          Read_Source_Log_Pos: 917
               Relay_Log_File: u22s1-relay-bin.000002
                Relay_Log_Pos: 326
        Relay_Source_Log_File: mysql-bin.000001
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB:
[...ommitted]

Step 3. On Master 2, create a table.

brendan@u22s2:~$ sudo mysql -u root -p

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb01           |
+--------------------+
5 rows in set (0.01 sec)

mysql> use testdb01
Database changed

mysql> CREATE TABLE students (id int, name varchar(255));
Query OK, 0 rows affected (0.07 sec)

mysql> show tables;
+--------------------+
| Tables_in_testdb01 |
+--------------------+
| students           |
+--------------------+
1 row in set (0.01 sec)


Step 4. On Master 1, check the changes.

brendan@u22s1:~$ sudo mysql -u root -p

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mydemodb           |
| mysql              |
| performance_schema |
| sys                |
| testdb01           |
+--------------------+
6 rows in set (0.01 sec)

mysql> use testdb01;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+--------------------+
| Tables_in_testdb01 |
+--------------------+
| students           |
+--------------------+
1 row in set (0.00 sec)

mysql> show create table students;
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table                                                                                                                                             |
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| students | CREATE TABLE `students` (
  `id` int DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into students value (1, 'John');
Query OK, 1 row affected (0.00 sec)


Step 5. On Master 2, check the student John has been inserted.

brendan@u22s2:~$ sudo mysql -u root -p

mysql> use testdb01
Database changed

mysql> show tables;
+--------------------+
| Tables_in_testdb01 |
+--------------------+
| students           |
+--------------------+
1 row in set (0.01 sec)


mysql> SELECT * FROM students;
+------+------+
| id   | name |
+------+------+
|    1 | John |
+------+------+
1 row in set (0.00 sec)


mysql> insert into students value (2, 'Karen');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM students;
+------+-------+
| id   | name  |
+------+-------+
|    1 | John  |
|    2 | Karen |
+------+-------+
2 rows in set (0.00 sec)



Step 6. Finally on the Master 1... check the tables again.

mysql> SELECT * FROM students;
+------+-------+
| id   | name  |
+------+-------+
|    1 | John  |
|    2 | Karen |
+------+-------+
2 rows in set (0.00 sec)

Reference: https://www.youtube.com/watch?v=RkbIqbXCWqI

MySQL 8 on Ubuntu 22.04 LTS – 1. Installation

November 28th 2022 at 08:05

This was based on the following blog:

https://www.cyberciti.biz/faq/installing-mysql-server-on-ubuntu-22-04-lts-linux/


----------------------------------------------------------------------------------------
Step 1 – Update your system
$ sudo apt update
$ sudo apt list --upgradable # get a list of upgrades
$ sudo apt upgrade
----------------------------------------------------------------------------------------
Step 2 – Searching for MySQL 8 server packages on Ubuntu 22.04 LTS
$ apt-cache search mysql-server
$ apt info -a mysql-server-8.0
----------------------------------------------------------------------------------------
Step 3 – Installing MySQL 8 server package
$ apt install mysql-server-8.0

3a. Setting up a password for the root account
$ sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'CHANGE_MY_PASSWORD';
$ exit
----------------------------------------------------------------------------------------
Step 4 – Securing MySQL 8 server
$ sudo mysql_secure_installation

----------------------------------------------------------------------------------------
Step 5 – Enabling the MySQL server at boot time
$ sudo systemctl is-enabled mysql.service
$ sudo systemctl enable mysql.service
$ sudo systemctl status mysql.service

----------------------------------------------------------------------------------------
Step 6 – Starting/Stopping/Restarting the MySQL server
$ sudo systemctl start mysql.service
$ sudo systemctl stop mysql.service
$ sudo systemctl restart mysql.service
$ sudo journalctl -u mysql.service -xe
$ sudo tail -f /var/log/mysql/error.log

----------------------------------------------------------------------------------------
Step 7 – Login into MySQL 8 server for testing purpose
mysql -u root -p
mysql -u root -h 192.168.0.211 -p
mysql -u root -p

7a. Next, run the STATUS command that displays the version and other info about your MySQL server:
STATUS;
SHOW VARIABLES LIKE "%version%";

----------------------------------------------------------------------------------------
Step 8 – Creating a new MySQL database and user/password
CREATE DATABASE demodb;
CREATE USER 'brendan'@'%' IDENTIFIED BY 'aa09dd995C72_5355a598fc7D8ab1230a';

8a.  give permissions:
GRANT SELECT, INSERT, UPDATE, DELETE ON demodb.* TO 'brendan'@'%';

8b.  grant ALL PRIVILEGES too as follows:
GRANT ALL PRIVILEGES ON demodb.* TO 'brendan'@'%';

8c. See MySQL users and their grants:
SELECT USER,host FROM mysql.user;
SHOW GRANTS FOR brendan;

8d. Test it as follows
$ mysql -u brendan -p demodb
$ mysql -u brendan -h localhost -p demodb

-u brendan : User for login
-h localhost : Connect to host named localhost
-p : Prompt for password
demodb : Connect to database named demodb

----------------------------------------------------------------------------------------
Step 9 – MySQL 8 server configurations
$ sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

brendan@u22s1:~$ cat /etc/mysql/mysql.conf.d/mysqld.cnf
#
# The MySQL database server configuration file.
#
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
#
# For explanations see
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html

# Here is entries for some specific programs
# The following values assume you have at least 32M ram

[mysqld]
#
# * Basic Settings
#
user            = mysql
pid-file        = /var/run/mysqld/mysqld.pid
socket  = /var/run/mysqld/mysqld.sock
port            = 3306
datadir = /var/lib/mysql
log-error       = /var/log/mysql/error.log

# server LAN/VLAN IP and port
bind_address = 192.168.0.211
port = 3306
skip_external_locking
skip_name_resolve
max_allowed_packet              = 256M
max_connect_errors              = 1000000

# InnoDB
default_storage_engine          = InnoDB
innodb_buffer_pool_instances    = 1
innodb_buffer_pool_size         = 512M
innodb_file_per_table           = 1
innodb_flush_log_at_trx_commit  = 0
innodb_flush_method             = O_DIRECT
innodb_log_buffer_size          = 16M
innodb_log_file_size            = 512M
innodb_stats_on_metadata        = 0
innodb_read_io_threads          = 64
innodb_write_io_threads         = 64

# MyISAM Settings (set if you are using MyISAM)
key_buffer_size                 = 32M

low_priority_updates            = 1
concurrent_insert               = 2

# Connection Settings
max_connections                 = 100

back_log                        = 512
thread_cache_size               = 100
thread_stack                    = 192K

interactive_timeout             = 180
wait_timeout                    = 180

# Buffer Settings
join_buffer_size                = 4M
read_buffer_size                = 3M
read_rnd_buffer_size            = 4M
sort_buffer_size                = 4M

# Table Settings (see below for open file limits)
table_definition_cache          = 40000
table_open_cache                = 40000
open_files_limit                = 60000

max_heap_table_size             = 128M
tmp_table_size                  = 128M

# Search Settings
ft_min_word_len                 = 3

# Logging
log_error                       = /var/lib/mysql/mysql_error.log
log_queries_not_using_indexes   = 1
long_query_time                 = 5
slow_query_log                  = 0     # Disabled for production
slow_query_log_file             = /var/lib/mysql/mysql_slow.log

[mysqldump]
quick
quote_names
max_allowed_packet


# If MySQL is running as a replication slave, this should be
# changed. Ref https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tmpdir
# tmpdir                = /tmp
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address            = 127.0.0.1
mysqlx-bind-address     = 127.0.0.1
#
# * Fine Tuning
#
key_buffer_size         = 16M
# max_allowed_packet    = 64M
# thread_stack          = 256K

# thread_cache_size       = -1

# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched
myisam-recover-options  = BACKUP

# max_connections        = 151

# table_open_cache       = 4000

#
# * Logging and Replication
#
# Both location gets rotated by the cronjob.
#
# Log all queries
# Be aware that this log type is a performance killer.
# general_log_file        = /var/log/mysql/query.log
# general_log             = 1
#
# Error log - should be very few entries.
#
log_error = /var/log/mysql/error.log
#
# Here you can see queries with especially long duration
# slow_query_log                = 1
# slow_query_log_file   = /var/log/mysql/mysql-slow.log
# long_query_time = 2
# log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
# note: if you are setting up a replication slave, see README.Debian about
#       other settings you may need to change.
# server-id             = 1
# log_bin                       = /var/log/mysql/mysql-bin.log
# binlog_expire_logs_seconds    = 2592000
max_binlog_size   = 100M
# binlog_do_db          = include_database_name
# binlog_ignore_db      = include_database_name


----------------------------------------------------------------------------------------
Step 10. Setting up open files (number of file descriptors)
$ sudo systemctl edit mysql.service


### Editing /etc/systemd/system/mysql.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file

[Service]
LimitNOFILE=1800000

### Lines below this comment will be discarded

### /lib/systemd/system/mysql.service
# # MySQL systemd service file
#
# [Unit]
# Description=MySQL Community Server
# After=network.target
#
# [Install]
# WantedBy=multi-user.target
#
# [Service]
# Type=notify
# User=mysql
# Group=mysql
# PIDFile=/run/mysqld/mysqld.pid
# PermissionsStartOnly=true
# ExecStartPre=/usr/share/mysql/mysql-systemd-start pre
# ExecStart=/usr/sbin/mysqld
# TimeoutSec=infinity
# Restart=on-failure
# RuntimeDirectory=mysqld
# RuntimeDirectoryMode=755
# LimitNOFILE=10000
#
# # Set enviroment variable MYSQLD_PARENT_PID. This is required for restart.
# Environment=MYSQLD_PARENT_PID=1

----------------------------------------------------------------------------------------
Step 11. Create or edit the /etc/sysctl.d/100-custom.conf and add:
$ sudo nano /etc/sysctl.d/100-custom.conf
$ cat /etc/sysctl.d/100-custom.conf
fs.nr_open=1800000

----------------------------------------------------------------------------------------
Step 12. Update the changes, restart mysql and verify.
$ sudo sysctl -p /etc/sysctl.d/100-custom.conf
$ sudo systemctl daemon-reload
$ sudo systemctl restart mysql
$ mysql -u root -p -e 'SHOW GLOBAL VARIABLES LIKE "open_files_limit";'

Enter password:
+------------------+---------+
| Variable_name    | Value   |
+------------------+---------+
| open_files_limit | 1800000 |
+------------------+---------+

----------------------------------------------------------------------------------------

========= TIP 1 =====================================================================
mysql-server-8.0 vs mysql-server-core-8.0 package:

mysql-server-8.0 – In almost all cases, you need this package. It contains MySQL database server binaries, clients and system database setup.
mysql-server-core-8.0 – This package includes the server binaries but doesn’t contain all the infrastructure needed to set up system databases. So this one is more useful for those setting up Linux containers (Docker, LXD and co) and don’t need all the stuff like mysql clients.

========= TIP 2 =====================================================================
MySQL 8.xx essentials config files and ports

mysql.service – The service name. You can control it using the following systemctl command:

sudo systemctl start mysql.service
sudo systemctl stop mysql.service
sudo systemctl restart mysql.service
sudo systemctl status mysql.service

/etc/mysql/ – Main MySQL server configuration directory.

/etc/mysql/my.cnf – The MySQL database server configuration file. Edit the .my.cnf ($HOME/.my.cnf) to set user-specific options. Additional settings that can override from the following two directories:

/etc/mysql/conf.d/
/etc/mysql/mysql.conf.d/

TCP/3306 port – The TCP/3306 is the default network for the MySQL server and binds to 127.0.0.1 for security reasons. However, you can change it if you need VLAN or VPN CIDR access. Then you can access the MySQL server using the localhost socket set in the/run/mysqld/ directory.
========================================================================================

Open the firewall and reload on the Linux server.

$ sudo apt install firewalld -y
$ sudo firewall-cmd --permanent --add-service=mysql
$ sudo firewall-cmd --reload

$ sudo apt update
$ sudo apt install net-tools

$ sudo netstat -ap | grep mysql
$ sudo netstat -tupan | grep 3306
$ sudo netstat -na | grep tcp6

brendan@u22s1:~$ sudo netstat -ap | grep mysql
tcp        0      0 u22s1:mysql             0.0.0.0:*               LISTEN      22524/mysqld
tcp6       0      0 [::]:33060              [::]:*                  LISTEN      22524/mysqld
unix  2      [ ACC ]     STREAM     LISTENING     72062    22524/mysqld         /var/run/mysqld/mysqlx.sock
unix  2      [ ACC ]     STREAM     LISTENING     72064    22524/mysqld         /var/run/mysqld/mysqld.sock
unix  2      [ ]         DGRAM      CONNECTED     71924    22524/mysqld

brendan@u22s1:~$ sudo netstat -tupan | grep 3306
tcp        0      0 192.168.0.211:3306      0.0.0.0:*               LISTEN      22524/mysqld
tcp6       0      0 :::33060                :::*                    LISTEN      22524/mysqld

brendan@u22s1:~$ sudo netstat -na | grep tcp6
tcp6       0      0 :::33060                :::*                    LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN

Now if you have second server, install it now repeating above processes.

To remove your MySQL instance and start all over again, run these commands.

$ sudo systemctl stop mysql


$ sudo apt-get purge mysql-server mysql-client mysql-common mysql-server-core-* mysql-client-core-*


$ sudo rm -rf /etc/mysql /var/lib/mysql
(Optional) 

$ sudo apt autoremove
(Optional) 

$ sudo apt autoclean

Cisco IOS XE upgrade on Cisco Switches (3850 example)

November 28th 2022 at 00:06

Step 1: Read this blog

https://zartmann.dk/how-to/update-ios_xe/

Step 2. Read this blog

Step 3. Sometimes, the above methods does not work. My switches went into rommon mode after failing to upgrade. I had to perform the emergency recovery using usbflash0: of my switches. 😦 Be careful with your upgrades.

switch:

switch: emergency-install usbflash0:/cat3k_caa-universalk9.16.12.08.SPA.bin
The bootflash will be erased during install operation, continue (y/n)?y
Starting emergency recovery (usbflash0:/cat3k_caa-universalk9.16.12.08.SPA.bin)…
Reading full image into memory……………………done

Bundle Image

Kernel Address : 0x537795d4
Kernel Size : 0x3faa6d/4172397
Initramfs Address : 0x53b74044
Initramfs Size : 0xdf2c77/14625911
Compression Format: .mzip

Bootable image at @ ram:0x537795d4
Bootable image segment 0 address range [0x81100000, 0x820a0000] is in range [0x80180000, 0x90000000].
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
File "sda9:cat3k_caa-recovery.bin" uncompressed and installed, entry point: 0x816734a0
Loading Linux kernel with entry point 0x816734a0 …
Bootloader: Done loading app on core_mask: 0x3f

Launching Linux Kernel (flags = 0x5)

Initiating Emergency Installation of bundle usbflash0:/cat3k_caa-universalk9.16.12.08.SPA.bin

Reading bundle usbflash0:/cat3k_caa-universalk9.16.12.08.SPA.bin…

If you are doing the upgrade in the production, take a caution on all steps. If you are doing the green field or staging in the pre-implementation, you can break the switches as much as you need to. Nobody will teach you this, you can only learn these in the lab. Priceless…

The rebooting takes around 10-15 minutes. After my lab attempts showed some inconsistent results, I have decided to keep the production switch in he BUNDLE mode to avoid further outages.

Linux – How to delete a user and user’s home directory?

November 23rd 2022 at 03:51

To list all users:

[brendan@CentOS9s1 ~]$ cut -d: -f1 /etc/passwd
root
bin
[…ommitted]
nfsnobody
brendan
ftpuser

To remove user :
[brendan@CentOS9s1 ~]$ sudo userdel username

To remove home directory :
[brendan@CentOS9s1 ~]$ sudo rm -r /home/username

To add a home directory to an existing user :

*create a home directory

*chown this directory for the user

[brendan@CentOS9s1 ~]$ sudo usermod -d /home/directory_user

How to check a file’s MD5 value on Windows Command Line, Linux and Cisco switch/router?

November 23rd 2022 at 03:42

File name: cat3k_caa-universalk9.16.12.08.SPA.bin MD5

Correct MD5 value: 84af76eeb90008ab67aa27416cc652fb

  1. Checking MD5 on the Windows Command Line:

C:\Users\bchoi\Downloads>certutil -hashfile cat3k_caa-universalk9.16.12.08.SPA.bin MD5


MD5 hash of cat3k_caa-universalk9.16.12.08.SPA.bin:
84af76eeb90008ab67aa27416cc652fb
CertUtil: -hashfile command completed successfully.

  1. Check MD5 value on Linux

[sa-admin@syd2mgmtsftp01 ~]$ md5sum /home/ftpuser/upload/cat3k_caa-universalk9.16.12.08.SPA.bin


84af76eeb90008ab67aa27416cc652fb /home/ftpuser/upload/cat3k_caa-universalk9.16.12.08.SPA.bin

  1. Check MD5 value on a Cisco switch

SW01#verify /md5 flash:cat3k_caa-universalk9.16.12.08.SPA.bin
……………………………………………………………………………………………………………………………………………………………………………………………………………………………………………………Done!
verify /md5 (flash:cat3k_caa-universalk9.16.12.08.SPA.bin) = 84af76eeb90008ab67aa27416cc652fb

Add a new user and give sudo access on CentOS/Fedora/Red Hat Linux

November 23rd 2022 at 00:06

There are two ways to give sudo access on CentOS/Fedora/Red Hat.

  1. How to add a user to wheel group? (For CentOS/Fedora/Red Hat)

$ sudo usermod -a -G wheel new-admin

2. How to add new user and give them the full root access?

$ adduser new-admin

$ passwd new-admin

$ sudo visudo

Add/Update the following line.

## Allow root to run any commands anywhere
root ALL=(ALL) ALL

new-admin ALL=(ALL) ALL

Shell Scripting 6/50 – if, if then else, else

November 22nd 2022 at 12:54

======================================
Integer comparison

# use [ ] single square brackets if using – plus the comparison shorthand.
-eq is equal to
eg) if [β€œ$a” -eq β€œ#b” ]

-ne is not equal to
eg) if [ β€œ$a” -ne β€œ$b” ]

-gt is greater than
eg) if [ β€œ$a” -gt β€œ$b” ]

-ge is greater than or equal to
eg) if [ β€œ$a” -ge β€œ$b” ]

-lt is less than or equal to
eg) if [ β€œ$a” -lt β€œ$b” ]

-le is less than or equal to
eg) if [ β€œ$a” -le β€œ$b” ]

# Use (( )) double round brackets if you want to use symbols. The [ ] brackets will still work, but the general convention is to use (( )) brackets.

< is less than
eg) (( β€œ$a” < β€œ$b” ))

<= is less than or equal to
eg) (( β€œ$a” <= β€œ$b” ))

> is greater than
eg) (( β€œ$a” > β€œ$b” ))

>= is greater than or equal to
eg) (( β€œ$a” >= β€œ$b” ))


======================================
String comparison

= is equal to
eg) if [β€œ$a” = β€œ$b” ]

== is equal to
eg) if [β€œ$a” == β€œ$b” ]

!= is not equal to
eg) if [β€œ$a” != β€œ$b” ]

< is less than, in ASCII alphabetical order
eg) if [[β€œ$a” < β€œ$b” ]]

> is greater than, in ASCII alphabetical order
eg) if [[β€œ$a” > β€œ$b” ]]

-z string is null, has zero length

======================================

Step 1. Basic format of an if statement. It starts with "if" and finishes with "fi".

brendan@LP50C:~/learn_bash$ cp hw.sh ifelse.sh
brendan@LP50C:~/learn_bash$ nano ifelse.sh
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

if [ condition ]
then
  statement
fi



Step 2. if with single condition.

eg1) If condition is not true (false), prints nothing
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

count=10

if [ $count -eq 5 ]
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
brendan@LP50C:~/learn_bash$

eg2) If condition is true.
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

count=10

if [ $count -ne 5 ]
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Condition is TRUE


Step 3. Using (( )) and signs.

brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

count=10

if (( $count < 5 ))
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
brendan@LP50C:~/learn_bash$

brendan@LP50C:~/learn_bash$ nano ifelse.sh
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

count=10

if (( $count > 5 ))
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Condition is TRUE


Step 4. Comparing the strings.

brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

word1=bagle
word2=scone

if [ $word1  == $word2 ]
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
brendan@LP50C:~/learn_bash$

brendan@LP50C:~/learn_bash$ nano ifelse.sh
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

word1=bagle
word2=bagle

if [ $word1  == $word2 ]
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Condition is TRUE

# Single = sign is also acceptable
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

word1=bagle
word2=bagle

if [ $word1  = $word2 ]
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Condition is TRUE

Step 5. Compare the strings.

# Using single [ ] will give an error
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

word1=a

if [ $word1 < "b" ]
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
./ifelse.sh: line 5: b: No such file or directory

# We must use the [[ ]], double square brackets when comparing strings.
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

word1=a

if [[ $word1 < "b" ]]
then
  echo "Condition is TRUE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Condition is TRUE

Step 6. if else condition examples.

brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

word1=a

if [[ $word1 < "b" ]]
then
  echo "Condition is TRUE"
else
  echo "Condition is FALSE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Condition is TRUE
brendan@LP50C:~/learn_bash$ nano ifelse.sh
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

word1=a

if [[ $word1 > "b" ]]
then
  echo "Condition is TRUE"
else
  echo "Condition is FALSE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Condition is FALSE


Step 7. if, elif then, else examples.

brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

word1=a

if [[ $word1 > "b" ]]
then
  echo "Condition b is TRUE"
elif [[ $word1 == "a" ]]
then
  echo "Condition a is true"
else
  echo "Condition is FALSE"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Condition a is true


Step 8. The script always exits when the first condition becomes TRUE. See the following examples. So you have to define the conditions carefully, so your lines of codes are not wasted like the following examples.

brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

num=3

if (( $num > 1 ))
then
  echo "Your number is greater than 1"
elif (( $num > 2 ))
then
  echo "Your number is greater than 2"
elif (( $num == 3 ))
then
  echo "Your number is equal to 3"
elif (( $num < 4 ))
then
  echo "Your number is less than 4"
elif (( $num < 5 ))
then
  echo "Your number is less than 5"
else
  echo "Your number is less than 1 or greater than 5"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Your number is greater than 1


brendan@LP50C:~/learn_bash$ nano ifelse.sh
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

num=0

if (( $num > 1 ))
then
  echo "Your number is greater than 1"
elif (( $num > 2 ))
then
  echo "Your number is greater than 2"
elif (( $num == 3 ))
then
  echo "Your number is equal to 3"
elif (( $num < 4 ))
then
  echo "Your number is less than 4"
elif (( $num < 5 ))
then
  echo "Your number is less than 5"
else
  echo "Your number is less than 1 or greater than 5"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Your number is less than 4


brendan@LP50C:~/learn_bash$ nano ifelse.sh
brendan@LP50C:~/learn_bash$ cat ifelse.sh
#! /bin/bash

num=10

if (( $num > 1 ))
then
  echo "Your number is greater than 1"
elif (( $num > 2 ))
then
  echo "Your number is greater than 2"
elif (( $num == 3 ))
then
  echo "Your number is equal to 3"
elif (( $num < 4 ))
then
  echo "Your number is less than 4"
elif (( $num < 5 ))
then
  echo "Your number is less than 5"
else
  echo "Your number is less than 1 or greater than 5"
fi
brendan@LP50C:~/learn_bash$ ./ifelse.sh
Your number is greater than 1

Cisco CRS1000v for your ESXi Lab use

November 22nd 2022 at 05:59

login as: brendan
Keyboard-interactive authentication prompts from server:
| Password:
End of keyboard-interactive prompts from server



csr1000v-1#show version
Cisco IOS XE Software, Version 17.03.05
Cisco IOS Software [Amsterdam], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 17.3.5, RELEASE SOFTWARE (fc2)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2022 by Cisco Systems, Inc.
Compiled Wed 09-Feb-22 10:35 by mcpre


Cisco IOS-XE software, Copyright (c) 2005-2022 by cisco Systems, Inc.
All rights reserved.  Certain components of Cisco IOS-XE software are
licensed under the GNU General Public License ("GPL") Version 2.0.  The
software code licensed under GPL Version 2.0 is free software that comes
with ABSOLUTELY NO WARRANTY.  You can redistribute and/or modify such
GPL code under the terms of GPL Version 2.0.  For more details, see the
documentation or "License Notice" file accompanying the IOS-XE software,
or the applicable URL provided on the flyer accompanying the IOS-XE
software.


ROM: IOS-XE ROMMON

csr1000v-1 uptime is 3 hours, 10 minutes
Uptime for this control processor is 3 hours, 12 minutes
System returned to ROM by reload
System image file is "bootflash:packages.conf"
Last reload reason: reload



This product contains cryptographic features and is subject to United
States and local country laws governing import, export, transfer and
use. Delivery of Cisco cryptographic products does not imply
third-party authority to import, export, distribute or use encryption.
Importers, exporters, distributors and users are responsible for
compliance with U.S. and local country laws. By using this product you
agree to comply with applicable laws and regulations. If you are unable
to comply with U.S. and local laws, return this product immediately.

A summary of U.S. laws governing Cisco cryptographic products may be found at:
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html

If you require further assistance please contact us by sending email to
export@cisco.com.

License Level: ax
License Type: N/A(Smart License Enabled)
Next reload license Level: ax

The current throughput level is 1000 kbps


Smart Licensing Status: UNREGISTERED/No Licenses in Use

cisco CSR1000V (VXE) processor (revision VXE) with 2071712K/3075K bytes of memory.
Processor board ID 9GYDW1WDZ6C
Router operating mode: Autonomous
3 Gigabit Ethernet interfaces
32768K bytes of non-volatile configuration memory.
3978416K bytes of physical memory.
6188032K bytes of virtual hard disk at bootflash:.

Configuration register is 0x2102

# Routing protocols supported
csr1000v-1#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
csr1000v-1(config)#router ?
  bgp       Border Gateway Protocol (BGP)
  eigrp     Enhanced Interior Gateway Routing Protocol (EIGRP)
  isis      ISO IS-IS
  iso-igrp  IGRP for OSI networks
  lisp      Locator/ID Separation Protocol
  mobile    Mobile routes
  nhrp      Next Hop Resolution Protocol (NHRP)
  odr       On Demand stub Routes
  ospf      Open Shortest Path First (OSPF)
  ospfv3    OSPFv3
  rip       Routing Information Protocol (RIP)


# BGP features
csr1000v-1(config)#router bgp 1
csr1000v-1(config-router)#address-family ?
  ipv4        Address family
  ipv6        Address family
  l2vpn       Address family
  link-state  Address family
  nsap        Address family
  rtfilter    Address family
  vpnv4       Address family
  vpnv6       Address family

csr1000v-1(config-router)#exit
csr1000v-1(config)#ipv6 unicast-routing
csr1000v-1(config)#router ospfv3 1
csr1000v-1(config-router)#address-family ?
  ipv4  Address family
  ipv6  Address family

# ospfv3 features
csr1000v-1(config-router)#address-family ipv4
csr1000v-1(config-router-af)#?
Router Address Family configuration commands:
  adjacency                Control adjacency formation
  area                     OSPF area parameters
  authentication           Authentication parameters
  auto-cost                Calculate OSPF interface cost according to bandwidth
  auto-cost-determination  Calculate OSPF interface cost according to bandwidth
  bfd                      BFD configuration commands
  compatible               Compatibility list
  default                  Set a command to its defaults
  default-information      Control distribution of default information
  default-metric           Set metric of redistributed routes
  discard-route            Enable or disable discard-route installation
  distance                 Define an administrative distance
  distribute-list          Filter networks in routing updates
  event-log                Event Logging
  exit-address-family      Exit from Address Family configuration mode
  graceful-restart         Graceful-restart options
  help                     Description of the interactive help system
  ignore                   Do not complain about specific event
  interface-id             Source of the interface ID
  limit                    Limit a specific OSPF feature
  local-rib-criteria       Enable or disable usage of local RIB as route criteria
  log-adjacency-changes    Log changes in adjacency state
  manet                    Specify MANET OSPF parameters
  max-lsa                  Maximum number of non self-generated LSAs to accept
  max-metric               Set maximum metric
  maximum-paths            Forward packets over multiple paths
  mpls                     MPLS Traffic Engineering configs
  no                       Negate a command or set its defaults
  nsr                      Enable non-stop routing
  passive-interface        Suppress routing updates on an interface
  prefix-suppression       Enable prefix suppression
  process-min-time         Percentage of quantum to be used before releasing CPU
  queue-depth              Hello/Router process queue depth
  redistribute             Redistribute information from another routing protocol
  router-id                router-id for this OSPF process
  shutdown                 Shutdown the router process
  snmp                     Modify snmp parameters
  statistics               Enable or disable OSPF statistics options
  summary-address          Configure IP address summaries
  summary-prefix           Configure IP address summaries
  table-map                Map external entry attributes into routing table
  timers                   Adjust routing timers

# Platform to virtual nic mapping
csr1000v-1(config-router-af)#end
csr1000v-1#show platform software vnic-if interface-mapping
-------------------------------------------------------------
 Interface Name        Driver Name         Mac Addr
-------------------------------------------------------------
 GigabitEthernet3       net_vmxnet3        000c.2981.b8c4
 GigabitEthernet2       net_vmxnet3        000c.2981.b8ba
 GigabitEthernet1       net_vmxnet3        000c.2981.b8b0
-------------------------------------------------------------

# Show int GigabitEthernet1
csr1000v-1#show run int g1
Building configuration...

Current configuration : 182 bytes
!
interface GigabitEthernet1
 ip dhcp client client-id ascii 9GYDW1WDZ6C
 ip address 192.168.0.221 255.255.255.0
 ip nat outside
 negotiation auto
 no mop enabled
 no mop sysid
end

# Only connects at 1MB on demo license. The device is unregistered and operates with a default throughput of 1 Mbps.
csr1000v-1#show platform hardware throughput level
The current throughput level is 1000 kb/s
csr1000v-1#

Shell Scripting 5/50 – Passing arguments to shell script

November 21st 2022 at 14:24


Example 01) passing arguments while running the shell script.
brendan@LP50C:~/learn_bash$ cat argument.sh
#! /bin/bash

echo $1 $2 $3 '> echo $1 $2 $3'

brendan@LP50C:~/learn_bash$ ./argument.sh John Mike Sandra
John Mike Sandra > echo $1 $2 $3


Example 02) $0 position will take the name of the shell script as the argument.

brendan@LP50C:~/learn_bash$ cat argument.sh
#! /bin/bash

echo $0 $1 $2 $3 '> echo $1 $2 $3'

brendan@LP50C:~/learn_bash$ ./argument.sh John Mike Sandra
./argument.sh John Mike Sandra > echo $1 $2 $3


Example 03) passing all arguments as array using "$@" options. Notice that the index 0 in this case is the script name and the first itme take the index value of 1, instead of 0.

brendan@LP50C:~/learn_bash$ cat argument.sh
#! /bin/bash

echo $0 $1 $2 $3 '> echo $1 $2 $3'

args=("$@")

echo  ${args[0]} ${args[1]} ${args[2]} ${args[3]}
brendan@LP50C:~/learn_bash$ ./argument.sh John Mike Sandra
./argument.sh John Mike Sandra > echo $1 $2 $3
John Mike Sandra


Example 04) When using the argument array using "$@", the argument starts at position 0. The result is the same as before.

brendan@LP50C:~/learn_bash$ cat argument.sh
#! /bin/bash

echo $0 $1 $2 $3 '> echo $1 $2 $3'

args=("$@")

echo  ${args[0]} ${args[1]} ${args[2]}
brendan@LP50C:~/learn_bash$ ./argument.sh John Mike Sandra
./argument.sh John Mike Sandra > echo $1 $2 $3
John Mike Sandra

Example 05) The Default array variable will save the record and when you print (echo) the record using $@ sign, it will print the all items.

brendan@LP50C:~/learn_bash$ cat argument.sh
#! /bin/bash

echo $0 $1 $2 $3 '> echo $1 $2 $3'

args=("$@")

echo $@

brendan@LP50C:~/learn_bash$ ./argument.sh John Mike Sandra
./argument.sh John Mike Sandra > echo $1 $2 $3
John Mike Sandra

Example 06) To print the number of arguments passed onto the script. Use $# to show the count of the arguments passed.

brendan@LP50C:~/learn_bash$ cat argument.sh
#! /bin/bash

echo $0 $1 $2 $3 '> echo $1 $2 $3'

args=("$@")

echo $@

echo $#
brendan@LP50C:~/learn_bash$ ./argument.sh
./argument.sh > echo $1 $2 $3

0
brendan@LP50C:~/learn_bash$ ./argument.sh John Mike Sandra
./argument.sh John Mike Sandra > echo $1 $2 $3
John Mike Sandra
3

Shell Scripting 4/50- User inputs using read method

November 21st 2022 at 11:20

User input using 'read' method

Example 01) Single user input variable using read.

brendan@LP50C:~/learn_bash$ cat user_inputs.sh
#! /bin/bash

# Single user input variable
echo "Please enter your name : "
read name
echo "Your name is $name."

brendan@LP50C:~/learn_bash$ ./user_inputs.sh
Please enter your name :
Brendan
Your name is Brendan.


Example 02) Multiple user input using multiple variables
brendan@LP50C:~/learn_bash$ cat user_inputs.sh
#! /bin/bash

# Multiple user input variables
echo "Please enter three names : "
read name1 name2 name3
echo "First favorite name is $name1."
echo "Second favorite name is $name2."
echo "Third favorite name is $name3."

brendan@LP50C:~/learn_bash$ ./user_inputs.sh
Please enter your name :
Brendan
Your name is Brendan.
Please enter three names :
Hugh Leah Caitlin
First favorite name is Hugh.
Second favorite name is Leah.
Third favorite name is Caitlin.

Example 03) Get the user input on the same line using -p option.
brendan@LP50C:~/learn_bash$ cat user_inputs.sh
#! /bin/bash

# -p option to get the user input on the same line.
read -p 'Username : ' uname
echo "Your username is $uname"
brendan@LP50C:~/learn_bash$ ./user_inputs.sh
Username : bchoi
Your username is bchoi

Example 04) Make the input silent, like password to hide it from others. Usse -sp option.
brendan@LP50C:~/learn_bash$ cat user_inputs.sh
#! /bin/bash

# -p option to get the user input on the same line.
read -p 'Username : ' ur_name
read -sp 'Password : ' ur_pass
echo
echo "Your username is $ur_name"
echo "Your have entered $ur_pass"

brendan@LP50C:~/learn_bash$ ./user_inputs.sh
Username : bchoi
Password :                         <<<I entered the password but does not show here.
Your username is bchoi
Your have entered Emu2022

Example 05) Reading the user input and read it as an array of values, using -a flag.

brendan@LP50C:~/learn_bash$ cat user_inputs.sh
#! /bin/bash

echo "Enter multiple names : "
read -a names
echo "Names : ${names[0]}, ${names[2]}"

brendan@LP50C:~/learn_bash$ ./user_inputs.sh
Enter multiple names :
Jane Michael John Mary Louis
Names : Jane, John
brendan@LP50C:~/learn_bash$

Example 06) read without any variable definition, $REPLY will kick in and display your variables.

brendan@LP50C:~/learn_bash$ cat user_inputs.sh
#! /bin/bash

echo "Enter multiple names : "
read
echo "Names : $REPLY"

brendan@LP50C:~/learn_bash$ ./user_inputs.sh
Enter multiple names :
George Sue Jack Bob Kate
Names : George Sue Jack Bob Kate

Shell Scripting 3/50 – Variables

November 21st 2022 at 10:30
1. System variables - created and maintained by the OS. Usually written in Upper case letters.
2. User defined variables - created and mained by the users. Uses Lower case letters preferrably.
3. You have to follow certain naming conventions for naming a user defined variable.

https://google.github.io/styleguide/shellguide.html#s7-naming-conventions
Variable Names: Lower-case, with underscores to separate words. Ex: my_variable_name
Constants and Environment Variable Names: All caps, separated with underscores, declared at the top of the file. Ex: MY_CONSTANT


Step 1. Copy the hellow world shell script (hw.sh) and modify the script as below.
brendan@LP50C:~/learn_bash$ cp hw.sh variables.sh
brendan@LP50C:~/learn_bash$ vi variables.sh
brendan@LP50C:~/learn_bash$ cat variables.sh
#! /bin/bash

# System defined variable examples
echo $BASH
echo $BASH_VERSION
echo $HOME
echo $PWD

echo Shell name is $BASH
echo Shell version name is $BASH_VERSION
echo Home directory is $HOME
echo Current working directory is $PWD

echo ====================================
# User defined variable examples
name=Brendan
echo $name
echo The name is $name
age=21
echo The name is $name and he is $age years old.

# You cannot name a variable with a digit. This will give an error.
5val=5
echo value $5val

# This variable name is works.
val5=5
echo value $val5

# This varialbe name is also works.
VALUE=10
echo The value is $VALUE

# This varialbe name is fine.
new_VALUE=30
echo The new value is $new_VALUE

# \ negates the meaning of a $ and can be used like this.
house_value=1000000
echo Your house value is \$$house_value dollars.

Step 2. Now run the variables.sh script, the result will looks similar to this.

brendan@LP50C:~/learn_bash$ ./variables.sh
/bin/bash
5.1.16(1)-release
/home/brendan
/home/brendan/learn_bash
Shell name is /bin/bash
Shell version name is 5.1.16(1)-release
Home directory is /home/brendan
Current working directory is /home/brendan/learn_bash
====================================
Brendan
The name is Brendan
The name is Brendan and he is 21 years old.
./variables.sh: line 23: 5val=5: command not found
value val
value 5
The value is 10
The new value is 30
Your house value is $1000000 dollars.

Linux FTP Server installation, configuration and testing – The ultimate guide

November 21st 2022 at 08:10

Surprisingly, still so many network and security devices only support FTP, not SFTP. I have been digging hard to get the FTP server installation and configuration right. Now this is the final vsftpd working version.


Step 1. Create a ftpuser
[brendan@centos9s1 ~]$ sudo useradd ftpuser
[brendan@centos9s1 ~]$ sudo passwd ftpuser


Step 2. Make a directory called 'ftp' under the new user's /home/ftpuser/ directory.
Take the full ownership of the ftp directory.

[brendan@centos9s1 ~]$ sudo mkdir /home/ftpuser/ftp
[brendan@centos9s1 ~]$ sudo chown -R ftpuser:ftpuser /home/ftpuser/ftp


Step 3a. Disable SSH login for sftpuser so he cannot manage the server via SSH connection.

[brendan@centos9s1 ~]$ sudo vim /etc/ssh/sshd_config
# Add this line at the end of sshd_config file.
DenyUsers	sftpuser

# Restart the sshd services.
[brendan@centos9s1 ~]$ sudo systemctl restart sshd

Step 3b. Allow ftp traffic on OS firewall.
[brendan@centos9s1 ~]$ sudo firewall-cmd --add-service=ftp
[brendan@centos9s1 ~]$ sudo firewall-cmd --permanent --add-port=40000-410000/tcp
[brendan@centos9s1 ~]$ sudo setsebool -P ftpd_full_access on
[brendan@centos9s1 ~]$ sudo firewall-cmd --reload

Step 4. Install FTP server using the following command

[brendan@centos9s1 ~]$ sudo yum install -y vsftpd

Step 5a. After the installation completes, enable, start and check ftp service.

[brendan@centos9s1 ~]$ sudo systemctl enable vsftpd
[brendan@centos9s1 ~]$ sudo systemctl start vsftpd
[brendan@centos9s1 ~]$ sudo systemctl stop vsftpd
[brendan@centos9s1 ~]$ sudo systemctl restart vsftpd
[brendan@centos9s1 ~]$ sudo systemctl status vsftpd

Step 5b. Use the netstat commands to see the working ports for FTP services.

[brendan@centos9s1 ~]$ netstat -ap | grep ftp
[brendan@centos9s1 ~]$ netstat -tupan | grep 21
[brendan@centos9s1 ~]$ netstat -tuna | grep tcp6

Step 6. Since we are using the user_list under etc/vsftpd/user_list to control who can access via FTP, we need to remove all users under user_list and add the user ftp as shown below. After modification, save the file.

[brendan@centos9s1 ~]$ sudo cat /etc/vsftpd/user_list
# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
# If userlist_deny=YES (default), never allow users in this file, and
# do not even prompt for a password.
# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
# for users that are denied.
ftpuser

Step 7. Modify /etc/vsftpd/vsftpd.conf file exactly as stated below. Leave all other settings as is, only change or add the following configs.

#Disable annonymous login
anonymous_enable=NO

# Allow local users to log in.
local_enable=YES

# Enable any form of FTP write command.
write_enable=YES

# Disable port 20 for security hardening.
connect_from_port_20=YES

# Jail the user to his/her own local user location only, if this is not set, they can navigate to other directories.
chroot_local_user=YES

# If YES, this supports both ipv4 and ipv6. If you want only ipv4, set listen_ipv4=YES.
listen_ipv6=YES

# This is configured as a default.
pam_service_name=vsftpd

# Use user_list file to control who can access via FTP. Modify user_list.
userlist_enable=YES
userlist_file=/etc/vsftpd/user_list
userlist_deny=NO

# Allow writing for the user.
allow_writeable_chroot=YES
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=41000

# This sets the user to their home directory. Create a directory called "ftp" under the user's home/username directory.
user_sub_token=$USER
local_root=/home/$USER/ftp


Step 8. Now restart your ftp service and test the file transfer.

[brendan@centos9s1 ~]$ sudo systemctl restart vsftpd


Step 9. From another Linux machine, log into your new FTP server and run the following test commands.

9a) login
[brendan@centos9s1 ~]$ ftp 192.168.0.101
Connected to 192.168.0.101 (192.168.0.101).
220 (vsFTPd 3.0.3)
Name (192.168.0.101:brendan): ftpuser
331 Please specify the password.
Password:************
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.

9b) Check present working directory
ftp> pwd
257 "/" is the current directory

9c) check the list of files in your root folder
ftp> ls
227 Entering Passive Mode (172,31,31,39,55,35).
150 Here comes the directory listing.
-rw-r--r--    1 1005     0               0 Nov 21 02:29 test.txt
drwxr-xr-x    2 1005     0               6 Nov 21 01:55 upload
226 Directory send OK.

9d) make and detelet a directory
ftp> mkdir test_dir
257 "/test_dir" created
ftp> rmdir test_dir
250 Remove directory operation successful.

9e) Upload a file called test.txt to the FTP server.
ftp> put test.txt
local: test.txt remote: test.txt
227 Entering Passive Mode (172,31,31,39,169,168).
150 Ok to send data.
226 Transfer complete.

9f) Download a file from the FTP server
ftp> get test77.txt
local: test77.txt remote: test77.txt
227 Entering Passive Mode (172,31,31,39,58,6).
150 Opening BINARY mode data connection for test77.txt (13 bytes).
226 Transfer complete.
13 bytes received in 8.7e-05 secs (149.43 Kbytes/sec)

9g) Check the files in your ftp directory now.
ftp> ls
227 Entering Passive Mode (172,31,31,39,227,212).
150 Here comes the directory listing.
-rw-r--r--    1 1005     1005        41416 Nov 21 06:07 sa-gs-cubicus-confg
-rw-r--r--    1 1005     1005        27737 Nov 21 05:49 syd1wan_r01-confg
-rw-r--r--    1 1005     1005        16478 Nov 21 05:49 syd3wan_rt01-confg
-rw-r--r--    1 1005     1005            0 Nov 21 06:44 test.txt
-rw-r--r--    1 0        0              13 Nov 21 06:46 test77.txt
-rw-r--r--    1 1005     1005            0 Nov 21 05:22 test_text_file01.txt
226 Directory send OK.

9h) Delete the downloaded file.
ftp> delete test77.txt
250 Delete operation successful.

9i) Open FTP and close, then quit from the session.
ftp> pwd
257 "/" is the current directory
ftp> open
Already connected to 192.168.0.101, use close first.
ftp> close
221 Goodbye.
ftp> quit

Step 10. Also use FileZilla and WinSCP from your windows machine to test your FTP server is working correctly.

If all of the above worked, then your FTP server will function beautifully. Enjoy your new FTP.

My /etc/vsftpd/vsftpd.conf file as below:

[brendan@centos9s1 ~]$ sudo cat /etc/vsftpd/vsftpd.conf
# Example config file /etc/vsftpd/vsftpd.conf
#
# The default compiled in settings are fairly paranoid. This sample file
# loosens things up a bit, to make the ftp daemon more usable.
# Please see vsftpd.conf.5 for all compiled in defaults.
#
# READ THIS: This example file is NOT an exhaustive list of vsftpd options.
# Please read the vsftpd.conf.5 manual page to get a full idea of vsftpd's
# capabilities.
#
# Allow anonymous FTP? (Beware - allowed by default if you comment this out).
anonymous_enable=no
#
# Uncomment this to allow local users to log in.
# When SELinux is enforcing check for SE bool ftp_home_dir
local_enable=YES
#
# Uncomment this to enable any form of FTP write command.
write_enable=YES
#
# Default umask for local users is 077. You may wish to change this to 022,
# if your users expect that (022 is used by most other ftpd's)
local_umask=022
#
# Uncomment this to allow the anonymous FTP user to upload files. This only
# has an effect if the above global write enable is activated. Also, you will
# obviously need to create a directory writable by the FTP user.
# When SELinux is enforcing check for SE bool allow_ftpd_anon_write, allow_ftpd_full_access
#anon_upload_enable=YES
#
# Uncomment this if you want the anonymous FTP user to be able to create
# new directories.
#anon_mkdir_write_enable=YES
#
# Activate directory messages - messages given to remote users when they
# go into a certain directory.
dirmessage_enable=YES
#
# Activate logging of uploads/downloads.
xferlog_enable=YES
#
# Make sure PORT transfer connections originate from port 20 (ftp-data).
connect_from_port_20=NO
#
# If you want, you can arrange for uploaded anonymous files to be owned by
# a different user. Note! Using "root" for uploaded files is not
# recommended!
#chown_uploads=YES
#chown_username=whoever
#
# You may override where the log file goes if you like. The default is shown
# below.
#xferlog_file=/var/log/xferlog
#
# If you want, you can have your log file in standard ftpd xferlog format.
# Note that the default log file location is /var/log/xferlog in this case.
xferlog_std_format=YES
#
# You may change the default value for timing out an idle session.
#idle_session_timeout=600
#
# You may change the default value for timing out a data connection.
#data_connection_timeout=120
#
# It is recommended that you define on your system a unique user which the
# ftp server can use as a totally isolated and unprivileged user.
#nopriv_user=ftpsecure
#
# Enable this and the server will recognise asynchronous ABOR requests. Not
# recommended for security (the code is non-trivial). Not enabling it,
# however, may confuse older FTP clients.
#async_abor_enable=YES
#
# By default the server will pretend to allow ASCII mode but in fact ignore
# the request. Turn on the below options to have the server actually do ASCII
# mangling on files when in ASCII mode. The vsftpd.conf(5) man page explains
# the behaviour when these options are disabled.
# Beware that on some FTP servers, ASCII support allows a denial of service
# attack (DoS) via the command "SIZE /big/file" in ASCII mode. vsftpd
# predicted this attack and has always been safe, reporting the size of the
# raw file.
# ASCII mangling is a horrible feature of the protocol.
#ascii_upload_enable=YES
#ascii_download_enable=YES
#
# You may fully customise the login banner string:
#ftpd_banner=Welcome to blah FTP service.
#
# You may specify a file of disallowed anonymous e-mail addresses. Apparently
# useful for combatting certain DoS attacks.
#deny_email_enable=YES
# (default follows)
#banned_email_file=/etc/vsftpd/banned_emails
#
# You may specify an explicit list of local users to chroot() to their home
# directory. If chroot_local_user is YES, then this list becomes a list of
# users to NOT chroot().
# (Warning! chroot'ing can be very dangerous. If using chroot, make sure that
# the user does not have write access to the top level directory within the
# chroot)
#chroot_local_user=YES
#chroot_list_enable=YES
# (default follows)
#chroot_list_file=/etc/vsftpd/chroot_list
#
# You may activate the "-R" option to the builtin ls. This is disabled by
# default to avoid remote users being able to cause excessive I/O on large
# sites. However, some broken FTP clients such as "ncftp" and "mirror" assume
# the presence of the "-R" option, so there is a strong case for enabling it.
#ls_recurse_enable=YES
#
# When "listen" directive is enabled, vsftpd runs in standalone mode and
# listens on IPv4 sockets. This directive cannot be used in conjunction
# with the listen_ipv6 directive.
listen=NO
#
# This directive enables listening on IPv6 sockets. By default, listening
# on the IPv6 "any" address (::) will accept connections from both IPv6
# and IPv4 clients. It is not necessary to listen on *both* IPv4 and IPv6
# sockets. If you want that (perhaps because you want to listen on specific
# addresses) then you must run two copies of vsftpd with two configuration
# files.
# Make sure, that one of the listen options is commented !!
listen_ipv6=YES

pam_service_name=vsftpd
userlist_enable=YES
userlist_file=/etc/vsftpd/user_list
userlist_deny=NO
tcp_wrappers=YES

allow_writeable_chroot=YES
pasv_enable=YES
pasv_min_port=40000
pasv_max_port=41000
user_sub_token=$USER
local_root=/home/$USER/ftp

Note: Understanding FTP Passive vs Active modes
β€’ Passive: This option transfers data over a random port specified by the FTP server from a connection made from the remote device.
β€’ Active: This option transfers data over a fixed, known port from a connection made from the FTP server.

My /etc/vsftpd/user_list file as below:

[brendan@centos9s1 ~]$ sudo cat /etc/vsftpd/user_list
# vsftpd userlist
# If userlist_deny=NO, only allow users in this file
# If userlist_deny=YES (default), never allow users in this file, and
# do not even prompt for a password.
# Note that the default vsftpd pam config also checks /etc/vsftpd/ftpusers
# for users that are denied.
ftpuser

Shell Scripting 2/50 – Comments

November 20th 2022 at 22:29

Comments - Lines of codes not executed but help readers to understand the code.
Start with '#' at the beginning of the line or after the code. This is same as in Python.

Example 1)
brendan@LP50C:~/learn_bash$ cat hw.sh
#! /bin/bash
# this is a comment
echo "Hello World!"

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!

Example 2)
#! /bin/bash
echo "Hello World!" # this is also a comment

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!


Example 3) : is shorthand for true and true does not process any parameters. The space between : and ' is important.
#! /bin/bash

: '
this is
a multi-line
comment
'
echo "Hello World!" 

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!

Example 4) BLOCK_COMMENT using : + space + '
#! /bin/bash

: '
This is a comment 1.
This is a comment 2.
This is a comment 3.
'

echo "Hello World!"

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!

Example 5) BLOCK_COMMENT Using the HEREDOC marker.

#! /bin/bash

<<'BLOCK_COMMENT'
This is a comment 1.
This is a comment 2.
This is a comment 3.
BLOCK_COMMENT

echo "Hello World!"

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!


Example 6) BLOCK_COMMENT Using : and HEREDOC marker. This also works.

#! /bin/bash

: <<'BLOCK_COMMENT'
This is a comment 1.
This is a comment 2.
This is a comment 3.
BLOCK_COMMENT

echo "Hello World!"

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!

Example 7a) Customizing your block comment. Using << with some meaningful symbols to you.

#! /bin/bash

<< ///
This is a comment 1.
This is a comment 2.
This is a comment 3.
///

echo "Hello World!"

Example 7b) 

#! /bin/bash

<< ???
This is a comment 1.
This is a comment 2.
This is a comment 3.
???

echo "Hello World!"

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!

Example 7c) Error using #
#! /bin/bash

<< ###
This is a comment 1.
This is a comment 2.
This is a comment 3.
###

echo "Hello World!"

brendan@LP50C:~/learn_bash$ ./hw.sh
./hw.sh: line 3: syntax error near unexpected token `newline'
./hw.sh: line 3: `<< ###'


Example 7d) This is OK, wrap the ### around a set of single quote to tell shell.
#! /bin/bash

<< '###'
This is a comment 1.
This is a comment 2.
This is a comment 3.
###

echo "Hello World!"


brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!


Example 7e) Using ''' as in Python? You will get an error.
#! /bin/bash

<< '''
This is a comment 1.
This is a comment 2.
This is a comment 3.
'''

echo "Hello World!"


brendan@LP50C:~/learn_bash$ ./hw.sh
./hw.sh: line 11: warning: here-document at line 7 delimited by end-of-file (wanted `
This is a comment 1.
This is a comment 2.
This is a comment 3.
')


Example 7f) Using the single triple quote would be a bad idea as demonstrated here. You will get an error.
#! /bin/bash

<< '''''
This is a comment 1.
This is a comment 2.
This is a comment 3.
'''

echo "Hello World!"

brendan@LP50C:~/learn_bash$ ./hw.sh
./hw.sh: line 11: warning: here-document at line 7 delimited by end-of-file (wanted `
This is a comment 1.
This is a comment 2.
This is a comment 3.
')

Example 7g) If you use a set of double quotes, this will work as in Python.
#! /bin/bash

<< '"""'
This is a comment 1.
This is a comment 2.
This is a comment 3.
"""

echo "Hello World!"

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!

Shell Scripting 1/50 – Introduction to Shell

November 19th 2022 at 13:49

Shell scripts are interpreted, not compiled (i.e. Perl, Javascript, Python etc.)

Step 1. Check OS version. What is my Linux version?

brendan@LP50C:~$ lsb_release -a  (or cat /etc/*release)
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:        22.04
Codename:       jammy

brendan@LP50C:~$ cat /etc/*release | grep DISTRIB_
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.1 LTS"

Step2. Check the type of shells installed on your OS. Which shells are available for use on my OS?

brendan@LP50C:~$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh              <<<Bourn Shell, the original shell
/bin/bash            <<<Bourn again Shell, standard and improved version of sh
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/usr/bin/sh
/bin/dash
/usr/bin/dash
/usr/bin/tmux
/usr/bin/screen

Step 3. Check the location and version of your bash shell. WHere is bash is installed and which version is my shell?

brendan@LP50C:~$ which bash
/usr/bin/bash

brendan@LP50C:~$ bash --version
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Step 4. Create a learn_bash directory to create your first bash shell script. Denot the file with the extension .sh and this tells the computer that this file is a shell file.

brendan@LP50C:~$ pwd
/home/brendan
brendan@LP50C:~$ mkdir learn_bash
brendan@LP50C:~$ cd learn_bash/
brendan@LP50C:~/learn_bash$ touch hw.sh
brendan@LP50C:~/learn_bash$ ls -lh
total 0
-rw-r--r-- 1 brendan brendan 0 Nov 20 19:34 hw.sh

Step 5. Open your first bash shell script using your favouriate text editor and modify it as shown in cat command.

brendan@LP50C:~/learn_bash$ nano hw.sh

# <<<This Shebang tells where the program is located and which program you want to use to run this script.

brendan@LP50C:~/learn_bash$ cat hw.sh
#! /bin/bash                
echo "Hello World!"

Step 6. Run the script from the file location, you will get an error message as it has not been converted into an executable.

brendan@LP50C:~/learn_bash$ ./hw.sh
-bash: ./hello.sh: Permission denied

Step 7. Use the chmod +x command to convert it into an excutable shell script.

brendan@LP50C:~/learn_bash$ chmod +x hw.sh
brendan@LP50C:~/learn_bash$ ls -al
total 12
drwxr-xr-x 2 brendan brendan 4096 Nov 20 19:38 .
drwxr-x--- 4 brendan brendan 4096 Nov 20 19:36 ..
-rwxr-xr-x 1 brendan brendan   34 Nov 20 19:38 hw.sh

Step 8. Execute the Hello World shell script one more time. Wahla~

brendan@LP50C:~/learn_bash$ ./hw.sh
Hello World!

Shell Scripting 0/50 – Let’s install WLS on Windows 11 to learn Shell Scripting from Ubuntu virtual machine

November 19th 2022 at 13:45

On your windows, install WSL for Windows 11.

Install using Command Prompt
Step 1:Β StartΒ CMDΒ with administrative privileges.
Step 2:ExecuteΒ β€œwsl –install” command.
Step 3:RunΒ β€œwsl -l -o” to list other Linux releases.
Step 4:You canΒ install your favorite Linux distribution, useΒ β€œwsl –install -d NameofLinuxDistro.”

Microsoft Windows [Version 10.0.22621.755]
(c) Microsoft Corporation. All rights reserved.

C:\Users\brendan>wsl –install
The requested operation requires elevation.
Installing: Virtual Machine Platform
Virtual Machine Platform has been installed.
Installing: Windows Subsystem for Linux
Windows Subsystem for Linux has been installed.
Installing: Ubuntu
Ubuntu has been installed.
The requested operation is successful. Changes will not be effective until the system is rebooted.

Reboot your Windows 11 PC and set your username and password. Then it will log you straight into the latest Ubuntu version, in this case 22.04.1 LTS. πŸ™‚

Now we are ready to learn shell scripting from Ubuntu 22.04 which is running on your Windows 11 PC. πŸ™‚

❌