summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Andres Klode <julian.klode@canonical.com>2020-08-10 20:16:11 +0200
committerJulian Andres Klode <julian.klode@canonical.com>2021-01-08 14:48:47 +0100
commitc5bc86d45e003905ef411146e66b414d26fb1ff8 (patch)
tree31c634c53df882a26dcbdb8b489c6c23101ec285
parent4d28ddc501738d571c21ff6d41168f6c53ea462d (diff)
Add support for Phased-Update-Percentage
This adds support for Phased-Update-Percentage by pinning upgrades that are not to be installed down to 1. The output of policy has been changed to add the level of phasing, and documentation has been improved to document how phased updates work. The patch detects if it is running in a chroot, and if so, always includes phased updates, restoring classic apt behavior to avoid behavioral changes on buildd chroots. Various options are added to control this all: * APT::Get::{Always,Never}-Include-Phased-Updates and their legacy update-manager equivalents to always or never include phased updates * APT::Machine-ID can be set to a UUID string to have all machines in a fleet phase the same * Dir::Etc::Machine-ID is weird in that it's default is sort of like ../machine-id, but not really, as ../machine-id would look up $PWD/../machine-id and not relative to Dir::Etc; but it allows you to override the path to machine-id (as opposed to the value) * Dir::Bin::ischroot is the path to the ischroot(1) binary which is used to detect whether we are running in a chroot.
-rw-r--r--apt-pkg/aptconfiguration.cc61
-rw-r--r--apt-pkg/aptconfiguration.h7
-rw-r--r--apt-pkg/cacheiterators.h14
-rw-r--r--apt-pkg/deb/deblistparser.cc7
-rw-r--r--apt-pkg/pkgcache.h12
-rw-r--r--apt-pkg/pkgcachegen.cc4
-rw-r--r--apt-pkg/policy.cc48
-rw-r--r--apt-pkg/policy.h3
-rw-r--r--apt-pkg/tagfile-keys.list1
-rw-r--r--apt-private/private-show.cc8
-rw-r--r--debian/NEWS7
-rw-r--r--doc/apt_preferences.5.xml19
-rw-r--r--doc/examples/configure-index10
-rw-r--r--test/integration/framework3
-rwxr-xr-xtest/integration/test-phased-updates272
15 files changed, 469 insertions, 7 deletions
diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc
index 61e53ec3a..b3b423fdc 100644
--- a/apt-pkg/aptconfiguration.cc
+++ b/apt-pkg/aptconfiguration.cc
@@ -480,4 +480,65 @@ std::string const Configuration::getBuildProfilesString() {
return list;
}
/*}}}*/
+
+// getMachineID - supported data.tar extensions /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+std::string const Configuration::getMachineID()
+{
+ std::string id = _config->Find("APT::Machine-ID");
+
+ if (id.empty())
+ {
+ std::string file = _config->FindFile("Dir::Etc::machine-id");
+
+ if (file.empty())
+ {
+ file = flCombine(_config->FindDir("Dir::Etc"), "../machine-id");
+ }
+ FileFd fd;
+ _error->PushToStack();
+
+ if (not OpenConfigurationFileFd(file, fd) || not fd.ReadLine(id))
+ {
+ if (_config->FindB("Debug::Phasing", false))
+ {
+ _error->DumpErrors(std::clog);
+ }
+ }
+
+ _error->RevertToStack();
+ }
+
+ return id;
+}
+ /*}}}*/
+// isChroot - whether we are inside a chroot /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool Configuration::isChroot()
+{
+ static struct once
+ {
+ bool res = false;
+ once()
+ {
+ pid_t child = ExecFork();
+ if (child == 0)
+ {
+ auto binary = _config->FindFile("Dir::Bin::ischroot", "/usr/bin/ischroot");
+ const char *const Args[] = {
+ binary.c_str(),
+ nullptr};
+ execvp(Args[0], const_cast<char **>(Args));
+ _exit(127);
+ }
+
+ res = ExecWait(child, "ischroot", true);
+ }
+ } once;
+
+ return once.res;
+}
+ /*}}}*/
}
diff --git a/apt-pkg/aptconfiguration.h b/apt-pkg/aptconfiguration.h
index 2cb2d823a..bbeb156b9 100644
--- a/apt-pkg/aptconfiguration.h
+++ b/apt-pkg/aptconfiguration.h
@@ -122,7 +122,12 @@ namespace Configuration { /*{{{*/
APT_PUBLIC std::vector<std::string> const getBuildProfiles();
/** \return Return a comma-separated list of enabled build profile specifications */
APT_PUBLIC std::string const getBuildProfilesString();
- /*}}}*/
+
+ std::string const getMachineID();
+
+ /** \return Whether we are running in a chroot */
+ bool isChroot();
+ /*}}}*/
}
/*}}}*/
}
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
index 1b049b6e5..6261b5089 100644
--- a/apt-pkg/cacheiterators.h
+++ b/apt-pkg/cacheiterators.h
@@ -242,6 +242,20 @@ class APT_PUBLIC pkgCache::VerIterator : public Iterator<Version, VerIterator> {
bool Automatic() const;
VerFileIterator NewestFile() const;
+#ifdef APT_COMPILING_APT
+ inline unsigned int PhasedUpdatePercentage() const
+ {
+ return (static_cast<Version::Extra *>(Owner->Map.Data()) + S->d)->PhasedUpdatePercentage;
+ }
+ inline bool PhasedUpdatePercentage(unsigned int percentage)
+ {
+ if (percentage > 100)
+ return false;
+ (static_cast<Version::Extra *>(Owner->Map.Data()) + S->d)->PhasedUpdatePercentage = static_cast<uint8_t>(percentage);
+ return true;
+ }
+#endif
+
inline VerIterator(pkgCache &Owner,Version *Trg = 0) : Iterator<Version, VerIterator>(Owner, Trg) {
if (S == 0)
S = OwnerPointer();
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 95f6f6fc8..b5c9c066e 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -338,6 +338,13 @@ bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg,
else if (std::find(forceImportant.begin(), forceImportant.end(), Pkg.Name()) != forceImportant.end())
Pkg->Flags |= pkgCache::Flag::Important;
+ auto phased = Section.FindULL(pkgTagSection::Key::Phased_Update_Percentage, 100);
+ if (phased != 100)
+ {
+ if (not Ver.PhasedUpdatePercentage(phased))
+ _error->Warning("Ignoring invalid Phased-Update-Percentage value");
+ }
+
if (ParseStatus(Pkg,Ver) == false)
return false;
return true;
diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h
index 6c6a4664e..55baa3cef 100644
--- a/apt-pkg/pkgcache.h
+++ b/apt-pkg/pkgcache.h
@@ -623,6 +623,8 @@ struct pkgCache::DescFile
or handled as separate versions based on the Hash value. */
struct pkgCache::Version
{
+ struct Extra;
+
/** \brief complete version string */
map_stringitem_t VerStr;
/** \brief section this version is filled in */
@@ -688,8 +690,16 @@ struct pkgCache::Version
map_pointer<Version> NextInSource;
/** \brief Private pointer */
- map_pointer<void> d;
+ map_pointer<Extra> d;
};
+
+#ifdef APT_COMPILING_APT
+/// \brief Extra information for packages. APT-internal use only.
+struct pkgCache::Version::Extra
+{
+ uint8_t PhasedUpdatePercentage;
+};
+#endif
/*}}}*/
// Description structure /*{{{*/
/** \brief datamember of a linked list of available description for a version */
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
index d02c49f03..bd81ca0f5 100644
--- a/apt-pkg/pkgcachegen.cc
+++ b/apt-pkg/pkgcachegen.cc
@@ -873,6 +873,10 @@ map_pointer<pkgCache::Version> pkgCacheGenerator::NewVersion(pkgCache::VerIterat
// Fill it in
Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
+ Ver->d = AllocateInMap<pkgCache::Version::Extra>();
+ if (not Ver.PhasedUpdatePercentage(100))
+ abort();
+
//Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
Ver->NextVer = Next;
Ver->ParentPkg = ParentPkg;
diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc
index 761a6ede1..bdb049ead 100644
--- a/apt-pkg/policy.cc
+++ b/apt-pkg/policy.cc
@@ -14,6 +14,7 @@
// Include Files /*{{{*/
#include <config.h>
+#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/cachefilter.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
@@ -26,6 +27,7 @@
#include <apt-pkg/versionmatch.h>
#include <iostream>
+#include <random>
#include <sstream>
#include <string>
#include <vector>
@@ -40,12 +42,17 @@ using namespace std;
constexpr short NEVER_PIN = std::numeric_limits<short>::min();
+struct pkgPolicy::Private
+{
+ std::string machineID;
+};
+
// Policy::Init - Startup and bind to a cache /*{{{*/
// ---------------------------------------------------------------------
/* Set the defaults for operation. The default mode with no loaded policy
file matches the V0 policy engine. */
pkgPolicy::pkgPolicy(pkgCache *Owner) : VerPins(nullptr),
- PFPriority(nullptr), Cache(Owner), d(NULL)
+ PFPriority(nullptr), Cache(Owner), d(new Private)
{
if (Owner == 0)
return;
@@ -77,6 +84,8 @@ pkgPolicy::pkgPolicy(pkgCache *Owner) : VerPins(nullptr),
CreatePin(pkgVersionMatch::Release,"",DefRel,990);
}
InitDefaults();
+
+ d->machineID = APT::Configuration::getMachineID();
}
/*}}}*/
// Policy::InitDefaults - Compute the default selections /*{{{*/
@@ -274,8 +283,38 @@ void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
// Policy::GetPriority - Get the priority of the package pin /*{{{*/
// ---------------------------------------------------------------------
/* */
+// Returns true if this update is excluded by phasing.
+static inline bool ExcludePhased(std::string machineID, pkgCache::VerIterator const &Ver)
+{
+ // The order and fallbacks for the always/never checks come from update-manager and exist
+ // to preserve compatibility.
+ if (_config->FindB("APT::Get::Always-Include-Phased-Updates",
+ _config->FindB("Update-Manager::Always-Include-Phased-Updates", false)))
+ return false;
+
+ if (_config->FindB("APT::Get::Never-Include-Phased-Updates",
+ _config->FindB("Update-Manager::Never-Include-Phased-Updates", false)))
+ return true;
+
+ if (machineID.empty() // no machine-id
+ || getenv("SOURCE_DATE_EPOCH") != nullptr // reproducible build - always include
+ || APT::Configuration::isChroot())
+ return false;
+
+ std::string seedStr = std::string(Ver.SourcePkgName()) + "-" + Ver.VerStr() + "-" + machineID;
+ std::seed_seq seed(seedStr.begin(), seedStr.end());
+ std::minstd_rand rand(seed);
+ std::uniform_int_distribution<unsigned int> dist(0, 100);
+
+ return dist(rand) > Ver.PhasedUpdatePercentage();
+}
APT_PURE signed short pkgPolicy::GetPriority(pkgCache::VerIterator const &Ver, bool ConsiderFiles)
{
+ if (Ver.ParentPkg()->CurrentVer && Ver.PhasedUpdatePercentage() != 100)
+ {
+ if (ExcludePhased(d->machineID, Ver))
+ return 1;
+ }
if (VerPins[Ver->ID].Type != pkgVersionMatch::None)
{
// If all sources are never pins, the never pin wins.
@@ -454,4 +493,9 @@ bool ReadPinFile(pkgPolicy &Plcy,string File)
}
/*}}}*/
-pkgPolicy::~pkgPolicy() {delete [] PFPriority; delete [] VerPins; }
+pkgPolicy::~pkgPolicy()
+{
+ delete[] PFPriority;
+ delete[] VerPins;
+ delete d;
+}
diff --git a/apt-pkg/policy.h b/apt-pkg/policy.h
index 7f30d40ed..589cebcde 100644
--- a/apt-pkg/policy.h
+++ b/apt-pkg/policy.h
@@ -83,7 +83,8 @@ class APT_PUBLIC pkgPolicy : public pkgDepCache::Policy
explicit pkgPolicy(pkgCache *Owner);
virtual ~pkgPolicy();
private:
- void * const d;
+ struct Private;
+ Private *const d;
};
APT_PUBLIC bool ReadPinFile(pkgPolicy &Plcy, std::string File = "");
diff --git a/apt-pkg/tagfile-keys.list b/apt-pkg/tagfile-keys.list
index a16bc686a..b5cc2f1a4 100644
--- a/apt-pkg/tagfile-keys.list
+++ b/apt-pkg/tagfile-keys.list
@@ -46,6 +46,7 @@ Package-List
Package_Revision
Package-Revision
Package-Type
+Phased-Update-Percentage
Pre-Depends
Priority
Protected
diff --git a/apt-private/private-show.cc b/apt-private/private-show.cc
index 103fa57e4..30b99b013 100644
--- a/apt-private/private-show.cc
+++ b/apt-private/private-show.cc
@@ -563,7 +563,13 @@ bool Policy(CommandLine &CmdL)
else
std::cout << " " << V.VerStr();
- std::cout << " " << Plcy->GetPriority(V) << std::endl;
+ std::cout << " " << Plcy->GetPriority(V);
+
+ if (V.PhasedUpdatePercentage() != 100)
+ std::cout << " "
+ << "(" << _("phased") << " " << V.PhasedUpdatePercentage() << "%)";
+
+ std::cout << std::endl;
for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; ++VF)
{
// Locate the associated index files so we can derive a description
diff --git a/debian/NEWS b/debian/NEWS
index 9d9c963c2..eb8e2c116 100644
--- a/debian/NEWS
+++ b/debian/NEWS
@@ -3,6 +3,13 @@ apt (2.1.16) UNRELEASED; urgency=medium
Automatically remove unused kernels on dist-upgrade. To revert to previous
behavior, set APT::Get::AutomaticRemove::Kernels to false.
+ Packages files can now set the Phased-Update-Percentage field to restrict
+ update rollout to a specified percentage of machines. Previously, this has
+ only been available to users of Ubuntu's update-manager tool. See
+ apt_preferences(5) for details and how to configure multiple systems to get
+ the same updates. Phased updates are disabled in chroots for now to not
+ break buildd-style setups.
+
-- Julian Andres Klode <jak@debian.org> Mon, 04 Jan 2021 10:47:14 +0100
apt (1.9.11) experimental; urgency=medium
diff --git a/doc/apt_preferences.5.xml b/doc/apt_preferences.5.xml
index 4ef5282e7..23f2d2d6b 100644
--- a/doc/apt_preferences.5.xml
+++ b/doc/apt_preferences.5.xml
@@ -102,7 +102,8 @@ algorithm to set the priorities of the versions of a package. Assign:
<term>priority 1</term>
<listitem><simpara>to the versions coming from archives which in their <filename>Release</filename>
files are marked as "NotAutomatic: yes" but <emphasis>not</emphasis> as "ButAutomaticUpgrades: yes"
-like the Debian <literal>experimental</literal> archive.</simpara></listitem>
+like the Debian <literal>experimental</literal> archive.</simpara></listitem>,
+as well as versions that are not phased on this systems.
</varlistentry>
<varlistentry>
@@ -175,6 +176,22 @@ because at least <emphasis>one</emphasis> of the available versions has a higher
priority than the installed version.</para>
</refsect2>
+<refsect2><title>Phased Updates</title>
+<para>APT understands a field called <literal>Phased-Update-Percentage</literal>
+which can be used to control the rollout of a new version. It is an integer between
+0 and 100.</para>
+
+<para>A system's eligibility to a phased update is determined by seeding
+random number generator with the package source name, the version number,
+and /etc/machine-id, and then calculating an integer in the range [0, 100].
+If this integer is larger than the <literal>Phased-Update-Percentage</literal>,
+the version is pinned to 1, and thus held back. Otherwise, normal policy rules apply.
+</para>
+
+<para>In case you have multiple systems that you want to receive the same set of updates, you can set
+<code>APT::Machine-ID</code> to a UUID such that they all phase the same, or set <code>APT::Get::Never-Include-Phased-Updates</code>
+or <code>APT::Get::Always-Include-Phased-Updates</code> to true such that APT will never/always consider phased updates.</para>
+</refsect2>
<refsect2><title>The Effect of APT Preferences</title>
<para>The APT preferences file allows the system administrator to control the
diff --git a/doc/examples/configure-index b/doc/examples/configure-index
index 15b020198..5ddf4132c 100644
--- a/doc/examples/configure-index
+++ b/doc/examples/configure-index
@@ -101,6 +101,8 @@ APT
Upgrade "<BOOL>";
Only-Upgrade "<BOOL>";
Upgrade-Allow-New "<BOOL>";
+ Always-Include-Phased-Updates "<BOOL>";
+ Never-Include-Phased-Updates "<BOOL>";
Purge "<BOOL>";
ReInstall "<BOOL>";
Compile "<BOOL>";
@@ -219,6 +221,8 @@ APT
// control parameters for cron jobs by /etc/cron.daily/apt documented there
Periodic {};
+
+ Machine-ID "<STRING>"; // Value of /etc/machine-id
};
// Options for the downloading routines
@@ -417,6 +421,7 @@ Dir "<DIR>"
SourceParts "<DIR>";
Trusted "<FILE>";
TrustedParts "<DIR>";
+ Machine-ID "<FILE>"; // by default points to ../machine-id effectively
};
// Locations of binaries
@@ -434,6 +439,7 @@ Dir "<DIR>"
bzip2 "<PROGRAM_PATH>";
lzma "<PROGRAM_PATH>";
uncompressed "<PROGRAM_PATH>";
+ ischroot "<PROGRAM_PATH>";
solvers "<LIST>"; // of directories
planners "<LIST>"; // of directories
@@ -561,6 +567,7 @@ Debug
APT::Progress::PackageManagerFd "<BOOL>";
SetupAPTPartialDirectory::AssumeGood "<BOOL>";
Locking "<BOOL>";
+ Phasing "<BOOL>";
};
pkgCacheGen
@@ -843,3 +850,6 @@ Rred::Compress "<STRING>";
APT::Internal::OpProgress::Absolute "<BOOL>";
APT::Color "<BOOL>";
+
+update-manager::always-include-phased-updates "<BOOL>";
+update-manager::never-include-phased-updates "<BOOL>";
diff --git a/test/integration/framework b/test/integration/framework
index 3973ad863..696fcd8cd 100644
--- a/test/integration/framework
+++ b/test/integration/framework
@@ -484,6 +484,8 @@ EOF
# Allow release files to be 10 hours in the future, rather than 10 seconds
echo 'Acquire::Max-FutureTime "'$((10 * 60 * 60))'";' > rootdir/etc/apt/apt.conf.d/future-time
+ echo 'APT::Machine-ID "912e43bd1c1d4ba481f9f8ccab25f9ee";' > rootdir/etc/apt/apt.conf.d/machine-id
+
configcompression '.' 'gz' #'bz2' 'lzma' 'xz'
confighashes 'SHA256' # these are tests, not security best-practices
@@ -505,6 +507,7 @@ EOF
# Make dpkg inherit testing path
echo 'DPkg::Path "";' >> aptconfig.conf
+ echo 'Dir::Bin::ischroot "/bin/false";' >> aptconfig.conf
# Make gcov shut up
export GCOV_ERROR_FILE=/dev/null
diff --git a/test/integration/test-phased-updates b/test/integration/test-phased-updates
new file mode 100755
index 000000000..50f151f79
--- /dev/null
+++ b/test/integration/test-phased-updates
@@ -0,0 +1,272 @@
+#!/bin/sh
+set -e
+
+TESTDIR="$(readlink -f "$(dirname "$0")")"
+. "$TESTDIR/framework"
+
+setupenvironment
+echo 'Debug::Phasing "1";' > rootdir/etc/apt/apt.conf.d/debug-phasing
+configarchitecture 'i386' 'armel'
+
+
+insertinstalledpackage 'phased1' 'all' '1'
+insertinstalledpackage 'phased2' 'all' '1'
+
+insertpackage 'unstable' 'phased1' 'all' '10' 'Phased-Update-Percentage: 10'
+insertpackage 'unstable' 'phased2' 'all' '10' 'Phased-Update-Percentage: 10'
+insertpackage 'unstable' 'phased3' 'all' '10' 'Phased-Update-Percentage: 10'
+
+insertpackage 'unstable' 'phased1' 'all' '100' 'Phased-Update-Percentage: 100'
+insertpackage 'unstable' 'phased2' 'all' '100' 'Phased-Update-Percentage: 100'
+insertpackage 'unstable' 'phased3' 'all' '100' 'Phased-Update-Percentage: 100'
+
+insertpackage 'unstable' 'phased1' 'all' '50' 'Phased-Update-Percentage: 50'
+insertpackage 'unstable' 'phased2' 'all' '50' 'Phased-Update-Percentage: 50'
+insertpackage 'unstable' 'phased3' 'all' '50' 'Phased-Update-Percentage: 50'
+
+setupaptarchive
+
+msgmsg "Basic test"
+testsuccessequal "phased1:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 1 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased2:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 1 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 1 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased3:
+ Installed: (none)
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages" aptcache policy phased1 phased2 phased3
+
+msgmsg "Test for always-include-phased-updates"
+for always in Update-Manager::Always-Include-Phased-Updates APT::Get::Always-Include-Phased-Updates; do
+testsuccessequal "phased1:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased2:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased3:
+ Installed: (none)
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages" aptcache policy phased1 phased2 phased3 -o $always=true
+done
+
+msgmsg "Test for never-include-phased-updates"
+for never in Update-Manager::Never-Include-Phased-Updates APT::Get::Never-Include-Phased-Updates; do
+testsuccessequal "phased1:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 1 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 1 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased2:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 1 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 1 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased3:
+ Installed: (none)
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages" aptcache policy phased1 phased2 phased3 -o $never=true
+done
+
+msgmsg "Test that being in a chroot equals always-include-phased-updates"
+testsuccessequal "phased1:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased2:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy phased1 phased2 -o Dir::Bin::ischroot=/bin/true
+
+msgmsg "Test that empty machine-id equals always-include-phased-updates"
+testsuccessequal "phased1:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased2:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy phased1 phased2 -o Dir::Etc::machine-id=/dev/null -o APT::Machine-Id=""
+
+msgmsg "Test that never-include-phased-updates trumps empty machine-id"
+testsuccessequal "phased1:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 1 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 1 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased2:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 1 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 1 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy phased1 phased2 -o Dir::Etc::machine-id=/dev/null -o APT::Machine-Id="" -o APT::Get::Never-Include-Phased-Updates=1
+
+
+msgmsg "Test that SOURCE_DATE_EPOCH set equals always-include-phased-updates"
+export SOURCE_DATE_EPOCH=0
+testsuccessequal "phased1:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased2:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 500 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy phased1 phased2
+unset SOURCE_DATE_EPOCH
+
+msgmsg "Test that different machine-id produces different outcome"
+testsuccessequal "phased1:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 1 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status
+phased2:
+ Installed: 1
+ Candidate: 100
+ Version table:
+ 100 500
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 50 500 (phased 50%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ 10 1 (phased 10%)
+ 500 file:${TMPWORKINGDIRECTORY}/aptarchive unstable/main all Packages
+ *** 1 100
+ 100 ${TMPWORKINGDIRECTORY}/rootdir/var/lib/dpkg/status" aptcache policy phased1 phased2 -o apt::machine-id="00000000000000000000000000000000"