Add "strict" mode for apt package removal
Currently, divingbell-apt will only remove packages that aren't on the current requested package list when they were previously installed by divingbell-apt. This patchset adds a "strict" mode which causes it to remove packages not on the requested package list regardless of whether divingbell installed them (i.e., it can remove unwanted packages that were part of the host's base image). Change-Id: Ie2ba5d47646bfaaf030cb54673e644ab0e917fd4
This commit is contained in:
parent
ac357b9bff
commit
44525162a5
@ -85,10 +85,10 @@ rm -rf /etc/apt/sources.list.d/*
|
||||
mv /etc/apt/trusted.gpg.d/divindbell_temp.gpg /etc/apt/trusted.gpg.d/divindbell.gpg
|
||||
rm -f /etc/apt/trusted.gpg
|
||||
find /etc/apt/trusted.gpg.d/ -type f ! -name 'divindbell.gpg' -exec rm {{ "{}" }} \;
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get update
|
||||
{{- end }}
|
||||
{{- if hasKey .Values.conf.apt "packages" }}
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get update
|
||||
|
||||
{{/* Build a unified list of packages */}}
|
||||
{{- $all_apt_packages := list }}
|
||||
@ -114,6 +114,7 @@ apt-get update
|
||||
dpkg --configure -a
|
||||
|
||||
# Perform package installs
|
||||
set +x
|
||||
{{- range $all_apt_packages }}
|
||||
{{- $pkg_name := .name }}
|
||||
if [[ "${CURRENT_PACKAGES[{{ .name | squote }}]+isset}" != "isset"{{- if .version }} || "${CURRENT_PACKAGES[{{ .name | squote }}]}" != {{ .version }}{{- end }} ]]; then
|
||||
@ -121,8 +122,9 @@ if [[ "${CURRENT_PACKAGES[{{ .name | squote }}]+isset}" != "isset"{{- if .versio
|
||||
fi
|
||||
REQUESTED_PACKAGES="$REQUESTED_PACKAGES {{$pkg_name}}"
|
||||
{{- end }}
|
||||
set -x
|
||||
# Run this in case some package installation was interrupted
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold {{- if .allow_downgrade }} "--allow-downgrades" {{ end }}{{- if .repo }} -t {{ .repo }}{{ end }} $INSTALLED_THIS_TIME
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold {{- if .Values.conf.apt.allow_downgrade }} "--allow-downgrades" {{ end }}{{- if .repo }} -t {{ .repo }}{{ end }} $INSTALLED_THIS_TIME
|
||||
{{- end }}
|
||||
|
||||
# Perform package upgrades
|
||||
@ -141,17 +143,51 @@ fi
|
||||
#Remove packages not present in conf.apt anymore
|
||||
################################################
|
||||
|
||||
{{- if .Values.conf.apt.strict }}
|
||||
APT_PURGE="apt-get purge -y --autoremove --allow-remove-essential"
|
||||
{{- else }}
|
||||
APT_PURGE="apt-get purge -y --autoremove"
|
||||
{{- end }}
|
||||
|
||||
{{- if hasKey .Values.conf.apt "packages" }}
|
||||
{{- if .Values.conf.apt.strict }}
|
||||
# in strict mode we execute this stage even on first run, so
|
||||
# touch the packages file here to avoid the short-circuit below
|
||||
touch ${persist_path}/packages
|
||||
{{- end }}
|
||||
|
||||
echo $INSTALLED_THIS_TIME | sed 's/ /\n/g' | sed '/^[[:space:]]*$/d' | sort > ${persist_path}/packages.new
|
||||
echo $REQUESTED_PACKAGES | sed 's/ /\n/g' | sed '/^[[:space:]]*$/d' | sort > ${persist_path}/packages.requested
|
||||
if [ -f ${persist_path}/packages ]; then
|
||||
# if strict mode, we reload the current package list to ensure we have an accurate list to audit from
|
||||
# (e.g., in case a package was requested but not installed for some reason)
|
||||
# note that in strict mode, $CURRENT_PACKAGES will duplicate the packages in $INSTALLED_THIS_TIME but in
|
||||
# non-strict mode (which has logic to use the "packages" file it writes so it doesn't touch anything it
|
||||
# didn't originally install) it doesn't.
|
||||
{{- if .Values.conf.apt.strict }}
|
||||
load_package_list_with_versions $(dpkg -l | awk 'NR>5 {print $2"="$3}')
|
||||
{{- end }}
|
||||
set +x
|
||||
for package in "${!CURRENT_PACKAGES[@]}"
|
||||
do
|
||||
CURRENT_PACKAGE_NAMES="$CURRENT_PACKAGE_NAMES $package"
|
||||
done
|
||||
set -x
|
||||
echo $CURRENT_PACKAGE_NAMES | sed 's/ /\n/g' | sed '/^[[:space:]]*$/d' | sort > ${persist_path}/packages.current
|
||||
{{- if .Values.conf.apt.strict }}
|
||||
TO_DELETE=$(comm -23 ${persist_path}/packages.current ${persist_path}/packages.requested)
|
||||
TO_KEEP=$(echo "$TO_DELETE" | comm -23 ${persist_path}/packages.current -)
|
||||
{{- else }}
|
||||
TO_DELETE=$(comm -23 ${persist_path}/packages ${persist_path}/packages.requested)
|
||||
TO_KEEP=$(echo "$TO_DELETE" | comm -23 ${persist_path}/packages -)
|
||||
{{- end }}
|
||||
if [ ! -z "$TO_DELETE" ]; then
|
||||
dpkg --configure -a
|
||||
for pkg in "$TO_DELETE"; do
|
||||
apt-get purge -y $pkg
|
||||
done
|
||||
apt-get autoremove -y
|
||||
PURGE_LIST=""
|
||||
while read -r pkg; do
|
||||
PURGE_LIST="$PURGE_LIST $pkg"
|
||||
done <<< "$TO_DELETE"
|
||||
DEBIAN_FRONTEND=noninteractive $APT_PURGE $PURGE_LIST
|
||||
fi
|
||||
if [ ! -z "$TO_KEEP" ]; then
|
||||
echo "$TO_KEEP" > ${persist_path}/packages
|
||||
@ -160,9 +196,12 @@ if [ -f ${persist_path}/packages ]; then
|
||||
fi
|
||||
fi
|
||||
if [ ! -z "$INSTALLED_THIS_TIME" ]; then
|
||||
{{- if not .Values.conf.apt.strict }}
|
||||
cat ${persist_path}/packages.new >> ${persist_path}/packages
|
||||
{{- end }}
|
||||
sort ${persist_path}/packages -o ${persist_path}/packages
|
||||
fi
|
||||
{{- end }}
|
||||
|
||||
######################################################
|
||||
#Stage 4
|
||||
@ -173,9 +212,8 @@ fi
|
||||
dpkg --configure -a
|
||||
{{- range .Values.conf.apt.blacklistpkgs }}
|
||||
{{- $package := . }}
|
||||
apt-get remove --autoremove -y {{ $package | squote }}
|
||||
DEBIAN_FRONTEND=noninteractive $APT_PURGE {{ $package | squote }}
|
||||
{{- end }}
|
||||
apt-get autoremove -y
|
||||
{{- end }}
|
||||
|
||||
log.INFO 'Putting the daemon to sleep.'
|
||||
|
@ -26,6 +26,8 @@ conf:
|
||||
log_colors: False
|
||||
apt:
|
||||
upgrade: false
|
||||
allow_downgrade: false
|
||||
strict: false
|
||||
blacklistpkgs:
|
||||
- telnetd
|
||||
- inetutils-telnetd
|
||||
|
@ -113,15 +113,29 @@ want to remove from the configuration).
|
||||
When ``conf.apt.upgrade`` is ``true``, packages are upgraded `after` the
|
||||
requested packages are installed.
|
||||
|
||||
.. NOTE::
|
||||
|
||||
When ``conf.apt.allow_downgrade`` is ``true``, the ``--allow-downgrades``
|
||||
flag is passed to ``apt-get install``, allowing it to downgrade a package
|
||||
if so specified in your packages list.
|
||||
|
||||
.. NOTE::
|
||||
|
||||
When ``conf.apt.strict`` is ``true``, any packages not in conf.apt.packages
|
||||
will be removed regardless of whether or not divingbell previously installed
|
||||
them. (The default behavior is for only packages previously installed by
|
||||
divingbell to be removed.) USE THIS OPTION WITH EXTREME CAUTION.
|
||||
|
||||
Here is an example configuration for it::
|
||||
|
||||
conf:
|
||||
apt:
|
||||
upgrade: false
|
||||
allow_downgrade: false
|
||||
strict: false
|
||||
packages:
|
||||
- name: <PACKAGE1>
|
||||
version: <VERSION1>
|
||||
allow_downgrade: true
|
||||
- name: <PACKAGE2>
|
||||
|
||||
It is also permissible to use ``conf.apt.packages`` as a map, in which case all
|
||||
@ -137,7 +151,6 @@ guarantees). For example::
|
||||
group1:
|
||||
- name: <PACKAGE1>
|
||||
version: <VERSION1>
|
||||
allow_downgrade: true
|
||||
- name: <PACKAGE2>
|
||||
group2:
|
||||
- name: <PACKAGE3>
|
||||
@ -150,7 +163,6 @@ Is equivalent to::
|
||||
packages:
|
||||
- name: <PACKAGE1>
|
||||
version: <VERSION1>
|
||||
allow_downgrade: true
|
||||
- name: <PACKAGE2>
|
||||
- name: <PACKAGE3>
|
||||
- name: <PACKAGE4>
|
||||
|
@ -81,6 +81,16 @@ APT_PACKAGE5=python-setuptools
|
||||
APT_PACKAGE6=telnetd
|
||||
APT_PACKAGE7=sudoku
|
||||
APT_PACKAGE8=ninvaders
|
||||
# helper function to generate a yaml config for all installed packages
|
||||
APT_YAML_SEPARATOR=$'\n - name: '
|
||||
build_all_packages_yaml(){
|
||||
set +x
|
||||
for f in "$@"; do
|
||||
IFS=":" read -r name arch <<< $f;
|
||||
APT_ALL_INSTALLED_PACKAGES="${APT_ALL_INSTALLED_PACKAGES}${APT_YAML_SEPARATOR}${name}"
|
||||
done
|
||||
set -x
|
||||
}
|
||||
APT_REPOSITORY1="http://us.archive.ubuntu.com/ubuntu/"
|
||||
APT_DISTRIBUTIONS1="[ xenial ]"
|
||||
APT_COMPONENTS1="[ main, universe, restricted, multiverse ]"
|
||||
@ -355,6 +365,8 @@ _reset_account(){
|
||||
}
|
||||
|
||||
init_default_state(){
|
||||
# TODO (dc6350) this needs retry logic to avoid race condition where tiller is not ready yet
|
||||
sleep 30 # temporary fix for race condition
|
||||
purge_containers
|
||||
clean_persistent_files
|
||||
# set sysctl original vals
|
||||
@ -1207,10 +1219,10 @@ test_apt(){
|
||||
local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml
|
||||
echo "conf:
|
||||
apt:
|
||||
allow_downgrade: true
|
||||
packages:
|
||||
- name: $APT_PACKAGE1
|
||||
version: $APT_VERSION1
|
||||
allow_downgrade: true
|
||||
- name: $APT_PACKAGE2" > "${overrides_yaml}"
|
||||
install_base "--values=${overrides_yaml}"
|
||||
get_container_status apt
|
||||
@ -1366,6 +1378,37 @@ $(printf '%s' "$APT_GPGKEY1" | awk '{printf " %s\n", $0}')" > "${overri
|
||||
_test_apt_package_version $APT_PACKAGE7 any
|
||||
_test_apt_package_version $APT_PACKAGE8 any
|
||||
echo '[SUCCESS] apt test9 passed successfully' >> "${TEST_RESULTS}"
|
||||
|
||||
# Test adding a package in strict mode
|
||||
local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set9.yaml
|
||||
APT_ALL_INSTALLED_PACKAGES=" packages:"
|
||||
build_all_packages_yaml $(dpkg -l | awk 'NR>5 {print $2}')
|
||||
echo "conf:
|
||||
apt:
|
||||
strict: true
|
||||
$APT_ALL_INSTALLED_PACKAGES
|
||||
- name: $APT_PACKAGE1" > "${overrides_yaml}"
|
||||
install_base "--values=${overrides_yaml}"
|
||||
get_container_status apt
|
||||
_test_apt_package_version $APT_PACKAGE1 any
|
||||
# PACKAGE4 used earlier is intended to be a package that is always installed
|
||||
_test_apt_package_version $APT_PACKAGE4 any
|
||||
echo '[SUCCESS] apt test10 passed successfully' >> "${TEST_RESULTS}"
|
||||
|
||||
# Test removing a package in strict mode
|
||||
local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set10.yaml
|
||||
# using the same APT_ALL_INSTALLED_PACKAGES from above,
|
||||
# which does NOT have APT_PACKAGE1
|
||||
echo "conf:
|
||||
apt:
|
||||
strict: true
|
||||
$APT_ALL_INSTALLED_PACKAGES" > "${overrides_yaml}"
|
||||
install_base "--values=${overrides_yaml}"
|
||||
get_container_status apt
|
||||
_test_apt_package_version $APT_PACKAGE1 none
|
||||
# PACKAGE4 used earlier is intended to be a package that is always installed
|
||||
_test_apt_package_version $APT_PACKAGE4 any
|
||||
echo '[SUCCESS] apt test11 passed successfully' >> "${TEST_RESULTS}"
|
||||
}
|
||||
|
||||
# test exec module
|
||||
|
Loading…
Reference in New Issue
Block a user