.. 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
or http://www.opensolaris.org/os/licensing.
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
.. Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
Chapter 10
----------
Advanced Update
................
This chapter deals with more complex package update issues, and describes
several features in IPS designed to simplify these problems.
For most update operations, IPS will automatically do exactly what is
needed to install updated packages. There are some cases, however,
that require the developer to provide additional information to IPS.
For performance reasons, the solver works purely on the dependency
information included in packages. Packages whose dependencies indicate
that they can be installed at the same time but whose content conflicts
cause conflict checking to fail in pre-installation.
An example of conflicting content is two packages installing the same
file. If conflict checking fails, the user must try different package
versions and then manually specify acceptable versions.
Ensuring that conflicting packages cannot be installed due to constraining
dependencies is a responsibility of the package developer. As mentioned in
*Chapter 4*, |pkglint| can assist with this task.
Renaming, Merging and Splitting Packages
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Often, the desired organization of a software component changes, whether because
of mistakes in the original packages, changes in the product or its usage over
time, or changes in the surrounding software environment. Also, sometimes
just the name of a package needs to change. When contemplating such changes,
thought must be given to the customer who is upgrading their system to ensure
that unintended side effects do not occur.
Three types of package reorganization are discussed in this section, in order of
increasingly complex considerations for pkg update:
1. Renaming single packages
2. Merging two packages
3. Splitting a package
Renaming a Single Package
`````````````````````````
Simple renames are straightforward. IPS provides a mechanism
to indicate that a package has been renamed. To rename a package, publish a
new version of the existing package with the following two actions:
* A ``set`` action in the following form::
set name=pkg.renamed value=true
* A ``require`` dependency on the new package
A renamed package cannot deliver contents other than depend or set actions.
The new package **must** ensure that it cannot be installed at the same
time as the original package before the rename. If both packages are
covered by the same incorporation dependency, this is automatic.
If not, the new package must contain an ``optional`` dependency on the old
package at the renamed version. This ensures that the solver will not
select both packages, which would fail conflict checking.
Anyone installing this renamed package will automatically receive the
new named package, since it is a dependency of the old version. If a
renamed package is not depended upon by any other packages, it is
automatically removed from the system. The presence of older software
can cause a number of renamed packages to be shown as ``installed``; when
that older software is removed the renamed packages are automatically
removed as well.
Packages can be renamed multiple times without issue, although this is not
recommended as it can be confusing to users.
Merging Two Packages
````````````````````
Merging packages is straightforward as well. The following two cases are
examples of merging packages:
* One package absorbs another package at the renamed version.
* Two packages are renamed to the same new package name.
One Package Absorbs Another
,,,,,,,,,,,,,,,,,,,,,,,,,,,
Suppose package *A@2* will absorb package *B@3*. Simply
rename package *B* to package *A@2*; remember to include an optional
dependency in *A@2* on *B@3* unless both packages are incorporated so
they update in lockstep as above. A user upgrading *B* to *B@3*
will now get *A* installed, which has absorbed *B*.
Two Packages Are Renamed
,,,,,,,,,,,,,,,,,,,,,,,,
In this case, simply rename both packages to the name of the new merged
package, including two ``optional`` dependencies on the old packages in
the new one if they are not otherwise constrained.
Splitting a Package
```````````````````
When you split a package, rename each resulting new package as described in
`Renaming a Single Package`_. If one of the resulting new packages is not
renamed, the pre-split and post-split versions of that package are not
compatible and might violate dependency logic when the end user tries to update
the package.
Rename the original package, including multiple ``require`` dependencies on all
new packages that resulted from the split. This ensures that any package that
had a dependency on the original package will get all the new pieces.
Some components of the split package can be absorbed into existing packages as a
merge. See `One Package Absorbs Another`_.
Obsoleting Packages
~~~~~~~~~~~~~~~~~~~
Package obsoletion is the mechanism by which packages are emptied of
contents and are removed from the system. Such a package does not
satisfy ``require`` dependencies, so an installed package with a ``require``
dependency on a package that becomes obsolete will prevent update
unless a newer version of the installed package is available that does
not contain the ``require`` dependency.
A package is made obsolete by publishing a new version with no content except
for the following ``set`` action:
::
set name=pkg.obsolete value=true
A package can be made non-obsolete by publishing newer versions.
Users who updated through the obsoletion will lose this package, while those
who did not will not.
Preserving Editable Files During Package Renaming or Path Changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
One common issue with updating packages is the migration of editable files,
either in the file system or between packages. IPS attempts to migrate
editable files that move between packages (for example, as the result of a
rename) if the file is not renamed and the path of the file has not changed.
However, if the path changes, the following must be done for the user's
customizations to be preserved:
If the ``file`` action in the old package does not contain the attribute
``original_name``, that attribute must be added. Set the value to the
original name of the package, followed by a colon and then the path to
the file without a leading '/'. Once this is present on an editable file,
it must not be changed. This value acts as a unique identifier for all
moves going forward so that regardless of the number of versions
skipped on an update, the user's content is properly preserved.
Moving Unpackaged Contents on Directory Removal or Rename
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Normally, unpackaged contents are salvaged when the containing
directory is removed, because the last reference to it disappears.
When a directory changes names, the packaging system treats this
as the removal of the old directory and the creation of a new one.
Any editable files that are still in the directory when the directory
is renamed or removed are salvaged.
If the old directory has unpackaged content such as log files that
should be moved to the new directory, this can be done with the
``salvage-from`` attribute if placed on the new directory.
For example, suppose we want to rename a directory from::
/opt/mydata/log
to::
/opt/yourdata/log
In the same package version that removes the former directory and
introduces the latter directory, include the following attribute on the ``dir``
action that creates ``/opt/yourdata/log``:
::
salvage-from=opt/mydata/log
Any unpackaged contents of any time are migrated to the new location.
The ``salvage-from`` attribute is covered later in this chapter, when
discussing data that should be shared between boot environments.
Delivering Multiple Implementations of a Given Application
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In some cases, it can be desirable to deliver multiple implementations of a
given application, having all implementations available on the system,
but with one implementation set as the *preferred* implementation.
The preferred implementation would have symlinks to its binaries
installed, say, to ``/usr/bin`` for ease of discovery. We would also like to
allow the administrator to change the preferred implementation as required,
without having to add or remove any additional packages.
A good example of this would be where we have several versions of GCC
installed, each in their own package, but would like ``/usr/bin/gcc``
to always point to our preferred version.
IPS uses the concept of *mediated links* for this purpose. A mediated link
is a symbolic link that is controlled by the ``pkg set-mediator`` and
``pkg unset-mediator`` commands, documented in the |pkg| man page.
The ``link`` actions in the packages that deliver different implementations
of that application are said to participate in a *mediation*.
.. raw:: pdf
PageBreak
The following attributes can be set on ``link`` actions to control how
mediated links are delivered:
mediator
Specifies the entry in the mediation namespace shared by all
path names participating in a given mediation group (for example
``python``).
Link mediation can be performed based on ``mediator-version`` and
``mediator-implementation``. All mediated links for a given path name
must specify the same ``mediator``. However, not all mediator versions
and implementations need to provide a link at a given path. If a
mediation does not provide a link, then the link is removed when that
mediation is selected.
A mediator, in combination with a specific version and/or
implementation represents a *mediation* that can be selected for use
by the packaging system.
mediator-version
Specifies the version (expressed as a dot-separated sequence
of non-negative integers) of the interface described by the
``mediator`` attribute. This attribute is required if ``mediator``
is specified and ``mediator-implementation`` is not. A local
system administrator can explicitly set the version to use. The
value specified should generally match the version of the package
delivering the link (for example, ``runtime/python-26`` should use
``mediator-version=2.6``), although this is not required.
mediator-implementation
Specifies the implementation of the mediator for use in addition to
or instead of the ``mediator-version``. Implementation strings are
not considered to be ordered. A string is arbitrarily selected by
|pkg5| if not explicitly specified by a system administrator.
The value can be a string of arbitrary length composed of
alpha-numeric characters and spaces. If the implementation itself can
be or is versioned, then the version should be specified at the
end of the string, after a '@' (expressed as a dot-separated
sequence of non-negative integers). If multiple versions of an
implementation exist, the default behavior is to select the
implementation with the highest version.
If only one instance of an implementation-mediation link at a
particular path is installed on a system, then that one is
chosen automatically. If future links at the path are installed,
the link will not be switched unless a vendor, site, or local
override applies, or if one of the links is version-mediated.
mediator-priority
When resolving conflicts in mediated links, |pkg5| normally
chooses the link with the greatest value of ``mediator-version`` or
based on ``mediator-implementation`` if that is not possible. This
attribute is used to specify an override for the normal conflict
resolution process.
If this attribute is not specified, the default mediator selection
logic is applied.
* If the value is ``vendor``, the link is preferred over those
that do not have a ``mediator-priority`` specified.
* If the value is ``site``, the link is preferred over those that
have a value of ``vendor`` or that do not have a
``mediator-priority`` specified.
A local system administrator can override the selection logic
described above.
Here are two sample manifests that participate in a mediation for the link
``/usr/bin/myapp``::
set name=pkg.fmri value=pkg://test/myapp-impl-1@1.0,5.11:20111021T035233Z
file path=usr/myapp/5.8.4/bin/myapp group=sys mode=0755 owner=root
link path=usr/bin/myapp target=usr/myapp/5.8.4/bin/myapp mediator=myapp mediator-version=5.8.4
::
set name=pkg.fmri value=pkg://test/myapp-impl-2@1.0,5.11:20111021T035239Z
file path=usr/myapp/5.12/bin/myapp group=sys mode=0755 owner=root
link path=usr/bin/myapp target=usr/myapp/5.12/bin/myapp mediator=myapp mediator-version=5.12
.. raw:: pdf
PageBreak
We can install both of these packages to the same image::
$ pkg list myapp-impl-1 myapp-impl-2
NAME (PUBLISHER) VERSION IFO
myapp-impl-1 1.0 i--
myapp-impl-2 1.0 i--
Using the ``pkg mediator`` command, we can see the mediations in use::
$ pkg mediator
MEDIATOR VER. SRC. VERSION IMPL. SRC. IMPLEMENTATION
myapp local 5.12 system
$ ls -al usr/bin/myapp
lrwxrwxrwx 1 root sys 23 Oct 21 16:58 usr/bin/myapp -> usr/myapp/5.12/bin/myapp
We can see which other packages participate in the ``myapp`` mediation using
``pkg search``::
$ pkg search -ro path,target,mediator,mediator-version,pkg.shortfmri ::mediator:myapp
PATH TARGET MEDIATOR MEDIATOR-VERSION PKG.SHORTFMRI
usr/bin/myapp usr/myapp/5.12/bin/myapp myapp 5.12 pkg:/myapp-impl-2@1.0
usr/bin/myapp usr/myapp/5.8.4/bin/myapp myapp 5.8.4 pkg:/myapp-impl-1@1.0
We can also change the mediation as desired::
# pkg set-mediator -V 5.8.4 myapp
Packages to update: 2
Mediators to change: 1
Create boot environment: No
Create backup boot environment: No
PHASE ITEMS
Indexing Packages 2/2
PHASE ACTIONS
Update Phase 1/1
PHASE ITEMS
Image State Update Phase 2/2
Reading Existing Index 8/8
Indexing Packages 2/2
# ls -al usr/bin/myapp
lrwxrwxrwx 1 root sys 24 Oct 21 17:02 usr/bin/myapp -> usr/myapp/5.8.4/bin/myapp
Delivering Directories To Be Shared Across Boot Environments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In general, IPS doesn't support delivery of packaged contents to datasets that
span boot environments (BEs). This is because such shared contents, if updated in
one boot environment, might not meet the definitions for other boot environments.
For example, we could foresee a case where a ``pkg verify`` of packaged content
that was delivered with different attributes by packages in two separate boot
environments, yet shared between them, would result in in errors.
However, some of the unpackaged files (the files stored in the file system that
were not delivered by any IPS package) found in a boot environment must be shared
across boot environments to preserve normal system operation in the
face of multiple boot environments.
Some examples include ``/var/mail``, ``/var/log`` and the like. Customers are
likely to place such data on separate datasets as well, or on remote file
servers. However, creating per-directory datasets would mean that many datasets
would be created per zone, which is not desirable.
The goal can be achieved using a shared dataset, mounted into the BE during boot,
with symbolic links from locations inside the BE pointing into that dataset.
Inside the BE, applications deliver primordial directory structure to a *.migrate*
staging directory.
As noted above, no packaged file content should be shared between boot
environments, furthermore, it is not possible or desirable to share any
file system objects other than files.
Update is supported from older versions of a package that did not share
content. Use a ``salvage-from`` attribute as discussed in
`Moving Unpackaged Contents on Directory Removal or Rename`_ and shown in
the example below.
The package should no longer deliver the old directory.
During boot, a script can be run as part of an SMF method script to move file
content from the *.migrate* directory into the shared dataset. This script is
responsible for recreating the directory structure that it finds under the
*.migrate* directory in the boot environment, and moving file contents from the
*.migrate* directory to the shared dataset.
For example, for a package that previously delivered the action::
dir path=opt/myapplication/logs owner=daemon group=daemon mode=0755
we first create a dataset ``rpool/OPTSHARE`` (which can be used by other shared
content from ``/opt``) This dataset creation could alternatively be done by the
SMF method script during boot::
# zfs create rpool/OPTSHARE
# zfs set mountpoint=/opt/share rpool/OPTSHARE
A package can then deliver a symbolic link from their previously packaged
directory to an as-yet nonexistent target beneath ``/opt/share``::
link path=opt/myapplication/logs target=../../opt/share/myapplication/logs
Packages can now deliver the directory into this *.migrate* area::
dir path=opt/.migrate/myapplication/logs owner=daemon group=daemon \
mode=0755 reboot-needed=true salvage-from=/opt/myapplication/logs
We use the ``salvage-from`` attribute to move files from the old location into
the *.migrate* directory.
We require a ``reboot-needed`` actuator for these directory entries in order to
properly support updates of |Immutable Zones| mentioned in *Chapter 1*, which
boot as far as the ``svc:/milestone/self-assembly-complete:default`` milestone
in read/write mode if self-assembly is required, before rebooting read-only.
See the discussion of ``file-mac-profile`` in the |zonecfg| manual page for more
on |Immutable Zones|.
Our SMF service, on reboot, will then move any salvaged directory content into
the shared dataset, and the symbolic links from ``/opt/myapplication`` point
into that shared dataset.