From Fedora Project Wiki

(Fix formatting inside the RPM Limitation pullbox)
(Completely revamp according to https://fedorahosted.org/fpc/ticket/520)
Line 1: Line 1:
= Fedora.next Per-Product Configuration Packaging =
= Fedora.next Per-Product Configuration Packaging =
This is an interim solution for Fedora 21 only. Work is in progress for Fedora 22 to simplify this using the new advanced dependencies available in RPM 4.11 and later


== Goals ==
== Goals ==
In the Fedora.next world, we will have a set of curated Fedora Products as well as the availability of classic Fedora. Historically, we have maintained a single set of configuration defaults for all Fedora installs, but different target use-cases have different needs. The goal of this document is to set out the guidelines for creating per-Product configuration defaults.
In the Fedora.next world, we have a set of curated Fedora Products as well as the availability of classic Fedora. Historically, we have maintained a single set of configuration defaults for all Fedora installs, but different target use-cases have different needs. The goal of this document is to set out the guidelines for creating per-Product configuration defaults.


We want to ensure that all packages have sensible defaults for whichever Product on which they are installed, while also avoiding situations where users would have some packages installed with one Product's defaults and some packages with another.
We want to ensure that all packages have sensible defaults for whichever Product on which they are installed, while also avoiding situations where users would have some packages installed with one Product's defaults and some packages with another.
Line 12: Line 10:


<b>Fedora.next</b>: Umbrella term for planning Fedora's future. Currently covering the creation of the Fedora Products, Fedora Base Design and Fedora Environments and Stacks.<br>
<b>Fedora.next</b>: Umbrella term for planning Fedora's future. Currently covering the creation of the Fedora Products, Fedora Base Design and Fedora Environments and Stacks.<br>
<b>$PRODUCT</b>: One of the Fedora.next Product deliverables, currently "cloud", "server" and "workstation".<br>
<b>$PRODUCT</b>: One of the Fedora.next Product deliverables, currently "Cloud", "Server" and "Workstation".<br>
<b>yum/dnf</b>: Package managers for Fedora used for installing and updating software.<br>
 


== Sub-package definition ==
== Per-product Configuration Packaging ==
{{admon/warning|These guidelines are not needed for all packages|Only packages whose defaults differ between Fedora Products are required to follow these instructions. Packages whose configuration is the same for all products can simply install the config files as they normally would.}}
{{admon/warning|These guidelines are not needed for all packages|Only packages whose defaults differ between Fedora Products are required to follow these instructions. Packages whose configuration is the same for all products can simply install the config files as they normally would.}}


=== Requirements ===
=== Requirements ===
* All packages <b>must</b> have a global default configuration. This configuration will be used whenever a Product-specific default configuration is not required. (For example, if a non-Product install is in use or only Fedora Cloud has a custom configuration and Fedora Workstation was installed).
* All packages <b>must</b> have a global default configuration. This configuration will be used whenever a Product-specific default configuration is not required. (For example, if a non-Product install is in use or only Fedora Cloud has a custom configuration and Fedora Workstation was installed).
* Any package that requires a per-product default configuration <b>must</b> provide a sub-package containing that configuration.
* Any package that requires a per-product default configuration <b>must</b> provide all alternate configuration files in the same package.
** Such packages <b>must</b> "Requires: foo-config" which will be provided by the configuration sub-package.
* Any package that requires a configuration that differs between Products <b>must</b> obtain permission from that Product's Working Group before packaging it.
* Any package that requires a configuration that differs between Products <b>must</b> obtain permission from that Product's Working Group before packaging it.


=== Global Default Configuration ===
=== Global Default Configuration ===
* The global default configuration <b>must</b> be specified by a sub-package named "foo-config-standard", where foo is the base package name.
* The global default configuration <b>must</b> be provided by the package that requires it.
* The global default configuration sub-package <b>must</b> "Requires: foo = %{version}-%{release}" (or appropriate variant including epoch)
* The global default configuration <b>must</b> be named based on the package's normal naming scheme, with the main part of the name being suffixed by -default. For example, if the package normally uses foo.conf, then the global default configuration must be named foo-default.conf
* The global default configuration sub-package <b>must</b> include a virtual "Provides: foo-config"
* The global default configuration sub-package <b>must</b> explicitly "Conflicts: system-release-$PRODUCT" for all Products for which there exists a separate configuration.
* The global default configuration sub-package <b>must</b> explicitly "Conflicts: foo-config-$PRODUCT" for all Products for which there exists a separate configuration.


=== Per-Product Default Configuration ===
=== Per-Product Default Configuration ===
* For each Product requiring a unique default configuration, the packager <b>must</b> provide a sub-package named "foo-config-$PRODUCT", where foo is the base package name and $PRODUCT is the Fedora Product in question. If the global default is sufficient, the packager <b>must not</b> create a Product-specific sub-package.
* For each Product requiring a unique default configuration, the packager <b>must</b> provide a copy of the default configuration file, modified as appropriate for the specific product.
* Each Product sub-package <b>must</b> include a virtual "Provides: foo-config".
* The product-specific configuration file must be named based on the package's normal naming scheme, with the main part of the name being suffixed by a dash followed by the name of the product. For example, if the package normally uses <code>foo.conf</code>, then the Server version must be named <code>foo-server.conf</code>.
* Each Product sub-package <b>must</b> "Requires: foo = %{version}-%{release}" (or appropriate variant including epoch)
* Each Product sub-package <b>must</b> "Requires: system-release-$PRODUCT", for the matching Product.
* Each Product sub-package <b>must</b> explicitly "Conflicts: foo-config-standard"
* Each Product sub-package <b>must</b> explicitly "Conflicts: foo-config-$PRODUCT" for all other Products for which there exists a separate configuration.


{{admon/warning|RPM Limitation|RPM does not currently have the ability to provide [http://rpm.org/ticket/874 separate installroots for different subpackages]. You will need to create separate config files for each product in the installroot and symlink them in the %post section for that Product}}
=== Applying Configuration ===
In order to apply the configuration, the packager must implement a mechanism in the <code>%posttrans</code> section of the specfile that behaves as follows:
* It must first check whether the final config file already exists. If so, the script <b>must</b> make no changes.
<pre>
%posttrans
if [ ! -e %{_sysconfdir}/foo/foo.conf ]; then
    ...
fi
</pre>


=== Example (firewalld) ===
* Then it must use the value of the Fedora <code>VARIANT</code> to symlink one of the divergent config files (or the default) to the final config file location. It will get this value by importing the contents of /etc/os-release as shell values.
We will assume for the sake of demonstration that firewalld will need a custom configuration for Fedora Server and Fedora Workstation, but that Fedora Cloud will not require any changes from the global default.
<pre>
    . /etc/os-release || :
    case "$VARIANT" in
        Server)
            ln -sf foo-server.conf %{_sysconfdir}/foo/foo.conf || :
            ;;
        *)
            ln -sf foo-default.conf %{_sysconfdir}/foo/foo.conf || :
            ;;
        esac
</pre>


* Lastly, the final config file location must be listed in the %files section with %ghost:
<pre>
<pre>
%ghost %config(noreplace) %{_sysconfdir}/foo/foo.conf
</pre>


Name: firewalld
* For tracking purposes, the package providing the various configuration files must also contain a virtual Provides: for each variant configuration that may be applied:
Version: 0.3.10
<pre>
Release: 1{?dist}
Provides: variant_config(Cloud)
Requires: firewalld-config
Provides: variant_config(Server)
Provides: variant_config(Workstation)
</pre>


%package config-standard
=== Example (firewalld) ===
Summary: Firewalld standard configuration settings
We will assume for the sake of demonstration that firewalld will need a custom configuration for Fedora Server and Fedora Workstation, but that Fedora Cloud will not require any changes from the global default.
Provides: firewalld-config
Requires: firewalld = %{version}-%{release}
Conflicts: system-release-server
Conflicts: firewalld-config-server
Conflicts: system-release-workstation
Conflicts: firewalld-config-workstation


%package config-server
<pre>
Summary: Firewalld server configuration settings
...
Provides: firewalld-config
Provides: variant_config(Server)
Requires: firewalld = %{version}-%{release}
Provides: variant_config(Workstation)
Requires: system-release-server
...
Conflicts: firewalld-config-workstation
Conflicts: firewalld-config-standard
 
%package config-workstation
Summary: Firewalld workstation configuration settings
Provides: firewalld-config
Requires: firewalld = %{version}-%{release}
Requires: system-release-workstation
Conflicts: firewalld-config-server
Conflicts: firewalld-config-standard
 
%files config-standard
%ghost %config(noreplace) %{_sysconfdir}/firewalld.conf
%config(noreplace) %{_sysconfdir}/firewalld-standard.conf


%files config-server
%posttrans
%ghost %config(noreplace) %{_sysconfdir}/firewalld.conf
# If we don't yet have a symlink or existing file for firewalld.conf,
%config(noreplace) %{_sysconfdir}/firewalld-server.conf
# create it. Note: this will intentionally reset the policykit policy
# at the same time, so they are in sync.
if [ ! -e %{_sysconfdir}/firewalld/firewalld.conf ]; then
    # Import /etc/os-release to get the variant definition
    . /etc/os-release || :


%files config-workstation
    case "$VARIANT" in
%ghost %config(noreplace) %{_sysconfdir}/firewalld.conf
        Server)
%config(noreplace) %{_sysconfdir}/firewalld-workstation.conf
            ln -sf firewalld-server.conf %{_sysconfdir}/firewalld/firewalld.conf || :
 
            ln -sf org.fedoraproject.FirewallD1.server.policy %{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.policy || :
%post config-standard
            ;;
if [ $1 -eq 1 ]; then
        Workstation)
    rm -f %{_sysconfdir}/firewalld/firewalld.conf
            ln -sf firewalld-workstation.conf %{_sysconfdir}/firewalld/firewalld.conf || :
    ln -sf %{_sysconfdir}/firewalld/firewalld-standard.conf %{_sysconfdir}/firewalld/firewalld.conf
            ln -sf org.fedoraproject.FirewallD1.desktop.policy %{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.policy || :
            ;;
        *)
            ln -sf firewalld-standard.conf %{_sysconfdir}/firewalld/firewalld.conf || :
            # The standard firewall policy will be the same as Server
            ln -sf org.fedoraproject.FirewallD1.server.policy %{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.policy || :
            ;;
        esac
fi
fi


%post config-server
...
if [ $1 -eq 1 ]; then
    rm -f %{_sysconfdir}/firewalld/firewalld.conf
    ln -sf %{_sysconfdir}/firewalld/firewalld-server.conf %{_sysconfdir}/firewalld/firewalld.conf
fi


%post config-workstation
%files -f %{name}.lang
if [ $1 -eq 1 ]; then
...
    rm -f %{_sysconfdir}/firewalld/firewalld.conf
%attr(0750,root,root) %dir %{_sysconfdir}/firewalld
    ln -sf %{_sysconfdir}/firewalld/firewalld-workstation.conf %{_sysconfdir}/firewalld/firewalld.conf
%ghost %config(noreplace) %{_sysconfdir}/firewalld/firewalld.conf
fi
%config(noreplace) %{_sysconfdir}/firewalld/firewalld-standard.conf
%config(noreplace) %{_sysconfdir}/firewalld/firewalld-server.conf
%config(noreplace) %{_sysconfdir}/firewalld/firewalld-workstation.conf
...
%ghost %{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.policy
%{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.desktop.policy
%{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.server.policy
</pre>
</pre>
== Reasoning ==
The configuration sub-packages Requires: the main package in order to guarantee that they always update together (since the reverse dependency is not versioned).
The version comparison algorithm used by yum will attempt to resolve the dependencies through whichever one best matches the Requires/Conflicts or whichever one will install the fewest dependencies. This should result in the appropriate Product configuration being installed or the standard configuration as the fallback.
== References ==
* http://yum.baseurl.org/wiki/CompareProviders


[[Category:Packaging guidelines]]
[[Category:Packaging guidelines]]

Revision as of 19:39, 23 April 2015

Fedora.next Per-Product Configuration Packaging

Goals

In the Fedora.next world, we have a set of curated Fedora Products as well as the availability of classic Fedora. Historically, we have maintained a single set of configuration defaults for all Fedora installs, but different target use-cases have different needs. The goal of this document is to set out the guidelines for creating per-Product configuration defaults.

We want to ensure that all packages have sensible defaults for whichever Product on which they are installed, while also avoiding situations where users would have some packages installed with one Product's defaults and some packages with another.


Definitions

Fedora.next: Umbrella term for planning Fedora's future. Currently covering the creation of the Fedora Products, Fedora Base Design and Fedora Environments and Stacks.
$PRODUCT: One of the Fedora.next Product deliverables, currently "Cloud", "Server" and "Workstation".


Per-product Configuration Packaging

These guidelines are not needed for all packages
Only packages whose defaults differ between Fedora Products are required to follow these instructions. Packages whose configuration is the same for all products can simply install the config files as they normally would.

Requirements

  • All packages must have a global default configuration. This configuration will be used whenever a Product-specific default configuration is not required. (For example, if a non-Product install is in use or only Fedora Cloud has a custom configuration and Fedora Workstation was installed).
  • Any package that requires a per-product default configuration must provide all alternate configuration files in the same package.
  • Any package that requires a configuration that differs between Products must obtain permission from that Product's Working Group before packaging it.

Global Default Configuration

  • The global default configuration must be provided by the package that requires it.
  • The global default configuration must be named based on the package's normal naming scheme, with the main part of the name being suffixed by -default. For example, if the package normally uses foo.conf, then the global default configuration must be named foo-default.conf

Per-Product Default Configuration

  • For each Product requiring a unique default configuration, the packager must provide a copy of the default configuration file, modified as appropriate for the specific product.
  • The product-specific configuration file must be named based on the package's normal naming scheme, with the main part of the name being suffixed by a dash followed by the name of the product. For example, if the package normally uses foo.conf, then the Server version must be named foo-server.conf.

Applying Configuration

In order to apply the configuration, the packager must implement a mechanism in the %posttrans section of the specfile that behaves as follows:

  • It must first check whether the final config file already exists. If so, the script must make no changes.
%posttrans
if [ ! -e %{_sysconfdir}/foo/foo.conf ]; then
    ...
fi
  • Then it must use the value of the Fedora VARIANT to symlink one of the divergent config files (or the default) to the final config file location. It will get this value by importing the contents of /etc/os-release as shell values.
    . /etc/os-release || :
    case "$VARIANT" in
        Server)
            ln -sf foo-server.conf %{_sysconfdir}/foo/foo.conf || :
            ;;
        *)
            ln -sf foo-default.conf %{_sysconfdir}/foo/foo.conf || :
            ;;
        esac
  • Lastly, the final config file location must be listed in the %files section with %ghost:
%ghost %config(noreplace) %{_sysconfdir}/foo/foo.conf
  • For tracking purposes, the package providing the various configuration files must also contain a virtual Provides: for each variant configuration that may be applied:
Provides: variant_config(Cloud)
Provides: variant_config(Server)
Provides: variant_config(Workstation)

Example (firewalld)

We will assume for the sake of demonstration that firewalld will need a custom configuration for Fedora Server and Fedora Workstation, but that Fedora Cloud will not require any changes from the global default.

...
Provides: variant_config(Server)
Provides: variant_config(Workstation)
...

%posttrans
# If we don't yet have a symlink or existing file for firewalld.conf,
# create it. Note: this will intentionally reset the policykit policy
# at the same time, so they are in sync.
if [ ! -e %{_sysconfdir}/firewalld/firewalld.conf ]; then
    # Import /etc/os-release to get the variant definition
    . /etc/os-release || :

    case "$VARIANT" in
        Server)
            ln -sf firewalld-server.conf %{_sysconfdir}/firewalld/firewalld.conf || :
            ln -sf org.fedoraproject.FirewallD1.server.policy %{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.policy || :
            ;;
        Workstation)
            ln -sf firewalld-workstation.conf %{_sysconfdir}/firewalld/firewalld.conf || :
            ln -sf org.fedoraproject.FirewallD1.desktop.policy %{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.policy || :
            ;;
        *)
            ln -sf firewalld-standard.conf %{_sysconfdir}/firewalld/firewalld.conf || :
            # The standard firewall policy will be the same as Server
            ln -sf org.fedoraproject.FirewallD1.server.policy %{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.policy || :
            ;;
        esac
fi

...

%files -f %{name}.lang
...
%attr(0750,root,root) %dir %{_sysconfdir}/firewalld
%ghost %config(noreplace) %{_sysconfdir}/firewalld/firewalld.conf
%config(noreplace) %{_sysconfdir}/firewalld/firewalld-standard.conf
%config(noreplace) %{_sysconfdir}/firewalld/firewalld-server.conf
%config(noreplace) %{_sysconfdir}/firewalld/firewalld-workstation.conf
...
%ghost %{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.policy
%{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.desktop.policy
%{_datadir}/polkit-1/actions/org.fedoraproject.FirewallD1.server.policy