NetDRMS - a shared data management system

Introduction

In order to process, archive, and distribute the substantial quantity of solar data captured by the Atmospheric Imaging Assembly (AIA) and Helioseismic and Magnetic Imager (HMI) instruments on the Solar Dynamics Observatory (SDO), the Joint Science Operations Center (JSOC) has developed its own data-management system, NetDRMS. This system comprises two PostgreSQL databases, multiple file systems, a tape back-up system, and software to manage these components. Related sets of data are grouped into data series, each, conceptually, a table of data where each row of data typically associated with an observation time, or a Carrington rotation. As an example, the data series hmi.M_45s contains the HMI 45-second cadence magnetograms, both observation metadata and image FITS files. The columns contain metadata, such as the observation time, the ID of the camera used to acquire the data, the image rotation, etc. One column in this table contains an ID that refers to a set of data files, typically a set of FITS files that contain images.

The Data Record Management System (DRMS) is the subsystem that contains and manages the "DRMS" database of metadata and data-file-locator information. One component is a software library, written in C, that provides client programs, also known as "DRMS modules", with an Application Programming Interface (API) that allows the users to access these data. The Storage Unit Management System (SUMS) is the subsystem that contains and manages the "SUMS" database and associated storage hardware. The database contains information needed to locate data files that reside on hardware. The entire system as a whole is typically referred to as DRMS. The user interfaces with the DRMS subsystem only, and the DRMS subsystem interfaces with SUMS - the user does not interact with SUMS directly. The JSOC provides NetDRMS to non-JSOC institutions so that those sites can take advantage of the JSOC-developed software to manage large amounts of solar data.

A NetDRMS site is an institution with a local NetDRMS installation. It does not generate the JSOC-owned production data series (e.g., hmi.M_720s, aia.lev1) that Stanford generates for scientific use. A NetDRMS site can generate its own data, production or otherwise. That site can create software that uses NetDRMS to generate its own data series. But it can also act as a "mirror" for individual data series. When acting as a mirror for a Stanford data series, the site downloads from Stanford DRMS database information and stores it in its own NetDRMS database, and it downloads SUMS files, and stores them in its own SUMS subsystem. As the data files are downloaded to the local SUMS, the SUMS database is updated with the information needed to manage the data files. It is possible for a NetDRMS site to mirror the DRMS data of any other NetDRMS site, but at this point, the only site whose data are currently mirrored is the Stanford JSOC.

Installing NetDRMS

Installing the NetDRMS system requires:

Optional steps include:

For best results, and to facilitate debugging issues, please follow these steps in order.

Conventions

In this document, parameters to be determined by you the NetDRMS administrator are denoted with angled brackes, <a parameter>. For example, you will need to select a machine to host the PostgreSQL database system, and the name of that host is represented by <PostgreSQL host>. If you choose a host named netdrms_db, let's say, then functionally, you can substitute netdrms_db for <PostgreSQL host> throughout this document.

Part of the process of installing NetDRMS is creating a configuration file named config.local. That file contains numerous parameters, such as SUMS_USEMTSUMS. Through this document, those parameters are denoted with square brackets. As such, this document refers to the the parameter SUMS_USEMTSUMS as [SUMS_USEMTSUMS].

Installing PostgreSQL

PostgreSQL is a relational database management system. Data are stored primarily in relations (tables) of records that can be mapped to each other - given one or more records, you can query the database to find other records. These relations are organized on disk in a hierarchical fashion. At the top level are one or more database clusters. A cluster is simply a storage location on disk (i.e., directory). PostgreSQL manages the cluster's data files with a single process, or PostgreSQL instance. Various operations on the cluster will result in PostgreSQL forking new ephemeral child processes, but ultimately there is only one master/parent process per cluster.

Each cluster contains the data for one or more databases. Each cluster requires a fair amount of system memory, so it makes sense to install a single cluster on a single host. It does not make sense to make separate clusters, each holding one database; each cluster can efficiently support many databases, which are then fairly independent of each other. In terms of querying the databases are completely independent (i.e., a query on one database cannot involve relations in different databases). However, two databases in a single cluster do share the same disk directory, so there is not the same degree of independence at the OS/filesystem level. This may only matter if an administrator is operating directly on the files (performing backups, replication, creating standby systems, etc.).

To install PostgreSQL, select a host machine, <PostgreSQL host>, to act as the PostgreSQL database server. We recommend installing only PostgreSQL on this machine, given the large amount of memory and resources required for optimal PostgreSQL operation. We find a Fedora-based system, such as CentOS, to be a good choice, but please visit https://www.postgresql.org/docs for system requirements and other information germane to installation. The following instructions assume a Fedora-based Linux system such as CentOS (documentation for other distributions, such as Debian and openSUSE can be found online) and a bash shell.

Install the needed PostgreSQL server packages on <PostgreSQL host> by first visiting https://yum.postgresql.org/repopackages.php to locate and download the PostgreSQL "repo" rpm file appropriate for your OS and architecture. Each repo rpm contains a yum configuration file that can be used to install all supported PostgreSQL releases. You should install the latest version if possible (version 12, as of the time of this writing). Although you can use your browser to download the file, it might be easier to use Linux command-line tools:

$ curl -OL https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm

Install the yum repo configuration file (pgdg-redhat-all.repo) from the downloaded repo rpm file:

$ sudo rpm -i pgdg-redhat-repo-latest.noarch.rpm

This installs the repo configuration file to /etc/yum.repos.d/. Find the names of the PostgreSQL packages needed from the repository; the following assumes PostgreSQL 12, but should you want to install an older version, replace "12" with one of 94, 95, 96, 10, or 11:

$ yum list --disablerepo='*' --enablerepo=pgdg12 2>/dev/null | grep -Eo '^.*postgresql[0-9]*\.' | cut -d '.' -f 1
postgresql12
$ yum list --disablerepo='*' --enablerepo=pgdg12 2>/dev/null | grep -Eo '^.*postgresql.*devel\.' | cut -d '.' -f 1 
postgresql12-devel
$ yum list --disablerepo='*' --enablerepo=pgdg12 2>/dev/null | grep -Eo '^.*postgresql.*contrib\.' | cut -d '.' -f 1
postgresql12-contrib
$ yum list --disablerepo='*' --enablerepo=pgdg12 2>/dev/null | grep -Eo '^.*postgresql.*libs\.' | cut -d '.' -f 1 
postgresql12-libs
$ yum list --disablerepo='*' --enablerepo=pgdg12 2>/dev/null | grep -Eo '^.*postgresql.*plperl\.' | cut -d '.' -f 1 
postgresql12-plperl
$ yum list --disablerepo='*' --enablerepo=pgdg12 2>/dev/null | grep -Eo '^.*postgresql.*server\.' | cut -d '.' -f 1 
postgresql12-server

Use yum to install all four packages:

$ sudo yum install <packages>

where <packages> are the package names determined in the previous step (postgresql12 postgresql12-contrib postgresql12-devel postgresql12-libs postgresql12-plperl postgresql12-server). The rpm package installation will have created the PostgreSQL superuser Linux account <PostgreSQL superuser> (i.e., postgres); <PostgreSQL superuser> will own the PostgreSQL database clusters and server processes that will be created in the following steps. To perform the next steps, you will need to become user <PostgreSQL superuser>:

$ sudo su - <PosgreSQL superuser>

Depending on where the package files are installed, you might need to add the PostgreSQL command to your PATH environment variable. To test this, run:

$ which initdb

If the initdb command cannot be found, then add the PostgreSQL binaries path to PATH. Find the path to the PostgreSQL installation:

$ rpm -ql postgresql12
<PostgreSQL install dir>/bin/clusterdb
...

In this example, <PostgreSQL install dir> is /usr/pgsql-12. Then add the binary path to PATH:

$ export PATH=/usr/pgsql-12/bin:$PATH

<PosgreSQL superuser> will be using the binaries in this directory, so it is a good idea to add the export command to .bashrc. As described above, create one database cluster for the two databases (one for DRMS data, and one for SUMS data):

$ whoami
postgres
$ initdb --locale=C -D <PostgreSQL cluster>

where <PostgreSQL cluster> should be /var/lib/pgsql/netdrms. Use this path, unless there is some good reason you cannot. initdb will initialize the cluster data directory (identified by the -D argument). This will result in the creation of template databases, configuration files, and other items.

The database cluster will contain two configuration files you need to edit: postgresql.conf and pghba.conf. Please refer to the PostgreSQL documentation to properly edit these files. Here are some brief suggestions:

Here are the recommended entries:

Should you need to edit either of these configuration files AFTER you have started the database instance (by running pg_ctl start, as described in the next section), you will need to either reload or restart the instance:

$ whoami
postgres
# reload
$ pg_ctl reload -D <PostgreSQL cluster>
# restart
$ pg_ctl restart -D <PostgreSQL cluster>

Initializing PostgreSQL

You need to now initialize your PostgreSQL instance by creating the DRMS and SUMS databases, installing database-server languages, creating a schema, creating a relation. To accomplish this become <PostgreSQL superuser>; all steps in this section must be performed by the superuser:

$ sudo su - postgres

Start the database instance for the cluster you created:

$ whoami
postgres
$ pg_ctl start -D <PostgreSQL cluster>

You previous created <PostgreSQL cluster>, which will most likely be /var/lib/pgsql/netdrms. Ensure the configuration files you created work. This can be done by attempting to connect to the database server as <PostgreSQL superuser> with psql from <PostgreSQL host>:

$ whoami
<PostgreSQL superuser>
$ hostname
<PostgreSQL host>
$ psql -h <PostgreSQL host> -p <PostgreSQL port>
psql (12.1)
Type "help" for help.

postgres=# \q
$ 

The PostgreSQL installation resulted in the creation of the postgres database superuser, and since psql connects to the database as the database user with the same name as the Linux user running psql, you will be logged in as database user postgres. This is indicated by the postgres=# prompt (the hash refers to a superuser).

After you successfully see the superuser prompt, create the two databases:

$ whoami
postgres
# create the DRMS database
$ createdb --locale C -E UTF8 -T template0 netdrms
# create the SUMS database
$ createdb --locale C -E UTF8 -T template0 netdrms_sums

Install the required database-server languages:

$ whoami
postgres
# create the PostgreSQL scripting language (versions <= 9.6)
# no need to create the PostgreSQL scripting language (versions > 9.6)
$ createlang plpgsql netdrms
# create the "trusted" perl language (versions <= 9.6)
createlang -h <PostgreSQL host> plperl netdrms
# create the "trusted" perl language (versions > 9.6)
$ psql -h <PostgreSQLhost> -p <PostgreSQL port> netdrms
netdrms=# CREATE EXTENSION IF NOT EXISTS plperl;
netdrms=# \q
# create the "untrused" perl language (versions <= 9.6)
$ createlang -h <PostgreSQL host> plperlu netdrms
# create the "untrused" perl language (versions > 9.6)
netdrms=# CREATE EXTENSION IF NOT EXISTS plperlu;
netdrms=# \q

The SUMS database does not use any language extensions so there is no need to create any for the SUMS database.

At this point, it is a good idea to create a password for the postgres database superuser:

$ whoami
<PostgreSQL superuser>
$ psql -h <PostgreSQLhost> -p <PostgreSQL port> netdrms
netdrms=# ALTER ROLE postgres WITH PASSWORD '<new password>';
ALTER ROLE
netdrms=# \q
$ 

Installing CFITSIO

The base NetDRMS release requires CFITSIO, a C library used by NetDRMS to read and write FITS files. Visit https://heasarc.gsfc.nasa.gov/fitsio/ to obtain the link to the CFITSIO source-code tarball. Create an installation directory <CFITSIO install dir> (such as /opt/cfitsio-X.XX, with a link from /opt/cfitsio to <CFITSIO install dir>), download the tarball, and extract the tarball into <CFITSIO install dir>:

$ sudo mkdir -p <CFITSIO install dir>
$ ctrl+d

$ curl -OL 'http://heasarc.gsfc.nasa.gov/FTP/software/fitsio/c/cfitsio-X.XX.tar.gz'
$ tar xvzf netdrms_X.X.tar.gz
$ cd cfitsio-X.XX

Please read the README file for complete installation instructions. As a quick start, run:

$ ./configure --prefix=<CFITSIO install dir>
# build the CFITSIO library
$ make
# install the libraries and binaries to <CFITSIO install dir>
$ sudo make install
# create the link from cfitsio to <CFITSIO install dir>
$ sudo su -
$ cd <CFITSIO install dir>/..
$ ln -s <CFITSIO install dir> cfitsio

CFITSIO has a dependency on libcurl - in fact, any program made by linking to cfitsio will also require libcurl-devel since cfitsio uses the libcurl API. We recommend using yum to install the two packages (if they are not already installed - it is quite likely that libcurl will already be installed):

$ sudo yum install libcurl-devel

Installing OpenSSL Development Packages

NetDRMS requires the OpenSSL Developer's API. If this API has not already been installed, do so now:

$ sudo yum install openssl-devel

Installing DBD::Pg

One step in the installation process will require running a perl script that accesses the PostgreSQL database. In order for this to work, you will need to ensure the DBD::Pg module has been installed. To check for installation, run:

$ perl -M'DBD::Pg'

If there is no error about not being able to locate the module, and the command simply hangs, then you are all set (enter ctrl-C to exit). If the module is not installed, and you are running the perl installed with the system, then run yum to identify the package:

$ yum list | grep -i 'dbd-pg'
...
perl-DBD-Pg.x86_64                         2.19.3-4.el7           base
...

then bringing to bear all your powers of divination, choose the correct package and install it:

$ sudo yum install 'perl-DBD-Pg'

If using a non-system perl, use the distro's installation method. If the distro does not have that module, or the distro installer does not work, as a final act of desperation use CPAN

$ sudo perl -MCPAN -e 'install DBD::Pg'

Installing Python3

NetDRMS requires that a number of python packages and modules be present that are not generally part of a system installation. In addition, many scripts require python3 and not python2. The easiest way to satisfy these eeds is to install a data-science-oriented python3 distribution, such as Anaconda. In that vein, install Anaconda into an appropriate installation directory such as /opt/anaconda3. To locate the Linux installer, visit https://docs.anaconda.com/anaconda/install/linux/:

$ curl -OL 'https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh'
$ sha256sum Anaconda3-2019.10-Linux-x86_64.sh
46d762284d252e51cd58a8ca6c8adc9da2eadc82c342927b2f66ed011d1d8b53  Anaconda3-2019.10-Linux-x86_64.sh
$ sudo bash Anaconda3-2019.10-Linux-x86_64.sh

After some initial prompts, the installer will display

PREFIX=/home/<user>/anaconda3

This path is the default installation directory (<user> is the user running bash). Replace the PREFIX path with <Anaconda3 install dir>.

Installing NetDRMS

To install NetDRMS, you will need to select an appropriate machine on which to install NetDRMS, an appropriate machine/hardware on which to host the SUMS service, create Linux users and groups, download the NetDRMS release tarball and extract the release source, initialize the Linux environment, create log directories, create the configuration file and run the configuration script, compile and install the executables, create the the DRMS- and SUMS-database users/relations/functions/objects, initialize the SUMS storage hardware, install the SUMS and Remote SUMS daemons.

The optimal hardware configuration will likely depend on your needs, but the following recommendations should suffice for most sites. DRMS and SUMS can share a single host machine. The most widely used and tested Linux distributions are Fedora-based, and at the time of this writing, CentOS is the most popular. Sites have successfully used openSUSE too, but if possible, we would recommend using CentOS. SUMS requires a large amount of storage to hold the DRMS data-series data/image files. The amount needed can vary widely, and depends directly on the amount of data you wish to keep online at any given time. Most NetDRMS sites mirror some amount of (but not all) JSOC SDO data - the more data mirrored, the larger the amount of storage needed. To complicate matters, a site can also mirror only a subset of each data series' data; perhaps one site wishes to retain only the current month's data of many data series, but another wishes to retain all data for one or two series. To decide on the amount of storage needed, you will have to ask the JSOC how much data each series comprises and decide how much of that data you want to keep online. Data that goes offline can always be retrieved automatically from the JSOC again. Data will arrive each day, so request from the JSOC an estimate of the rate of data growth. We recommend doing a rough calculation based upon these considerations, and then doubling the resulting number and installing that amount of storage.

Next, create a production Linux user <NetDRMS production user> (named netdrms_production by default):

$ sudo useradd <NetDRMS production user>
$ sudo passwd <NetDRMS production user>
Changing password for user <NetDRMS production user>.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
$

NOTE: ensure that <NetDRMS production user> is a valid PostgreSQL name because NetDRMS makes use of the PostgreSQL feature whereby attempts to connect to a database are made as the database user whose name matches the name of the Linux user connecting to the database. Please see https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS for a description of valid PostgreSQL names.

NetDRMS requires additional Python packages not included in the Anaconda distribution, but if you install Anacoda, then the number of additional packages you need to install is minimal. If you have a different python distribution, then you may need to install additional packages. To install new Anaconda packages, as <NetDRMS production user> first create a virtual environment for NetDRMS (named netdrms):

$ whoami
<NetDRMS production user>
# Sets path to Anaconda3 binaries so that the next conda command will success (will edit .bashrc)
$ <Anaconda install dir>/bin/conda init bash
$ source ~/.bashrc
$ conda create --name netdrms
Collecting package metadata (current_repodata.json): done
Solving environment: done

## Package Plan ##

  environment location: /home/netdrms_production/.conda/envs/netdrms

Proceed ([y]/n)? y

Preparing transaction: done
Verifying transaction: done
Executing transaction: done
#
# To activate this environment, use
#
#     $ conda activate netdrms
#
# To deactivate an active environment, use
#
#     $ conda deactivate

VERY IMPORTANT!! As described above in the conda create output, run:

$ conda activate netdrms

If you do not do this, then conda might invoke the system Python, which could be version 2.7, when in fact your Anaconda is Python 3. If that happens, then all hope is lost and you'll need to remove the netdrms virtual environment and re-create it.

You will use conda to install additional Anaconda3 packages. To succees, you must have already installed PostgreSQL, and the PostgreSQL executables must be in $PATH (one step in the installation process is running pg_config. Add the following to <NetDRMS production user>'s .bashrc ensure PostgreSQL executables can be located:

$ whoami
<NetDRMS production user>
$ vi ~/.bashrc
i
...
# PostgreSQL executables
export PATH=<PostgreSQL install dir>/bin:$PATH
ESC
:wq
$ 

Make sure you have either re-logged-in or sourced .bashrc.

Then install the new Anaconda packages using conda:

$ whoami
<NetDRMS production user>
$ conda install -n netdrms psycopg2 psutil python-dateutil
Collecting package metadata (current_repodata.json): done
...

NOTE: By installing these packages in the netdrms virtual environment, you will also install the python package in the environment since the explicitly listed packages have a dependency on python. This is important, because the next step requires that pip, part of python, be present in the environment.

The NetDRMS script needed for series subscription requires installation of the pySmartDL Python 3 package - a package that generally is not part of any distro. Unfortunately, conda supports this package for Python 2.7 only, and NetDRMS requires Python 3. But pip supports a Python 3 version. To install Python 3 pySmartDL, first make sure you have activated your virtual environment, as described above. Then run:

$ whoami
<NetDRMS production user>
$ which pip
<NetDRMS production user home dir>/.conda/envs/netdrms/bin/pip
$ pip install pySmartDL

If which pip displays an Anaconda path in <Anaconda3 install dir>, then do not run pip just yet. Go back and activate your virtual environment first.

From now on, the <NetDRMS production user> should use the virtual environment. You should make sure that $PYTHONPATH is not set, otherwise it might interfere with the running of Anaconda3 python. Modify that user's .bashrc to do so:

$ whoami
<NetDRMS production user>
$ vi ~/.bashrc
i
# .bashrc

# use Python virtual environment by default
unset PYTHONPATH

# call conda activate AFTER # <<< conda initialize <<<
conda activate netdrms
ESC
:wq
$ 

For the changes to .bashrc to take effect, either logout/login or source .bashrc.

All non-production users will use the netdrms virtual environment. Make sure that users can access the environment:

$ whoami
<NetDRMS production user>
$ chmod o+x <NetDRMS production user home dir>

Create the Linux group <SUMS users>, e.g. sums_users, to which all SUMS users belong, including <NetDRMS production user>. This group will be used to ensure that all SUMS users can create new data files in SUMS:

$ sudo groupadd <SUMS users>

Add <NetDRMS production user> to this group (later you will add each SUMS user - users who will read/write SUMS data files - to this group as well):

$ sudo usermod -a -G <SUMS users> <NetDRMS production user>
$ id <NetDRMS production user>
uid=1001(netdrms_production) gid=1001(netdrms_production) groups=1001(netdrms_production),1002(sums_users)

On NetDRMS host, select a path <NetDRMS root> for the root directory of the NetDRMS source tree installed by <NetDRMS production user>. A typical choice for <NetDRMS root> is /opt/netdrms or /usr/local/netdrms, and a typical strategy is to install the source tree into a directory that contains the release version in its name (<NetDRMS install dir>), e.g., /opt/netdrms-9.3. Then <NetDRMS production user> makes a link from <NetDRMS root> to <NetDRMS install dir>. This facilitates the maintenance of multiple releases. To switch between releases, <NetDRMS production user> simply updates the link to point to the desired release directory. Create <NetDRMS install dir> and make <NetDRMS production user> the owner:

$ sudo mkdir -p <NetDRMS install dir>
$ sudo chown <NetDRMS production user>:<NetDRMS production user> <NetDRMS install dir>

As <NetDRMS production user>, obtain a NetDRMS tarball from http://jsoc.stanford.edu/netdrms/dist/ and extract it into a release-specific directory:

$ whoami
<NetDRMS production user>
$ cd <NetDRMS install dir>
$ curl -OL 'http://jsoc.stanford.edu/netdrms/dist/netdrms_X.X.tar.gz'
$ tar xvzf netdrms_X.X.tar.gz
$ <ctrl-d>

Create the link from <NetDRMS root> to <NetDRMS install dir>:

$ cd <NetDRMS install dir>/..
$ sudo ln -s <NetDRMS install dir> netdrms
$ 

As <NetDRMS production user>, set the two environment variables that are needed for proper NetDRMS operation. To do so, you'll need first to determine the appropriate <architecture> string for one of these variables:

$ whoami
<NetDRMS production user>
$ cd <NetDRMS root>
$ build/jsoc_machine.csh
<architecture>

It is best to set the following two environment variables in <NetDRMS production user>'s .bashrc file since they must always be set whenever any NetDRMS code is run. And please put the NetDRMS executables in the path:

$ whoami
<NetDRMS production user>
$ vi ~/.bashrc
i
# .bashrc
export JSOCROOT=/opt/netdrms
export JSOC_MACHINE=<architecture>
export PATH=/opt/netdrms/bin/<architecture>:$PATH
ESC
:wq
$ 

Make the SUMS log directory <SUMS logs> on the SUMS server machine. Various SUMS log files will be written to this directory. A suitable directory would reside in the <NetDRMS production user> user's home directory, e.g., $HOME/log/SUMS

$ whoami
<NetDRMS production user>
$ mkdir -p <SUMS logs>

Select appropriate C and Fortran compilers. The DRMS part of NetDRMS must be compiled with a C compiler. NetDRMS supports both the GNU C compiler (gcc), and the Intel C++ compiler (icc). Certain JSOC-specific code requires Fortran compilation. For those projects, NetDRMS supports the GNU Fortran compiler (gfortran), and the Intel Fortran compiler (ifort). SUMS is implemented as a Python daemon, so no compilation step is needed. Both GNU and Intel are widely used, so feel free to use either. By default, Intel compilers are used. There are two methods for changing the compilers:

Create the <NetDRMS root>/config.local, the master configuration file for both DRMS and SUMS, using <NetDRMS root>/config.local.newstyle.template as a template. This file contains a number of configuration parameters, along with detailed descriptions of what they control and suggested values for those parameters. The configuration script, configure, reads this file, and then creates one output file, drmsparams.*, in <NetDRMS root>/localization for each of several programming languages/tools (C, GNU make, perl, python, bash). In this manner, the parameters are directly readable by several languages/tools used by NetDRMS. Lines that start with whitespace or the hash symbol, # are ignored.

NOTE: if you have an older NetDRMS and you are going to use the config.local from that NetDRMS installation for a new NetDRMS installation, then you might have an old-style config.local. You know you have an old-style configuration file if the __STYLE__ section does not exist in the file, or if it does exist, the value in that section is old. If that is the case, then you will need to compare <NetDRMS root>/config.local.template in the old installation to the analogous file in the new installation to determine the set of parameters that have changed between releases.

Several sections compose config.local:

__STYLE__
new

__DEFS__
# these are NetDRMS-wide parameter values; the format is <quote code>:<parameter name><whitespace>+<parameter value>;
# the configuration script uses <quote code> to assist in creating language-specific parameters; <quote code> is one of:
#   'q' (enclose the parameter value in double quotes)
#   'p' (enclose the parameter value in parentheses)
#   'a' (do not modify the parameter value). 

__MAKE__
# these are make variables used by the make system during compilation - they generally contain paths to third-party code

Before creating config.local, please request from the JSOC a value for DRMS_LOCAL_SITE_CODE. This code uniquely identifies each NetDRMS installation. Each site requires one ID for each of its NetDRMS installations.

The __DEFS__ section:

The __MAKE__ section:

When installing NetDRMS updates, copy the existing config.local to the new <NetDRMS install dir> and edit the copy as needed, using the new config.local.newstyle.template to obtain information about parameters new to the newer release. Many of the parameter values have been determined during the previous steps of the installation process.

Run the configuration script, configure, a csh shell script which is included in <NetDRMS install dir>.

configure reads config.local and uses the contained parameters to configure many of the NetDRMS features. It creates several directories in <NetDRMS install dir>:

Compile DRMS. To make the DRMS part of NetDRMS, run:

As <PostgreSQL superuser>, create the DRMS database production user <DRMS DB production user>. Since PostgreSQL automatically attempts to use the Linux user name as the PostgreSQL user name when a connection attempt is made, use Linux user <NetDRMS production user> for database user <DRMS DB production user>. Create a password for this user, and also GRANT all database privileges to <DRMS DB production user> (this is necessary so that <DRMS DB production user> can create namespaces in the netdrms database):

$ whoami
<PostgreSQL superuser>
$ psql -h <PostgreSQL host> -p <PostgreSQL port>
postgres=# CREATE ROLE <DRMS DB production user> WITH LOGIN;
postgres=# ALTER ROLE <DRMS DB production user> WITH PASSWORD '<new password>';
postgres=# GRANT ALL ON DATABASE netdrms TO <DRMS DB production user>;
postgres=# \q
$ 

As <NetDRMS production user>, create a .pgpass file. This file contains the PostgreSQL user account password, obviating the need to manually enter the database password each time a database connection attempt is made:

$ whoami
<NetDRMS production user>
$ cd $HOME
$ vi .pgpass
i
<PostgreSQL host>:*:*:<DRMS DB production user>:<new password>
ESC
:wq
$ chmod 0600 .pgpass

As <PostgreSQL superuser>, run an SQL script, and a perl script (which executes several SQL scripts), both included in the NetDRMS installation, to create the admin and drms schemas and their relations, the jsoc and sumsadmin database users, data types, and functions:

$ whoami 
<PostgreSQL superuser>
# use psql to execute SQL script
$ psql -h <PostgreSQL host> -p <PostgreSQL port> -U postgres -f <NetDRMS install dir>/base/drms/scripts/NetDRMS.sql netdrms
CREATE SCHEMA
GRANT
CREATE TABLE
CREATE TABLE
GRANT
GRANT
CREATE SCHEMA
GRANT
CREATE ROLE
CREATE ROLE
$ perl <NetDRMS install dir>/base/drms/scripts/createpgfuncs.pl netdrms

For more information about the purpose of these objects, read the comments in the NetDRMS.sql and createpgfuncs.pl.

Although we'd like for the <DRMS DB production user> to own all these database objects that were just created by these scripts (these objects are all specific to NetDRMS), we had to run the scripts as <PostgreSQL superuser>, so the superuser owns them at this point. This was necessary since <DRMS DB production user> lacks the elevated privileges necessary to create these database objects. Run the following, as <PostgreSQL superuser> to alter ownerships:

$ whoami 
<PostgreSQL superuser>
$ psql -h <PostgreSQL host> -p <PostgreSQL port> netdrms << EOF
ALTER SCHEMA admin OWNER TO <DRMS DB production user>;
ALTER TABLE admin.ns OWNER TO <DRMS DB production user>;
ALTER TABLE admin.sessionns OWNER TO <DRMS DB production user>;
ALTER SCHEMA drms OWNER TO <DRMS DB production user>;
ALTER TYPE drmskw OWNER TO <DRMS DB production user>;
ALTER TYPE drmsseries OWNER TO <DRMS DB production user>;
ALTER TYPE drmssession OWNER TO <DRMS DB production user>;
ALTER TYPE drmssg OWNER TO <DRMS DB production user>;
ALTER TYPE rep_item OWNER TO <DRMS DB production user>;
EOF
ALTER SCHEMA
ALTER TABLE
ALTER TABLE
ALTER SCHEMA
ALTER TYPE
ALTER TYPE
ALTER TYPE
ALTER TYPE
ALTER TYPE
$ 

We recommend using the NetDRMS database user <DRMS DB production user> as the SUMS database user <SUMS DB production user>. However, feel free to create a new user if necessary. If the DRMS and SUMS databases reside in different clusters, then you will need to create the <SUMS DB production user>. Again, since PostgreSQL automatically attempts to use the Linux user name as the PostgreSQL user name when a connection attempt is made, use Linux user <NetDRMS production user> for database user <SUMS DB production user>. If you choose a <SUMS DB production user> that is not <NetDRMS production user>, then you will need to pass <SUMS DB production user> to both Remote SUMS and SUMS when starting them.

$ # DO THIS ONLY IF <SUMS DB production user> != <DRMS DB production user> OR IF <DRMS database cluster> != <SUMS database cluster>
$ whoami
<PosgreSQL superuser>
$ psql -h <PostgreSQL host> -p <PostgreSQL port>
postgres=# CREATE ROLE <SUMS DB production user>;
postgres=# \q
$ 

In addition, you will need to create a SUMS database user that has read-only access to the SUMS database objects:

$ whoami
<PosgreSQL superuser>
$ psql -h <PostgreSQL host> -p <PostgreSQL port>
postgres=# CREATE ROLE <SUMS DB readonly user> WITH LOGIN;
postgres=# ALTER ROLE <SUMS DB readonly user> WITH PASSWORD 'readonlyuser';
postgres=# \q

where <SUMS DB readonly user> is [SUMS_READONLY_DB_USER]. This database account is used by the Remote SUMS Client, a daemon used to manage the auto-download of SUs for subscriptions. Remote SUMS Client will be run by <NetDRMS production user>, so add the password to <NetDRMS production user>'s .pgpass file:

$ whoami
<NetDRMS production user>
$ cd $HOME
$ vi .pgpass
i
<PostgreSQL host>:*:*:[SUMS_READONLY_DB_USER]:readonlyuser
ESC
:wq
$ chmod 0600 .pgpass

If you created a new SUMS DB production user, add a password for this user. Ensure that you use the same password that you used for <DRMS DB production user> - you will use the same Linux user when connecting to either database, so the same .pgpass file will be used for authentication. As <PostgreSQL superuser>, run psql to add a password for this new database user:

$ # DO THIS ONLY IF <SUMS DB production user> != <DRMS DB production user>
$ whoami
<PostgreSQL superuser>
$ psql -h <PostgreSQL host> -p <PostgreSQL port>
postgres=# ALTER ROLE <DRMS DB production user> WITH PASSWORD '<DRMS DB production user password>';
postgres=# \q
$

SUMS stores directory and file information in relations in the SUMS database. To create those relations and initialize tables, as <NetDRMS production user> run:

$ whoami
<NetDRMS production user>
$ psql -h <PostgreSQL host> -p <PostgreSQL port> -U <SUMS DB production user> -f <NetDRMS root>/base/sums/scripts/postgres/create_sums_tables.sql netdrms_sums
CREATE TABLE
CREATE INDEX
CREATE INDEX
GRANT
CREATE TABLE
GRANT
CREATE TABLE
GRANT
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE TABLE
GRANT
CREATE TABLE
CREATE INDEX
GRANT
CREATE SEQUENCE
GRANT
CREATE SEQUENCE
GRANT
CREATE TABLE
GRANT
CREATE TABLE
GRANT
CREATE TABLE
GRANT
$ psql -h <PostgreSQL host> -p <PostgreSQL port> -U <SUMS DB production user> netdrms_sums
netdrms_sums=> ALTER SEQUENCE sum_ds_index_seq START <min val> RESTART <min val> MINVALUE <min val> MAXVALUE <max val>;
ALTER SEQUENCE
netdrms_sums=> \q
$ 

where <min val> is <drms site code> << 48, and <max val> is <min val> + <maximum unsigned 48-bit integer> - 1, where <drms site code> is the value of the [DRMS_LOCAL_SITE_CODE], and <maximum unsigned 48-bit integer> is 248 (which is 281474976710656). For the JSOC (site code 0x0000), this ALTER SEQUENCE command looks like:

netdrms_sums=> ALTER SEQUENCE sum_ds_index_seq START 0 RESTART 0 MINVALUE 0 MAXVALUE 281474976710655;

Lastly, as <PostgreSQL superuser> you will need to ensure that [SUMS_READONLY_DB_USER] can read from the sum_partn_alloc table:

$ whoami
<PostgreSQL superuser>
$ psql -h <PostgreSQL host> -p <PostgreSQL port> netdrms_sums
netdrms_sums=# GRANT SELECT ON sum_partn_alloc TO [SUMS_READONLY_DB_USER];
GRANT
netdrms_sums=# \q
$ 

You now have the base part of NetDRMS installed. This excludes projects that are private to other NetDRMSs, such as the JSOC. It is often the case that your team would like to use private code as part of a data-generation pipeline. For example, the JSOC maintains time-distance analysis code that is part of the JSOC DRMS code tree, but not part of the base NetDRMS installation. To obtain this code, you can install those projects into your existing NetDRMS by: 1. obtaining the projects from the its source (like the JSOC), and placing it in your <NetDRMS install dir>/proj directory; and 1. modifying your config.local to refer to new projects, running configure, and then running make

Initializing SUMS Storage

In addition to SUMS database relations, SUMS requires a file system on which SUMS maintains storage areas called SUMS partitions. A SUMS paritition is really just a directory that contains SUMS Storage Units (each of which is implemented as a subdirectory inside the SUMS partition).

New Storage

As <NetDRMS production user> create one or more partitions now - although we have had success making them as large as 60 TB, make 40 TB partitions. For example, if you plan on setting aside X TB of SUMS storage, then make approximately N = <total storage TB> / X 40 TB partitions. The partitions can reside on a file server and be mounted onto all machines that will use NetDRMS, but the following example simply creates directories on a single file system on <SUMS partition host>. First, make the root directory that contains the SUMS paritions (something like /opt/sums):

$ sudo mkdir <SUMS root>
# allow SUMS users to write into SUMS
$ sudo chown <NetDRMS production user>:<SUMS users> <SUMS root>
# when a user writes a file into SUMS, make sure that the file's group owner is <SUMS users>
$ sudo chmod g+s <SUMS root>

<SUMS users> is the Linux group that is allowed to write to SUMS. You created it in a previous step. Second, make the SUMS partitions:

$ whoami
<NetDRMS production user>
$ hostname
<SUMS partition host>
$ mkdir -p <SUMS root>/partition01
$ mkdir -p <SUMS root>/partition02
...
$ mkdir -p <SUMS root>/partitionN

Initialize the SUMS DB sum_partn_avail table with the names of these partitions. For each SUMS partition run the following:

$ whoami
<NetDRMS production user>
$ psql -h <PostgreSQL host> -p <PostgreSQL port> -U <SUMS DB production user> netdrms_sums
netdrms_sums=> INSERT INTO sum_partn_avail (partn_name, total_bytes, avail_bytes, pds_set_num, pds_set_prime) VALUES ('<SUMS partition path>', <avail bytes>, <avail bytes>, 0, 0);

where <SUMS partition path> is the full path of the partition as seen from <SUMS host> (which is where the SUMS daemon will run) and <avail bytes> is some number less than the number of bytes in the directory (multiply the number of blocks in the directory by the number of bytes per block). The number does not matter, as long as it is not bigger than the total number of bytes available. SUMS will adjust this number as needed.

Existing Storage

It might be the case that you would like to have a new NetDRMS installation use existing SUMS partitions. To do this, you would enter the paths to the existing partitions into the sum_partn_avail table. At this point, the SUMS database tables that contain the pointers to SUs (sum_main and sum_partn_alloc) do not contain any references to the existing SUs. Most likely the existing SUMS partitions are part of an existing, old NetDRMS, in which case these references are in that old NetDRMS SUMS database table. If so, then you can manually dump four database tables/sequences from the old NetDRMS to files that can be ingested into the new NetDRMS installation. To do that, as the old NetDRMS <NetDRMS production user> run the following:

$ whoami
<NetDRMS production user>
$ psql -h <OLD NetDRMS host> -p <OLD NetDRMS port> netdrms_sums
netdrms_sums=> COPY public.sum_main TO '/tmp/sum_main_dump.txt' WITH ENCODING 'UTF8';
netdrms_sums=> COPY public.sum_partn_alloc TO '/tmp/sum_partn_alloc_dump.txt' WITH ENCODING 'UTF8';
netdrms_sums=> COPY public.sum_seq TO '/tmp/sum_seq_dump.txt' WITH ENCODING 'UTF8';
netdrms_sums=> COPY public.sum_ds_index_seq TO '/tmp/sum_ds_index_seq_dump.txt' WITH ENCODING 'UTF8';

The COPY command will save the table data onto a file on the OLD NetDRMS PostgreSQL server. Copy those files to the NEW NetDRMS <PostgreSQL host> and then ingest them:

$ whoami
<NetDRMS production user>
$ psql -h <NEW NetDRMS host> -p <NEW NetDRMS port> netdrms_sums
netdrms_sums=> COPY public.sum_main FROM '/tmp/sum_main_dump.txt' WITH ENCODING 'UTF8';
netdrms_sums=> COPY public.sum_partn_alloc FROM '/tmp/sum_partn_alloc_dump.txt' WITH ENCODING 'UTF8';
netdrms_sums=> COPY public.sum_seq FROM '/tmp/sum_seq_dump.txt' WITH ENCODING 'UTF8';
netdrms_sums=> COPY public.sum_ds_index_seq FROM '/tmp/sum_ds_index_seq_dump.txt' WITH ENCODING 'UTF8';

Creating DRMS User Accounts

For each Linux user, <new DRMS user> who will run installed DRMS modules, or who will write new DRMS modules, you will need to set up their environment, create their DRMS account, and create their .pgpass file so they can run DRMS modules without having to manually authenticate to the database. Just like you did for the <NetDRMS production user>, you will need to unset the PYTHONPATH environment variable, and put PostgreSQL executables into the user's $PATH. You will also need to put the <NetDRMS production user>'s netdrms Python virtual environment into the user's $PATH - each user will use this Python environment, not the base installation. Also set the JSOCROOT, JSOC_MACHINE, COMPILER, and FCOMPILER environment variables:

# .bashrc

# PostgreSQL executables
export PATH=/usr/pgsql-12/bin:$PATH

# python production virtual environment
unset PYTHONPATH
export PATH=<NetDRMS production home>/.conda/envs/netdrms/bin:$PATH

# NetDRMS binary path
export PATH=<NetDRMS root>/bin/<architecture>:$PATH

# root of NetDRMS source/installation
export JSOCROOT=<NetDRMS root>

# architecture
export JSOC_MACHINE=<architecture>

# set COMPILER to icc for the Intel C++ compiler, and to gcc for the GNU C++ compiler
export COMPILER=<C compiler>

# set to ifort for the Intel Fortran compiler, and to gfortran for the GNU Fortran compiler
export FCOMPILER=<Fortan compiler>

You will also need to add them to the <SUMS users> group:

$ sudo usermod -a -G <SUMS users> <new DRMS user>

To create a DRMS account, you create a database account for the user, plus you add user-specific rows to various DRMS database tables. The script newdrmsuser.pl exists to facilitate these tasks:

$ whoami
<NetDRMS production user>
$ perl <NetDRMS root>/base/drms/scripts/newdrmsuser.pl netdrms <PostgreSQL host> <PostgreSQL port> <new DRMS user> <initial password> <new DB user namespace> user 1
Connection to database with 'dbi:Pg:dbname=netdrms;host=drms;port=<PostgreSQL port>' as user '<new DRMS user>' ... success!
executing db statment ==> CREATE USER <new DRMS user>
executing db statment ==> ALTER USER <new DRMS user> WITH password '<initial password>'
executing db statment ==> GRANT jsoc to <new DRMS user>
running cmd-line ==> masterlists dbuser=<new DRMS user> namespace=<new DB user namespace> nsgrp=user
Please type the password for database user "postgres":
Connected to database 'netdrms' on host '<PostgreSQL host>' and port '<PostgreSQL port>' as user 'postgres'.
Created new drms_series...
Created new 'drms_keyword'...
Created new 'drms_link'...
Created new 'drms_segment'...
Created new 'drms_session'...
Created new drms_sessionid_seq sequence...
Commiting...
Done.
executing db statment ==> INSERT INTO admin.sessionns VALUES ('<new DRMS user>', '<new DB user namespace>')

where <new DB user namespace> is the PostgreSQL namespace dedicated to the new user. A namespace is a logical container that allows a database user to own database objects, like relations, that have the same name as objects owned by other users - items in a namespace need only be uniquely named within the namespace, not between namespaces. For example, the relation drms_series in the namespace su_arta is not the same relation as the drms_series relation in the su_phil namespace - the relations have the same name, but they are different relations. In virutally all PostgreSQL operations, a user can prefix the name of a relation with the namespace: su_arta.drms_series refers to the first relation, and su_phil.drms_series refers to the second relation.

The purpose of <new DB user namespace> is to hold non-production, private data series - sort of a private user space to develop new DRMS modules to create data. If those data should become a production-level products, then the data and the code that generates the data need to be moved to a production namespace. At the JSOC, we have several such production namespaces (e.g., aia, hmi, mdi). A site creates production namespaces with a different module (masterlists; newdrmsuser.pl is only for creating non-production namespaces.

Please see the NOTE in this page for assistance with choosing <new DB user namespace>. The general naming convention is to prepend the namespace with an abbreviation to identify the site that owns the data in the namespace. For example, all private data created at Stanford reside in dataseries whose namespaces start with su_ (Stanford University), regardless of the affiliation of the user who creates data in this namespace. Data created at NASA Ames start with nas_ (NASA Supercomputing Division). Following the underscore is a string to identify a particular user - su_arta for Art, and su_phil for Phil. You can also specify a group with the suffix (e.g., su_uscsolar for a solar group at the University of Southern California that creates data at Stanford. <initial password> is the initial password for this account - the initial password does not matter much since you are going to have the user change it next.

Running newdrmsuser.pl will create a new DRMS database user that has the same name as the user's Linux account name.

Have the user change their password:

$ whoami
<new DRMS user>
$ psql -h <PostgreSQL host> -p <PostgreSQL port> netdrms
netdrms=> ALTER USER <new DRMS user> WITH PASSWORD '<new password>';
netdrms=> \q
$ 

And then have the user create their .pgpass file (to allow auto-login to their database account) and set permissions to 0600:

$ whoami
<new DRMS user>
$ cd $HOME
$ vi .pgpass
i
<PostgreSQL host>:*:*:<DRMS DB production user>:<new password>
ESC
:wq
$ chmod 0600 .pgpass

Please click here for additional information on the .pgpass file.

If you plan on creating data that will be publicly distributed, you should also create one or more data-production users. For example, if you plan on making a new public HMI data series, you could create a user named hmi_production. Although you could follow previous steps to create a new Linux account for this database user, you do not necessarily need to. Instead you can use the existing <NetDRMS production user> and have it connect as the hmi_production user. To do that, first create the new hmi_production database user by running newdrmsuser.pl as just described. Choose a descriptive namespace that follows the naming guidelines described about, like hmi. Because a .pgpass already exists for <NetDRMS production user>, you want to ADD a new line to .pgpass for this user. Continuing with the hmi_production user example, add a password line for hmi_production:

# .pgpass
<PostgreSQL host>:*:*:hmi_production:<hmi_production password>

At this point, it is a good idea to test that the new DRMS user can use a basic NetDRMS program. Although your NetDRMS has no DRMS data series, running show_series is a good way to test various components, like authentication, database connection, etc. Test DRMS by running the show_series command:

$ whoami
<new DRMS user>
$ show_series
$ 

Nothing will be printed when this command is run, since your NetDRMS is devoid of data at the moment, but if you see no errors, then life is good. If not, then contact the JSOC for help troubleshooting.

To perform a more thorough test involving SUMS, you will need to have a least one DRMS data series that has SUMS data. You can obtain such a data series by registering for subscriptions.

Running SUMS Services

Before you can use NetDRMS, you, as <NetDRMS production user> on <SUMS host>, will need to start SUMS. To launch one or more SUMS daemons, sumsd.py, use the start-mt-sums.py script:

$ whoami
<NetDRMS production user>
$ hostname
<SUMS host>
$ python3 <NetDRMS root>/base/sums/scripts/start-mt-sums.py daemon=<NetDRMS root>/base/sums/scripts/sumsd.py ports=[SUMSD_LISTENPORT] --loglevel=debug
running /home/netdrms_production/.conda/envs/netdrms/bin/python3 /opt/netdrms/base/sums/scripts/sumsd.py --sockport=6102 --loglevel=debug
started instance /opt/netdrms/base/sums/scripts/sumsd.py:6102 (pid 27515)
{"started": [27515]

}

NOTE: as of this writing, ports MUST be the value of [SUMSD_LISTENPORT]. In future releases, this parameter will be made optional, in which case the value will be obtained from [SUMSD_LISTENPORT] in config.local.

This command starts sumsd.py, which then listens for connections from DRMS modules, such as show_info, on port [[SUMSD_LISTENPORT]]. In the example above, [[SUMSD_LISTENPORT]] is 6102, which is displayed in the output. sumsd.py creates an instances file and a log file in [SUMLOG_BASEDIR] by default. The instances file is a state file used by start-mt-sums.py and stop-mt-sums.py to manage the running sumsd.py instances. By default, the log file is named sumsd-<PPPPP>-<YYYYMMDD.HHMMSS>.txt, where <PPPPP> is the PID of the sumsd.py process, and <YYYYMMDD.HHMMSS> is the time string representing the time the instance was launched.

The complete usage is:

usage: start-mt-sums.py daemon=<path to daemon> ports=<listening ports> [ --instancesfile=<instances file path> ] [ --loglevel=<critical, error, warning, info, or debug>] [ --logfile=<file name> ] [ --quiet ]

optional arguments:
  -h, --help            show this help message and exit
  -i <instances file path>, --instancesfile <instances file path>
                        the json file which contains a list of all the
                        sumsd.py instances running
  -l LOGLEVEL, --loglevel LOGLEVEL
                        specifies the amount of logging to perform; in order
                        of increasing verbosity: critical, error, warning,
                        info, debug
  -L <file name>, --logfile <file name>
                        the file to which sumsd logging is written
  -q, --quiet           do not print any run information

required arguments:
  d <path to daemon>, daemon <path to daemon>
                        path of the sumsd.py daemon to launch
  p <listening ports>, ports <listening ports>
                        a comma-separated list of listening-port numbers, one
                        for each instance to be spawned

start-mt-sums.py will fork one or more sumsd.py daemon processes. The ports argument identifies the SUMS host ports on which sumsd.py will listen for client (DRMS module) requests. One sumsd.py process will be invoked per port specified. Each process creates a log-file in [SUMLOG_BASEDIR] named, by default, sumsd-<port>-<YYYYMMDD>.<HHMMSS>.txt. The -L/--logfile argument allows you to override the path and name to this log file.

To stop one or more SUMS services, use the stop-mt-sums.py script:

$ whoami
<NetDRMS production user>
$ hostname
<SUMS host>
$ python3 <NetDRMS root>/base/sums/scripts/stop-mt-sums.py daemon=<NetDRMS root>/base/sums/scripts/sumsd.py

This will stop all running sumsd.py daemons.

The complete usage is:

usage: stop-mt-sums.py [ -h ] daemon=<path to daemon> [ ---ports=<listening ports> ] [ --instancesfile=<instances file path> ] [ --quiet ]

optional arguments:
  -h, --help            show this help message and exit
  -p <listening ports>, --ports <listening ports>
                        a comma-separated list of listening-port numbers, one
                        for each instance to be stopped
  -i <instances file path>, --instancesfile <instances file path>
                        the json file which contains a list of all the
                        sumsd.py instances running
  -q, --quiet           do not print any run information

required arguments:
  d <path to daemon>, daemon <path to daemon>
                        path of the sumsd.py daemon to halt

Registering for Subscriptions

A NetDRMS site can optionally register for a data-series subscription to any NetDRMS site that offers subscription service. The JSOC NetDRMS offers subscriptions, but at the time of this writing, no other site does. Once a site registers for a data series subscription, the site will become a mirror for that data series. The subscription process ensures that the mirroring site will receive regular and timely updates made to the data series by the serving site. The subscribing site can configure the interval between updates such that the mirror can synchronize with the server and receive updates within a couple of minutes, keeping the mirror up-to-date in (almost) real time.

To register for a subscription, <Subscription production user> will set up ssh keys (for SU transfer), start daemons, and run the subscription script, subscribe.py. The assumption is that <Subscription production user> is <NetDRMS production user>, but you are free to choose a different user. subscribe.py makes subscription requests to the serving site's subscription manager. The process entails the creation of a snapshot of the data-series DRMS database information at the serving site. Those data are downloaded, via HTML, to the subscribing site, where they are ingested by subscribe.py. get_slony_logs.pl, a client-side cron task, updates the data-series snapshot with any server-side changes that have been made since the snapshot was created. Ingestion of the snapshot results in the creation of the DRMS database objects that maintain and store the data series, and get_slony_logs.pl updates those objects when the server makes changes. At this time, no SUMS data files are downloaded. Instead, and optionally, the IDs for the series' SUMS Storage Units (SU) are saved in a database relation. It is the function of Remote SUMS (rsums.py), another NetDRMS daemon, to download the SUs and ingest them into your SUMS.

Remote SUMS accepts requests from DRMS for SUs. It then communicates with the serving NetDRMS and manages the scp download and ingestion of those SUs. Once Remote SUMS is running, should any DRMS code/module request an SU that is not present in the local NetDRMS, DRMS will send a download request to Remote SUMS. The Remote SUMS Client (rsums-clientd.py), an optional NetDRMS daemon, can automate this process so that when new subscription data are ingested into the DRMS database, it submits requests for the associated SUs to Remote SUMS. In this way, it is possible to pre-fetch the SU files before any user requests them. But pre-fetching is optional. The SUs will be downloaded on-demand as described above. In fact, if the subscribing NetDRMS site were to automatically download an SU, then delete the SU (there is a method to do this, described later), then an on-demand download is the only way to re-fetch the deleted SU. On-demand downloads happen automatically; any DRMS module that attempts to access an SU (like with a show_info -p command) that is not present for any reason will trigger an rsumsd.py request. The module will pause until the SU has been downloaded, then automatically resume its operation on the previously missing SU.

As get_slony_logs.pl users scp to download update files (Slony logs) and rsumsd.py uses scp to automatically download SUs, SSH public-private keys must be created at the subscribing site, and the public key must be provided to the serving site. Setting this up requires coordinated work at both the susbscribing and serving sites. As <Subscription production user> on the subscribing site, run

$ whoami
<Subscription production user>
$ ssh-keygen -t rsa

This will allow you to create a passphrase for the key. If you choose to do this, then save this phrase for later steps. In the home directory of <Subscription production user>, ssh-keygen will create a public key named id_rsa.pub. Provide this public key to the serving site.

The serving site must then add the public key to its list of authorized keys. If the .ssh directory does not exist, then the serving site must first create this directory and give it 0700 permissions. If the authorized_keys file in .ssh does not exist, then it must first be created and given 0644 permissions:

$ whoami
<Subscription manager user>
$ mkdir .ssh
$ chmod 0700 .ssh
$ cd .ssh
$ touch authorized_keys
$ chmod 0644 authorized_keys

Once the .ssh and authorized_keys files exist and have the proper permissions, the serving site administrator can then add the client site's public key to its list of authorized keys:

$ whoami
<Subscription manager user>
$ cd $HOME/.ssh
$ cat <remote-site public key file> >> authorized_keys

Back at the client NetDRMS site, if an ssh passphrase was chosen, then as <Subscription production user> start an ssh-agent instance to automate the passphrase authentication. If no passphrase was provided when ssh-keygen was run, this step can be skipped. Otherwise, run:

$ whoami
<Subscription production user>
$ ssh-agent > $HOME/.ssh-agent
$ source $HOME/.ssh-agent # needed for ssh-add, and also for rsumsd.py and get_slony_logs.pl
$ ssh-add $HOME/.ssh/id_rsa

and provide the passphrase. To keep ingested data series synchronized with changes made to it at the serving site, a client-side cron tab runs get_slony_logs.pl periodically. This perl script uses scp to download slony log files - SQL files that insert, delete, or update database relation rows. get_slony_logs.pl communicates with the Slony-I replication software running at the serving site. Slony-I generates these log (SQL) files at the server which are then downloaded by the client.

To register for a subscription to a new series, run:

$ python3 <NetDRMS root>/base/drms/replication/subscribe_series/subscribe.py cfg=<subscription config file> reqtype=subscribe series=<published DRMS data series> --loglevel=debug

The complete usage is:

usage: subscribe.py [ -hjpl ] cfg=<client configuration file> reqtype=<subscribe, resubscribe, unsubscribe> series=<comma-separated list of series> [ --archive=<0, 1>] [ --retention=<number of days>] [ --tapegroup=<tape-group number> ] [ --pg_user=<subscripton client DB user> ] [ --logfile=<log-file name> ]

optional arguments:
  -h, --help            show this help message and exit
  archive <series archive flag>, --archive <series archive flag>
                        The tape archive flag for the series - either 0 (do not archive) or 1 (archive).
  retention <series SU disk retention>, --retention <series SU disk retention>
                        The number of days the series SUs remain on disk before becoming subject to deletion.
  tapegroup <series SU tape group>, --tapegroup <series SU tape group>
                        If the archive flag is 1, the number identifying the group of series that share tape files.
  pg_user <series SU tape group>, --pg_user <series SU tape group>
                        The DB account the subscription client uses.
  -p, --pause           Pause and ask for user confirmation before applying the downloaded SQL dump file.
  --loglevel LOGLEVEL   Specifies the amount of logging to perform. In increasing order: critical, error, warning, info, debug
  --logfile <file name>
                        The file to which logging is written.
  --filtersus <SU filter>
                        Specifies a series keyword K and a number of days D, comma separated; a remote-SUMS request for an SU will occur only if the keyword K of the record
                        containing the SU has a value that lies within the time interval determined by the days D.

required arguments:
  cfg <client configuration file>, --config <client configuration file>
                        The client-side configuration file used by the subscription service.
  reqtype <request type>, --reqtype <request type>
                        The type of request (subscribe, resubscribe, or unsubscribe).
  series SERIES, --series SERIES
                        A comma-separated list of DRMS series to subscribe/resubscribe to, or to unsubscribe from.

The debug level logging is not necessary, but if this is your first subscription, we recommend running with lots of debug statement - if there are issues, you can send this output to the JSOC for help.

<subscription config file> contains parameters used by both the subscription client subscribe.py and the program that downloads Slony logs file, get_slony_logs.pl. We recommend making a directory subscription in the home directory of <NetDRMS production user> and saving the configuration file in that directory. The parameters to be set in <subscription config file> are as follows:

You may find that a subscription has gotten out of sync, for various reasons, with the serving site's data series (accidental deletion of database rows, for example). You can re-register for the subscription to true-up. The existing DRMS data will be deleted, and replaced with a fresh snapshot. You will be prompted asking if you would like to delete the series' SUMS data (SUs, FITS files, etc.). If you are sure you no longer need them, go ahead and say yes.

python <NetDRMS root>/base/drms/replication/subscribe_series/subscribe.py cfg=<subscription config file> reqtype=resubscribe series=<subscription series> --loglevel=debug

Finally, there might come a time where you no longer which to hold on to a registration. To remove the subscription from your set of registered data series run: subscribe.py can be used to alleviate this problem. Run the following to re-do the subscription registration:

python <NetDRMS root>/base/drms/replication/subscribe_series/subscribe.py cfg=<subscription config file> reqtype=unsubscribe series=<subscription series> --loglevel=debug

NOTE: In this case, the subscribe.py will prompt you to ask if you would like to delete the existing DRMS data series. The answer is usually yes. However, if you need to keep the existing data series snapshot for some reason (e.g., you want to work with the existing data, but simply do not want to ingest new data), then respond no. Keep in mind that you will not be able to register for a subscription to the same series if that series already exists - you will need to run delete_series.

In all the above commands, the logging level is set to debug. It is a good idea to enable verbose logging like this the first time you run one of these commands, just in case an issue occurs (usually do to some configuration issue). Providing the debug log to the JSOC when troubleshooting will be invaluable.

Once you have successfully registered for subscription to at least one series, you will need to install a crontab to run get_slony_logs.pl, which updates the subscription series, on a regular basis. get_slony_logs.pl has a dependency on the Net::SSH perl package. If you are running CentOS, then there is an rpm package available from the epel/x86_64 yum repository that contains this perl package:

$ yum list | grep perl-Net-SSH
perl-Net-SSH.noarch                        0.09-26.el7            epel
$ sudo yum install perl-Net-SSH
...
Installed:
  perl-Net-SSH.noarch 0:0.09-26.el7

Complete!
$

You will also need String::ShellQuote:

$ yum list | grep ShellQuote
perl-String-ShellQuote.noarch              1.04-10.el7            base
$ sudo yum install perl-String-ShellQuote
...
Installed:
  perl-String-ShellQuote.noarch 0:1.04-10.el7

Complete!

If you cannot find a package, then you can use CPAN.

Once you have the Net::SSH and String::ShellQuote Perl packages installed, run get_slony_logs.pl as <Subscription production user>from a cron tab:

$ whoami
<Subscription production user>
$ crontab -e
*/5 * * * * (. ~/.ssh-agent; <NetDRMS root>/base/drms/replication/get_slony_logs.pl <subscription config file> >> ~/<path>/get_slony_logs.log 2>&1 )

NOTE: you should manually run get_slony_logs.pl the first time since an interactive prompt will be displayed the first time an SSH connection is made to {.[kRSServer]}

At the JSOC, Slony log files are created every minute. It is not the case that your series' subscriptions will have been updated every minute (this depends on the cadence of the series to which you have subscriptions), but checking every minute will minimize the lag between the state of your series and the state of your series at the serving site.

Running Remote SUMS

Your NetDRMS may contain data produced by other, non-local NetDRMSs. Via a variety of means, the local NetDRMS can obtain and ingest the database information for these data series produced non-locally. In order to use the associated data files (typically image files), the local NetDRMS must download the storage units (SUs) associated with these data series too. Remote SUMS, a tool that comes with NetDRMS, downloads SUs as needed - i.e., if a DRMS module or program requests the path to the SU or attempts to read it, and it is not present in the local SUMS yet, Remote SUMS will download the SUs. While the SUs are being downloaded, the initiating module or program will poll waiting for the download to complete.

Several components compose Remote SUMS. On the client side, the local NetDRMS, is a daemon that must be running rsumsd.py. There also must exist some database tables, as well as some binaries used by the daemon. On the server side, all NetDRMS sites that wish to act as a source of SUs for the client, is a CGI (rs.sh). This CGI returns file-server information (hostname, port, user, SU paths, etc.) for the SUs the server has available in response to requests that contain a list of SUNUMs. When the client encounters requests for remote SUs that are not contained in the local SUMS, it sends a request the Remote SUMS daemon to download those SUs. It does so by inserting a row into the <Remote SUMS requests> database table in the [RS_DBNAME] database table. The client code then polls waiting for the request to be serviced. The daemon in turn sends requests to all rs.sh CGIs at all the relevant providing sites. The owning sites return the file-server information to the daemon, and then the daemon downloads the SUs the client has requested, via scp, and notifies the client module once the SUs are available for use. The client module will then exit from its polling code and continue to use the freshly downloaded SUs.

To use Remote SUMS, several config.local parameters must be present. If you followed the steps in this document, then you have already set those parameters. Please see Installing NetDRMS for a description of each one. Each SU that is downloaded has an associated expiration date, a flag indicating whether or not the SU is archived, and if the SU is archived the tapegroup to which the SU belongs. The manner in which the values for these parameters are determined is a bit complicated. When you register for a series subscription, the series is created at your site, and at that time, the values for these parameters are determined. The series is then initialized with these values. There are default value for these parameters that are overridden by optional parameters supplied during the call to subscribe.py. In the following list, the lower-numbered items, if present, override the higher-numbered items, in this order:

  1. the --archive, --retention, --tapegroup command-line arguments to subscribe.py

  2. the archive, retention, tapegroup parameters in subscription config file

Now, when Remote SUMS runs, the values of the parameters for SUs downloaded and ingested are determined in a similar hierarchical fashion, with higher-numbered items overriding lower-numbered items:

  1. the parameters associated with the series, as determined above
  2. the --archive, --expiration, --lifespan, --tapegroup command-line arguments to rsumsd.py

  3. [RS_SU_ARCHIVE], [RS_SU_EXPIRATION], [RS_SU_LIFESPAN], [RS_SU_TAPEGROUP]

To run Remote SUMS, as NetDRMS production user run the following to create the requests database table:

$ whoami
<NetDRMS production user>
$ python3 <NetDRMS root>/base/drms/scripts/rscreatetabs.py op=create tabs=req

Remote SUMS downloads SUs via scp. As such, you will need to create SSH keys, distribute the public one to the site serving the SUs, and start up an ssh-agent if you have not already done so - you should have already though since it is needed by get_slony_logs.pl, a component of the subscription system (please see [ Registering for Subscriptions ]).

To launch Remote SUMS, as <NetDRMS production user> create [RS_LOGDIR] and the directory that will contain the Remote SUMS lock file [RS_LOCKFILE], source the ssh-agent environment file, and then run rsumsd.py in the background:

$ whoami
<NetDRMS production user>
$ mkdir -p [RS_LOGDIR]
$ mkdir -p `dirname [RS_LOCKFILE]`
$ source $HOME/.ssh-agent
$ python <NetDRMS root>/base/drms/scripts/rsumsd.py --loglevel=debug &

For now, we recommend setting the log level to debug; when things appear to be running smoothly, then you can restart with the default level (info). The output log named <rslog_YYYYMMDD.txt> will be written to the directory identified by [RS_LOGDIR], so make sure that directory exists before running rsumsd.py.

To stop rsumsd.py, send a SIGINT signal (kill -2 to the process. Remote SUMS will intercept that signal and shut down cleanly. If you need to shut it down with a SIGKILL signal for any reason, then you will need to manually clean up. To do that, delete the lock file ([RS_LOCKFILE]) and delete all requests in the requests database table (i.e., delete all rows in [RS_REQUEST_TABLE]).

Running Remote SUMS Client

If you have at least one subscription, and you have Remote SUMS running (not the JMD), then you can automate the download of SUs for the subscriptions. This is optional, however. If you skip this step, then when a NetDRMS user attempts to use one or more SUs that are part of a subscription (and hence not at your NetDRMS site initially), the SUs will be downloaded in an on-demand fashion. However, it may be desirable to pre-fetch the SUs if certain usage patterns hold. If one or more users are going to use a block of SUs for a two-week period, for example, then downloading hundreds or thousands of SUs one at a time would be very inefficient. Also, it is very common for NetDRMS users to use newly produced SUs soon after they are created at the subscription server. In this case, a good strategy might be to automatically download the latest SUs for all subscriptions, knowing that lots of very recent SUs will be popular.

The Remote SUMS Client, rsums-clientd.py, monitors SU references in incoming Slony logs. It groups SUs into batches, and submits requests containing these batches to Remote SUMS, rsumsd.py. rsums-clientd.py then monitors the progress of these requests, logging the results.

In addition to a running rsumsd.py, rsums-clientd.py requires the existence of three components. The capture table is a database table that contains a list of all SUNUMs that are to be downloaded. It gets automatically populated as Slony logs are ingested. The capture function is a database function that performs the actual work of inserting rows into the capture table. It is called every time a Slony log inserts a row into a subscribed series' series table. You will need to create a capture trigger database trigger for each series table for which you want to automate SU downloads. These components work together as follows:

IF YOU REGISTERED FOR YOUR FIRST SUBSCRIPTION FROM A >= 9.0 NetDRMS then the capture table and capture function already exist. In addition, a capture trigger has been installed on each of your subscribed series. As <NetDRMS production user>, ensure that rsumsd.py is running, and then you can start rsums-clientd.py:

$ whoami
<NetDRMS production user>
$ python3 <NetDRMS root>/base/drms/replication/subscribe_series/rsums-clientd.py --loglevel=debug &

If you do not have a >= 9.0 NetDRMS OR you were already a subscriber before upgrading to >= 9.0 NetDRMS, then to use rsums-clientd.py, <NetDRMS production user> must first create the capture table and the capture function. You must also add the capture trigger to the series table of the DRMS data series for which they want to enable automatic SU downloads. rsums-clientd.py can be run with arguments so that it will print SQL that will create the capture table and function, and the capture triggers on the existing DRMS data series:

$ whoami
<NetDRMS production user>
$ python3 <NetDRMS root>/base/drms/replication/subscribe_series/rsums-clientd.py [ --setup [ --capturesetup ] [ --seriessetup=<series> ]... ]

--capturesetup creates the capture table and capture function. --seriessetup creates the capture trigger for a single series.

For example, to set up automatic SU downloads for hmi.M_45s and hmi.V_720s for a site that lacks the capture table and capture function, the <NetDRMS production user> can run:

$ whoami
<NetDRMS production user>
$ python3 <NetDRMS root>/base/drms/replication/subscribe_series/rsums-clientd.py [ --setup [ --capturesetup ] [ --seriessetup=hmi.M_45s --seriessetup=hmi.V_720s ] ]

Once these capture components are in place, you can start rsumsd.py if it is not already running, then start rsums-clientd.py:

$ whoami
<NetDRMS production user>
$ python3 <NetDRMS root>/base/drms/replication/subscribe_series/rsums-clientd.py --loglevel=debug &

To stop rsums-clientd.py, send a SIGINT signal (kill -2 to the process. Remote SUMS Client will intercept that signal and shut down cleanly. If you need to shut it down with a SIGKILL signal for any reason, then you will need to manually clean up. To do that, delete the lock file ([DRMS_LOCK_DIR]/rsums-client.lck).

Installing the DRMS Python Package

The DRMS package is a python client interface to DRMS. By default, it obtains DRMS data series information and SUMS storage units / FITS files from the JSOC DRMS via a CGI API. As such, it can be installed and used without independently of DRMS. However, it can be configured so that it uses your NetDRMS site directly and not the JSOC.

Two interfaces to your NetDRMS are available: a web-based one, and an ssh-based one. The web-based interface requires setting up a web server and several CGI scripts. The ssh-based one requires a python module that is not currently available online. Instead, the module, securedrms, is included as part of the NetDRMS installation. With either interface, a user can run the python package on a machine that is not the NetDRMS host. Since the ssh interface is much simpler to set up, not requiring a web context, the following describes how to set up the ssh interface.

To install the drms python package, first obtain it from GitHub. If git is not yet installed on your system, use yum to install it:

$ sudo yum install git-all
...
Installed:
  git-all.noarch 0:1.8.3.1-21.el7_7
...
Complete!
$ 

After cloning the drms package, you will need to copy the securedrms module into the cloned drms package. As <NetDRMS production user>, use git to clone the drms python package, copy securedrms.py into the cloned tree, and then install the code into the netdrms virtual environment:

$ whoami
<NetDRMS production user>
$ git clone https://github.com/sunpy/drms
Cloning into 'drms'...
...
$ cp <NetDRMS root>/base/libs/py/securedrms.py drms
$ which pip
~/.conda/envs/netdrms/bin/pip
$ pip install ./drms
Processing ./drms
...
Successfully installed drms-0.5.7+1.ga9de281

securedrms.py has python dependencies on packages/modules that may not exist. Use conda to install them:

$ whoami
<NetDRMS production user>
$ conda install -n netdrms pexpect
Collecting package metadata (current_repodata.json): done
...