Task
Using libvirt (virt-install), create a new virtual machine named cool-moray from an existing disk image at /vms/cool-moray/jammy-server-cloudimg-amd64.img with the following specifications:
Setting
Value
Memory in MB
1024
You must use --noautoconsole for the installation to complete and exit.
See the complete solution in Explanation.
Objective: Create a new virtual machine using the existing Ubuntu 22.04 disk image, allocate 1024 MiB of RAM, register the virtual machine with libvirt, and ensure virt-install exits without opening an interactive console.
The correct solution uses virt-install with the --import and --noautoconsole options. The --import option is essential because the task provides an existing operating system disk image rather than requesting a fresh installation.
Step 1: Connect to the correct Linux server.
The video specifies that this task must be completed on host lfcs00083.
From the candidate terminal, execute:
ssh lfcs00083
This connects to the virtualization host where the VM must be created.
All subsequent commands must be executed on this host.
Step 2: Verify that virtualization tools are available.
Check the virt-install utility:
virt-install --version
Check the virsh utility:
virsh --version
Also check the QEMU image-management utility:
qemu-img --version
These tools serve different purposes:
virt-install creates and configures virtual machines.
virsh manages and inspects virtual machines through libvirt.
qemu-img examines and manages virtual disk images.
The task states that libvirt must be used, so creating the VM directly with a standalone qemu-system command would not be the appropriate solution.
Step 3: Verify connectivity to the libvirt hypervisor.
Execute:
sudo virsh --connect qemu:///system list --all
virsh communicates with the libvirt virtualization manager.
--connect qemu:///system selects the system-wide QEMU/KVM connection.
list --all displays both running and stopped virtual machines.
An illustrative result is:
Id Name State
--------------------------------
1 existing-vm running
- test-vm shut off
The actual VM list will depend on the host.
If libvirt cannot be contacted, check the host's libvirt services and sockets:
sudo systemctl status libvirtd
Some systems use modular libvirt daemons such as virtqemud, so inspect the installed service arrangement rather than assuming libvirtd is always present.
Step 4: Check whether cool-moray already exists.
Execute:
sudo virsh --connect qemu:///system list --all
Look for a virtual machine named:
cool-moray
You can check directly:
sudo virsh --connect qemu:///system dominfo cool-moray
If libvirt reports that the domain does not exist, proceed.
If the domain already exists, inspect it before making changes. Do not delete or recreate an existing machine without establishing why it is present.
The --name option of virt-install requires a name unique to the target libvirt connection.
Step 5: Verify that the existing disk image is present.
The task specifies the exact disk image path:
/vms/cool-moray/jammy-server-cloudimg-amd64.img
Execute:
ls -lh /vms/cool-moray/jammy-server-cloudimg-amd64.img
If normal user permissions do not allow inspection:
sudo ls -lh /vms/cool-moray/jammy-server-cloudimg-amd64.img
The image must exist before creating the VM.
Do not create an empty virtual disk in its place. The requirement is to use the existing disk image.
Step 6: Inspect the existing virtual disk image.
Execute:
sudo qemu-img info /vms/cool-moray/jammy-server-cloudimg-amd64.img
An example of the resulting information is:
image: /vms/cool-moray/jammy-server-cloudimg-amd64.img
file format: qcow2
virtual size: 2 GiB
disk size: 650 MiB
These size values are illustrative.
qemu-img info identifies the image's format, virtual size, actual allocated storage, and any backing image relationship.
Ubuntu cloud images commonly use QCOW2, but verify the actual image format instead of assuming it from the .img extension.
The existing image must remain intact.
Step 7: Confirm the guest operating-system type.
The disk filename contains:
jammy-server-cloudimg-amd64.img
jammy refers to Ubuntu 22.04 LTS, and amd64 indicates the x86-64 architecture.
Check the installed OS profiles:
virt-install --osinfo list
To find Ubuntu 22.04 specifically:
virt-install --osinfo list | grep -i ubuntu22
If ubuntu22.04 is available, it can be selected using:
--osinfo ubuntu22.04
This provides appropriate guest operating-system metadata and configuration defaults.
If that profile is unavailable, the upstream Ubuntu cloud-image procedure supports using:
--osinfo generic
Do not install a new operating system or download a different disk image merely to complete the task.
Step 8: Create the virtual machine using virt-install.
Once the disk exists, the libvirt connection works and the Ubuntu profile is supported, execute:
sudo virt-install \
--connect qemu:///system \
--name cool-moray \
--memory 1024 \
--disk path=/vms/cool-moray/jammy-server-cloudimg-amd64.img \
--osinfo ubuntu22.04 \
--import \
--noautoconsole
This is the principal solution.
If ubuntu22.04 is not recognized by the installed libosinfo database, substitute --osinfo generic, following the official Ubuntu cloud-image instructions.
The command leaves CPU count, network configuration and other parameters at their supported defaults because the visible task does not prescribe specific values for them.
Step 9: Understand every parameter in the command.
Parameter
Explanation
sudo
Executes with administrative privileges
virt-install
Creates and defines a VM through libvirt
--connect qemu:///system
Targets the system-wide QEMU/KVM hypervisor
--name cool-moray
Assigns the required VM name
--memory 1024
Allocates 1024 MiB of guest memory
--disk path=...
Attaches the existing virtual disk image
--osinfo ubuntu22.04
Selects the Ubuntu 22.04 operating-system profile
--import
Boots an existing OS image without running an installer
--noautoconsole
Prevents automatic attachment to the guest console and allows the command to return
Three arguments are especially important.
--memory 1024
The task specifies memory of 1024 MB. The virt-install utility interprets this parameter in MiB.
Therefore:
--memory 1024
sets the guest's configured RAM to 1024 MiB, equivalent to 1 GiB.
--import
This tells virt-install to create the VM around an existing disk image and skip the operating-system installation process.
Without an appropriate installation method such as --import, virt-install may expect installation media or fail to determine how the guest should be created.
--noautoconsole
The task explicitly requires this flag.
It prevents virt-install from automatically connecting to the guest's graphical or text console. Official documentation states that it also allows virt-install to exit promptly rather than waiting on an interactive console session.
Step 10: Verify that the creation command succeeds.
When virt-install succeeds, it normally prints messages indicating that the VM has been created and the domain is being started.
An illustrative successful message could be:
Starting install...
Creating domain...
Domain creation completed.
Do not treat these example messages as an actual result from the video.
Immediately after the command completes, check the exit status:
echo $?
Expected successful exit status:
0
If the command fails, read the actual error before attempting it again.
Common failure conditions include an existing VM name, inaccessible image path, unsupported OS profile, missing virtualization support or an unavailable default network.
Step 11: Verify that the new virtual machine is registered.
Execute:
sudo virsh --connect qemu:///system list --all
The output should now contain:
cool-moray
For example:
Id Name State
---------------------------
2 cool-moray running
The domain ID and runtime state may differ.
This command verifies that libvirt recognizes the VM.
Step 12: Verify the virtual machine's assigned memory.
Execute:
sudo virsh --connect qemu:///system dominfo cool-moray
Inspect the memory information.
For a VM configured with 1024 MiB, an expected value is:
Max memory: 1048576 KiB
Calculation:
\[ 1024 \times 1024 = 1,048,576 \text{ KiB} \]
This confirms that libvirt has the required memory allocation.
Also verify the VM name and general status in the same output.
Step 13: Verify the attached virtual disk.
Execute:
sudo virsh --connect qemu:///system domblklist cool-moray --details
The output should identify a disk whose source is:
/vms/cool-moray/jammy-server-cloudimg-amd64.img
This verifies that the VM uses the exact existing image required by the task.
Do not confuse creating a new blank disk with attaching the existing disk. The latter is required.
Step 14: Inspect the VM's persistent configuration.
Execute:
sudo virsh --connect qemu:///system dumpxml cool-moray
This displays the libvirt domain definition in XML format.
Look for the guest name:
< name > cool-moray < /name >
Also inspect the memory setting and the disk source.
The relevant configuration should contain the equivalent of:
< memory unit='KiB' > 1048576 < /memory >
And a disk source referencing:
< source file='/vms/cool-moray/jammy-server-cloudimg-amd64.img'/ >
The actual XML may include additional attributes, devices, generated addresses and machine-specific settings.
Step 15: Verify the VM's runtime state.
Execute:
sudo virsh --connect qemu:///system domstate cool-moray
A successful initial launch should normally report:
running
If it reports shut off, investigate the reason:
sudo virsh --connect qemu:///system dominfo cool-moray
You can also inspect the appropriate libvirt/QEMU logs.
Importing a cloud image registers and starts a guest, but it does not automatically establish guest login credentials or configure cloud-init user data. Those operations are not requested by this task.
Step 16: Verify that virt-install has returned control to the terminal.
Because --noautoconsole was specified, the virt-install command should return to the shell after initiating VM creation.
For example, the terminal prompt should become available again:
candidate@lfcs00083:~$
The presence of the normal shell prompt indicates that the creation utility is no longer occupying the terminal.
This is separate from the VM's own runtime state: the virtual machine may continue running after virt-install exits.
Step 17: Perform final verification.
Execute:
sudo virsh --connect qemu:///system list --all
sudo virsh --connect qemu:///system dominfo cool-moray
sudo virsh --connect qemu:///system domblklist cool-moray --details
sudo virsh --connect qemu:///system domstate cool-moray
Confirm the following:
Requirement
Expected result
VM name
cool-moray
Existing disk image
/vms/cool-moray/jammy-server-cloudimg-amd64.img
Memory
1024 MiB
Installation method
Existing image imported
Mandatory option
--noautoconsole used
VM registration
Present in libvirt
VM initial startup
Successful
Terminal
Returns to shell after creation
Final Solution
The essential commands are:
# Connect to the designated server
ssh lfcs00083
# Verify the existing disk image
ls -lh /vms/cool-moray/jammy-server-cloudimg-amd64.img
# Inspect the image
sudo qemu-img info /vms/cool-moray/jammy-server-cloudimg-amd64.img
# Check the VM name is available
sudo virsh --connect qemu:///system list --all
# Confirm the guest OS profile exists
virt-install --osinfo list
# Create the VM
sudo virt-install \
--connect qemu:///system \
--name cool-moray \
--memory 1024 \
--disk path=/vms/cool-moray/jammy-server-cloudimg-amd64.img \
--osinfo ubuntu22.04 \
--import \
--noautoconsole
# Verify the new VM
sudo virsh --connect qemu:///system list --all
sudo virsh --connect qemu:///system dominfo cool-moray
sudo virsh --connect qemu:///system domblklist cool-moray --details
sudo virsh --connect qemu:///system domstate cool-moray
Technical Verification and References
The solution is based on the official virt-install, libvirt and Ubuntu cloud-image documentation.
Ubuntu virt-install(1) Manual — Describes the --memory, --disk, --import, --osinfo and --noautoconsole options.
libvirt virsh Command Reference — Documents VM inspection commands, including list, dominfo, domblklist and domstate.
Ubuntu — Launch QCOW Cloud Images Using libvirt — Provides a practical example of launching an existing Ubuntu cloud image with virt-install, --import and --noautoconsole.
Video verification finding: At approximately 28:30, the recording shows Question 7 and the required host lfcs00083. The candidate begins entering the SSH command but cancels it and moves to Question 8. The recording therefore does not demonstrate a successful VM creation. The solution above is independently documentation-validated, not confirmed as executed in that recording.
Expected result: A virtual machine named cool-moray is created and registered through libvirt using the existing Ubuntu image, with 1024 MiB RAM. The VM starts successfully, and virt-install exits without attaching to the VM's console.
Task
The system service apache2 is failing to start.
First, troubleshoot the failure and fix it.
Finally, start the systemd service and ensure it is running.
See the complete solution in Explanation.
Step 1: Connect to the correct Linux server.
The video specifies that this task must be performed on host lfcs00101a.
From the candidate terminal, execute:
ssh lfcs00101a
This establishes an SSH session with the server where the Apache service is failing.
All subsequent troubleshooting, configuration changes, and service operations must be performed on this host.
Step 2: Check the current status of the Apache service.
Execute:
sudo systemctl status apache2
This is the primary systemd command for checking the status of Apache.
It displays information such as:
Whether the apache2 service is loaded.
Whether the service is running, inactive or failed.
The process ID and execution status.
Recent service log messages.
Errors reported during startup.
An illustrative failure might appear as follows:
× apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled)
Active: failed (Result: exit-code)
Process: 1234 ExecStart=/usr/sbin/apachectl start
Main PID: 1234 (code=exited, status=1/FAILURE)
This is an example, not an output confirmed from the supplied video.
The Active: failed status means the service was unable to complete startup successfully.
Use the actual error messages to determine the cause.
Step 3: Examine the Apache service logs.
Execute:
sudo journalctl -u apache2 -b --no-pager
journalctl displays logs collected by systemd.
-u apache2 filters messages associated with the Apache service.
-b restricts results to the current boot.
--no-pager prints output directly without opening an interactive pager.
To display only the latest 50 messages:
sudo journalctl -u apache2 -n 50 --no-pager
These logs help identify why Apache failed.
Possible causes include:
Incorrect permissions on the Apache executable.
Invalid configuration directives.
Missing configuration files.
Another process using the required network port.
Inaccessible log directories.
Missing modules or other dependencies.
The official systemd documentation supports using journalctl -u to investigate the logs associated with a particular service.
Freedesktop
Step 4: Check the Apache executable.
On Ubuntu, the Apache server executable is normally located at:
/usr/sbin/apache2
Verify its existence:
ls -l /usr/sbin/apache2
For a more detailed permissions check:
stat -c '%A %a %U:%G %n' /usr/sbin/apache2
A correctly installed executable would typically have permissions similar to:
-rwxr-xr-x 755 root:root /usr/sbin/apache2
The x characters represent execute permission.
For example, if the permissions were incorrectly changed to:
-rw-r--r--
the executable would lack execution permission.
This can prevent Apache from starting successfully.
Step 5: Inspect the complete path permissions.
Execute:
namei -l /usr/sbin/apache2
This examines the permission bits and ownership of each directory component leading to the executable.
It helps distinguish between:
A non-executable Apache binary.
A directory that lacks search permission.
Incorrect ownership or permissions elsewhere in the path.
Also verify which package owns the executable:
dpkg -S /usr/sbin/apache2
On Ubuntu, it normally belongs to the apache2-bin package.
If required, check package-file integrity:
sudo dpkg -V apache2-bin
Package verification can help identify unexpectedly modified permissions or file contents.
Step 6: Correct the executable permission if it is the source of the failure.
In the supplied video, the candidate executes:
sudo chmod +x /usr/sbin/apache2
This is an important observation.
The command adds execute permission to the Apache executable according to the applicable chmod rules.
However, the candidate does not visibly demonstrate the earlier diagnostic output proving that missing execute permission caused the failure.
If the executable genuinely lacks its required execute permission, restore its expected mode:
sudo chmod 755 /usr/sbin/apache2
chmod changes file permissions.
755 grants read, write and execute permissions to the owner.
755 grants read and execute permissions to the group.
755 grants read and execute permissions to other users.
This is appropriate for a standard root-owned Apache executable when its mode has been incorrectly changed.
Do not execute this as a universal fix if the actual failure is a configuration error or port conflict.
Step 7: Verify the corrected permissions.
Execute:
ls -l /usr/sbin/apache2
Expected permissions, assuming the standard installation:
-rwxr-xr-x
For numerical verification:
stat -c '%a %n' /usr/sbin/apache2
Expected:
755 /usr/sbin/apache2
If the file's ownership is also incorrect, compare it with the package's expected ownership before making additional changes.
Step 8: Check the Apache configuration syntax.
Execute:
sudo apache2ctl configtest
This checks the Apache configuration for syntax errors.
For a valid configuration, the expected output is:
Syntax OK
The Apache control utility supports the configtest operation specifically for validating configuration syntax.
Apache HTTP Server Version 2.4
If it reports an error, inspect the identified file and line.
For example, an illustrative error might be:
Syntax error on line 42 of /etc/apache2/apache2.conf
Invalid command 'InvalidDirective'
In that case, correct the configuration directive instead of modifying executable permissions.
A successful syntax check does not guarantee that Apache can start, but it eliminates many configuration-related problems.
Step 9: Check whether Apache's required network ports are available.
Apache commonly listens on TCP port 80 for HTTP and port 443 for HTTPS.
Execute:
sudo ss -ltnp
To examine those ports specifically:
sudo ss -ltnp | grep -E ':(80|443)\b'
If another service already occupies a port configured for Apache, startup may fail with an address-binding error.
The official Apache documentation identifies port-binding conflicts as a common startup failure.
Apache HTTP Server Version 2.4
Do not stop another service unless the diagnostic evidence establishes that it is the source of the problem and the change is appropriate.
Step 10: Check Apache's own error log if necessary.
Execute:
sudo tail -n 50 /var/log/apache2/error.log
This displays recent entries from the standard Ubuntu Apache error log.
The file may contain additional details not included in the systemd journal.
Look for permission errors, configuration failures, missing resources or binding errors.
If the executable-permission repair was the only required correction, there may be no additional configuration changes to make.
Step 11: Start the Apache service.
After correcting the identified problem, execute:
sudo systemctl start apache2
sudo provides administrative privileges.
systemctl manages systemd services.
start requests that the specified service begin running.
apache2 identifies the Apache service unit.
This command directly satisfies the task's instruction to start the systemd service.
In the video, the candidate uses:
sudo systemctl restart apache2
The restart operation stops and starts an active service or starts it when appropriate.
Either operation can result in Apache running, but systemctl start apache2 is the more direct choice when the service is currently stopped or failed.
Step 12: Verify that Apache is running.
Execute:
sudo systemctl status apache2
Expected successful status:
● apache2.service - The Apache HTTP Server
Loaded: loaded
Active: active (running)
The critical field is:
Active: active (running)
This indicates that systemd considers the service active.
The official systemctl documentation defines the status command as the way to inspect the current runtime state of a service unit.
Linux manual page
Step 13: Verify the active service state directly.
Execute:
systemctl is-active apache2
Expected output:
active
Check the exit status immediately afterward:
echo $?
Expected:
0
The service is considered active when systemctl is-active returns active with a successful exit status.
Step 14: Verify that Apache is listening for connections.
Execute:
sudo ss -ltnp | grep apache2
This should display Apache processes listening on the ports specified in its configuration, provided those sockets can be associated with the process in the command output.
Alternatively, check the configured HTTP port:
sudo ss -ltnp | grep ':80'
An illustrative successful result might include:
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
The actual listening address and ports depend on Apache's configuration.
Step 15: Test the Apache HTTP service.
Execute:
curl -I http://localhost
This sends an HTTP HEAD request to the local web server.
An example of a successful HTTP response is:
HTTP/1.1 200 OK
Server: Apache/2.4.x (Ubuntu)
Content-Type: text/html
The exact response code depends on the website's configuration. For example, a redirect or authentication response can still show that Apache is accepting connections.
If the service is active but HTTP requests fail, inspect its listener configuration and logs.
Step 16: Confirm that the service remains running.
Execute:
sleep 5
systemctl is-active apache2
Expected:
active
This additional check helps detect a service that starts briefly and then fails.
You can also inspect recent logs:
sudo journalctl -u apache2 -n 20 --no-pager
Confirm that no further startup or runtime failures have occurred.
Step 17: Perform final verification.
Execute:
sudo apache2ctl configtest
systemctl is-active apache2
sudo systemctl status apache2 --no-pager
curl -I http://localhost
The final requirements are:
Verification
Expected result
Apache configuration test
Syntax OK
Apache executable permission
Valid executable permissions
systemd service status
active (running)
HTTP connectivity
A valid response from the configured service
Original startup failure
Resolved
Final Solution
The video suggests the failure may be related to execute permission on /usr/sbin/apache2. The following is the concise command sequence for that specific confirmed failure.
1. Connect to the server.
ssh lfcs00101a
2. Check the service failure.
sudo systemctl status apache2
sudo journalctl -u apache2 -n 50 --no-pager
3. Inspect the Apache executable permissions.
ls -l /usr/sbin/apache2
4. Restore executable permissions if they are incorrect.
sudo chmod 755 /usr/sbin/apache2
5. Validate the Apache configuration.
sudo apache2ctl configtest
6. Start the Apache service.
sudo systemctl start apache2
7. Verify the running service.
sudo systemctl status apache2
systemctl is-active apache2
Expected:
active
8. Verify HTTP connectivity.
curl -I http://localhost
Technical Verification and References
The procedures are consistent with official Apache and systemd documentation:
Apache HTTP Server — apachectl and configtest
Apache HTTP Server — Startup and Troubleshooting
Linux systemctl — Managing Service Units
systemd journalctl — Service Log Inspection
Expected result: The cause preventing apache2 from starting is corrected, and the service is successfully started with systemd and remains in the active (running) state.
Video verification finding: The candidate visibly runs sudo chmod +x /usr/sbin/apache2 and then attempts to restart Apache. That is a valid repair if missing executable permission was the actual fault, but the visible commands do not independently prove the diagnosis or final service state. The diagnostic and verification steps above are necessary for a reliable solution.
Task
First, create a user james with the password set to Foundation.
Next, create a group commander with GID 15002 and add user james.
Do not change user james's primary group.
Then, create a group pilot with GID 15001 and edit user james to use pilot as the primary group.
See the complete solution in Explanation.
Objective: Create the Linux user james, assign the specified password, create two groups with exact group IDs, and configure the user's primary and supplementary group memberships.
The task requires these operations to be performed in the specified order:
Requirement
Expected configuration
Username
james
Password
Foundation
Supplementary group
commander
Supplementary group GID
15002
Primary group
pilot
Primary group GID
15001
Important: Adding james to commander must not change the user's primary group. Only the final operation changes the primary group to pilot.
Step 1: Connect to the correct Linux server.
The video specifies host lfcs00091.
From the candidate terminal, execute:
ssh lfcs00091
This establishes an SSH connection to the designated Linux server.
All account and group-management operations must be performed on this host.
Step 2: Check whether user james already exists.
Execute:
id james
If the account does not exist, an expected message is:
id: ‘james’: no such user
You can also execute:
getent passwd james
This searches the configured user-account databases.
If the account already exists, inspect it before changing anything. Since the task explicitly requests creating the user, the normal exam starting state should not already contain the account.
Step 3: Create the user james.
Execute:
sudo useradd -m james
sudo runs the command with administrative privileges.
useradd creates a new Linux user account.
-m creates a home directory for the user.
james is the required username.
On a typical Ubuntu system configured for private user groups, the command creates an account with a home directory at:
/home/james
The default primary group is determined by the system's account-creation policy. It is commonly a private group named james.
The official Linux useradd(8) documentation confirms that -m creates a home directory and that default primary-group behavior depends on system configuration.
Linux manual page
Step 4: Verify that the user was created successfully.
Execute:
id james
An illustrative output is:
uid=1001(james) gid=1001(james) groups=1001(james)
The numerical UID and initial GID can differ on the actual system.
Check the account entry:
getent passwd james
Verify the home directory:
ls -ld /home/james
The account should exist before proceeding.
Step 5: Set the user's password to Foundation.
Execute:
sudo passwd james
The system will request a new password.
Enter:
Foundation
When prompted to confirm, enter:
Foundation
The password is case-sensitive.
A successful operation normally displays:
passwd: password updated successfully
The passwd command securely processes the supplied password and updates the account's password authentication information.
The official passwd(1) manual confirms that an administrator can assign a password to another user and that the utility requests the new password interactively.
Linux manual page
Step 6: Verify the user's password status.
Execute:
sudo passwd -S james
The output may resemble:
james P 2026-10-12 0 99999 7 -1
The date and password-aging fields will depend on the system.
The important value is:
P
This indicates that the account has a usable password.
This command does not reveal or independently confirm the plaintext password. To verify the actual credential, authenticate as james using Foundation through an appropriate login method.
Do not attempt to read the plaintext password from /etc/shadow. Linux stores password hashes rather than recoverable plaintext passwords.
Step 7: Check whether the group commander already exists.
Before creating the group, execute:
getent group commander
If the group does not exist, the command normally produces no output.
Also check whether GID 15002 is already allocated:
getent group 15002
If both checks produce no results, the requested group name and ID are available.
Step 8: Create group commander with GID 15002.
Execute:
sudo groupadd -g 15002 commander
groupadd creates a new Linux group.
-g 15002 assigns the exact numerical GID.
commander is the required group name.
The -g option explicitly controls the group's numerical identifier.
The official groupadd(8) documentation confirms that this option creates a group using the specified GID and normally requires it to be unique.
Linux manual page
Step 9: Verify that group commander was created.
Execute:
getent group commander
Expected output, before adding members:
commander:x:15002:
The fields in /etc/group are arranged as:
group_name:password:GID:user_list
Therefore:
commander is the group name.
x indicates the group password field is not stored directly in /etc/group.
15002 is the assigned GID.
The final field lists supplementary group members.
Step 10: Record james's current primary group.
Before adding james to commander, execute:
id -gn james
This displays the user's current primary group name.
To display its numerical GID:
id -g james
On a typical Ubuntu system, the group name may initially be:
james
The purpose of this step is to establish the primary-group value before making any changes to supplementary memberships.
Step 11: Add james to commander as a supplementary group.
Execute:
sudo usermod -aG commander james
This is one of the most important commands in the task.
Option
Purpose
usermod
Modifies an existing user account
-a
Appends to existing supplementary group memberships
-G commander
Specifies the supplementary group
james
Specifies the target user
The combination -aG adds commander to the user's supplementary memberships without changing the primary group.
The official usermod(8) manual confirms this behavior.
Linux manual page
Step 12: Understand why -aG is required.
Compare these commands:
sudo usermod -aG commander james
This is correct because it appends commander to the supplementary groups.
sudo usermod -G commander james
This can replace the user's existing supplementary group list with the specified list, removing memberships that were not included.
sudo usermod -g commander james
This would change the primary group to commander.
The last command is incorrect at this stage because the task explicitly states:
Do not change user james's primary group.
Therefore, use:
sudo usermod -aG commander james
Step 13: Verify supplementary group membership.
Execute:
id james
An illustrative result is:
uid=1001(james) gid=1001(james) groups=1001(james),15002(commander)
This confirms that commander was added as a supplementary group.
Check the group entry:
getent group commander
Expected:
commander:x:15002:james
Step 14: Verify that the primary group has not changed.
Execute:
id -gn james
Compare its output against the primary group recorded in Step 10.
The value must remain unchanged at this stage.
For example, if the original primary group was james, the output should remain:
james
Also check:
id -g james
This should return the original primary GID.
Do not proceed until both conditions are met: james belongs to commander, and the original primary group is unchanged.
Step 15: Check whether the group pilot already exists.
Execute:
getent group pilot
Check whether GID 15001 is available:
getent group 15001
The group name and numerical GID should be available for the requested group creation.
Step 16: Create group pilot with GID 15001.
Execute:
sudo groupadd -g 15001 pilot
groupadd creates a new group.
-g 15001 sets its numerical GID to 15001.
pilot is the requested group name.
The exact GID matters. Do not allow Linux to choose an automatically assigned GID.
Step 17: Verify group pilot.
Execute:
getent group pilot
Expected:
pilot:x:15001:
This verifies the group name and assigned numerical identifier.
At this stage, the group has been created, but the user's primary group has not yet been changed.
Step 18: Set pilot as the primary group for james.
Execute:
sudo usermod -g pilot james
This is the final account-modification command required by the task.
usermod modifies the existing user account.
-g pilot sets the primary login group to pilot.
james identifies the account being modified.
Unlike uppercase -G, which controls supplementary groups, lowercase -g specifies the primary group.
The official usermod(8) documentation distinguishes these options explicitly.
Linux manual page
The new primary group must already exist, which is why pilot was created first.
Step 19: Verify the user's new primary group.
Execute:
id -gn james
Expected output:
pilot
Verify the numerical GID:
id -g james
Expected:
15001
These commands establish that the account's primary group is now pilot.
Step 20: Verify that commander remains a supplementary group.
Execute:
id james
An illustrative final result is:
uid=1001(james) gid=15001(pilot) groups=15001(pilot),15002(commander)
The UID and any additional supplementary groups may differ.
The important conditions are:
Primary GID: 15001, belonging to pilot.
Supplementary membership: commander, GID 15002.
Changing the primary group with usermod -g should not remove the existing supplementary commander membership.
Step 21: Inspect the final account database entry.
Execute:
getent passwd james
An illustrative entry is:
james:x:1001:15001::/home/james:/bin/sh
The fourth field is the primary GID, which must be 15001.
The login shell and other fields may vary according to the system defaults.
Step 22: Verify the group definitions.
Execute:
getent group commander
getent group pilot
Expected group definitions:
commander:x:15002:james
pilot:x:15001:
It is normal for the pilot group entry not to list james explicitly in its final member field. A user's primary group is determined by the GID stored in the user-account record, while /etc/group lists explicit supplementary group membership.
The id james command is the most convenient way to verify both kinds of group membership together.
Linux manual page
Step 23: Verify the password status again.
Execute:
sudo passwd -S james
Confirm that the account still reports a usable password with status P.
The group modifications should not change the password.
Step 24: Perform the final verification.
Execute:
id james
id -gn james
id -g james
id -Gn james
getent group commander
getent group pilot
sudo passwd -S james
The required final configuration is:
Requirement
Expected result
User exists
james
Password configured
Foundation
commander exists
Yes
commander GID
15002
commander membership
Supplementary
pilot exists
Yes
pilot GID
15001
pilot membership
Primary
Other supplementary memberships
Preserved
Final Solution
Execute the following commands in order.
# Connect to the required server
ssh lfcs00091
# Create user james with a home directory
sudo useradd -m james
# Set password interactively to Foundation
sudo passwd james
# Create commander with GID 15002
sudo groupadd -g 15002 commander
# Add james to commander as a supplementary group
sudo usermod -aG commander james
# Verify primary group has not changed
id -gn james
# Create pilot with GID 15001
sudo groupadd -g 15001 pilot
# Change james's primary group to pilot
sudo usermod -g pilot james
# Verify the complete user configuration
id james
id -gn james
id -g james
# Verify the created groups
getent group commander
getent group pilot
# Verify the account has a usable password
sudo passwd -S james
When executing:
sudo passwd james
enter Foundation twice when prompted.
Expected final result:
uid=1001(james) gid=15001(pilot) groups=15001(pilot),15002(commander)
The UID is illustrative. The required group names, GIDs, and memberships must match exactly.
Technical Verification and References
The commands have been checked against the Linux account-management manuals:
Linux useradd(8)
— Creating user accounts.
Linux passwd(1)
— Assigning and checking user passwords.
Linux groupadd(8)
— Creating groups with specified GIDs.
Linux usermod(8)
— Managing primary and supplementary group memberships.
Linux id(1)
— Verifying user and group identities.
Video verification finding: Question 15 is visible at approximately 32:14–32:18 of the recording. Its full task statement and target host lfcs00091 are readable. The candidate moves to the next task without demonstrating these account-management commands, so the solution is independently documentation-verified rather than confirmed through successful execution in the video.
Expected result: User james has password Foundation, belongs to commander (GID 15002) as a supplementary group, and uses pilot (GID 15001) as the primary group.
next now
Worked for 4m 23s
Task
Set the "number of processes" hard limit for the existing user james to 32768 and the soft limit to 16384.
Ensure that changes are made persistently.
See the complete solution in Explanation.
Objective: Configure persistent Linux resource limits for the existing user james, ensuring that:
The hard process limit is 32768.
The soft process limit is 16384.
The limits are applied when the user starts a new PAM-managed login session.
The configuration remains available after a system reboot.
The appropriate solution uses Linux-PAM's resource-limit configuration, typically in /etc/security/limits.d/.
The official Linux-PAM documentation specifies the configuration syntax and confirms that nproc is the resource identifier for process limits.
Step 1: Connect to the correct Linux server.
The video specifies host lfcs00089.
From the candidate terminal, execute:
ssh lfcs00089
This establishes an SSH session with the designated server.
All subsequent configuration changes must be performed on this host.
Step 2: Verify that the user james exists.
Execute:
id james
This displays the user's UID, primary group and supplementary group memberships.
Example output:
uid=1001(james) gid=1001(james) groups=1001(james)
The numeric identifiers may differ on the actual server.
You can also check the account database:
getent passwd james
The task specifies an existing user, so there is no need to create a new account or modify the user's password.
Step 3: Understand soft and hard process limits.
Linux implements process-related resource restrictions using RLIMIT_NPROC.
Limit
Required value
Purpose
Soft
16384
Default process/thread creation limit enforced for the user's processes
Hard
32768
Maximum value to which an unprivileged user may raise the soft limit
The hard limit must be at least as large as the soft limit. Here:
\[ 16384 \leq 32768 \]
Therefore, the requested configuration is valid.
On Linux, RLIMIT_NPROC actually accounts for processes and threads associated with the real user ID, subject to kernel privilege exceptions. It is not a separate allowance for every running application.
Step 4: Inspect any existing persistent limits.
Before changing the system, execute:
sudo cat /etc/security/limits.conf
Then list any existing supplemental configuration files:
sudo ls -la /etc/security/limits.d/
Search specifically for process-limit settings:
sudo grep -RnsE \
'^[[:space:]]*([^#[:space:]] +[[:space:]]+)+(soft|hard|-)[[:space:]] +nproc' \
/etc/security/limits.conf /etc/security/limits.d/ 2 > /dev/null
Also check for any existing entries concerning james:
sudo grep -RnsE '^[[:space:]]*james[[:space:]] ' \
/etc/security/limits.conf /etc/security/limits.d/ 2 > /dev/null
These checks help identify existing user-specific limits and avoid contradictory configuration entries.
Step 5: Understand the persistent configuration locations.
The primary resource-limit configuration file is:
/etc/security/limits.conf
Additional administrator-defined limits can be stored under:
/etc/security/limits.d/
Both locations are supported by Linux-PAM.
The configuration format is:
< domain > < type > < item > < value >
For this task:
Field
Required value
Description
Domain
james
Existing username
Type
soft or hard
Which resource limit to configure
Item
nproc
Number of processes/threads
Value
16384 or 32768
Required limit
A dedicated configuration file is preferable because it keeps the account-specific policy separate from the system's general resource-limit settings.
Step 6: Create the persistent configuration file.
Execute:
sudo nano /etc/security/limits.d/90-james-nproc.conf
This opens a new configuration file.
If the file already exists, inspect its contents before modifying it.
Step 7: Add the required soft and hard process limits.
Insert the following two lines:
james soft nproc 16384
james hard nproc 32768
This is the exact configuration required for the task.
Explanation of the first line:
james soft nproc 16384
james selects the target user.
soft specifies the default soft resource limit.
nproc refers to the process/thread limit.
16384 establishes the required soft value.
Explanation of the second line:
james hard nproc 32768
james selects the same user.
hard specifies the hard resource limit.
nproc identifies the resource.
32768 establishes the maximum hard value.
These settings apply specifically to james rather than all users.
The Linux-PAM manual explicitly supports user-specific soft and hard nproc entries.
Step 8: Save the configuration.
If using Nano:
Press Ctrl + O to save.
Press Enter to confirm the filename.
Press Ctrl + X to exit.
If using Vim:
Press Esc.
Type :wq.
Press Enter.
The file should be located at:
/etc/security/limits.d/90-james-nproc.conf
Step 9: Verify the saved configuration.
Execute:
sudo cat /etc/security/limits.d/90-james-nproc.conf
Expected output:
james soft nproc 16384
james hard nproc 32768
Check the file permissions:
ls -l /etc/security/limits.d/90-james-nproc.conf
A typical configuration file has permissions of 644 and is owned by root.
If the file permissions are incorrect, restore appropriate permissions:
sudo chmod 644 /etc/security/limits.d/90-james-nproc.conf
The file should be readable by the PAM module when login sessions are established.
Step 10: Verify that PAM applies resource limits.
The settings are interpreted by the PAM module:
pam_limits.so
Check whether the module is configured:
sudo grep -Rns 'pam_limits.so' /etc/pam.d/
A relevant configuration entry resembles:
session required pam_limits.so
session identifies the PAM session-management phase.
required means the module must succeed for the relevant PAM operation to succeed.
pam_limits.so applies the configured resource limits when the session is established.
The official Linux-PAM documentation confirms that this module applies resource limits to user sessions.
On Ubuntu, inspect the PAM configuration used by the relevant login method, including sshd, login, su, and any referenced common-session files.
Do not blindly add duplicate pam_limits.so entries. If the module is absent from the actual login path, configure it appropriately before testing.
Step 11: Understand when the changes take effect.
The limits defined in /etc/security/limits.d/90-james-nproc.conf are persistent settings, but they are not automatically applied to every currently running process.
Linux-PAM applies these limits when an applicable new login session begins.
Therefore:
Existing sessions may retain their previous limits.
New PAM-managed sessions can receive the new values.
Changes survive reboot because the configuration is stored on disk.
There is no need to restart the entire operating system simply to load the configuration.
The Linux-PAM manual specifically explains that configured resource limits are applied per login session.
Step 12: Start a fresh session as james.
If you have administrative access, you can attempt to create a new login session with:
sudo su - james
This starts a login-style shell using the su PAM service, provided that service is configured to apply PAM resource limits.
Alternatively, open a new SSH login as james, using the account's existing credentials if permitted:
ssh james@localhost
A fresh SSH login is particularly useful if the actual login service is the intended target of the configuration.
Check the active user:
whoami
Expected:
james
Do not assume that simply running sudo -u james ulimit ... is a valid test. ulimit is a shell builtin, and changing the execution user does not necessarily create a PAM session or apply its resource-limit policy.
Step 13: Verify the soft process limit.
Inside the new login session belonging to james, execute:
ulimit -Su
ulimit displays or controls process resource limits.
-S selects the soft limit.
-u selects the maximum process/thread resource limit.
Expected output:
16384
This confirms that the session received the required soft limit.
Step 14: Verify the hard process limit.
In the same session, execute:
ulimit -Hu
-H selects the hard limit.
-u selects the process/thread resource limit.
Expected output:
32768
The GNU Bash manual confirms that -S and -H distinguish soft and hard limits, and that -u refers to the maximum number of processes available to a user.
Step 15: Verify both limits together.
Execute:
printf 'Soft limit: '
ulimit -Su
printf 'Hard limit: '
ulimit -Hu
Expected output:
Soft limit: 16384
Hard limit: 32768
This is the most direct practical verification of the two requested values.
Step 16: Verify the kernel's process-limit information.
Linux also exposes resource limits through the /proc filesystem.
Inside the new james session, execute:
cat /proc/self/limits
Find the line:
Max processes
The relevant values should be:
Limit Soft Limit Hard Limit
Max processes 16384 32768
The displayed output contains additional columns and other resource limits, but the Max processes entry is the one relevant to this task.
For a more concise check, execute:
grep 'Max processes' /proc/self/limits
Expected values:
Max processes 16384 32768
You can also use:
prlimit --pid $$
This displays resource limits for the current shell process.
Step 17: Check for conflicting limits if the values are incorrect.
If the new session does not show the required values, investigate rather than repeatedly adding duplicate configuration entries.
First, inspect user-specific rules:
sudo grep -Rns 'james' \
/etc/security/limits.conf /etc/security/limits.d/
Next, inspect all process-limit rules:
sudo grep -Rns 'nproc' \
/etc/security/limits.conf /etc/security/limits.d/
Then check whether pam_limits.so is active in the login method used for testing.
Potential reasons for an unexpected value include an overriding limits configuration, a session started without PAM resource-limit processing, or resource limits imposed by a systemd-managed service.
If the user runs an application under a systemd service, systemd's LimitNPROC= setting may also be relevant. However, configuring a systemd service is not required by the task.
Step 18: Verify persistence.
The persistent configuration resides at:
/etc/security/limits.d/90-james-nproc.conf
Execute:
sudo cat /etc/security/limits.d/90-james-nproc.conf
Expected:
james soft nproc 16384
james hard nproc 32768
Because this configuration is stored under /etc, it remains present after the system reboots unless it is changed or removed.
For end-to-end verification, start a fresh login session after reboot and repeat:
ulimit -Su
ulimit -Hu
Expected:
16384
32768
A reboot is not necessary for normal verification, and should not be performed unnecessarily during the LFCS exam.
Step 19: Confirm that unrelated users remain unchanged.
The file contains rules for:
james
It does not use the wildcard:
*
Therefore, this particular configuration does not apply indiscriminately to all users.
Avoid adding entries such as:
* soft nproc 16384
* hard nproc 32768
Those would impose the specified limits more broadly, instead of targeting the user named in the task.
Step 20: Perform final verification.
The final configuration must satisfy all requirements:
Requirement
Expected result
Existing user
james
Resource type
nproc
Soft limit
16384
Hard limit
32768
Persistent configuration
Present
Fresh login session
Correct limits applied
Other users
No unnecessary changes
Final Solution
The essential commands are:
Copy commands
# Connect to the correct server
ssh lfcs00089
# Verify the user exists
id james
# Create the persistent resource-limit configuration
printf '%s\n' \
'james soft nproc 16384' \
'james hard nproc 32768' | \
sudo tee /etc/security/limits.d/90-james-nproc.conf
# Verify the configuration
sudo cat /etc/security/limits.d/90-james-nproc.conf
# Confirm PAM resource-limit integration
sudo grep -Rns 'pam_limits.so' /etc/pam.d/
# Start a new PAM-managed login session
# (provided the su PAM stack applies pam_limits)
sudo su - james
# Verify the soft limit
ulimit -Su
# Verify the hard limit
ulimit -Hu
# Verify through procfs
grep 'Max processes' /proc/self/limits
The required configuration is:
james soft nproc 16384
james hard nproc 32768
Technical Verification and References
Linux-PAM limits.conf(5) — Confirms the configuration file syntax and nproc resource identifier.
Linux-PAM pam_limits(8) — Explains how limits are applied when PAM sessions are established.
GNU Bash — ulimit — Documents soft and hard resource-limit verification.
Linux getrlimit(2) — Defines the kernel's process-limit behavior.
Video verification finding: At approximately 29:01–29:05, Question 9 appears with host lfcs00089. The recording shows the full task statement but does not demonstrate the required configuration being completed. The solution above is independently validated against Linux-PAM documentation.
Expected result: User james receives a soft process limit of 16384 and a hard process limit of 32768 in applicable new login sessions. The settings are stored persistently and remain configured after reboot.
Task
First, inspect all application data partitions and find partitions utilizing more than 85% disk space.
Then, save the absolute path of these partitions' device files, one per line, to ~/partitions.txt.
Next, in data partitions using more than 85% disk space, delete the *.log files greater than 5 MB.
Do not modify any other data partitions.
See the complete solution in Explanation.
Step 1: Connect to the correct Linux server.
The video specifies that this task must be completed on host lfcs00077.
From the candidate terminal, execute:
ssh lfcs00077
All disk inspection, file creation, and deletion operations must be performed on this host.
Step 2: Inspect all mounted filesystems and disk utilization.
Execute:
df -hT
This displays information about mounted filesystems, including their utilization.
An illustrative output is:
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda1 ext4 40G 16G 24G 40% /
/dev/sdb1 ext4 20G 18G 2G 90% /data/app1
/dev/sdc1 ext4 30G 27G 3G 90% /data/app2
/dev/sdd1 ext4 50G 30G 20G 60% /data/app3
This output is an example, not data obtained from the actual exam host.
Explanation of the columns:
Column
Description
Filesystem
Device or filesystem source
Type
Filesystem type, such as ext4 or XFS
Size
Total filesystem capacity
Used
Used disk space
Avail
Available disk space
Use%
Percentage of disk space utilized
Mounted on
Directory where the filesystem is mounted
The task requires identifying application data partitions utilizing more than 85%.
For example:
/dev/sdb1 — 90% utilized — qualifies.
/dev/sdc1 — 90% utilized — qualifies.
/dev/sdd1 — 60% utilized — does not qualify.
The system partition /dev/sda1 should not be included merely because it appears in df output. The task specifically refers to application data partitions.
Step 3: Identify the available block devices.
Execute:
lsblk
For more detailed output:
lsblk -p -o NAME,SIZE,FSTYPE,MOUNTPOINTS
lsblk lists available block devices.
-p displays full device paths.
-o specifies the output columns.
NAME identifies the device.
SIZE displays its capacity.
FSTYPE shows the filesystem type.
MOUNTPOINTS lists its mountpoints.
An illustrative output is:
NAME SIZE FSTYPE MOUNTPOINTS
/dev/sda 40G
└─/dev/sda1 40G ext4 /
/dev/sdb 20G
└─/dev/sdb1 20G ext4 /data/app1
/dev/sdc 30G
└─/dev/sdc1 30G ext4 /data/app2
/dev/sdd 50G
└─/dev/sdd1 50G ext4 /data/app3
The output establishes the relationship between block devices, filesystems, and application data mountpoints.
This is necessary because the task requires saving device file paths, not mountpoint paths.
Step 4: Display filesystems using a consistent output format.
Execute:
df -P
The -P option uses the POSIX output format, which displays each filesystem on a single line.
This is useful when processing filesystem information with awk.
To identify all mounted filesystems whose reported utilization exceeds 85%, execute:
df -P | awk 'NR > 1 {
usage = $5
gsub(/%/, "", usage)
if (usage > 85)
print $1, usage "%", $6
}'
NR > 1 skips the header.
$5 extracts the utilization percentage.
gsub(/%/, "", usage) removes the percentage symbol.
usage > 85 selects filesystems whose reported utilization exceeds 85%.
$1 displays the filesystem source.
$6 displays the mountpoint.
An illustrative result is:
/dev/sdb1 90% /data/app1
/dev/sdc1 90% /data/app2
Important: This command identifies all filesystems over the threshold, not necessarily only application data filesystems. You must inspect the results and exclude unrelated system partitions.
Official GNU documentation confirms the purpose and output format of df -P.
Step 5: Verify the mountpoint associated with each qualifying device.
Execute:
findmnt -rno SOURCE,TARGET,FSTYPE
This shows the source devices, their mountpoints, and filesystem types.
For an individual qualifying mountpoint, use:
findmnt --mountpoint /data/app1
And:
findmnt --mountpoint /data/app2
These paths are illustrative. Replace them with the actual qualifying application data mountpoints.
Ensure that each selected filesystem:
Is an application data partition.
Has reported utilization greater than 85%.
Has an identified block-device path.
Is mounted at a known location.
Only proceed once these conditions are confirmed.
Step 6: Create the required ~/partitions.txt file.
The task requires saving the absolute paths of qualifying device files, one per line.
For example, suppose the qualifying devices are:
/dev/sdb1
/dev/sdc1
Execute:
printf '%s\n' /dev/sdb1 /dev/sdc1 > ~/partitions.txt
Replace /dev/sdb1 and /dev/sdc1 with the actual device paths identified on the exam server.
printf '%s\n' prints each supplied argument on a separate line.
/dev/sdb1 and /dev/sdc1 represent the qualifying device files.
> redirects output into the required file.
~/partitions.txt is the output file specified in the task.
The file must contain device paths rather than utilization percentages or mountpoint paths.
Step 7: Verify the contents of partitions.txt.
Execute:
cat ~/partitions.txt
For the illustrative devices, the expected content is:
/dev/sdb1
/dev/sdc1
Each qualifying device must appear on a separate line.
You can also number the lines to inspect the format:
cat -n ~/partitions.txt
Example:
1 /dev/sdb1
2 /dev/sdc1
Verify that no device from an application data filesystem at 85% or below appears in this file.
Step 8: Confirm that each saved path is a block device.
Execute:
while IFS= read -r device; do
ls -l "$device"
done < ~/partitions.txt
The device entries should represent valid block devices.
To check one device directly:
test -b /dev/sdb1
echo $?
An exit status of 0 indicates that the path refers to a block device.
Use the actual path from partitions.txt.
Step 9: Identify log files larger than 5 MB on qualifying partitions.
The next requirement is to delete *.log files greater than 5 MB, but only from qualifying data partitions.
For example, if /dev/sdb1 is mounted at /data/app1, execute:
sudo find /data/app1 -xdev -type f \
-name '*.log' -size +5000000c -print
Parameter
Purpose
/data/app1
Searches the selected qualifying filesystem
-xdev
Prevents descending into other mounted filesystems
-type f
Selects regular files
-name '*.log'
Selects filenames ending with .log
-size +5000000c
Selects files larger than 5,000,000 bytes
Displays matching files without deleting them
The task says 5 MB. The command above uses the strict decimal definition of 5 MB.
In GNU find, the alternative:
-size +5M
uses 5 MiB (5,242,880 bytes) rather than decimal megabytes. Both conventions occur in Linux administration, but they are not numerically identical. GNU Findutils documents these units explicitly.
Step 10: Preview the matching files on every qualifying partition.
For example, if /data/app1 and /data/app2 are the two qualifying mountpoints, execute:
sudo find /data/app1 -xdev -type f \
-name '*.log' -size +5000000c -print
Then:
sudo find /data/app2 -xdev -type f \
-name '*.log' -size +5000000c -print
Example results might be:
/data/app1/logs/application.log
/data/app1/logs/error.log
/data/app2/reports/debug.log
These filenames are illustrative.
Review the output before deleting anything.
This matters because the task expressly prohibits modifying other data partitions.
Step 11: Delete qualifying log files from the first selected partition.
After confirming the filesystem and matching files, execute:
sudo find /data/app1 -xdev -type f \
-name '*.log' -size +5000000c -delete
The -delete action removes the matching files permanently.
Do not execute the command against the entire root filesystem or an unqualified data partition.
The -xdev option is particularly important. It prevents traversal into other mounted filesystems located beneath the selected mountpoint.
Step 12: Delete qualifying log files from any additional qualifying partition.
For the second illustrative mountpoint:
sudo find /data/app2 -xdev -type f \
-name '*.log' -size +5000000c -delete
Repeat only for the remaining application data partitions whose utilization was greater than 85% during the initial inspection.
Do not apply deletion commands to other partitions.
GNU Findutils documents that -delete performs deletion directly and that its predicates should be tested using -print first.
Step 13: Verify that the matching log files have been removed.
Execute:
sudo find /data/app1 -xdev -type f \
-name '*.log' -size +5000000c -print
Then:
sudo find /data/app2 -xdev -type f \
-name '*.log' -size +5000000c -print
If there are no matching files remaining, the commands should produce no output.
If files remain, investigate permission errors or files that changed during the operation.
Step 14: Verify disk utilization after deletion.
Execute:
df -hT
Compare the disk utilization with the initial results.
For example:
Partition
Before
After
/dev/sdb1
90%
77%
/dev/sdc1
90%
82%
/dev/sdd1
60%
60%
These percentages are illustrative, not measured results.
There is no requirement to reduce the qualifying partitions below 85%; the task asks only to delete matching log files.
If a deleted file remains open in a running process, its storage space might not be released until the process closes the file. That does not justify stopping unrelated services without evidence.
Step 15: Confirm that other data partitions were not modified.
Review the original list of partitions and verify that deletion was limited to the selected qualifying mountpoints.
For example, do not execute:
sudo find /data/app3 -name '*.log' -delete
if /data/app3 had utilization of only 60%.
The task explicitly states:
Do not modify any other data partitions.
Therefore, applying a blanket cleanup command across /data, /, or all mounted filesystems would be incorrect.
Step 16: Verify the saved device list again.
Execute:
cat ~/partitions.txt
Confirm that it still contains the original qualifying device paths.
Do not regenerate this list after deletion.
For example, suppose /dev/sdb1 was initially 90% utilized but dropped to 77% after cleanup. It must still appear in ~/partitions.txt because it qualified during the initial inspection.
Step 17: Perform final verification.
Execute:
cat ~/partitions.txt
df -hT
lsblk -p -o NAME,FSTYPE,MOUNTPOINTS
Then run the file search on each qualifying mountpoint once more.
The completed task must meet these conditions:
Requirement
Expected result
Application data partitions inspected
Yes
Partitions greater than 85% identified
Yes
Device paths saved in ~/partitions.txt
Yes
One absolute device path per line
Yes
Matching log files greater than 5 MB deleted
Yes
Only qualifying partitions affected
Yes
Unrelated data partitions unchanged
Yes
Final Solution
The essential command sequence below illustrates the procedure. The two device paths and mountpoints are examples and must be replaced with the actual qualifying values on lfcs00077.
Copy commands
# Connect to the correct host
ssh lfcs00077
# Inspect disk utilization and mounted devices
df -hT
lsblk -p -o NAME,SIZE,FSTYPE,MOUNTPOINTS
# Find filesystems over 85%
df -P | awk 'NR > 1 {
usage=$5
gsub(/%/, "", usage)
if (usage > 85)
print $1, usage "%", $6
}'
# Confirm actual device-to-mountpoint relationships
findmnt -rno SOURCE,TARGET,FSTYPE
# EXAMPLE DEVICES: replace after identifying qualifying partitions
printf '%s\n' /dev/sdb1 /dev/sdc1 > ~/partitions.txt
# Verify the saved list
cat ~/partitions.txt
# EXAMPLE MOUNTPOINTS: preview before deleting
sudo find /data/app1 -xdev -type f \
-name '*.log' -size +5000000c -print
sudo find /data/app2 -xdev -type f \
-name '*.log' -size +5000000c -print
# Delete only on confirmed qualifying partitions
sudo find /data/app1 -xdev -type f \
-name '*.log' -size +5000000c -delete
sudo find /data/app2 -xdev -type f \
-name '*.log' -size +5000000c -delete
# Final verification
df -hT
cat ~/partitions.txt
Technical Verification and References
The procedures are consistent with the following official documentation:
GNU Coreutils — df command
Linux lsblk(8) — Block Device Inspection
GNU Findutils — File Size Matching
GNU Findutils — Filesystem Boundary Control
GNU Findutils — Deleting Files
Video verification finding: I located Question 6 at approximately 28:04–28:10 of the recording and confirmed the task wording and required host. The video moves to Question 7 without showing a completed terminal solution for Question 6. Therefore, the commands above are an independently documented solution, not a reproduction of commands successfully executed in the recording.
Expected result: The file ~/partitions.txt contains the absolute device paths of the application data partitions that initially exceeded 85% disk utilization. All qualifying .log files larger than the specified threshold are deleted from those partitions only, without modifying any other data partitions.
