Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:mbussolotto:branches:systemsmanagement:Uyuni:Master
server-image
uyuni-configfiles-sync
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File uyuni-configfiles-sync of Package server-image
#!/bin/bash # # Uyuni config files defaults synchronization tool # # 1) The "init" command needs to run during container buildtime. # This will create the backups and create a random ".buildhash" # which will be later stored at SYSCONFIG_FILE during 'sync' # command to identify if there is an upgrade of the container image. # (backups only packaged files on the persistent directories to initialize) # # 2) During "sync" command, this tool checks for differences between # the stored files and the actual files stored in the previously # initializated persitent volumes. # If changes are detected, the tool determines if those are caused by # either: # a) Upgrade of the container image (new version) # b) Local changes made by the users # # The tool won't delete any files in the persistent volumes, and will # create "rpmsave" or "rpmnew" according to what is defined for that # file in its RPM SPEC. # # As a last step during "sync", this tool takes care of running the # RPM scriptlets for the packages which provides files to the persistent # volumes, simulating an RPM upgrade, so necessary actions than an RPM # upgrade bring can be also performed. # # 3) The "sync" command is automatically triggered during container startup, # but once the "sync" command has been executed in a container that runs a # particular container image, then the "sync" is locked and won't be executed # until the container image has changed, triggering the "sync" again for this # new container image. # set -e DEFAULTS_STORAGE="/etc/uyuni-configfiles-sync/" SYSCONFIG_FILE="/etc/sysconfig/uyuni-configfiles-sync" help() { printf "Uyuni config files defaults synchronization tool Usage: uyuni-configfiles-sync [command] Available Commands: init Add persistent volume to track package and config files. list List initializated persistent volumes environments. sync Synchronize files to persistent volumes and run RPM scripts. " } init() { PV=$(echo "$1/" | tr -s /) if [ ! -d $DEFAULTS_STORAGE ]; then mkdir $DEFAULTS_STORAGE fi if [ ! -f $DEFAULTS_STORAGE/.buildhash ]; then echo $RANDOM | sha256sum | head -c 64 > $DEFAULTS_STORAGE/.buildhash fi echo -n "Initializing environment for persistent volume $PV ... " TARGET="$DEFAULTS_STORAGE/$(echo $PV | sed 's/\//-/g')" mkdir -p $TARGET echo "$PV" > $TARGET/.pv # Calculate the packages that are owning the files under this path PKGNAMES=$(LANG=C rpm -q -qf $(find $PV) | egrep -v "^file .+ is not owned by any package" | sort -u) # Sync the package files (non-configuration and configuration files) to our storage for pkg in $PKGNAMES; do for cfgfile in $(rpm -ql $pkg | grep "^$PV"); do if [ -f $cfgfile ]; then echo ${cfgfile#"$PV"} | rsync -a --files-from=- --exclude={'*'} $PV $TARGET fi done done echo "done!" } sync_file() { SOURCE_FILE=$1 TARGET_FILE=$2 # Synchronize package and config files if echo $LIST_CONFIG_NO_REPLACE | egrep -q "( |^)$i( |$)"; then # Configuration (no replace) files echo " - $TARGET_FILE - Contains modifications made by the user. Not replacing and saving new file content as rpmnew file" rsync -a $SOURCE_FILE $TARGET_FILE.rpmnew else # Config (replace) and rest of package files echo " - $TARGET_FILE - Contains modifications made by the user. Replacing and saving old file content as rpmsave file" rsync -ab --suffix ".rpmsave" $SOURCE_FILE $TARGET_FILE fi } sync() { # We skip the sync if already triggered on this container if [ ! -f $DEFAULTS_STORAGE/.buildhash ]; then echo "Missing $DEFAULTS_STORAGE.buildhash file. You probably need to run 'init' command first. Skipping." exit elif [ -f $SYSCONFIG_FILE ] && [ "$(cat $DEFAULTS_STORAGE/.buildhash)" = "$(cat $SYSCONFIG_FILE)" ]; then echo "Skipping 'sync' as it was already executed on this container" exit fi echo "Synchronizing defaults for all initializated environments" echo PACKAGES_ALL="" for PV_DIR in $(ls $DEFAULTS_STORAGE | grep -v "^\.buildhash$"); do SOURCES=$(echo "$DEFAULTS_STORAGE/$PV_DIR/" | tr -s /) PV=$(cat $SOURCES/.pv) PKGNAMES=$(LANG=C rpm -q -qf $(find $PV) | egrep -v "^file .+ is not owned by any package" | sort -u) PACKAGES_ALL=$(echo -e "$PACKAGES_ALL\n$PKGNAMES") echo "- Processing pv: $PV" echo -n " * Getting information for files to synchronize ... " LIST_CONFIG_NO_REPLACE="" LIST_CONFIG_REPLACE="" LIST_ALL_FILES_FULL_PATH=$(rpm -ql $PKGNAMES | grep "^$PV") LIST_ALL_FILES_REL_PATH="${LIST_ALL_FILES_FULL_PATH//$PV/}" # For each config file, we check the noreplace flag for cfgfile in $(rpm -q --configfiles $PKGNAMES | grep "^$PV"); do FILEFLAG=$(rpm -q --qf '[%{filenames}: %{fileflags}\n]' $PKGNAMES | egrep "^$cfgfile: .+" | cut -d":" -f2) if [ "$((FILEFLAG & 16))" = "16" ]; then LIST_CONFIG_NO_REPLACE="$LIST_CONFIG_NO_REPLACE ${cfgfile#"$PV"}" else LIST_CONFIG_REPLACE="$LIST_CONFIG_REPLACE ${cfgfile#"$PV"}" fi done echo "done!" echo -n " * Syncing non configuration files ... " RSYNC_ARGS="" # We exclude configuration files as they are going to be processed later # Exclude args, if apply, must has formatted as: {'file1','file2'} LIST_FILES_TO_EXCLUDE="'$(echo $LIST_CONFIG_REPLACE $LIST_CONFIG_NO_REPLACE | sed "s/ /','/g")'" if [ ! "$LIST_FILES_TO_EXCLUDE" = "''" ]; then RSYNC_ARGS="--exclude={$LIST_FILES_TO_EXCLUDE}" fi # Synchronize package files from source excluding (configuration files) CMD="rsync -ab $RSYNC_ARGS --exclude=".pv" --suffix ".rpmsave" $SOURCES $PV" eval $CMD echo "done!" echo " * Syncing configuration files ..." for i in $(echo $LIST_CONFIG_NO_REPLACE $LIST_CONFIG_REPLACE); do SOURCE_FILE=$(echo $SOURCES/$i | tr -s /) TARGET_FILE=$(echo $PV/$i | tr -s /) # Some files listed in the package may be removed, we don't want to recreate them, so we skip. if [ ! -f $SOURCE_FILE ]; then echo " - WARNING: $TARGET_FILE is listed as beloging to a package but it was not existing at the time the persistent volume was initializated. Skipping." continue fi # Check possible changes to sync. Excluding changes on creation/modification times # We need to parse output: # - no output or line starting with "." -> nothing to sync # - else -> changes to sync CHECK_CHANGES=$(rsync --dry-run -a --itemize-changes --size-only $SOURCE_FILE $TARGET_FILE) if [ -z "$CHECK_CHANGES" ] || echo $CHECK_CHANGES | grep -q "^\."; then # No changes are needed for this file echo " - $TARGET_FILE - No changes needed" else # Changes are needed for this file. # Now we need to determine if changes are coming from a package upgrade # or local changes made by user in order to determine the sync strategy. if [ -f $TARGET_FILE ]; then # Target file does exist in persistent volume # We check stored checksum to know if changes are from coming by the user or from a package upgrade # NOTE: stored checksum file may not exist yet, when "sync" has been never executed yet (first start) if [ -f $PV/.defaults_checksums ]; then CHECKSUM=$(grep " $SOURCE_FILE$" $PV/.defaults_checksums | awk '{print $1}') else CHECKSUM="" fi if [ ! -z "$CHECKSUM" ] && [ "$CHECKSUM" = "$(sha256sum $SOURCE_FILE | awk '{print $1}')" ]; then # Checksum are equal between new defaults and cached defaults # this mean changes are made by the user sync_file $SOURCE_FILE $TARGET_FILE elif [ ! -z "$CHECKSUM" ] && [ ! "$CHECKSUM" = "$(sha256sum $SOURCE_FILE | awk '{print $1}')" ]; then # Checksum are different between new defaults and cached defaults checksums # Meaning changes in file due an upgrade or local user changes if [ "$CHECKSUM" = "$(sha256sum $TARGET_FILE | awk '{print $1}')" ]; then # Checksum is equal between cached defaults and target file # Meaning no local changes and changes are due an upgrade echo " - $TARGET_FILE - No local modifications but new changes coming from a package upgrade, replacing file" rsync -a $SOURCE_FILE $TARGET_FILE else # Local changes made by the user. sync_file $SOURCE_FILE $TARGET_FILE fi else # First sync - no checksums stored yet. Syncing sync_file $SOURCE_FILE $TARGET_FILE fi else # File does not exist - we synchronize it echo " - $TARGET_FILE - Does not exist, we synchronize it" rsync -a $SOURCE_FILE $TARGET_FILE fi fi done # Regenerate checksum cache for defaults rm $PV/.defaults_checksums &> /dev/null || : for i in $(echo $LIST_ALL_FILES_REL_PATH); do SOURCE_FILE=$(echo $SOURCES/$i | tr -s /) if [ -f "$SOURCE_FILE" ]; then sha256sum $SOURCE_FILE >> $PV/.defaults_checksums fi done echo " * Completed" echo done # Run RPM scriptslets simulating a package upgrade echo "- Running scriptlets for packages:" PACKAGES_ALL=$(echo "$PACKAGES_ALL" | sort -u) run_scripts "$PACKAGES_ALL" echo " * Completed" # We lock the sync so it cannot run until next upgrade of the container image cp $DEFAULTS_STORAGE/.buildhash $SYSCONFIG_FILE } run_scripts() { PACKAGE_NAMES=$1 for PKG in $PACKAGE_NAMES; do echo " * Running scripts for $PKG ..." # RPM scriptlets ordering: # https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/#ordering PREIN_SCRIPT=$(rpm -q --qf "%{PREIN}" $PKG) if [ ! "$PREIN_SCRIPT" = "(none)" ]; then echo "$PREIN_SCRIPT" | DISABLE_RESTART_ON_UPDATE=1 sh -s -- 2 fi POSTIN_SCRIPT=$(rpm -q --qf "%{POSTIN}" $PKG) if [ ! "$POSTIN_SCRIPT" = "(none)" ]; then echo "$POSTIN_SCRIPT" | DISABLE_RESTART_ON_UPDATE=1 sh -s -- 2 fi PREUN_SCRIPT=$(rpm -q --qf "%{PREUN}" $PKG) if [ ! "$PREUN_SCRIPT" = "(none)" ]; then echo "$PREUN_SCRIPT" | DISABLE_RESTART_ON_UPDATE=1 sh -s -- 1 fi POSTUN_SCRIPT=$(rpm -q --qf "%{POSTUN}" $PKG) if [ ! "$POSTUN_SCRIPT" = "(none)" ]; then echo "$POSTUN_SCRIPT" | DISABLE_RESTART_ON_UPDATE=1 sh -s -- 1 fi POSTTRANS_SCRIPT=$(rpm -q --qf "%{POSTTRANS}" $PKG) if [ ! "$POSTTRANS_SCRIPT" = "(none)" ]; then echo "$POSTTRANS_SCRIPT" | DISABLE_RESTART_ON_UPDATE=1 sh -s -- 2 fi done } list() { echo "List of initialized persistent volumes" echo "--------------------------------------" echo for pv in $(ls $DEFAULTS_STORAGE | grep -v "^\.buildhash$"); do SOURCES=$(echo "$DEFAULTS_STORAGE/$pv" | tr -s /) PV=$(cat $SOURCES/.pv) echo "$PV - $(find $SOURCES -type f | grep -v ".pv$" | wc -l) configuration and package files - $SOURCES/" done } if [ "$1" == "init" ] && [ -n "$2" ]; then PV=$2 init $PV elif [ "$1" == "sync" ]; then sync elif [ "$1" == "list" ]; then list else help fi
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor