To share data across BEs, use a shared dataset and a symbolic link from a directory structure inside the BE pointing into that shared dataset. An IPS package delivers a symbolic link inside the BE. The same package or another package delivers an SMF service that creates and mounts the shared dataset. The link from the BE where the package is installed into the new shared dataset is similar to the links to /var/share shown in Existing Shared Content in Oracle Solaris. Applications running in the BE write to and read from the shared area via the link.
Best practice is to create one dataset where many applications running in different BEs can share content. Creating a separate dataset for each directory of data that you want to share results in creating many datasets in each non-global zone, and creating many datasets per zone is not desirable. For example, you could create an OPTSHARE dataset mounted at /opt/share. Different applications could share data in different directories under /opt/share.
While you could use a separate package and service to create the shared dataset, note that such a package could be installed from a different BE. The shared dataset might be available even though the package and service that created the dataset are not installed in the current BE. The service delivered by the application package shown in these examples checks whether the dataset already exists and creates the dataset if it does not already exist.
This procedure shows how to provide a shared dataset and a link from the current BE into the shared dataset to enable this application to share data with multiple applications in multiple BEs. The application package delivers the following:
An SMF service that creates the shared dataset
A link in the current BE whose target is in the shared dataset
The package in this example only shows the actions needed to create and link to the shared dataset. Other actions for the application, such as executables and configuration files, are omitted for this example.
Create an area for your package development that contains the directories that you need in the BE and a link to the shared area outside the BE.
$ mkdir -p proto/lib/svc/manifest/site $ mkdir -p proto/lib/svc/method
$ mkdir -p proto/opt/myapp $ ln -s ../../opt/share/myapp/logfiles proto/opt/myapp/logfiles
In proto/lib/svc/method, create a script that performs the following tasks:
Create the dataset, rpool/OPTSHARE, that is shared across BEs. Creating the shared dataset needs to be done only one time for each pool. All current and future BEs in the pool can access that dataset. Check whether the dataset already exists before you create it.
Create the directory structure you want in the shared dataset, including the target of the link in this example: /opt/share/myapp/logfiles.
This script is the start method of the service. In this example, the script is named myapp-share-files.sh. You will need this file name when you create the service manifest in the next step.
The script needs the elements shown in the following prototype. Recall that by default, sh is ksh93. The smf_include.sh file is needed for smf_method_exit. The third argument to smf_method_exit will appear in the service log file and in output from the svcs command.
#!/bin/sh # Load SMF shell support definitions . /lib/svc/share/smf_include.sh # Create rpool/OPTSHARE with mount point /opt/share if it does not already exist # Create /opt/share/myapp/logfiles if it does not already exist # After this script runs, the service does not need to remain online. smf_method_exit $SMF_EXIT_TEMP_DISABLE done "shared area created"
In proto/lib/svc/manifest/site, use the svcbundle command to create the service manifest. In the service-name, include the category site because this is a custom service. The value of start-method is the name of the script that was created in the previous step.
$ svcbundle -o ./myapp-share-files.xml -s service-name=site/myapp-share-files \ > -s start-method=/lib/svc/method/myapp-share-files.sh -s start-timeout=120
By default, the instance that is created is named default and is enabled. If you want the instance to have a different name, specify the instance-name property. You can also specify instance-property, service-property, enabled, and other properties on the svcbundle command line. See the svcbundle(8) man page for descriptions.
The ./myapp-share-files.xml manifest is shown below.
Verify that the content of the manifest is what you need. You might need to edit the manifest to add a dependency or make some other change.
Add common_name and description information in the template data area. You can also add documentation and other template data.
<?xml version="1.0" ?> <!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'> <!-- Manifest created by svcbundle (2020-Oct-11 22:07:39-0700) --> <service_bundle name="site/myapp-share-files" type="manifest"> <service name="site/myapp-share-files" version="1" type="service"> <!-- The following dependency keeps us from starting until the multi-user milestone is reached. --> <dependency name="multi_user_dependency" grouping="require_all" restart_on="none" type="service"> <service_fmri value="svc:/milestone/multi-user"/> </dependency> <exec_method name="start" type="method" timeout_seconds="120" exec="/lib/svc/method/myapp-share-files.sh"/> <!-- The exec attribute below can be changed to a command that SMF should execute to stop the service. Use svcbundle -s stop-method to set the attribute. --> <exec_method name="stop" type="method" timeout_seconds="60" exec=":true"/> <!-- The exec attribute below can be changed to a command that SMF should execute when the service is refreshed. Use svcbundle -s refresh-method to set the attribute. --> <exec_method name="refresh" type="method" timeout_seconds="60" exec=":true"/> <property_group name="startd" type="framework"> <propval name="duration" type="astring" value="transient"/> </property_group> <instance name="default" enabled="true"/> <template> <common_name> <!-- Replace loctext content with a short name for the service. --> <loctext xml:lang="C"> site/myapp-share-files </loctext> </common_name> <description> <!-- Replace loctext content with a brief description of the service --> <loctext xml:lang="C"> The site/myapp-share-files service. </loctext> </description> </template> </service> </service_bundle>
$ svccfg validate myapp-share-files.xml
Use the pkgsend generate command to create the initial package manifest from your package development area.
$ pkgsend generate proto | pkgfmt > share.p5m.1 $ cat share.p5m.1 dir path=lib owner=root group=bin mode=0755 dir path=lib/svc owner=root group=bin mode=0755 dir path=lib/svc/manifest owner=root group=bin mode=0755 dir path=lib/svc/manifest/site owner=root group=bin mode=0755 file lib/svc/manifest/site/myapp-share-files.xml \ path=lib/svc/manifest/site/myapp-share-files.xml owner=root group=bin \ mode=0644 dir path=lib/svc/method owner=root group=bin mode=0755 file lib/svc/method/myapp-share-files.sh \ path=lib/svc/method/myapp-share-files.sh owner=root group=bin mode=0755 dir path=opt owner=root group=bin mode=0755 dir path=opt/myapp owner=root group=bin mode=0755 link path=opt/myapp/logfiles target=../../opt/share/myapp/logfiles
Give the package a name, version, summary, and description.
Delete the opt, lib/svc/manifest/site, and lib/svc/method directory actions because these directories are already delivered by other packages.
Change the group for the service manifest to sys to match other manifests in /lib/svc/manifest.
Change the mode of the service manifest to 0444 and the mode of the service method to 0555 to match other manifests and methods on the system.
Add actuators for the service manifest and method files to restart the manifest-import service whenever those files are installed or updated.
set name=pkg.fmri email@example.com set name=pkg.summary value="Deliver shared directory" set name=pkg.description value="This example package delivers a directory \ and link that allows myapp content to be shared across BEs." set name=variant.arch value=$(ARCH) set name=info.classification \ value=org.opensolaris.category.2008:Applications/Accessories <transform dir path=opt$->drop> <transform dir path=lib$->drop> <transform dir path=lib/svc$->drop> <transform dir path=lib/svc/manifest$->drop> <transform dir path=lib/svc/manifest/site$->drop> <transform dir path=lib/svc/method$->drop> <transform file path=lib/svc/manifest/site/myapp-share-files.xml -> \ edit group bin sys> <transform file path=lib/svc/manifest/site/myapp-share-files.xml -> \ edit mode 0644 0444> <transform file path=lib/svc/manifest/site/myapp-share-dir.xml -> \ add restart_fmri svc:/system/manifest-import:default> <transform file path=lib/svc/method/myapp-share-files.sh -> \ edit mode 0755 0555> <transform file path=lib/svc/method/myapp-share-dir.sh -> \ add restart_fmri svc:/system/manifest-import:default>
$ pkgmogrify -DARCH=`uname -p` share.p5m.1 share.mog | pkgfmt > share.p5m.2 $ cat share.p5m.2 set name=pkg.fmri firstname.lastname@example.org set name=pkg.summary value="Deliver shared directory" set name=pkg.description \ value="This example package delivers a directory and link that allows myapp content to be shared across BEs." set name=info.classification \ value=org.opensolaris.category.2008:Applications/Accessories set name=variant.arch value=i386 file lib/svc/manifest/site/myapp-share-files.xml \ path=lib/svc/manifest/site/myapp-share-files.xml owner=root group=sys \ mode=0444 file lib/svc/method/myapp-share-files.sh \ path=lib/svc/method/myapp-share-files.sh owner=root group=bin mode=0755 dir path=opt/myapp owner=root group=bin mode=0555 link path=opt/myapp/logfiles target=../../opt/share/myapp/logfiles
Use the pkgdepend command to automatically generate and resolve dependencies for the package. The output from resolving dependencies is automatically stored in a file with suffix .res.
In this example, dependencies are generated for ksh93. Additional dependencies might be generated, depending on what your start method does. Also, the service and service instance are declared in org.opensolaris.smf.fmri.
$ pkgdepend generate -md proto share.p5m.2 | pkgfmt > share.p5m.3 $ pkgdepend resolve -m share.p5m.3
The following lines are added in the output share.p5m.3.res file:
set name=org.opensolaris.smf.fmri value=svc:/site/myapp-share-files \ value=svc:/site/myapp-share-files:default depend fmri=pkg:/email@example.com type=require depend fmri=pkg:/firstname.lastname@example.org type=require
$ pkglint share.p5m.3.res
$ pkgsend -s site publish -d proto share.p5m.3.res pkg://email@example.com,5.11:20140417T000014Z PUBLISHED
Install the package.
$ pkg install -g ./site myapp
Verify that the dataset and link exist.
$ zfs list rpool/OPTSHARE NAME USED AVAIL REFER MOUNTPOINT rpool/OPTSHARE 38.5K 24.8G 38.5K /opt/share $ ls -l /opt/myapp lrwxrwxrwx 1 root root 21 Apr 16 17:32 logfiles -> /opt/share/myapp/logfiles
Uninstall the package. The /opt/myapp/logfiles link should be gone, and the service manifest and method script should be gone. The rpool/OPTSHARE dataset should still exist because that is not packaged content: It was created by the service.
This procedure extends the previous procedure. In this example, some data that needs to be shared already exists. The application package delivers a staging area and copies the data to be shared to the staging area. The SMF service moves the data from the staging area to the shared area.
In addition to the link, the package delivers a staging area in the BE to save any unpackaged content that already exists in the directory that will be redefined to be a link.
In addition to creating the shared dataset, the SMF service moves any content that exists in the staging area to the shared area.
Change all occurrences of logfiles to logs.
$ mkdir -p proto/lib/svc/manifest/site $ mkdir -p proto/lib/svc/method $ mkdir -p proto/opt/myapp $ ln -s ../../opt/share/myapp/logs proto/opt/myapp/logs
In this example, the firstname.lastname@example.org package installed /opt/myapp/logs as a directory and the myapp application wrote content to this directory. When this new email@example.com package installs /opt/myapp/logs as a link, any content in the /opt/myapp/logs directory will be saved in /var/pkg/lost+found. To instead save that content to the new shared area, deliver an area to hold a copy of that content.
$ mkdir -p proto/opt/myapp/.migrate/logs
The service will move the content from this staging area in the BE to the shared area.
Content that the firstname.lastname@example.org package writes to /opt/myapp/logs will go directly to the shared area through the link, as in the previous example.
Add the following task to the proto/lib/svc/method/myapp-share-files.sh script that you created in the previous procedure: Move content from the staging area to the shared area.
Do not use the service to remove the empty staging area. The staging area is packaged content and should only be removed by uninstalling the package.
#!/bin/sh # Load SMF shell support definitions . /lib/svc/share/smf_include.sh # Create rpool/OPTSHARE with mount point /opt/share if it does not already exist # Create /opt/share/myapp/logfiles if it does not already exist # Move any content from /opt/myapp/.migrate/logs to /opt/share/myapp/logs # After this script runs, the service does not need to remain online. smf_method_exit $SMF_EXIT_TEMP_DISABLE done "myapp shared files moved"
See How to Enable Your Application to Use a Shared Area for more details about this step.
$ svcbundle -o ./myapp-share-files.xml -s service-name=site/myapp-share-files \ > -s start-method=/lib/svc/method/myapp-share-files.sh -s start-timeout=180
Use the svccfg validate command to make sure the service manifest is valid.
The manifest is the same as the package manifest in the previous example with the following modifications:
All occurrences of logfiles are changed to logs.
The following two actions are added:
dir path=opt/myapp/.migrate owner=root group=bin mode=0755 dir path=opt/myapp/.migrate/logs owner=root group=bin mode=0755
Add the following lines to your share.mog input file for pkgmogrify from the previous example. The salvage-from attribute moves any unpackaged content in the /opt/myapp/logs directory to the /opt/myapp/.migrate/logs directory. The service then moves the content from /opt/myapp/.migrate/logs to /opt/share/myapp/logs.
<transform dir path=opt/myapp/.migrate/logfiles -> \ add salvage-from /opt/myapp/logfiles>
Name this package email@example.com.
Run pkgmogrify as in the previous example.
Create /opt/myapp/logs as a regular directory and put some files in it.
Install the firstname.lastname@example.org package. Verify that the existence of the dataset was correctly detected and handled, the new link exists, the /opt/myapp/logs directory is empty, the /opt/myapp/.migrate/logs directory exists and is empty, and the /opt/share/myapp/logs directory exists and contains the content that was initially in the /opt/myapp/logs directory.