Transfer Commands
The Cloud CMS command-line tool provides developers with a command-line driven mechanism that allows them to:
- export content from Cloud CMS as an Archive
- import content into new Cloud CMS environments using that Archive
Archives consist of ZIP files that store a full capture of the exported content. Archives may consist of an entire snapshot export or they may be partial (spanning date ranges or changeset ranges in the case of Repositories).
The Cloud CMS Transfer Services make it possible for all data stores and object instances to be exported, passified in a ZIP and then imported anew. This service is used to power a number of features within Cloud CMS including Deployment, Publishing, Content Replication and Multi-Zone Content Delivery.
While the Transfer Service can be invoked via the REST API or via the user interface, it is also available within the Command Line Client as this provides the greatest service to developers and DevOp teams in terms of incorporating content deployment and migration into their build and deployment pipelines.
Export
cloudcms transfer export --source <source> --group <group> --artifact <artifact> --version <version> [--vault] [--includeACLs] [--includeTeams] [--includeTeamMembers] [--includeRoles] [--includeActivities] [--includeBinaries] [--includeAttachments] [--startDate <startDate>] [--endDate <endDate>] [--startChangeset <startChangeset>] [--endChangeset <endChangeset>] [--selectedBranchId <selectedBranchId>] [--tipChangesetOnly] [--contentIncludeFolders] [--contentIncludeRelators] [--branchIncludeRootChangeset]
Source
Use the --source
switch to specify one or more resources to be exported. For example, if you wanted to export a project, you would specify a project reference (i.e. project://{platformId}/{projectId}
). You can specify multiple --source
switches to export multiple things to export.
The only requirement is that the sources must all be of the same type (i.e. project
).
To export a project, you can use a reference like: project://{platformId}/{projectId}
To export a repository, you can use a reference like: project://{platformId}/{repositoryId}
To export a branch, you can use a reference like: branch://{platformId}/{repositoryId}/{branchId}
To export a node, you can use a reference like: node://{platformId}/{repositoryId}/{branchId}/{nodeId}
Archive
Use the --group
, --artifact
and --version
switches to specify the archive properties. These properties can then be used to reference the exported archive in the future.
Includes
Use the following flags to specify what ancillary elements to include in the archive:
--includeACLs
--includeTeams
--includeTeamMembers
--includeRoles
--includeActivities
--includeBinaries
--includeAttachments
Replication using Date Ranges
The --startDate
and --endDate
switches can be used to specify a starting date and ending date for any selected items. Generally, these are used for cases where, say, you're exporting a branch and will use the --childrenOnly
switch on import.
These date switches specify a range of modification dates to be exported and can be used to migrate modified content between environments.
Replication using Changesets
When replicating Repository content between environments, you can also utilize changeset ranges.
The --startChangeset
and --endChangeset
switches to identify a range of repository changesets to replicate.
Content Exports
When exporting a project or a repository, you can target specific branches by using the --selectedBranchId
switch. This switch identifies a specific branch (by ID) that you would like to include. By using this switch, you implicitly exclude all other branches.
In addition, if you're exporting only a single branch, you can use the --tipChangesetOnly
flag to tell the exporter to export only the tip (or denormalized view) of the branch. This exports a single changeset that contains the tip view of the branch. The historical changesets for the branch are not exported.
This results in a smaller archive and is often preferrable for cases where you're simply copying content between environments (or pulling down content for ingestion).
When the --tipChangesetOnly
switch is used, you can additionally specify the following:
--contentIncludeFolders
to have the exporter include any parent folder hierarchies for any exported nodes. With this switch set, the parental folders containing any nodes will also be exported, allowing the content to be situated in the same folder tree on the target after import.--contentIncludeRelators
to force the inclusion of any relator associations and any related nodes. Many relator associations are modeled as linked relationships and wouldn't normally be included with an export. However, there may be times where you'd like to force the inclusion of those relator structures. This switch allows you to do so.
Using Snapshots for Point in Time Consistency
The Export process can take some time depending on how many things you're exporting and how large they are. As such, it is possible and even expected that content in your branches may change as they are being exported. These changes can sometimes result in inconsistent exports or cause the exporter to fail as it runs.
For example, you might have a very large branch with a very large number of nodes. The exporter walks over these nodes and marks them for export. It then walks over the nodes and exports them. If one of those nodes were to be deleted by an editor in between the time it was marked for export and the time when it was actually exported, the exporter will fail with an exception.
To solve for this, consider using branch snapshots. A snapshot captures the branch at a specific point in time. The snapshot can then be exported while your editors continue to work on the master branch.
When exporting a project, use the --selectedBranchId
switch to indicate that the snapshot branch should be exported. This allows your editors to continue their work on the master branch (or any other branch) and guarantees that your export will be consistent.
Examples
Suppose we want to export the master
branch from project 62226556b2fe5f3555db
.
We can run this command to find the repository for the project:
cloudcms project info --project 62226556b2fe5f3555db --pretty -light
We get back something like this:
{
"_doc": "62226556b2fe5f3555db",
"title": "My Project",
"stackId": "4eb2afb1ee2a21b3d027",
"datastores": [
{
"key": "content",
"title": "repository",
"datastoreId": "bc616206262bd6813dfa",
"datastoreTypeId": "repository"
},
{
"key": "principals",
"title": "domain",
"datastoreId": "564dcd18913930faf4b7",
"datastoreTypeId": "domain"
}
]
}
The repository ID is bc616206262bd6813dfa
.
We can now read the master branch for the repository:
cloudcms repository read-branch --repository bc616206262bd6813dfa --branch master --pretty
You might get back something like this:
{
"_doc": "24b3131bd87a4cc4a9cf",
"root": "0:root",
"tip": "44:95f85022da145981fc85",
"title": "master",
"type": "MASTER",
"archived": false,
"snapshot": false
}
The branch starts at changeset 0:root
and the tip is currently at changeset 44:95f85022da145981fc85
.
Now, let's create a snapshot at the tip changeset:
cloudcms repository create-snapshot --repository bc616206262bd6813dfa --changeset 44:95f85022da145981fc85
When that finishes, you'll get back something like this:
{
"_doc": "7cb195a231c7299e1994",
"ok": true
}
We now have a snapshot branch with ID 7cb195a231c7299e1994
.
We can now export the project and tell it to use the snapshot as the selected branch. To export the project, we need to provide a project reference of the structure (project://platformId/projectId
). To get the platform ID, we can run:
cloudcms platform info --pretty --light
Which gives back something like:
{
"_doc": "a270b6f4517d19ccc684"
}
Thus, we can use a project reference of project://a270b6f4517d19ccc684/62226556b2fe5f3555db
.
We can now run the export like this:
cloudcms transfer export --source project://a270b6f4517d19ccc684/62226556b2fe5f3555db --artifact myArchive --group myGroup --version 1.0 --selectedBranchId 7cb195a231c7299e1994
When this finishes, you'll get a report back of the export job that includes start time, completion time, settings and job state:
{
"_doc": "5610dd3c4ec38b5f742d",
"type": "transfer_export",
"state": "FINISHED",
"started": true,
"attempts": 1,
"max_attempts": 1,
"log_entries": [
{
"timestamp": {
"timestamp": "20-Jan-2021 21:12:33",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 12,
"second": 33,
"millisecond": 741,
"ms": 1611195153741,
"iso_8601": "2021-01-20T21:12:33-05:00"
},
"type": "STATUS",
"message": "Job Dispatcher started job"
}
],
"progressMax": 100,
"progressCurrent": 100,
"asynchronous": false,
"sources": [
[
{
"typeId": "platform",
"id": "a270b6f4517d19ccc684",
"ref": "platform://a270b6f4517d19ccc684",
"key": "platform_a270b6f4517d19ccc684"
},
{
"typeId": "project",
"id": "62226556b2fe5f3555db",
"ref": "project://a270b6f4517d19ccc684/62226556b2fe5f3555db",
"key": "project_62226556b2fe5f3555db",
"title": "ABC"
}
]
],
"archiveProperties": {},
"runAsPrincipalId": "cbf6629f4dbb22773236",
"runAsPrincipalDomainId": "default",
"vaultId": "394a0145f4408d6d55c5",
"archiveGroup": "myGroup",
"archiveArtifact": "myArchive",
"archiveVersion": "1.0",
"platformId": "a270b6f4517d19ccc684",
"configuration": {
"selectedBranchId": [
"7cb195a231c7299e1994"
],
"includeACLs": false,
"includeTeams": false,
"includeTeamMembers": false,
"includeRoles": false,
"includeActivities": false,
"includeBinaries": true,
"includeAttachments": true,
"artifactParts": [],
"artifactIncludes": [],
"forceIncludes": false,
"branchIncludeRootChangeset": true,
"platformId": "a270b6f4517d19ccc684"
},
"submitted_by": "cbf6629f4dbb22773236",
"submitted_timestamp": {
"timestamp": "20-Jan-2021 21:12:33",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 12,
"second": 33,
"millisecond": 687,
"ms": 1611195153687,
"iso_8601": "2021-01-20T21:12:33-05:00"
},
"queueMs": 1611195153697,
"stopped": true,
"started_timestamp": {
"timestamp": "20-Jan-2021 21:12:33",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 12,
"second": 33,
"millisecond": 748,
"ms": 1611195153748,
"iso_8601": "2021-01-20T21:12:33-05:00"
},
"server_timestamp": 1611193963835,
"server_thread": "job-thread-1",
"server_key": "fdfcae4223814145da85",
"phase": "export",
"stopped_timestamp": {
"timestamp": "20-Jan-2021 21:12:40",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 12,
"second": 40,
"millisecond": 820,
"ms": 1611195160820,
"iso_8601": "2021-01-20T21:12:40-05:00"
}
}
The job state is FINISHED
which indicates that the job completed successfully.
We can now list the archives in the vault:
cloudcms vault list-archives --vault primary --pretty
And you'll see the archive listed. It might look something like this:
{
"rows": [
{
"group": "myGroup",
"artifact": "myArchive",
"version": "1",
"type": "project",
"_doc": "a3d0c170922081b5244a",
"contentType": "application/zip",
"length": 5374053,
"_info": {
"length": 5374053,
"type": "application/zip"
}
}
],
"total_rows": 1,
"offset": 0,
"size": 1
}
We can now download this archive:
cloudcms archive download --group myGroup --artifact myArchive --version 1.0
The archive will be downloaded and saved as myGroup-myArchive-1.0.zip
.
We can now create a new project using this very archive. To do so, we need to pass in the reference to the archive. The archive reference is of the form archive://platformId/vaultId/archiveId
.
Thus, we can do:
cloudcms platform create-project --title "My Second Project" --type archive://a270b6f4517d19ccc684/primary/a3d0c170922081b5244a
And we'll get back a response that indicates how the project creation went:
{
"_doc": "cb71894fa043c4ec49e5",
"type": "create-project",
"state": "FINISHED",
"started": true,
"attempts": 1,
"max_attempts": 1,
"log_entries": [
{
"timestamp": {
"timestamp": "20-Jan-2021 21:57:34",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 57,
"second": 34,
"millisecond": 204,
"ms": 1611197854204,
"iso_8601": "2021-01-20T21:57:34-05:00"
},
"type": "STATUS",
"message": "Job Dispatcher started job"
},
{
"timestamp": {
"timestamp": "20-Jan-2021 21:57:41",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 57,
"second": 41,
"millisecond": 567,
"ms": 1611197861567,
"iso_8601": "2021-01-20T21:57:41-05:00"
},
"type": "STATUS",
"message": "Finished"
}
],
"progressMax": 100,
"progressCurrent": 100,
"asynchronous": false,
"runAsPrincipalId": "cbf6629f4dbb22773236",
"runAsPrincipalDomainId": "default",
"platformId": "a270b6f4517d19ccc684",
"project-object": {
"title": "My Second Project",
"projectType": "archive://a270b6f4517d19ccc684/primary/a3d0c170922081b5244a",
"family": "oneteam"
},
"submitted_by": "cbf6629f4dbb22773236",
"submitted_timestamp": {
"timestamp": "20-Jan-2021 21:57:34",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 57,
"second": 34,
"millisecond": 69,
"ms": 1611197854069,
"iso_8601": "2021-01-20T21:57:34-05:00"
},
"queueMs": 1611197854202,
"stopped": true,
"started_timestamp": {
"timestamp": "20-Jan-2021 21:57:34",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 57,
"second": 34,
"millisecond": 209,
"ms": 1611197854209,
"iso_8601": "2021-01-20T21:57:34-05:00"
},
"server_timestamp": 1611193963835,
"server_thread": "job-thread-0",
"server_key": "fdfcae4223814145da85",
"created-project-id": "0873f94d85ec1c1cc9e2",
"stopped_timestamp": {
"timestamp": "20-Jan-2021 21:57:41",
"year": 2021,
"month": 0,
"day_of_month": 20,
"hour": 21,
"minute": 57,
"second": 41,
"millisecond": 574,
"ms": 1611197861574,
"iso_8601": "2021-01-20T21:57:41-05:00"
}
}