EF Tips and Tricks

EnginFrame is a very powerful HPC and visualization session management portal. In this section we want to highlight some of the features and configuration options of EnginFrame.

A powerful overview of EnginFrame customization options can be found in the Technology Showcase available from the startpage of EnginFrame as administrator user.

Automatic Login

The steps to scrape data from Enginframe through curl are the following:

  1. Get JSESSIONID cookie end CSRF token
  2. Make login (use a license)
  3. Retrieve data
  4. Make log out (to release the license)

The following script implements these steps:

#!/bin/bash

workdir='/tmp/'

curl="curl --silent --insecure \
       --cookie $workdir/cookies.txt \
       --cookie-jar $workdir/cookies.txt"

endpoint='http://localhost:8080'

user='efadmin'
password='123456'

function session {
   $curl --junk-session-cookies "$endpoint/enginframe/admin/com.enginframe.admin.xml" > /dev/null
   $curl -X POST \
       -H "Referer: $endpoint/enginframe" \
       -H "FETCH-CSRF-TOKEN: 1" \
       "$endpoint/enginframe/CsrfGuardServlet" | awk -F ':' '{print $1"=" $2}' > $workdir/csrftoken
}

function login {
   $curl -X POST \
       -H "Referer: $endpoint/enginframe" \
       -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
       -H 'Accept-Language: en,it;q=0.5' \
       -H 'Content-Type: application/x-www-form-urlencoded' \
       -H 'Upgrade-Insecure-Requests: 1' \
       --data "_username=$user" \
       --data "_password=$password" \
       --data 'submit=Login' \
       --data $(< $workdir/csrftoken) \
       "$endpoint/enginframe/admin/com.enginframe.admin.xml?_uri=//com.enginframe.admin/server.load" > /dev/null
}

function logout {
   $curl \
       -H "Referer: $endpoint/enginframe" \
       -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
       -H 'Accept-Language: en,it;q=0.5' \
       -H 'Content-Type: application/x-www-form-urlencoded' \
       -H 'Upgrade-Insecure-Requests: 1' \
       "$endpoint/enginframe/admin/com.enginframe.admin.xml?_uri=//com.enginframe.system/logout"  > /dev/null
}

function license_status {
   $curl -X POST \
       -H "Referer: $endpoint/enginframe" \
       -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
       -H 'Accept-Language: en,it;q=0.5' \
       -H 'Content-Type: application/x-www-form-urlencoded' \
       -H 'Upgrade-Insecure-Requests: 1' \
       --data "$(< $workdir/csrftoken)" \
       "$endpoint/enginframe/admin/com.enginframe.admin.xml?_uri=//com.enginframe.admin/view.license.usage"
}

session
login
license_status
logout

To get human readable results install w3m package and pipe the output of the script to:

w3m -dump  -T text/html

To extract only the numbers you need you can use xmllint with an XPath expression.

Add a custom location in EnginFrame File Manager

To add a custom file manager location  in “Files” page, proceed as follows:

  1. Identify the plugin you’re using. E.g. applications, views or demo
    You can also check it by looking at the browser url: it is the string immediately following EnginFrame root context (default: /enginframe), e.g. /enginframe/applications
  2. Log into EnginFrame server node
  3. Change directory to $EF_ROOT/plugins/applications (or your plugin folder), bin subdirectory
  4. Create a file named fm.browse.ui with the following contents:
#!/bin/bash
newFilesLocation=/tmp
 
newFileslabel="Temporary folder"
 
source "${EF_ROOT}/plugins/ef/conf/ef.xmlns.conf"
source "${EF_ROOT}/plugins/ef/lib/xmlfuncs"
 
printf '<ef:ui-configure-widget ui="hydrogen" id="fm-browse" %s %s %s>\n' \
        "${EF_XMLNS_ef}" "${EF_XMLNS_hy}" "${EF_XMLNS_efactions}"
 
vroot=$("${EF_ROOT}/plugins/fm/bin/fm.vroot.create" "${FM_BROWSE_SPOOLER}" 'fm' "file://${newFilesLocation}")
 
printf '<hy:add-vroot id="%s">\n' "${vroot}"
 
printf '<hy:label>%s</hy:label>\n' "$(ef_xml_escape_content --input "${newFileslabel}")"
 
printf '</hy:add-vroot>\n'
printf '</ef:ui-configure-widget>\n'
  1. You can customize the first 2 parameters, the new filesystem location and the associated label in Files page 
  2. Give fm.browse.ui executable permissions:
    chmod +x fm.browse.ui

Multi-Factor-Authentication (MFA) for EnginFrame

EnginFrame SSO and MFA with OKTA

The AWS team has created a guide how to integrate EnginFrame with OKTA to provide Single-Sign-On and MFA.

Add a custom location in EnginFrame File Manager

To add a custom file manager location  in “Files” page, proceed as follows:

  1. Identify the plugin you’re using. E.g. applications, views or demo
    You can also check it by looking at the browser url: it is the string immediately following EnginFrame root context (default: /enginframe), e.g. /enginframe/applications
  2. Log into EnginFrame server node
  3. Change directory to EF_ROOT/plugins/applications (or your plugin folder), bin subdirectory
  4. Create a file named fm.browse.ui with the following contents
#!/bin/bash
newFilesLocation=/tmp
 
newFileslabel="Temporary folder"
 
source "${EF_ROOT}/plugins/ef/conf/ef.xmlns.conf"
source "${EF_ROOT}/plugins/ef/lib/xmlfuncs"
 
printf '<ef:ui-configure-widget ui="hydrogen" id="fm-browse" %s %s %s>\n' \
        "${EF_XMLNS_ef}" "${EF_XMLNS_hy}" "${EF_XMLNS_efactions}"
 
vroot=$("${EF_ROOT}/plugins/fm/bin/fm.vroot.create" "${FM_BROWSE_SPOOLER}" 'fm' "file://${newFilesLocation}")
 
printf '<hy:add-vroot id="%s">\n' "${vroot}"
 
printf '<hy:label>%s</hy:label>\n' "$(ef_xml_escape_content --input "${newFileslabel}")"
 
printf '</hy:add-vroot>\n'
printf '</ef:ui-configure-widget>\n'
  1. You can customize the first 2 parameters, the new filesystem location and the associated label in Files page 
  2. Give fm.browse.ui executable permissions

Some content is inspired by NICE Support articles.

Extend the administration rights to other users

There are two ways to add extra admin users:

  • Static, where you define admin users manually
  • Dynamic, where you define admin users based in rules

Static

In this case, EnginFrame will read a authorization.xconf file and store in the database which users are admin.

Create or edit the /opt/nisp/enginframe/conf/enginframe/authorization.xconf (needs to be the global config) and add the users like this:

<?xml version="1.0"?>
<ef:authorization xmlns:ef=\"http://www.enginframe.com/2000/EnginFrame\">
  <ef:acl-actor-list>
    <ef:acl-actor id="efadmins" type="osgroup" plugin="ef">
      <ef:info>EF Portal Administrators</ef:info>
      <ef:acl-member type="efuser">${EF_ADMIN}</ef:acl-member>
      <ef:acl-member type="efuser">myuser1</ef:acl-member>
      <ef:acl-member type="efuser">myuser2</ef:acl-member>
    </ef:acl-actor>
  </ef:acl-actor-list>
</ef:authorization>

Notes:

  • Do not remove the ${EF_ADMIN}, to preserve efadmin user rights.
  • You do not need to restart EF Portal.
  • If you remove the file, the users will continue being admin users. The information will be stored in the database. You need to manually remove the users from EF dashboard (users section), or at least disable them as admin users.

Dynamic

Create or edit the /opt/nisp/enginframe/conf/enginframe/authorization.xconf (needs to be the global config) to have this content:

<?xml version="1.0"?>
<ef:authorization xmlns:ef="http://www.enginframe.com/2000/EnginFrame">
  <ef:acl-actor-list>
    <ef:acl-actor id="efadmins" type="osgroup" plugin="ef"/>
  </ef:acl-actor-list>
</ef:authorization>

You do not need to add anything more in authorization.xconf file.

Then, create the /opt/nisp/enginframe/VERSION/enginframe/plugins/ef/bin/ef.load.users file, with the dynamic config:

#!/bin/bash
admin_group_usernames = myadminsgroup
admin_users=$(getent group $admin_group_usernames | cut -d: -f4 | tr ',' ' ')

echo "<?xml version=\"1.0\"?>"
echo "<ef:authorization xmlns:ef=\"http://www.enginframe.com/2000/EnginFrame\">"
echo "  <ef:acl-actor-list>"
echo "  <ef:acl-actor id=\"efadmins\" type=\"osgroup\" plugin=\"ef\">"
echo "  <ef:info>EF Portal Administrators</ef:info>"

for admin_user in $admin_users
do
  echo "<ef:acl-member type=\"efuser\">${admin_user}</ef:acl-member>"
done

echo "</ef:acl-actor>"
echo "  </ef:acl-actor-list>"
echo "</ef:authorization>"

Notes:

  • Add execution permission (chmod +x) to ef.load.users
  • Set in admin_group_usernames variable the group that will have all users with admin rights under EnginFrame.
  • If you remove the file, the users will continue being admin users. The information will be stored in the database. You need to manually remove the users from EF dashboard (users section), or at least disable them as admin users.

Session cleanup

To clean persistent of the damaged user, please follow the below steps:

  • Identify all files from the damaged user. As example, the use will be “nisp”.
    ls /opt/nice/enginframe/{repository,sessions,spoolers}/nisp/

    Note: Replace the path with your real EnginFrame path.
  • Stop the EF systemd service:
    systemctl stop enginframe
  • Backup and remove all files and directories found in the previous step.
  • Backup the below files and replace them with original files from fresh users (usually located in /etc/skel directory):
    • .bashrc
    • .bash_profile
    • .profile
  • Then start the EnginFrame again:
    systemctl stop enginframe

Minimizing the built-in account locking mechanism

Edit the file  /opt/nice/enginframe/conf/enginframe/server.conf and set these parameters to mitigate your locking account problem:

ef.account.lockout.after.attempts=1000  # Set an high value
ef.account.lockout.time.admins=0        # Zero disable the lockout for admins
ef.account.lockout.time.users=1         # Minimum time is 1 minute

Then restart the EnginFrame service:

systemctl restart enginframe

Output size of this service exceeds the maximum limit defined in EnginFrame configuration

Please edit your $EF_ROOT/conf/server.conf file and increase the maximum limit:

ef.output.limit=52428800

Then you need to restart EnginFrame service:

systemctl stop enginframe
systemctl start enginframe

EnginFrame login is taking 25 seconds

This is a known issue with systemd, is not related with EnginFrame. There is an old bug in systemd that does not remove sessions scope and, mainly in environments with a lot of users doing login and logout, eventually the abandoned sessions list will increase making systemctl list-unit-files performance very bad. For servers that depends of systemd to login (check your /etc/nsswitch.conf for systemd string), systemctl list-unit-files will have a very bad performance and just after systemd default timeout (25000ms or 25s), you will be able to login (ssh, sudo, su etc). As this is related with systemd bug, it can affect a lot of linux distributios versions. In case of RedHat linux based distributions, it will affect EL 7, 8 and 9. The permanent solution is update systemd for a version where the bug was fixed (2022+ releases). If is not an option to you, you can set a cronjob that will execute this script (author):

#!/bin/bash

system_show () {
    local t="${1##*.}"
    systemctl show "$1" --no-pager --no-legend --no-ask-password | sed -e 's/"/\\"/g' -e 's/\([^=]*\)=\(.*\)/'"$t"'_\1="\2"/'
}

for unit in $(systemctl list-units --state=abandoned -t scope --no-legend --no-pager --no-ask-password | cut -d' ' -f1) ; do
    eval "$(system_show "$unit")"
    [ "$(systemd-cgls "$scope_ControlGroup" 2>/dev/null | wc -l)" -eq 1 ] && systemctl stop "$unit"
done

If you want to do a simple test before set this cronjob, you can run this command to check the 25 seconds timeout:

systemctl list-unit-files –all

And then execute this command to remove all scopes:

find /run/systemd/system -name "session-*.scope" -delete
rm -rf /run/systemd/system/session*scope*
systemctl | grep "abandoned" | grep -e "-[[:digit:]]" | sed "s/\.scope.*/.scope/" | xargs systemctl stop

And then run again this command to see the problem fixed:

systemctl list-unit-files –all

Mapping internal hosts with public DNS names

If you installed your EF Portal in the intranet, the connection file or remote browser access will use the internal DCV Server DNS name. However, for external users, the local name can not be resolved because is not a valid name under internet. To fix the URL of the remote browser access or the connection file, you need to edit the /opt/nisp/enginframe/conf/plugins/interactive/nat.conf file and follow this syntax:

  • The syntax consists of a line made of a pair: the real host:port followed by the public host:port pair.
  • It is possible to omit the :port which case it is assumed to be the same for the real and public hosts.
  • It is also possible to specify a group of ports using this syntax: host:fromport-toport.
  • If you want to redirect all internal nodes to the same public name, you can use *

Some examples:

node01 remote.mycompany.com
node02 121.122.123.124
node0342976 remote.mycompany.com:42976
node04:7900-7910 remote.mycompany.com:5900-5910
node05:7900-7910 121.122.123.124:5900-5910

Mapping EF Portal users to local Linux users

EF Portal need to set the right permissions to the session and spoolers directories to provide correct access to the logged users. If you are using the PAM plugin, you need to have the remote users mapped locally. When you are using services like SSSD, this is automatically done, but if you are using using a custom ef.auth that query for the users that does not exist locally, you need to mape external users in local users.

You can map the users 1:1 or in groups (2:1, 5:1 or a random number by 1). You just need to create a bash script with the logic to map the users. We will exemplify with the most common case, 1:1 (each user will be mapped to one user locally).

First, find the ef.auth.conf file with the command:

find /opt/nisp -iname ef.auth.conf | egrep -i "enginframe/plugins/pam/conf"

Edit the file and set:

EFAUTH_USERMAPPING=”true”

Then you need to edit the file ef.user.mapping. The file will be in the same common path of ef.auth.conf file, but instead of conf/ dir, it needs to be created under bin/ dir.

Suppose that you want to map one user by one user, which means that every user will have your own rights, without share any EF Portal resources. This means that remote user Francisco will be local user Francisco, or the remote user id12345 will be mapped to the local user id12345. The username does not matter, you just need to make sure that the username (mapped) will be a valid linux username.

Valid characters for Linux usernames include:

  • Lower and upper case letters
  • Digits
  • Underscores
  • Dashes
  • A dollar sign at the end 
  • Linux usernames must not contain spaces or “@”.
  • They must also start with an alphabetic character and be 30 characters or fewer.

Now that is clear why you need to map the external users to EF Portal environment, you can edit the file ef.user.mapping and add this content:

#!/bin/bash

# Check if a username was provided
if [ $# -eq 0 ]; then
    exit 1
fi

username="$1"

# Check if the user exists
if ! id "$username" > /dev/null 2>&1
then
    sudo useradd -m "$username" > /dev/null 2>&1
fi

# Generate a random password
password=$(openssl rand -base64 12)

# Set the password for the user
echo "$username:$password" | sudo chpasswd > /dev/null 2>&1

# Set password expiration to 1 month (30 days)
sudo chage -M 30 "$username" > /dev/null 2>&1

# map the user to EF
echo $username

Then save the file and give executable permissions (chmod +x).

Basically the script will do:

  • Check if the username was provided as parameter
  • Check if the user already exist. If not, it will create it.
  • Create a random password and set.
  • Set expiration time for 30 days.
  • Print the mapped user.

This printed user is the user that EF Portal will use locally.

Important: If your external usernames are not valid Linux usernames, then you need to create a logic that will remove the non allowed characters, but at the same time still make them unique.

For example, if your username start with number, you can write a logic that will replace the number for a alphapetic char (example: 1 will be A, 2 will be B, 3 will be C etc). But if sometimes it start with number and sometimes not, then is more simple just add an extra char before everything (exemple: 0abcde will be a0abdce, 5asdfg will be a5asdfg, 9zxcvb will be a9zxcvb, etc).

You can also just map all users to one user. This is not usual, but can be done. For example, if you want all external users being mapped to “efadmin” user, you can set the ef.user.mapping file to have just this:

#!/bin/bash
echo “efadmin”

And you can combine the ideas. You can create a bash script that will map some specific users to “efadmin”, and the rest will be 1:1, like this:

#!/bin/bash

# Check if a username was provided
if [ $# -eq 0 ]; then
    exit 1
fi

username="$1"
admin_users="francisco john mary"
if echo $admin_users | egrep -iq "username"
then
    echo "efadmin"
else
    # Check if the user exists
    if ! id "$username" > /dev/null 2>&1
        sudo useradd -m "$username" > /dev/null 2>&1
    fi

    # Generate a random password
    password=$(openssl rand -base64 12)

    # Set the password for the user
    echo "$username:$password" | sudo chpasswd > /dev/null 2>&1

    # Set password expiration to 1 month (30 days)
    sudo chage -M 30 "$username" > /dev/null 2>&1

    # map the user to EF
    echo $username
fi

Finally you need to add efnobody into sudoers. Please execute visudo and add in the last line:

efnobody ALL=(ALL) NOPASSWD: ALL

Unusual or high storage usage

If you are seeing EF Portal using a good amount of storage space, this guide will present a checklist to help you understand if the storage usage is normal or not.

Is expected that two directories will grow through the time:

  • /opt/nisp/enginframe/spoolers/ : Data container used to store user files in the host
  • /opt/nisp/enginframe/sessions/ : Data container used to store user sessions in the host

You can not manually delete those files. If you need to clear this content, you need to contact us.

Another directory that can grow, but is limited due the rotation:

  • /opt/nisp/enginframe/logs/HOSTNAME/ : All logs related with EF Portal services

If needed, you can remove the oldest logs or even all the files. Before that, you need to stop EF Portal service, remove the files and start the service again.

  • /opt/nisp/enginframe/tmp/ : The EF Portal temporary directory

If needed, the content of the directory can be completely removed. Before that, you need to stop EF Portal service, remove the content and start the service again.

  • /opt/nisp/enginframe/202{1,4}-r* : Every EF Portal setup will happen in a new directory based in the version

If you have multiple versions installed, you will see multiple directories here. You can remove all unused versions, but make sure to do a backup before remove anything.

  • find /opt/nisp -type f -size +10M -exec du -hs {} \;

You can also look for files with certain size (or more) to check if there is something not usual. +10M means 10 Mb or more.

  • Logs being flooded by “Warning: Nashorn engine is planned to be removed from a future JDK release” message

You need to use the right Java version to avoid issues. Please check in the EF Portal site the updated requirements to run the service.

Note: This warning can be mitigated using JDK-8 version.

If you have any other question about a possible not usual storage usage, please contact us.