svc-pkg-mirror revision 2953
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
#
# This is the method script for the svc:/application/pkg/mirror service
#
# When called using the 'start' or 'stop' SMF method script, it adds
# or removes a crontab entry for the user running the service, pkg5srv
# by default.
#
#
# When called using the 'refresh' method, it runs pkgrecv(1) to update a
# pkg(5) repository using configuration stored in the SMF instance.
#
# The following SMF properties are used to configure the service:
#
# config/repository the local pkg5 repository we update.
#
# origin information that we should update
# from.
#
# config/publishers a comma-separated list of the publishers
# from ref_image that we pkgrecv from.
#
# config/crontab_period the first five fields of a crontab(4)
# entry, with the 3rd field allowing the
# special value 'random'.
#
# to log more output when debugging.
#
# Load SMF constants and functions
#
# Since we deal with '*' values in crontab fields, we never want
# globbing.
#
set -o noglob
#
# Multiple instances of this service should not point at the
# same local repository, since they could step on each other's toes
# during updates, so we check for this before enabling the service.
#
# Usage:
# check_duplicate_repos
#
function check_duplicate_repos {
#
# if the unique list of repositories is not the same as the
# list of repositories, then we have duplicates.
#
return 1
fi
return 0
}
#
# In order that all instances don't hit the remote origins on the same
# day, when configured with a 'config/crontab_period' containing a
# special value 'random' in the 'day of the month' field of the crontab
# schedule, we randomize the day, choosing a value from 1-28, storing
# that to the service config instead. We then print the crontab period.
#
# Usage:
# add_date_jitter
#
function add_date_jitter {
#
# Validate the cron_period property value, checking that we have
# exactly 5 fields, and that 'random' only appears in the 3rd
# field. We leave other validation up to cron(1).
#
NF != 5 {
print "config/crontab_period property must contain 5 " \
"values.";
exit 1
}
$1 == "random" || $2 == "random" || $4 == "random" || \
$5 == "random" {
print "only field 3 can have the value random";
exit 1
}'
$SMF_FMRI exit
#
# Save the schedule in the instance. Note that this
# will not appear in the running instance until the
# refresh method has fired.
#
config/crontab_period = astring: \"$new_schedule\"
fi
print $new_schedule
}
#
# Add a crontab entry that does periodic pkgrecvs from a series of
# remote pkg5 origins to a local repository. This is run as part of the
# SMF start method for this service. If the repository doesn't exist,
# we create it. We also attempt to create a zfs dataset if the parent
# directory for the repository is the leaf of a zfs dataset.
#
function smf_schedule_updates {
check_failure $? "Two or more instances of $SVCNAME contain the
same 'config/repository' value, which is not supported." $SMF_FMRI exit
typeset repo=$($SVCPROP -p config/repository $SMF_FMRI)
IFS=,
set -A publishers $($SVCPROP -p config/publishers $SMF_FMRI)
if [ ! -f $repo/pkg5.repository ]; then
#
# $special gets set by readmnttab in
# /lib/svc/share/fs_include.sh
#
check_failure $? \
fi
fi
}
#
# Remove the crontab entry that was added by 'schedule_updates'. This is
# run as part of the SMF stop method for this service.
#
function smf_unschedule_updates {
}
#
# and if not, sets it to the given publisher.
#
# Usage:
# set_default_publisher <path to repo> <publisher>
#
function set_default_publisher {
typeset repo="$1"
typeset pub=$2
fi
}
#
# Intended to be called as part of a cron job firing, this calls
# 'pkgrecv_from_origin' for each publisher configured in the SMF
# instance.
#
# Usage:
# update_repository <smf fmri>
#
function update_repository {
typeset SMF_FMRI=$1
if [ -f $lockfile ]; then
check_failure 1 "A mirror operation was already running
override, or check the SMF property 'config/crontab_period' to ensure
return 1
fi
# write our pid into the lock file
echo $$ > $lockfile
typeset repo=$($SVCPROP -p config/repository $SMF_FMRI \
IFS=,
set -A publishers $($SVCPROP -p config/publishers $SMF_FMRI)
echo "ERROR: no publishers found in 'config/publishers'"
return $SMF_EXIT_FATAL
fi
set -A origins ""
set -A ssl_keys ""
set -A ssl_certs ""
set -A http_proxies ""
set -A https_proxies ""
#
# Gather the details we need to connect to the origins
# we want to pkgrecv from.
#
i=0
index=0
while [ $i -lt ${#publishers[@]} ]; do
pub=${publishers[$i]}
sslkey=$($PKG -R $ref_image publisher $pub \
sslcert=$($PKG -R $ref_image publisher $pub \
$PKG -R $ref_image publisher -F tsv > /tmp/pkg.mirror.$$
#
# this function depends on the output of
# 'pkg publisher -F tsv'. It really ought to use
# 'pkg publisher -o' option when that's available.
#
continue
fi
echo "WARNING: no URI \
configured for publisher $pub"
continue
fi
if [ $? -eq 0 ]; then
else
fi
proxy=''
fi
done < /tmp/pkg.mirror.$$
$RM /tmp/pkg.mirror.$$
i=$(( $i + 1 ))
done
# Iterate over all configured origins
i=0
while [ $i -lt ${#origins[@]} ]; do
http_proxy=${http_proxies[$i]}
https_proxy=${https_proxies[$i]}
check_failure $? \
if [ $? -ne 0 ]; then
return 1
fi
i=$(( $i + 1 ))
done
EXIT=$?
return $EXIT
}
#
# When retrieving values from SMF, we can get the string '""'
# (two quotes) returned. For our purposes, this is equivalent to the
# null string, so we normalize it to ''. This function reads from stdin.
#
function reduce_null_str {
while read value; do
echo ''
else
echo $value
fi
done
}
#
# Perform a pkgrecv from the given origin to the given repository.
# We assume that the repository exists.
#
# Usage:
# pkgrecv_from_origin <repo> <origin> <key path> <cert path> <FMRI>
# <cache dir> <http_proxy> <https_proxy>
#
function pkgrecv_from_origin {
typeset repo=$1
typeset origin=$2
typeset key=$(echo $3 | reduce_null_str)
typeset cert=$(echo $4 | reduce_null_str)
typeset SMF_FMRI=$5
typeset cachedir=$6
typeset http_proxy=$(echo $7 | reduce_null_str)
typeset https_proxy=$(echo $8 | reduce_null_str)
typeset debug_flag=$($SVCPROP -p config/debug $SMF_FMRI)
export http_proxy=$http_proxy
export https_proxy=$https_proxy
>> $LOG
fi
# show the command we're running
fi
EXIT=$?
#
# in the case of errors, getting the full pkgrecv output
# can be helpful.
#
else
# otherwise, we only log messages containing pkg5 FMRIs
# we only destroy the cache if a pkgrecv was successful
fi
return $EXIT
}
# $1 start | stop | an FMRI containing configuration
case "$1" in
'start')
if [ $? -eq 0 ]; then
else
echo "Problem mirroring repository for $SMF_FMRI"
fi
;;
'stop')
if [ $? -eq 0 ]; then
else
echo "Problem mirroring repository for $SMF_FMRI"
fi
;;
#
# A note on logging.
#
# The following log files are created while this service is running:
#
# This is the top-level log file for the service. This log
# shows a summary of each pkgrecv, listing a timestamp and the
# packages that were received during that run of the cron job.
#
# This is a temporary log file, which should contain very little
# output - it exists to capture all other output from the service
# full pkgrecv(1) command that is executed.
#
# Another temporary log file, which captures the complete output
# of each pkgrecv command as it runs. At the end of the pkgrecv
# process, we extract a summary and append it to
# of this log are appended to mirror.<instance>.log. If any errors
# were encountered while running pkgrecv, the contents of this log
# are appended to mirror.<instance>.log.
#
'refresh')
typeset debug_flag=$($SVCPROP -p config/debug $SMF_FMRI)
# Most output should get captured by update_repository, but we
# capture any remaining output.
RET=$?
fi
if [ "$debug_flag" = "false" ]; then
fi
else
echo "Mirror refresh failed: see $LOG for more detail."
# try to remove the cron job so we don't keep failing
fi
;;
esac
exit $result