Docker Basics

Docker Basics

This post isn't going to be about everything Docker, it is just about the basics of using Docker in a Linux operating system.  In Fedora 25, I used the following commands.

Getting Started with Docker

First, you need to get Docker software installed on your Linux system using your package manager.
In Fedora, I executed the following command to install docker:
dnf install docker
or in SUSE:
zypper install docker
or in Debian/Ubuntu:
apt-get install docker

Next, you need to start and enable the docker service.

systemctl start docker
systemctl enable docker

To verify that your installation is successful execute:

docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:

For more examples and ideas, visit:

Exploring Docker

If all went well, then you can begin to search for images that you might want to use like "minimal", "centos", "suse", "ubuntu" or "mariadb".

docker search minimal

If you execute the docker command without any sub-commands, then it will display a summary of the usage of the docker command:

Usage: docker [OPTIONS] COMMAND [arg...]
       docker [ --help | -v | --version ]

A self-sufficient runtime for containers.


  --config=~/.docker              Location of client config files
  -D, --debug                     Enable debug mode
  -H, --host=[]                   Daemon socket(s) to connect to
  -h, --help                      Print usage
  -l, --log-level=info            Set the logging level
  --tls                           Use TLS; implied by --tlsverify
  --tlscacert=~/.docker/ca.pem    Trust certs signed only by this CA
  --tlscert=~/.docker/cert.pem    Path to TLS certificate file
  --tlskey=~/.docker/key.pem      Path to TLS key file
  --tlsverify                     Use TLS and verify the remote
  -v, --version                   Print version information and quit

    attach    Attach to a running container
    build     Build an image from a Dockerfile
    commit    Create a new image from a container's changes
    cp        Copy files/folders between a container and the local filesystem
    create    Create a new container
    diff      Inspect changes on a container's filesystem
    events    Get real time events from the server
    exec      Run a command in a running container
    export    Export a container's filesystem as a tar archive
    history   Show the history of an image
    images    List images
    import    Import the contents from a tarball to create a filesystem image
    info      Display system-wide information
    inspect   Return low-level information on a container, image or task
    kill      Kill one or more running containers
    load      Load an image from a tar archive or STDIN
    login     Log in to a Docker registry.
    logout    Log out from a Docker registry.
    logs      Fetch the logs of a container
    network   Manage Docker networks
    node      Manage Docker Swarm nodes
    pause     Pause all processes within one or more containers
    port      List port mappings or a specific mapping for the container
    ps        List containers
    pull      Pull an image or a repository from a registry
    push      Push an image or a repository to a registry
    rename    Rename a container
    restart   Restart a container
    rm        Remove one or more containers
    rmi       Remove one or more images
    run       Run a command in a new container
    save      Save one or more images to a tar archive (streamed to STDOUT by default)
    search    Search the Docker Hub for images
    service   Manage Docker services
    start     Start one or more stopped containers
    stats     Display a live stream of container(s) resource usage statistics
    stop      Stop one or more running containers
    swarm     Manage Docker Swarm
    tag       Tag an image into a repository
    top       Display the running processes of a container
    unpause   Unpause all processes within one or more containers
    update    Update configuration of one or more containers
    version   Show the Docker version information
    volume    Manage Docker volumes
    wait      Block until a container stops, then print its exit code

Run 'docker COMMAND --help' for more information on a command.

For the next recommended test, try out the ubuntu image.  To start the bash shell inside the ubuntu container, execute:

docker run -it ubuntu bash


To see the this container running from another terminal execute:

docker ps

CONTAINER ID    IMAGE            COMMAND   CREATED            STATUS              PORTS        NAMES
bb21045eda79        ubuntu              "bash"              8 seconds ago       Up 5 seconds                            hopeful_fermi

The name shown "hopeful_fermi" was automatically generated. Replace this name with the name automatically generated by your system in the command below.

To stop this container  from another terminal execute:

docker stop hopeful_fermi

To start a container based upon the ubuntu image with a specific name like "zesty" execute:

docker run -it --name "zesty" ubuntu bash

To see the this container running from another terminal execute:

docker ps

CONTAINER ID    IMAGE            COMMAND   CREATED            STATUS              PORTS        NAMES

2658f64e637a        ubuntu              "bash"              37 seconds ago      Up 35 seconds                          zesty

Saving Docker Container Changes

What if you've customized your docker container, and you want to launch the customized changes the next time you use it?One technique that can be used with the docker is the commit sub-command to save the changes to a new container. 

Start running a docker container for the mariadb database mapping with -p local:remote and -e ENVIRONMENT_VARIABLE=value:

docker run  -p 3306:3306 -e MYSQL_ROOT_PASSWORD='secret' mariadb

The name that you see for your container may not be what you want it to be when you use the command to view running processes. You can use the name sub-command or pass a --name option when beginning to run the container.

docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                              NAMES
0675838efe90             mariadb              "docker-entrypoint.sh"   46 minutes ago      Up 46 minutes>3306/tcp   wright-mariadb

You may want to rename the container based upon the image like:

docker rename 0675838efe90 colorsdb

Then, you can save the changes to your container with a docker commit command:

docker commit colorsdb

For more details, you can look at the help available for the commit command.

docker commit --help

Usage:  docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
Create a new image from a container's changes
Options:  -a, --author string    Author (e.g., "John Hannibal Smith ")  -c, --change value     Apply Dockerfile instruction to the created image (default [])      --help             Print usage  -m, --message string   Commit message  -p, --pause            Pause container during commit (default true)
To stop running the container, you can now use:

docker stop colorsdb

To start the container with the changes that have been committed to it after it has been stopped, you can use:

docker start colorsdb

Using Docker Containers

So now what? You can download and run an image and create a container or execute commands inside of it. You might be wondering like me, how do you use this container? 
In order to access to use some containers, you can access these containers through ports they expose to the host system or to other containers.

To connect to the container that has exposed port 3306 on the localhost to map to 3306 on the remote the machine, you could execute:

mysql -h localhost -P 3306 --protocol=tcp -p


Solving CA Certificate Errors

Solving CA Certificate Errors

Do you get an CA Certificate error of "unable to get local issuer certificate" or
"certificate verify failed?"

Copy the certificate to /usr/local/share/ca-certificates (or similar) and execute:


Read the man page on update-ca-certificates for more details.


Android Studio 2.2 Ready for Prime Time!

Android Studio 2.2 Ready for Prime Time!

I've tried Android Studio several times over the last year or so, but each time, it was not ready for prime time. By this statement, I mean that by default, it was so broken so that it was unable to build a new unmodified project. To be honest, Eclipse for Android Developers has been similarly broken, and was broken at the time I wrote this.

Recently, Google released Android Studio 2.2,0.12 and it is ready to build apps for API 24 right out of the box. I'm excited about being able to start developing without having to fight to get my build environment working!


JOOSAN NVR Admin Password Reset

JOOSAN NVR Admin Password Reset

I purchased a 4 Camera Wireless Surveillance NVR kit from CCTV Systems on Amazon in 2016. Somehow the password for the admin account stopped working, and I don't remember changing it. It had better not happen again, or I might return the unit! Without the admin password, I was unable to change any settings on the device.

When I got stuck without being able to login as admin, thankfully the vendor, CCTV Systems was able to tell me how to reset the admin password. Apparently, if they know the date on your unit, then they can generate a password for admin account that will allow a login, which is a bit scary. Maybe my unit won't be running with the actual date...

When I told them that the date had been reset to 1970/01/01 because I had unplugged the battery from the unit in trying to reset the system, they gave me a different solution. Here is what I was told via email:

This date is not normal.
So now you can on the screen of login,and input the wrong password,when it pop-up a message with invalid password,you can right-click,left-click  with the mouse,cycle times.Then it will let you reset the user and password.

This led to me developing the following procedure to reset the admin password for the JOOSAN NVR:

  1. Unplug the unit.
  2. Open the top cover by unscrewing the necessary screws.
  3. Remove the battery from the unit by pulling it up.
  4. Replace the battery and cover after a minute or two.
  5. Power the unit back on and wait until system is initialized.
  6. Right-click to try System Setup.
  7. Attempt to login as admin with the wrong password.
  8. Alternately, right-click and left-click several times. 
  9. A dialog should pop up and let you reset the admin password back to nothing or being blank.

Here are some steps you will want to perform after resetting the system.

Reset the time:

  1. Right-click to go to System setup.
  2. Click General setup on the top, Time setup on the left, and set up the time in the middle.
  3. Be sure to click Apply before you click OK.

Reset the admin user password:

  1. Right-click to go to System setup.
  2. Click System Admin on the top, User management on the left.
  3. Select the row of the admin user.
  4. Click the Set password button.
  5. Type the old admin password or leave it blank after resetting the system.
  6. Type and repeat the new password.
  7. Click the Ok button.
Since resetting the admin password, I have also created an extra super user account to avoid being locked out in the future by using System Admin, User management, Add user. In addition, I created an account for family members that can be used for just viewing the cameras.

I hope this helps you! Best wishes!


LDAP: On-Line Configuration (OLC) and Static slapd.conf

LDAP: On-Line Configuration (OLC) and Static slapd.conf

Installing OpenLDAP 

To install both the client and server packages on RHEL/CentOS 7:

yum -y install openldap-servers openldap-clients

Enable and start the service:

systemctl enable slapd
systemctl start slapd


Until OpenLDAP 2.3, an OpenLDAP server was configured by editing a /etc/openldap/slapd.conf. This required that the server had to be restarted to make changes to the server configuration.

With OpenLDAP 2.3+ On-Line Configuration of the server was made possible by adding a Directory Information Tree (DIT) called cn=config.

To view the OLC, you can execute as root:

ldapsearch -H ldapi:/// -Y EXTERNAL -b cn=config

olcSuffix, olcRootDN and olcRootPW
The first step in configuring your domain will be to set the suffix for the DIT for your domain, the information about the administrative user's Distinguished Name (DN) and password. The olcRootDN must end with the same suffix specified by the olcSuffix.

Create an LDIF file with the follow contents updated for your own domain, and the olcRootPW generated by executing slappasswd. This information can then be modified on the LDAP server with the following command:

ldapmodify -H ldapi:/// -Y EXTERNAL -f olc-root.ldif


dn:  olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=samba,dc=org
replace: olcRootDN
olcRootDN: cn=admin,dc=samba,dc=org
replace: olcRootPW

Configuring Logging with OLC

ldapmodify -H ldapi:/// -Y EXTERNAL -f olc-logging.ldif


dn: cn=config
changetype: modify
add: olcLogFile
olcLogFile: /var/log/slapd.log
add: olcLogLevel
olcLogLevel: filter config acl

Configuring Organizational Units(OUs)

If want to configure the LDAP Directory to contain information for authenticating users of your domain, then you will need to create the following dcObject, organization, and organization unit entries. The simpleSecurityObject and organizationalRole entry can be used as a administrator account for the suffix. Entries for this suffix will need to be modified using the DN of this LDAP Administrator entry.

Create an LDIF file with the follow contents updated for your own domain, and then update the LDAP server by executing:

ldapadd -D cn=admin,dc=samba,dc=org -w secret -f olc-domain.ldif


dn: dc=samba,dc=org
objectClass: top
objectClass: dcObject
objectClass: organization
o: samba.org
dc: samba

dn: cn=admin,dc=samba,dc=org
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: secret

dn: ou=users,dc=samba,dc=org
objectClass: top
objectClass: organizationalUnit
ou: users

dn: ou=groups,dc=samba,dc=org
objectClass: top
objectClass: organizationalUnit
ou: groups

dn: ou=idmap,dc=samba,dc=org
objectClass: top
objectClass: organizationalUnit
ou: idmap

dn: ou=computers,dc=samba,dc=org
objectClass: top
objectClass: organizationalUnit
ou: computers

Configuring OLC Schema

To discover which schema have been added to your server, you can execute the following query:

ldapsearch -H ldapi:/// -Y EXTERNAL -b cn=schema,cn=config cn

Most installations will only have the "core" schema installed. The others that are often added for use in authentication by executing the following commands in order, otherwise an attribute that may be defined in one schema that cannot be referenced will prevent adding another schema. 

ldapadd -H ldapi:/// -Y EXTERNAL -f /etc/openldap/schema/cosine.ldif

ldapadd -H ldapi:/// -Y EXTERNAL -f /etc/openldap/schema/corba.ldif

ldapadd -H ldapi:/// -Y EXTERNAL -f \ /etc/openldap/schema/inetorgperson.ldif

ldapadd -H ldapi:/// -Y EXTERNAL -f \


Help for Vi or Vim in Python

Help for Vi or Vim in Python

Using vi or vim can be tricky to be sure! It has syntax color coding for Python, but the way it handles tabs and spaces can be problematic. It's also nice to be able to control the indentation of the text in the editor. The following settings can help with these issues.

Hidden Tabs and Spaces

Using :set list can display the hidden tabs and spaces that might cause you problems.

Custom Vim Configuration

If you want to make vi or vim your primary editor, then you can use a custom resource ~/.vimrc file to store preferences that will make using it easier with Python.

~/.vimrc Comments

One thing to note is that comments in a vi or vim resource file are different from most configuration files. To add a comment to the custom file you use the quote (") as shown below.

Python ~/.vimrc Example

As someone who writes Python frequently, I like my tab key to indent four spaces, and convert the tabs into a spaces. I like to also be able to select text to indent or un-indent it for Python levels of scope. Here are the settings I add to my ~/.vimrc file:

set expandtab " expand tabs to spaces
set tabstop=4 " use four spaces for each tab
set shiftwidth=4 " select with V and use  < or > to shift for spaces

In order to take advantage of the shiftwidth, you can press V and then select the lines to indent, or un-indent. Pressing < or > will un-indent or indent the selected lines.


How to change the UUID of a VirtualBox Image in Windows

Set your path to include the installation directory for VirtualBox, typically C:\Program Files\Oracle\VirtualBox, or else you will need to prefix the following command with that path.

VBoxManage internalcommands sethduuid CentOS.vdi


Windows Command Line

Windows Command Line


The FINDSTR command works almost like grep, so it can be useful with other commands:


A couple of Windows command line tools that are helpful for dealing with Windows programs from the command line are: ASSOC and FTYPE.


ASSOC will list all the file associations if given no arguments.
If provided a file extension like ".py", then it will give you the file type for that association:

C:\>ASSOC .py


FTYPE will get or set the command to execute for a specific file type. For example:

C:\>ftype Python.File
Python.File="C:\WINDOWS\py.exe" "%1" %*

For me, this was associating with a Python 2.7 interpreter, instead of the Python 3.4 one I wanted. To fix my problem, I executed:

C:\Python34\myscripts>ftype Python.File

Python.File="C:\Python34\python.exe" "%1" %*

Restoring F8 key at Boot

If you want to be able to use the F8 key at boot time in Windows 8+, you need to execute the following before it's too late!

bcdedit /set {default} bootmenupolicy legacy


Creating an Encrypted Partition in CentOS 7

Creating an Encrypted Partition in CentOS 7

First, prepare a partition with fdisk. In this example, it is assumed that /dev/sdb1 has been created.

Then, use cryptsetup to luksFormat the partition with a passphrase.

cryptsetup -y luksFormat /dev/sdb1

You will need to type: YES
if you are sure you want to continue.

You will be prompted to Enter and Verify your passphrase.  Be sure to select one that is not too simple or less than 8 characters, as now it does verify the complexity. If you complete this successfully, then you will need the passphrase that you used to open the device.  You can open the device under any name that you want to appear underneath /dev/mapper/.

Next, use cryptsetup to luksOpen the partition to a name like "confidential" that will become part of the path to the new /dev/mapper/confidential device.

crypstsetup luksOpen /dev/sdb1 confidential

You will then be prompted with the passphrase that you used when you executed cryptsetup with luksFormat subcommand.

The device will now appear as /dev/mapper/confidential, but it will actually be a symbolic link to a /dev/dm* device.

Format the open (unencrypted) device by making a filesystem.

mkfs.ext4 /dev/mapper/confidential

Create a mount point and mount the new filesystem.

mkdir /var/lib/confidential
mount /dev/mapper/confidential /var/lib/confidential

Put the data that you want to be encrypted onto the filesystem. For example, to copy confidential data from a user's home directory to the encrypted device, you could execute something like:

cp /home/user/confidential.data /var/lib/confidential

Unmount the filesystem and use cryptsetup to luksClose the filesystem.

umount /var/lib/confidential
cryptsetup luksClose confidential

Create /etc/crypttab
confidential /dev/sdb1


Creating an iSCSI target and and initiator with CentOS 7

Creating an iSCSI target and and initiator with CentOS 7

First, you will probably need to install the necessary packages, as they are not installed by default. For the iSCSI server, target portal, you will need to install scsi-target-utils and targetcli packages, and on the client, the iscsi-initiator-utils package.  For testing purposes, it may be useful to have all three installed on the server, or if you are just trying out iSCSI using just a single system for practice.  The following command will install all three packages:

yum -y install scsi-target-utils targetcli iscsi-initiator-utils

iSCSI Qualified Name (IQN) 

You will need to assign a unique iSCSI Qualified Name (IQN) for your server, client, and each target.  The IQN starts with "iqn." followed by the year-month that the target will be available after, like "2015-11".  After that, the domain name in reverse, like "com.example", and finally a colon followed by the name of the specific entity like ":lun0", or ":centos7".  Put all together the IQN looks like this: "iqn.2015-11.com.example:lun0" or "iqn.2015-11.com.example:centos7".

If you want to have a IQN generated for your system that should be universally unique that you can place into /etc/iscsi/initiatorname.iscsi, instead of setting your own, you can execute:


which should output something like:


iSCSI Target Portal (Server) Configuration

Your system is already identified with an IQN in the file /etc/iscsi/initiatorname.iscsi.  You can modify this to something unique for your network (or the world), such as: iqn.2015-11.com.example:centos7.  You will need all the IQNs for the clients that will connect to your iSCSI portal. After updating the previous file, the iscsid service should be restarted with:

systemctl restart iscsid

Rather than having to edit configuration files by hand, the targetcli command provides an interface for managing the targets of your portal which uses a directory metaphor for organization and navigation.  Start the interface by executing:


First navigate, and then create an appropriate backing store.  If you have a block device, like /dev/sdd, then you could a backing store named back1 by executing:

cd /backstores/block
create back1 /dev/sdd

To use a file image backing store with a size of 100Mb, you could execute:

cd /backstores/fileio
create back1 /var/lib/iscsi-lun0.img 100M

Next, to create target IQNs, you can create entries under /iscsi.  For example, to create a  target of iqn.2015-11.com.example:lun0, you would execute:

cd /iscsi
create iqn.2015-11.com.example:lun0

The backing store created earlier must be associated with the target IQN. You do this by navigating under the IQN, the target portal group, and the luns directory like /iscsi/iqn.2015-11.com.example:lun0/tpg1/luns.

Pay attention to which /backstore file you used previously. If you created the block device /backstores/block/back1 earlier then you would execute:

cd /iscsi/iqn.2015-11.com.example:lun0/tpg1/luns
create /backstores/block/back1 

If you created the fileio backstore earlier, then you would execute:

cd /iscsi/iqn.2015-11.com.example:lun0/tpg1/luns
create /backstores/fileio/back1

Then, for each client, an acl must be added. Begin by changing to the acls under your IQN/tpg1:

cd /iscsi/iqn.2015-11.com.example:lun0/tpg1/acls

For each client, add the acl by creating an IQN entry:

create iqn.2015-11.com.example.com:centos7

Optionally, add authentication information (this matches the initiator configuration below):

cd iqn.2015-11.com.example.com:centos7
set auth userid=student
set auth password=password

If you return to the targetcli interface interface later, you can navigate to this "directory" and use the following command to view the authentication information for this client (this command is useful in user "directories" within targetcli, too):

cd /iscsi/iqn.2015-11.com.example.com:lun0/tpg1/acls/iqn.2015-11.com.example.com:centos7

which output:

chap_password: password
chap_userid: student


When you are done, you can leave the program.


Hot Tip! Each time you exit targetcli, it informs you that it has updated the /etc/target/saveconfig.json file, which could be edited.  Also, targetcli keeps a copy of the last ten configurations you have used in /etc/target/backup. So it is easy to edit the current configuration or restore one of these configuration files by copying the /etc/target/backup/saveconfig-[TIMESTAMP].json file over the /etc/target/saveconfig.json, and then restart the iscsid service.

After you have finished providing each client acl, you can should review the configuration by using the following suggestions.  You can navigate the configuration like a normal filesystem with cd and ls, and use info and help to get information specific to each directory of the configuration:

cd /
cd /backstores/fileio
cd /iscsi

If you are satisfied, then exit the interface by executing:


Finally, enable and start the iscsid service:

systemctl enable iscsid
systemctl start iscsid

If this is working correctly, then the port 3260/tcp should be listening and shown by the following command:

ss -tln | grep 3260

which should show:

LISTEN     0      5                         *:3260                     *:*  

You may need to enable the port through the firewalld configuration, which is used for the firewall by default.  You have several ways that you could achieve this with greater security, but this example assumes that you want to make the port open for all addresses:

firewall-cmd --zone public --add-port 3260/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all

iSCSI Initiator (Client) Configuration

Just as was done on the server, the client should be identified by a IQN in the /etc/iscsi/initiatorname.iscsi file. Make sure that the you use the same IQN for each client that you used to create the acl entries on the server.  Don't forget to update the /etc/iscsi/initiatorname.iscsi file and restart the iscsid service:

systemctl restart iscsid

If you set a userid and password in the acl you created on the server, then in /etc/iscsi/iscsid.conf on the client, uncomment and modify the userid and password to match the one that you used:

node.session.auth.authmethod = CHAP
node.session.auth.username = student
node.session.auth.password = password

First, you need to discover the target at the portal by executing:

iscsiadm -m discovery -t sendtargets -p # where the IP is the target portal server above

The above command should show the IQNs available at the target portal server.  You can attempt to login to see if you have any errors, especially if using authentication by using:

iscsiadm -m node --login

For information about the session which is hopefully created, you can use iscsiadm in the session mode.  In the session mode, you can print session information in increasing verbosity by setting the -P option from 0 for the lowest verbosity to 3 the highest verbosity.  For example, here's the inetadm command run in session mode to print out medium high verbosity:

inetadm -P 2 -m session

which had the output of:

Target: iqn.2015-11.com.example:lun0 (non-flash)
Current Portal:,1
Persistent Portal:,1
Iface Name: default
Iface Transport: tcp
Iface Initiatorname: iqn.2015-11.com.example:centos7
Iface IPaddress:
Iface HWaddress:
Iface Netdev:
SID: 1
iSCSI Connection State: LOGGED IN
iSCSI Session State: LOGGED_IN
Internal iscsid Session State: NO CHANGE
Recovery Timeout: 120
Target Reset Timeout: 30
LUN Reset Timeout: 30
Abort Timeout: 15
username: student
password: ********
password_in: ********
Negotiated iSCSI params:
HeaderDigest: None
DataDigest: None
MaxRecvDataSegmentLength: 262144
MaxXmitDataSegmentLength: 262144
FirstBurstLength: 65536
MaxBurstLength: 262144
ImmediateData: Yes
InitialR2T: Yes
MaxOutstandingR2T: 1

Once you have resolved any issues with making a connection, you should enable and start the iscsi service:

systemctl enable iscsi
systemctl start iscsi

If everything has gone successfully, then a new SCSI disk device should appear with a name found by listing /dev/sd*.  In this example, the new disk appears as /dev/sdb.

ls /dev/sd*

Shows the output:

/dev/sda  /dev/sda1  /dev/sda2  /dev/sdb 

Most likely, the new device will be the last one shown like /dev/sdb above.  To get it ready for a filesystem, you can use fdisk and the new device name to create a partition.  In the following example, one new partition is created that uses all the space on the device:

fdisk /dev/sdb
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
   e   extended
Select (default p): 
Using default response p
Partition number (1-4, default 1): 
First sector (8192-204799, default 8192): 
Using default value 8192
Last sector, +sectors or +size{K,M,G} (8192-204799, default 204799): 
Using default value 204799
Partition 1 of type Linux and of size 96 MiB is set

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

Now executing the following command should show the new partition, /dev/sdb1:

ls /dev/sd*

Shows the output:

/dev/sda  /dev/sda1  /dev/sda2  /dev/sdb /dev/sdb1

To prepare the partition for mounting, create a filesystem on it it, in this case an ext4 filesystem will be created:

mkfs -t ext4 /dev/sdb1

Create the directory where you want to mount the new filesystem such as /mnt/lun0

mkdir /mnt/lun0

Verify that the filesystem can be successfully mounted:

mount /dev/sdb1 /mnt/lun0
mount | grep lun0

If successful, this should output something like:

/dev/sdb1 on /mnt/lun0 type ext4 (rw,relatime,seclabel,stripe=4096,data=ordered)

When you want to make this mount permanent, you have to be careful to add the "_netdev" mount option in your /etc/fstab entry.  It is also a good idea to use UUID identifiers instead of device names as device names may change depending on the order in which devices are detected.  To discover the UUID for the new device execute:


or for this specific example

blkid /dev/sdb1

which had the output of:

/dev/sdb1: UUID="3735827d-b4f4-48ed-aca1-a264a3ec956e" TYPE="ext4"

The entry in this example would look similar to the following, but your UUID will be different.

UUID=3735827d-b4f4-48ed-aca1-a264a3ec956e /mnt/lun0  ext4 _netdev 0 0

After adding the entry, unmount your new device, and the mount all /etc/fstab entries to verify that your new entry is correct.  

umount /dev/sdb1
mount -a
mount | grep lun0

should output:

/dev/sdb1 on /mnt/lun0 type ext4 (rw,relatime,seclabel,stripe=4096,data=ordered,_netdev)

If that works, and you won't disturb anyone else on the system, you might reboot the system(s) starting with the server first, and then the client, to verify that everything has been enabled correctly for automatic mounting of the iSCSI device. After the systems have rebooted, check that the client is still mounting the lun0 target with:

mount | grep lun0

If you made it this far, then congratulations! You have a persistent iSCSI target portal server and an iSCSI initiator client able to perform CHAP authentication.

Wrap-up and Troubleshooting

If you are still having issues, then review the files that were updated, and the firewall settings.  For example, the wrong IQN for a client will mean failure to authorize, the wrong userid or password, a failure to authenticate.  Also, revisit the targetcli interface and review the configuration information.  Here's a quick tour of some troubleshooting with commands in bold, the output of the command in italics. and the relevant information highlighted.

cat /etc/iscsi/initiatorname.iscsi

fdisk -l
Disk /dev/sda: 42.9 GB, 42949672960 bytes, 83886080 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000d9dbb

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048    39938047    19968000   83  Linux
/dev/sda2        39938048    41943039     1002496   82  Linux swap / Solaris

Disk /dev/sdb: 104 MB, 104857600 bytes, 204800 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 4194304 bytes
Disk label type: dos
Disk identifier: 0x761d8fba

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            8192      204799       98304   83  Linux

/dev/sda1: UUID="cfc6be43-cf4b-4cb5-9bf3-67f24d1d5205" TYPE="ext4" 

/dev/sda2: UUID="d5c08700-0ff1-4062-a13b-f3782b80c66b" TYPE="swap" 
/dev/sdb1: UUID="3735827d-b4f4-48ed-aca1-a264a3ec956e" TYPE="ext4"

cat /etc/fstab
# /etc/fstab
# Created by anaconda on Fri Nov 6 16:02:18 2015
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
UUID=cfc6be43-cf4b-4cb5-9bf3-67f24d1d5205 /                       ext4    defaults        1 1
UUID=d5c08700-0ff1-4062-a13b-f3782b80c66b swap                    swap    defaults        0 0

UUID=3735827d-b4f4-48ed-aca1-a264a3ec956e /mnt/lun0  ext4 _netdev 0 0 

grep -Ev '^#|^$' /etc/iscsi/iscsid.conf  # exclude comments and blank lines
iscsid.startup = /bin/systemctl start iscsid.socket iscsiuio.socket
node.startup = automatic
node.leading_login = No
node.session.auth.authmethod = CHAP
node.session.auth.username = student
node.session.auth.password = password
node.session.timeo.replacement_timeout = 120
node.conn[0].timeo.login_timeout = 15
# remaining output omitted

firewall-cmd --list-all
public (default, active)
  interfaces: enp0s3
  services: dhcpv6-client ssh
  ports: 23/tcp 3260/tcp 23/udp
  masquerade: no
  rich rules:

/iscsi> cd /
/> ls
o- / ..................................................................... [...]
  o- backstores .......................................................... [...]
  | o- block .............................................. [Storage Objects: 0]
  | o- fileio ............................................. [Storage Objects: 1]
  | | o- back1 ....... [/var/lib/iscsi-lun0.img (100.0MiB) write-back activated]
  | o- pscsi .............................................. [Storage Objects: 0]
  | o- ramdisk ............................................ [Storage Objects: 0]
  o- iscsi ........................................................ [Targets: 1]
  | o- iqn.2015-11.com.example:lun0 .................................. [TPGs: 1]
  |   o- tpg1 ........................................... [no-gen-acls, no-auth]
  |     o- acls ...................................................... [ACLs: 1]
  |     | o- iqn.2015-11.com.example:centos7 .................. [Mapped LUNs: 1]
  |     |   o- mapped_lun0 ............................ [lun0 fileio/back1 (rw)]
  |     o- luns ...................................................... [LUNs: 1]
  |     | o- lun0 ..................... [fileio/back1 (/var/lib/iscsi-lun0.img)]
  |     o- portals ................................................ [Portals: 1]
  |       o- ................................................. [OK]
  o- loopback ..................................................... [Targets: 0]

/> cd /iscsi/iqn.2015-11.com.example:lun0/tpg1/acls/iqn.2015-11.com.example:centos7/
/iscsi/iqn.20...ample:centos7> info
chap_password: password
chap_userid: student

iscsiadm -m discovery -t sendtargets -p # the -p must be the correct IP for the portal,1 iqn.2015-11.com.example:lun0

iscsiadm -m node -v --login,1 iqn.2015-11.com.example:lun0

iscsiadm -P3 -m session 
iSCSI Transport Class version 2.0-870
Target: iqn.2015-11.com.example:lun0 (non-flash)
Current Portal:,1
Persistent Portal:,1
Iface Name: default
Iface Transport: tcp
Iface Initiatorname: iqn.2015-11.com.example:centos7
Iface IPaddress:
Iface HWaddress:
Iface Netdev:
SID: 1
iSCSI Connection State: LOGGED IN
iSCSI Session State: LOGGED_IN
Internal iscsid Session State: NO CHANGE
Recovery Timeout: 120
Target Reset Timeout: 30
LUN Reset Timeout: 30
Abort Timeout: 15
username: student
password: ********
password_in: ********
Negotiated iSCSI params:
HeaderDigest: None
DataDigest: None
MaxRecvDataSegmentLength: 262144
MaxXmitDataSegmentLength: 262144
FirstBurstLength: 65536
MaxBurstLength: 262144
ImmediateData: Yes
InitialR2T: Yes
MaxOutstandingR2T: 1
Attached SCSI devices:
Host Number: 3 State: running
scsi3 Channel 00 Id 0 Lun: 0
Attached scsi disk sdb State: running

Good Luck!

Creating a loop device for testing filesystems in Linux

Creating a loop device for testing filesystems in Linux

If you wanted to have a disk for testing different file systems, but were not able to add a disk to your system, then you might be stuck. By creating a filesystem within a file, you can use a loop mounted device, and you do not have to be stuck!

For example, you could create a 100M /var/lib/testdisk file with the following command:

dd if=/dev/zero of=/var/lib/testdisk bs=1M count=100

Then, you can set up that file as a loop device:

losetup --find # to find the next available loop device, typically /dev/loop0 as shown used below
losetup /dev/loop0 /var/lib/testdisk

Next, you can format the loop device with a filesystem:
mkfs -t ext4 /dev/loop0

Use the filesystem by creating a directory and mounting it:

mkdir /test-ext4
mount /dev/loop0 /test-ext4

In the future to mount this filesystem image, you will be able to just use the command:

mount -o loop /var/lib/testdisk /test-ext4

To make this device permanent you could add the following lines to /etc/fstab:

/var/lib/testdisk       /test-ext4              ext4    loop,nodev      0 0


Fast Forward to the Nikon D5500 from the D3100 - Part II

Fast Forward to the Nikon D5500 from the D3100 - Part II


In the previous part of this series, I mentioned several features that were not available that I wanted to have on my camera, but were not on the Nikon D3100:

  • Bracketing of Exposure and Shutter Speed
  • Wireless remote control
  • Intervalometer
  • Advanced Flash integration
  • GPS
  • Wi-Fi
Another motivating factor was that I really wanted a new lens!  Between my 18-55mm AF-S f/3.5-5.6G lens and my 55-300mm AF-S f/3.5-5.6G ED, I would need to keep switching lenses to go from a wide-angle shot to a telephoto shot.  I wanted just one lens that I could just keep on my camera and be able to get both shots.

As I shopped for the camera upgrade, I noticed that the D5500 was often bundled with a 18-140mm AF-S f/3.5-5.6G ED.  So far, this new lens has been almost perfect for all my needs.  Occasionally, I still reach for the 55-300mm AF-S f/3.5-5.6G ED for a real up-close shot, but most of the time I'm happy with the range provided by the 18-140mm lens.

Comparable Specifications

The following table compares the specifications of the two cameras where a quantitative comparison can be made:

ProcessorExpeed 4Expeed 3
Photo Frames Per Second 
Movie 1920x1080 Frames Per Second6024
ISO100 to 25600100 to 12800

The Biggest Difference 

The most noticeable difference between the Nikon D5500 and the D3100 is that the D5500 has an articulating (movable) touch screen monitor.  Congratulations to Nikon for having the first serious DSLR camera to have a touch screen.

I know it's not just me!  If I'm shown a TFT display, I want to touch it to control it.  On the Nikon D3100, I often would catch myself trying to pinch to zoom in on a picture that was displayed on it's fixed 3.0" diagonal monitor.  

Not only do I appreciate the pinch to zoom for a detailed look at shots in the field, but it's nice to flick through photos quickly on the D5500.  The D5500 also presents an excellent touch screen interface for configuring the settings of the camera. 

When put into LiveView mode, the D5500 touch screen can also be used to select a focus point and take a photo.  Since the D5500 monitor screen can be articulated, whereas the D3100 could not, you can turn it 180 degrees, so you can take selfies too!

The one thing that frustrates me about the touch screen interface is that double-tap is not implemented except for a few places.  I really would want it to be able to zoom all the way back out of a picture that I had zoomed all the way in on.

Get a Grip

The grip on the newer Nikon D5500 feels deeper than that of the D3100, so I feel as if I have a better, stronger grip on the camera while just holding it in my right hand.  Surprisingly, the D5500 is slightly smaller and about one ounce lighter (14.9 oz) than the D3100 (16 oz).

More To Come

I'll write more about the Nikon D5500 soon!  I've got to spend a bit more time with it to really get to know its pros and cons, but I thought I'd share my first impressions with everyone for now.

Upgrading to Windows 10 (and how an SSD really matters)

Upgrading to Windows 10 

Right now I am wondering why I did it.  I started an upgrade to Windows 10 last night, and my primary work laptop is stuck in a boot loop.  I hadn't even received a notification yet, even though I had "reserved" my upgrade a long time ago.  Since I decided I couldn't wait, I searched and found the MediaCreationToolx64.exe from Microsoft at: https://www.microsoft.com/en-us/software-download/windows10.

I know I must be good at finding bugs, or them me.  On my first attempt at using the MediaCreationToolx64.exe tool, I didn't choose to upgrade and was just letting it do a download to a USB key.  I was busy doing other things at the same time, and one of them required that I reboot my system.  The tool was reporting a status of about 50% complete at the time I executed:

shutdown /r /f

After restarting, the MediaCreationToolx64 kept reporting that it wasn't able to start properly, and suggesting rebooting to solve the problem.  That recommendation was not helpful, but I was able to use information in this link to fix the problem I created: https://answers.microsoft.com/en-us/insider/wiki/insider_wintp-insider_install/how-to-troubleshoot-common-setup-and-stop-errors/324d5a5f-d658-456c-bb82-b1201f735683

This was the procedure that was successful for me:
a. Press Windows key + X on the desktop screen of the computer.
b. Select Command Prompt (Admin)
c. On the open Command Prompt window copy and paste the commands (all at once).
net stop wuauserv
net stop cryptSvc
net stop bits
net stop msiserver
ren C:\Windows\SoftwareDistribution
ren C:\Windows\System32\catroot2
net start wuauserv
net start cryptSvc
net start bits
net start msiserver

 Next, I tried to Upgrade this PC, instead of making a USB disk for installation on another computer.  The first stage of the installation went successfully to 100% and then my computer rebooted.  I am now stuck with it continually rebooting.  There seems to be a phantom entry in the UEFI, as there are two choices to boot the system, one that is still labeled Windows 8.1 and another one without a label.  Neither one will boot my system, and none of the choices on the boot menu are helpful either.

As I write, I am now downloading Windows 10 for installation on another computer from my spare laptop.  According to the information found at the site of the last link, I should be able to boot the USB to repair the start up of the system.  I hope so!

My download just finished.  The MediaCreationToolx64 first verified the download, and now it is creating the Windows 10 Media.  Creating the media seems to take a long time... about as long as the download!  For the first 50% of the time it is preparing the media, and then for the second 50% it writes it out to the USB drive.

No luck using the Windows 10 setup program booting off the USB drive. I was not able to repair the start up of the system, despite that option being available within the Windows 10 setup program.  I was also unable to restore any previous system restore points that I had created.  

In order to upgrade, the setup program told me that I had to boot that version of Windows, which was still not happening.  When I tried to do a fresh install I was told that I was not allowed because the only partition big enough to hold the new Windows was a "reserved OEM partition".  

The Good News

One option that was available in the Windows 10 setup program was helpful.  It at least allowed me to open a command prompt.  This setup mode of Windows also allowed me to have access to not only the internal hard drive partitions, but also to any external hard drives or USB flash drives.

After connecting my Western Digital "My Passport Ultra" 2 TB external hard drive, it was recognized as the G: drive.  Oddly, what was normally my C: drive showed up as the D:.  To backup all of my users data, I used the following commands:

mkdir g:\users
robocopy /r:0 /w:0 /s d:\users  g:\users

The /r:0 option is to attempt 0 retries on a failed copy, the /w:0 option is to wait 0 seconds between retries, and the /s option is to make it act recursively on the source directory d:\users.
When I saw it was copying a very deep and unwanted directory, I used CTRL-C to stop the copying.  I then used the following command to prune a directory and all of its contents:

rmdir /s d:\users\Keith\Documents\Github

The Best News

Since I don't have time to spend backing up other parts of the original drive outside of the "users" directory, I ran out and got a new Toshiba Q Series Pro SSD.  Best Buy had a great deal on them for the same price I'd pay for it on Amazon, so I jumped on it.  

It will be a bit hard to say I suppose whether I get a boost in speed from the new Solid State Drive, from Windows 10 versus Windows 8.1, or by just having a fresh clean install.  If it is slower than before, then I'd be really surprised. 

The setup of Windows 10 was so fast I was really surprised.  It was done in less than ten minutes with what it had to do from the USB drive.  Then, it took about another 20 minutes of running of the hard drive to set up the apps and the updates.  

The best news:  My work laptop is now booting Windows 10!  It would be better news if it wasn't running Windows, but it's my work laptop, so it must!

Update - SSD is a MUST Upgrade

The speed of my system is dramatically improved! There is no way I can attribute the speed increase to more than anything the Toshiba Q Series Pro SSD replacing a 5400 RPM Toshiba traditional hard drive.  Applications with exactly the same code that was running a couple of days ago on Windows 8.1 now load so much faster, it is unbelievable to me!  If you are a person who swears at your computer for being slow, then you MUST upgrade to a SSD drive!


Fast Forward to the Nikon D5500 from the D3100

Fast Forward to the Nikon D5500 from the D3100

Part I - The Nikon D3100


A little more than a year ago, I took the leap back into serious photography, and starting doing business at http://wrightrocket.smugmug.com.  With a very limited budget, I started with the entry-level Nikon D3100, which provides beginning users with a guide mode, but intermediate or advanced users the basics of a DSLR with the sophistication and quality of Nikon.  At the time, I really wanted the Nikon D5300, but didn't have the budget for it, so I settled for a little less than I wanted to get what I really needed.

Here are the technical specifications of the D3100:
  • Expeed 3 Processor
  • 14.2 Megapixels
  • DX Sensor 23.1mm x 15.4mm
  • 3 Frames per second continuous
  • ISO 100 to 12800
  • HD 1920x1080 at 24 frames per second
  • 3.0 inch diagonal non-touchscreen monitor
  • 16.0 ounces weight for camera body

The kit that I bought included a 18-55mm and 55-200mm f/3.5-5.6G AF-S Nikkor VR lenses.  Over time, I have enjoyed using the camera very much taking over 6,000 photographs in about a year. Here's a couple of my favorites:

I added a Nikkor AF-S 35mm f/1.8G prime VR lens and a 55-300mm AF-S f/3.5-5.6G ED VR II lens, and lots of other stuff.  Here's one of my favorites from the 300mm, which has VR II so taking hand-held photos like this are possible:

After exploring more advanced photography techniques through reading and experimentation, I found several features which I wished were built-in to the camera, but were not. Here's a short list of features I wish that the Nikon D3100 had:
  • Bracketing of Exposure and Shutter Speed
  • Wireless remote control
  • Intervalometer
  • Advanced Flash integration
  • GPS
  • Wi-Fi
Prior to upgrading, the following explains how I dealt with these short-comings of the D3100.


It was not much of a problem to overcome the lack of bracketing controls by simply varying the exposure or shutter speed manually, but to do it effectively required a tripod to keep the camera at the same view.  For the outdoor photography that I tend to do, I usually would set up the camera on the tripod and set it to the aperture (A) mode. Then, I would simply turn the adjustment knob for the aperture between each frame.  Otherwise, I might set it up with the camera set to shutter speed mode (S) and adjust the shutter speed as shown below.

1/15th of a second, f10, ISO 100

1/20th of a second

1/25th of a second

1/30th of a second

1/40th of a second

1/50th of a second

Wireless Remote Control

I bought a wired intervalometer for taking time-lapse photography, and it also served as a way to release the shutter remotely, at a shorter distance, but like a wireless remote control.  It's also nice because in manual mode (M), if I set the shutter speed to Bulb, then I can hold the release button for as long as I would like to create long exposures like these:

Advanced Flash Integration

The small built-in flash is only adequate for up-close or very small room photography.  Any outdoor or large space photography required more.  By going with the Nikon SB-700 Speedlight flash, I was able to get an integrated flash that could provide Commander capabilities for the Nikon Creative Lighting System.  This flash isn't quite as large or as powerful as the SB-910, but is more than adequate even for outdoor or photos taken in moderate to large rooms.


There is a GPS port on the D3100, but I never acquired the Nikon GP-1A module which lists for $312 as of today at www.nikonusa.com. Within Adobe Lightroom or Photoshop, as well as other tools, there are ways to embed location information, although I never bothered.


There is no Wi-Fi on the Nikon D3100, so you have to wait until you can get to a computer and import them.  There is also no Eye-Fi support built-in, although I didn't explore this option, I should note that there is some option for Eye-Fi support built-in on the Nikon D5500.  Eye-Fi allow you to have the SDcard in the camera connect to upload to a Wi-Fi access point.

Current Offerings

Nikon no longer offers the D3100, except possibly as refurbished, which I saw one today at their site for $749, which made me smile.  The kit for the D5500 which I purchased with the 18-140mm f3.5-5.6G ED VR is listed at $1,049,95 after a $350 instant savings, but lacks many of the extras that I got in my kit, which you can read about in my next part of this post.

A much improved entry-level cameras can be found in the D3200 and D3300 still offered at $449.95 and $499.95, respectively.  They now feature 24.2 megapixels.  The D3200 still has the same Expeed 3 processor as the D3100, but the D3300 now has the Expeed 4 processor. With an extra WU-1a Mobile Adapter module for $59.95 you can connect to both of these cameras through Wi-Fi on your smartphone.

Part II - Fast Forward to the Nikon D5500 from the D3100 - The D5500

The second part to this post will be upcoming soon! I plan to share the benefits and downsides to the Nikon D5500 in comparison to the D3100, as well as a few new photos!

About Me - WrightRocket

My photo

I've worked with computers for over 30 years, programming, administering, using and building them from scratch.

I'm an instructor for technical computer courses, an editor and developer of training manuals, and an Android developer.