Pulp Import and Export


Support for import and export is provided as a tech preview in Pulp 3. Functionality may not work or may be incomplete. Also, backwards compatibility when upgrading is not guaranteed.


There is a use-case for extracting the content and Artifacts for a set of RepositoryVersions, out of a running instance of Pulp and into a file that can then be transferred to another Pulp instance and imported. This is not the Pulp-to-Pulp sync case; the assumption is that the receiving Pulp instance is network-isolated.

The high-level workflow for this use case is

1. On the Upstream Pulp instance, an Exporter is defined for the set of Repositories that are to be exported to some Downstream Pulp instance.

2. That Exporter is requested to produce and execute an Export for the current RepositoryVersions of the specified Repositories

  1. The resulting .tar.gz Export is transferred to the appropriate Downstream.

4. On the Downstream Pulp instance, an Importer is defined, that maps the incoming Upstream Repositories to matching Downstream Repositories.

5. That Importer is requested to produce and execute an Import, pointing to the provided export file from the Upstream.

In order to minimize space utilization, import/export operates on sets of Repositories. This allows the Export operation to export shared Artifacts only once per-export, rather than once for each Repository being exported.


Export will not operate on RepositoryVersions that have been synchronized using policy=on_demand. Artifacts must actually exist in order to be exported - this is, after all the only way for the Downstream Pulp instance to gain access to them!


Import and Export strictly control which directories may be read from/written to via the settings options ALLOWED_IMPORT_PATHS and ALLOWED_EXPORT_PATHS. These default to empty, if not explicitly set attempts to import or export will fail with a validation error like

"Path '/tmp/exports/' is not an allowed export path"



Pulp instance whose RepositoryVersions we want to export


Pulp instance that will be importing those RepositoryVersions


entity that understands how to map the metadata for a specific Model owned/controlled by a plugin to an exportable file-format (see django-import-export)


resource that exports content from Pulp for a variety of different use cases


kind-of Exporter, that is specifically used to export data from an Upstream for consumption by a Downstream


specific instantiation/run of a PulpExporter

Export file

compressed tarfile containing database content and Artifacts for RepositoryVersions, generated during execution of an Export


resource that accepts an Upstream PulpExporter export file, and manages the process of importing the content and Artifacts included


specific instantiation/run of a PulpImporter


configuration file that provides the ability to map an Upstream Repository, to a Downstream Repository, into which the Upstream’s RepositoryVersion should be imported by a PulpImporter

Import order

for complicated repository-types, managing relationships requires that ModelResources be imported in order. Plugins are responsible for specifying the import-order of the ModelResources they own



The following examples assume a Pulp instance that includes the pulp_file and pulp_rpm plugins. They also assume that the http and jq packages are installed.

These workflows are executed on an Upstream Pulp instance.

Creating an Exporter

In this workflow, you define an Exporter for a set of Repositories. This Exporter can be invoked repeatedly to regularly export the current RepositoryVersion of each of the specified Repositories.

First, let’s make a pair of Repositories named zoo and isofile, and save their UUIDs as ZOO_UUID and ISOFILE_UUID

Set up ‘zoo’ repository”:

# Create the repository
export ZOO_HREF=$(http POST :/pulp/api/v3/repositories/rpm/rpm/ name=zoo | jq -r '.pulp_href')
# add a remote
http POST :/pulp/api/v3/remotes/rpm/rpm/ name=zoo url=https://repos.fedorapeople.org/pulp/pulp/fixtures/rpm/  policy='immediate'
# find remote's href
export REMOTE_HREF=$(http :/pulp/api/v3/remotes/rpm/rpm/ | jq -r ".results[] | select(.name == \"zoo\") | .pulp_href")
# sync the repository to give us some content
http POST :$ZOO_HREF'sync/' remote=$REMOTE_HREF

Set up ‘isofile’ repository:

# create the repository
ISOFILE_HREF=$(http POST :/pulp/api/v3/repositories/file/file/ name=isofile | jq -r '.pulp_href')
# add remote
http POST :/pulp/api/v3/remotes/file/file/ name=isofile url=https://repos.fedorapeople.org/pulp/pulp/fixtures/file/PULP_MANIFEST
# find remote's href
REMOTE_HREF=$(http :/pulp/api/v3/remotes/file/file/ | jq -r ".results[] | select(.name == \"isofile\") | .pulp_href")
# sync the repository to give us some content
http POST :$ISOFILE_HREF'sync/' remote=$REMOTE_HREF

Now that we have Repositories with content, let’s define an Exporter named test-exporter that will export these Repositories to the directory /tmp/exports/:

export EXPORTER_HREF=$(http POST :/pulp/api/v3/exporters/core/pulp/ \
    name=test-exporter                                              \
    repositories:=[\"${ISOFILE_HREF}\",\"${ZOO_HREF}\"]             \
    path=/tmp/exports/ | jq -r '.pulp_href')

Exporting Content

Once we have an Exporter defined, we invoke it to generate an export-file in the directory specified by that Exporter’s path attribute:

http POST :${EXPORTER_HREF}exports/

The resulting Export writes to a .tar.gz file, in the directory pointed to by the Exporter’s path, with a name that follows the convention export-<export-UUID>-YYYYmmdd_HHMM.tar.gz:

ls /tmp/exports

This export file can now be transferred to a Downstream Pulp instance, and imported.

Exporting Specific Versions

By default, the latest-versions of the Repositories specified in the Exporter are exported. However, you can export specific RepositoryVersions of those Repositories if you wish using the versions= parameter on the /exports/ invocation.

Following the above example - let’s assume we want to export the “zero’th” RepositoryVersion of the repositories in our Exporter.:

http POST :${EXPORTER_HREF}exports/ \

Note that the “zero’th” RepositoryVersion of a Repository is created when the Repository is created, and is empty. If you unpack the resulting Export tar.gz you will find, for example, that there is no artifacts/ directory and an empty ArtifactResource.json file:

cd /tmp/exports
tar xvzf export-930ea60c-97b7-4e00-a737-70f773ebbb14-20200511_2005.tar.gz
python -m json.tool pulpcore.app.modelresource.ArtifactResource.json

Exporting Incrementally

By default, PulpExport exports all of the content and artifacts of the RepositoryVersions being exported. A common use-case is to do regular transfers of content from an Upstream to a Downstream Pulp instance. While you can export everything every time, it is an inefficient use of time and disk storage to do so; exporting only the “entities that have changed” is a better choice. You can accomplish this by setting the full parameter on the /exports/ invocation to False:

http POST :${EXPORTER_HREF}exports/ full=False

This results in an export of all content-entities, but only Artifacts that have been added since the last_export of the same Exporter.

You can override the use of last_export as the starting point of an incremental export by use of the start_versions= parameter. Building on our example Exporter, if we want to do an incremental export of everything that’s happened since the second RepositoryVersion of each Repository, regardless of what happened in our last export, we would issue a command such as the following:

http POST :${EXPORTER_HREF}exports/ \
    full=False                      \

This would produce an incremental export of everything that had been added to our Repositories between RepositoryVersion ‘1’ and the current_version RepositoryVersions of our Repositories.

Finally, if we need complete comtrol over incremental exporting, we can combine the use of start_versions= and versions= to produce an incremental export of everything that happened after start_versions= up to and including versions=:

http POST :${EXPORTER_HREF}exports/                                         \
    full=False                                                              \
    start_versions:=[\"${ISO_HREF}versions/1/\",\"${ZOO_HREF}versions/1/\"] \


Note that specifying start_versions= without specifying full=False (i.e., asking for an incremental export) is an error, since it makes no sense to specify a ‘starting version’ for a full export.

Exporting Chunked Files

By default, PulpExport streams data into a single .tar.gz file. Since Repositories can contain a lot of artifacts and content, that can result in a file too large to be copied to transport media. In this case, you can specify a maximum-file-size, and the export process will chunk the tar.gz into a series of files no larger than this.

You accomplish this by setting the chunk_size parameter to the desired maximum number of bytes. This parameter takes an integer, or size-units of KB, MB, or GB. Files appear in the Exporter.path directory, with a four-digit sequence number suffix:

http POST :/pulp/api/v3/exporters/core/pulp/1ddbe6bf-a6c3-4a88-8614-ad9511d21b94/exports/ chunk_size="10KB"
        "task": "/pulp/api/v3/tasks/da3350f7-0102-4dd5-81e0-81becf3ffdc7/"
ls -l /tmp/exports/
    total 76
    10K export-780822a4-d280-4ed0-a53c-382a887576a6-20200522_2325.tar.gz.0000
    10K export-780822a4-d280-4ed0-a53c-382a887576a6-20200522_2325.tar.gz.0001
    10K export-780822a4-d280-4ed0-a53c-382a887576a6-20200522_2325.tar.gz.0002
    10K export-780822a4-d280-4ed0-a53c-382a887576a6-20200522_2325.tar.gz.0003
    10K export-780822a4-d280-4ed0-a53c-382a887576a6-20200522_2325.tar.gz.0004
    10K export-780822a4-d280-4ed0-a53c-382a887576a6-20200522_2325.tar.gz.0005
    2.3K export-780822a4-d280-4ed0-a53c-382a887576a6-20200522_2325.tar.gz.0006

Updating an Exporter

You can update an Exporter to modify a subset of its fields:

http PATCH :${EXPORTER_HREF} path=/tmp/newpath


Creating the importer

The first step to importing a Pulp export archive is to create an importer:

http :/pulp/api/v3/importers/core/pulp/ name="test"

By default, Pulp will map Repositories in the export to Repositories in Pulp by name. This can be overriden by supplying a repo mapping that maps names from the Pulp export to the names of repos in Pulp. For example, suppose the name of the repo in the Pulp export achive was ‘source’ and the repo in Pulp was ‘dest’. The following command would set up this mapping:

http :/pulp/api/v3/importers/core/pulp/ name="test" repo_mapping:="{\"source\": \"dest\"}"

After the importer is created, a POST request to create an import will trigger the import process:

http POST :/pulp/api/v3/importers/core/pulp/f8acba87-0250-4640-b56b-c92597d344b7/imports/ \

One thing worth noting is that the path must be defined in the ALLOWED_IMPORT_PATHS setting.

The command to create an import will return a task that can be used to monitor the import. You can also see a history of past imports:

http :/pulp/api/v3/importers/core/pulp/f8acba87-0250-4640-b56b-c92597d344b7/imports/