Details
-
Type:
Epic
-
Status: Done
-
Priority:
Medium
-
Resolution: Fixed
-
Affects Version/s: None
-
Fix Version/s: None
-
Component/s: Promise type: packages
-
Labels:None
Description
The promise
<pre>
bundle agent main
{
packages:
"firefox" # package name or file path
policy => "absent/present",
package_module => apt_get, # Optional, default taken from common/file control
- More about package_module below.
version => "32.0", # Optional, will only match exact version. May be "latest" for present policy type.
architecture => x86_64";
- Optional. Package-module specific and needs to accept anything.
options =>
{ "--target-release precise" };# Options passed directly to the package module. Could be to select repository or special options for dependencies. Or special quirks for package modules like the solaris admin file. Overrides default_options in package_module body
# additional_packages => { "firefox", "chrome", "opera", "vivaldi" };
# ^-- Possible way to specify multiple package installs in one promise, for dependency resolution and performance reasons.
# Might also be a list of absolute file paths if using file-based package management (if the promiser is absolute file path).
# I propose we keep this out of the first iteration.
}
</pre>
The reason for having file as separate attribute is that it's hard to deduce the
name that we need to check in the package list without it.
The package body
Idea is to have an extremely small package_module body, and put the logic of
arranging the commands for installation in a dedicated script directory instead,
like:
<pre>
$(sys.workdir)/modules/packages/<package_module>
</pre>
The body would only contain ifelapsed values for the different package modules,
but no reference to commands.
<pre>
body package_module apt_get
{
query_installed_ifelapsed => "60";
query_updates_ifelapsed => "1440";
default_options => { "--target-release precise" }
; # overridden by options if present
}
</pre>
Syntax for the package module:
<pre>
apt_get supports-api-version
Stdout:
1 # The number "one". In case we need to extend the API later.
apt_get repo-install
Stdin:
options=<from-policy-attribute list item 1>
options=<from-policy-attribute list item 2>
...
Name=firefox
Version=32-ubuntu # <-- May be omitted
Architecture=amd64 # <-- May be omitted
Name=chrome # Each "Name=" denotes a new package entry. Note that current promise spec will only allow one, but this may be extended.
Version=32-ubuntu
Architecture=amd64
...
apt_get file-install
Stdin:
options=<from-policy-attribute list item 1>
options=<from-policy-attribute list item 2>
...
File=/media/cdrom/firefox_32-ubuntu1_amd64.deb
File=/media/cdrom/chrome_32-ubuntu1_amd64.deb
...
apt_get remove
Stdin:
options=<from-policy-attribute list item 1>
options=<from-policy-attribute list item 2>
...
Name=firefox
Version=32-ubuntu # <-- May be omitted
Architecture=amd64 # <-- May be omitted
...
apt_get list-installed
Stdin:
options=<from-policy-attribute list item 1>
options=<from-policy-attribute list item 2>
...
Stdout:
Name=firefox
Version=32-ubuntu
Architecture=amd64
...
apt_get list-updates
Stdin:
options=<from-policy-attribute list item 1>
options=<from-policy-attribute list item 2>
Stdout:
Name=firefox
Version=32-ubuntu
Architecture=amd64
...
apt_get list-updates-local
- Exactly same semantics as previous, but does not go online.
Stdin:
options=<from-policy-attribute list item 1>
options=<from-policy-attribute list item 2>
Stdout:
Name=firefox
Version=32-ubuntu
Architecture=amd64
...
apt_get get-package-data
Stdin:
options=<from-policy-attribute list item 1>
options=<from-policy-attribute list item 2>
...
File=/media/cdrom/firefox_32-ubuntu1_amd64.deb
Version=32-ubuntu # <-- May be omitted if not provided in policy
Architecture=amd64 # <-- May be omitted if not provided in policy
Stdout:
PackageType=file # Can also be repo. Depends on the type of string passed into the script.
Name=firefox
Version=32-ubuntu # <-- May not be returned if the package module does not know.
Architecture=amd64 # <-- May not be returned if the package module does not know.
</pre>
All '...' entries mean that a list is expected (which can have only one element, of course). Otherwise lists are not accepted.
Error handling will be supported for each and every command except @supports-api-version@. In case of error, script can print to stderr, either:
<pre>
File=/path/to/broken/file
ErrorMessage=File is broken and can not be parsed. # <-- This is optional and may not be returned in case of error.
</pre>
..or:
<pre>
Name=broken-package-name
Version=broken-package-version # If available
Architecture=broken-package-architecture # If available
ErrorMessage=File is broken and can not be parsed. # <-- This is optional and may not be returned in case of error.
</pre>
..depending on what the input was. In addition a nonzero error code denotes error, regardless of what was printed to stderr.
The choice of language for the package module is free, good candidates are of course
shell or Perl, which should be quite portable, but can also be PowerShell or a
binary for that matter (the last one is not recommended). But the key point is that it
is an actual programming language where we can have decision logic, and preferably a
scripted one.
The attribute defining which package module is used for inventory query.
<pre>
body common control
{
bundlesequence =>
inputs => { ... }
;
package_inventory =>
{ $(package_module_knowledge.platform_default) };
package_module => $(package_module_knowledge.platform_default);
}
in masterfiles/lib/3.7/packages.cf
bundle common package_module_knowledge
{
vars:
debian::
"platform_default" string => "apt_get";
redhat::
"platform_default" string => "yum";
...
}
</pre>
If the exact package module is not specified in the promise itself the package_module in body common control is chosen. In other words the order in which the package_module script will be chosen is as follows: promise definition, body common control. If neither is set, an error is generated; preferably at parse-time.
Requirements for implementation
- All installations/removals/updates must trigger an inventory update to prove that the operation was successful, since most package managers are bad at reporting this, and this should be used in the promise result.
- If a cf-agent is calling a package module, a second cf-agent should not call it, in order to avoid cascading cf-agents when the package manager hangs. This happens regularly when the rpm db is corrupted or there is a slow network operation.
Attachments
Release management
Issue Links
- relates to
-
CFE-2332 Switch to new packages promise by default
-
- Done
-
-
CFE-1832 Add support for lock and unlock functions in stdlib package handling
-
- Open
-
-
CFE-2104 apt_get package module is too verbose
-
- Done
-
-
CFE-1985 Improve diagnostics logging for new packages promise
-
- Open
-
-
CFE-1896 Package promise: Implement yum/rpm package manager wrapper
-
- Done
-
-
CFE-1909 Package promise: API documentation
-
- Done
-
-
CFE-1910 Package promise: Promise documentation
-
- Done
-
-
CFE-1912 Package promise: Write acceptance tests based on use cases for apt/dpkg and have them pass locally
-
- Done
-
-
CFE-1913 Package promise: Adapt acceptance tests for apt/dpkg to yum/rpm and have them pass locally as well
-
- Done
-
-
CFE-1914 Package promise: Run all tests through Jenkins and fix issues until all supported platforms pass
-
- Done
-
-
CFE-1926 Package promise: include yum and apt package modules in CFE package
-
- Done
-
-
CFE-2246 packageupdatesmatching() and packagesmatching() should be able to leverege information from new package promise implementation
-
- Done
-
-
CFE-1897 Package promise: Implement apt-get/dpkg package manager wrapper
-
- Done
-
-
CFE-1898 Package promise: Implement installed packages and available updates caching mechanism
-
- Done
-
-
CFE-1899 Package promise: Implement global locking mechanism for package promises
-
- Done
-
-
CFE-1900 Package promise: support default_package_inventory and default_package_manager
-
- Done
-
-
CFE-1808 Persistent variables
-
- Need more Info
-
-
CFE-1951 Make new inventory reporting the default for Debian and RHEL platforms.
-
- Rejected
-
-
CFE-1911 Package promise: Write acceptance tests for the dummy package manager, just the basics
-
- Rejected
-