PostgreSQL database model
Database structure
cust_cluster
The description of a single deployed StorPool cluster, whether in our internal testing environment or at a customer site.
Data model fields:
namecltype
Additional fields:
deleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Referential integrity:
cltypereferencescust_cluster_type(id)
Automated event journalling:
cust_cluster_record_trigger
cust_cluster_type
The type (support state) of a StorPool cluster, whether deployed in our testing environment or in a customer's production site.
Data model fields:
idname
Additional fields:
None
Automated event journalling:
None
cust_host_kver
A single kernel version installed on a host in a StorPool cluster.
Data model fields:
cluster_namehost_namedistroversioncurrent
Additional fields:
deleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Referential integrity:
cluster_namereferencescust_cluster(name)- (
distro,version) referencekver(distro, version)
Automated event journalling:
cust_host_kver_record_trigger
distro
A Linux distribution that StorPool can be installed on.
Data model fields:
namevariantsupported
Additional fields:
None
Automated event journalling:
distro_record_trigger
event
An automatically-maintained log-like table of changes made to
some types of records, e.g. distro, kver,
sp_build, etc.
Data model fields:
table_namepkeyactiongenerationfieldststamp
Additional fields:
id(integer): a unique identifier of this event, assigned by the database management system
Functions invoked by client:
generation_drop_empty(generation_id)generation_drop_empty_current()
generation
A single set of related changes made to
the sqern database.
Data model fields:
idcommentusernameipaddrtstamp
Additional fields:
None
Functions invoked by the clients:
generation_id()generation_start(comment)
Internal functions:
generation_id_if_assigned()
kver
A Linux kernel version for a specific Linux distribution. These objects carry no state at all by themselves; they exist for the purposes of referential integrity (foreign key constraints).
Informational queries should probably use
the kver_not_ignored view instead.
Data model fields:
distroversion
Additional fields:
archived(boolean): is this kernel version no longer taken into consideration
Referential integrity:
distroreferencesdistro(name)
Automated event journalling:
kver_record_trigger
kver_fetched
A Linux kernel version that our build infrastructure can attempt to build a StorPool package for, i.e. the OS packages containing the kernel header files have been successfully fetched from the upstream repositories of the Linux distribution.
Data model fields:
distroversiontstamp
Additional fields:
None
Referential integrity:
- (
distro,version) referencekver(distro, version)
Automated event journalling:
kver_fetched_record_trigger
kver_ignore
A Linux distribution-specific pattern that specifies that some kernel versions should be ignored.
Informational queries should not use this table directly, but
the kver_not_ignored view instead.
Data model fields:
distropatterncomment
Additional fields:
deleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Automated event journalling:
kver_ignore_record_trigger
kver_not_ignored
A view over the kver table that skips any versions that match
the patterns recorded in the kver_ignore table for
the corresponding Linux distribution.
This view is automatically refreshed after any changes to the kver and
kver_ignore tables by triggers invoking the kver_update_not_ignored() function.
Fields inherited from the kver table:
distropatterncomment
Additional fields:
None
Automated refreshing:
kver_update_not_ignored()kver_update_not_ignored_kverkver_update_not_ignored_kver_ignore
kver_seen
A Linux kernel version that has been seen in the upstream package repositories of a specific Linux distribution.
Data model fields:
distroversiontstamp
Additional fields:
None
Referential integrity:
- (
distro,version) referencekver(distro, version)
Automated event journalling:
kver_seen_record_trigger
sp_available_kver
FIXME: something about StorPool packages uploaded to the vault that may be used for testing or deployment or something.
Data model fields:
FIXME: this one is not even described in the data model...
Additional fields:
storpool_revision(string): the "21.0.243.620bc3729" version string of the StorPool source treerelease_target(string): the StorPool testing infrastructure suite that this build is initially meant for e.g. "sp-lab"distro(string): the Linux distribution the modules were built forversion(string): the kernel version the modules were built fordeleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Referential integrity:
- (
distro,version) referencekver(distro, version)
Automated event journalling:
sp_available_kver_record_trigger
sp_build
An attempt to build StorPool from a specific source tree.
Data model fields:
idtstampresultsuccess(generated)jenkins_jobstorpool_revisionchange_idofficialrelease_targetdockernel_profile
Additional fields:
deleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Automated event journalling:
sp_build_record_trigger
sp_build_kver
A single kernel version that a particular StorPool build attempts to build the StorPool kernel modules for.
Data model fields:
build_iddistroversion
Additional fields:
deleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Referential integrity:
build_idreferencessp_build(id)- (
distro,version) referencekver(distro, version)
Automated event journalling:
sp_build_kver_record_trigger
sp_test
An attempt to run the StorPool testing suite on
the packages produced by a StorPool build.
Data model fields:
idtstampbuild_idtest_flavortest_cluster
Additional fields:
deleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Referential integrity:
build_idreferencessp_build(id)
Automated event journalling:
sp_test_record_trigger
sp_test_kver
A single kernel version that a particular StorPool test run attempts to validate the StorPool kernel modules for.
Data model fields:
test_iddistroversion
Additional fields:
deleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Referential integrity:
test_idreferencessp_test(id)- (
distro,version) referencekver(distro, version)
Automated event journalling:
sp_test_kver_record_trigger
sp_test_result
The result of a test run.
Data model fields:
test_idtstampresultsuccess
Additional fields:
deleted_at(timestamp): the moment this record was marked as deleted, or the special value-infinityotherwise
Referential integrity:
test_idreferencessp_test(id)
Automated event journalling:
sp_test_kver_record_trigger
General workflow recommendations
Use the psql command-line tool in shell programs, but carefully!
When passing string values to INSERT, SELECT, UPDATE, DELETE, etc.
queries, the values MUST be quoted appropriately: any single-quote characters
must be doubled.
The following shell function may come in useful:
Newline characters within the string values will still pose a problem. If possible, avoid them. If not, take extra care and use PostgreSQL's string constants with C-style escapes ...but only with extreme care!
For multiline queries, as well as queries that insert more than one row,
it is better to construct the query beforehand in a temporary file and
use the psql tool's --filename (-f) option.
Run informational queries against the database (Python)
- connect to the database using the appropriate PostgreSQL
service=sqern-...record - do not issue a
generation_start(...)orgeneration_id()query - issue
SELECT ...queries as needed - disconnect from the database
Run informational queries against the database (shell programs)
- use the
psqlcommand-line tool - specify the appropriate PostgreSQL
service=sqern-...record - do not issue a
generation_start(...)orgeneration_id()query - pass one or more
-c 'SELECT ...'query parameters as needed - IMPORTANT: quote string values by doubling any single-quote characters!
- use the
psqltool's--no-align(-A),--field-separator(-F),--tuples-only(-t), and other output formatting options as needed - IMPORTANT: check the exit code of the psql tool
Add, update, or delete database records (Python)
- connect to the database using the appropriate PostgreSQL
service=sqern-...record - start a transaction using a
BEGINquery - optionally (recommended), issue a
generation_start()query with a brief comment describing the purpose of the changes to the database - insert new records using
INSERT INTO ...(ON CONFLICT DO NOTHINGif needed) orCOPY ... FROM STDINqueries - optionally (recommended), issue a
generation_drop_empty_current()orgeneration_drop_empty(generation_id)query if there is the possibility that no new records were inserted at all - commit the transaction using a
COMMITquery
Note that several of the above steps (connect, start a transaction,
invoke generation_start(), invoke generation_drop_empty(), commit the transaction)
are made easier by the sqern_tools.util.connect() helper function:
with util.connect(comment="update customer host kernel versions") as (conn, cur, generation):
# use the psycopg client cursor object cur's methods
If any of the values returned by the connect() helper function are not needed,
_ placeholders may be used (e.g. with connect(...) as (_, cur, _):).
FIXME: make connect() return a frozen dataclass instead.
Add, update, or delete database records (shell programs)
- prepare the queries to run, either in shell variables or, if more than one record should be inserted, into a temporary file
- IMPORTANT: if using
INSERT,UPDATE, orDELETEqueries, quote any string values by doubling any single-quote characters! - IMPORTANT: if using
COPY ... FROM STDINqueries, make sure that the values do not contain the separator character! - use the
psqlcommand-line tool and pass at least the--single-transaction(-1) and-v 'ON_ERROR_STOP=on'command-line options - specify the appropriate PostgreSQL
service=sqern-...record - optionally (recommended), pass a
-c 'SELECT generation_start(...)query with a brief comment describing the purpose of the changes to the database - pass one or more
-c 'INSERT/UPDATE/DELETE ...'or-f "$copyfile"query parameters as needed - optionally (recommended), pass a
-c 'SELECT generation_drop_empty_current()'query if there is the possibility that no new records were inserted at all - IMPORTANT: check the exit code of the psql tool
Sample workflow scenarios
Record the kernel versions used by customer hosts
- see the sample
load-cust-dataPython tool (python/src/sqern_tools/load_cust_data.py) - grab data from the monitoring reports
- insert newly-seen kernel versions into the
kvertable - insert, update, and/or mark as deleted cluster records in
the
cust_clustertable (one record for each customer cluster) - insert, update, and/or mark as deleted host records in
the
cust_host_kvertable: cluster, host, distro, version (many records for each customer host) - we do not need a separate
cust_hosttable, right? (aggregate queries exist after all)
The StorPool automated build-and-test pipelines
- check for new kernel versions in the upstream distros
(
sh/check-new-distro-kver.sh): - fetch the development packages for newly-seen kernel versions
(
sh/fetch-distro-kver.sh):- grab
kver_seenrecords that are not yet present inkver_fetched - run
kernqto fetch the files - insert newly-fetched kernel versions into
the
kver_fetchedtable; this is the input table for the next step
- grab
- build StorPool for kernel versions that we have the devel files for
(not yet implemented, autobuild? the Jenkins pipelines?):
- if we're building for newly-seen kernel versions,
grab
kver_fetchedrecords that are not yet present in thesp_buildtable - otherwise, make sure there are
kver_fetchedrecords for what we want to build - when a build is started, insert a record into the
sp_buildtable with a nullresultfield, and note theidof the record (e.g. PostgreSQL'sINSERT INTO ... RETURNING idsyntax). Make the build ID part of the build artifacts so that the next step can use it. - if we know which kernel versions we are building for, immediately
insert records into the
sp_build_kvertable - when a build succeeds or fails, update the
resultfield (this will automatically make thesuccessfield non-null) - possibly, only update the kernel versions now... figure this out
- if we're building for newly-seen kernel versions,
grab
- run the autotest suite for ready StorPool builds
- we should always know what we are testing for; make sure there is
a
sp_buildrecord for that - when a test run is started, insert a record into
the
sp_testtable with a nullresultfield, and note theidof the record (e.g. PostgreSQL'sINSERT INTO ... RETURNING idsyntax). Make the test run ID part of the run artifacts so that any reports can use it. - we should always know which kernel versions we are testing for;
immediately insert records into the
sp_test_kvertable - when a test run succeeds or fails, update the
resultfield (this will automatically make thesuccessfield non-null)
- we should always know what we are testing for; make sure there is
a