When you create a vSphere Content Library using vCenter Server, the content library is comprised of both the raw uploaded files (OVF, OVA, VM Templates, ISO, etc) which are stored in a vSphere Datastore and the metadata that is generated by vCenter Server for the individual files, which are stored in the vCenter Server Database (VCDB). In contrast, when an External vSphere Content Library is created, which can be backed by any HTTP(s) endpoint, both the metadata along with the raw files are stored external to the vCenter Server and is managed separately.
Today, there is not an easy way to relocate or move an existing vSphere Content Library from one vSphere Datastore to another. The process would require creating a new vSphere Content Library, then manually using either the vSphere UI or API to then copy all the files from the previous content library to the newly created one which is backed by a different vSphere Datastore.
Typically, the reason for this use case is either you are running out of storage and can not expand further or you need to decomission the underlying storage backing the content library.
Recently, I needed to look into this for my own homelab setup where I plan to rebuild one of my setup which is running on vSAN and I wanted to preserve existing content library without having to transfer content back/fourth. The context above was important as I was able to figure out this could be done with some minor tweaks to the VCDB (which I typically do not recommend touching for this reason) but for this purpose, it really is the only way which I had also confirmed with Engineering.
Disclaimer: This is not officially supported by VMware, use at your own risk.
Step 1 - Stop the vCenter Server service by running the following command:
service-control --stop vmware-vpxd
Step 2 - Login to the VCDB using the psql command-line utility:
psql -U postgres -d VCDB
Step 3 - We need to find the ID of our content library from the cl_library table by using the content library name as a filter:
select id,name from cl_library where name='my-content-library';
As highlighted in the screenshot, my-content-library is mapped to id b14c9fc4-c3ee-4053-bde1-20a99a3761a9
Step 4 - Using the content library ID, we can now search for the associated storage ID from the cl_library_storage table by using the previous id as a filter:
select * from cl_library_storage where library_id='b14c9fc4-c3ee-4053-bde1-20a99a3761a9';
As highlighted in the screenshot, the associated storage id is 7093350f-cce7-49f6-973e-42e4cdecebdd
Step 5 - Using the storage ID, we can finally retrieve the storageuri property which contains our datastore mapping from the cl_storage table and using the storage id as a filter:
select * from cl_storage where id='7093350f-cce7-49f6-973e-42e4cdecebdd';
As highlighted in the screenshot, the storageuri property is mapped to Datastore:datastore-14:a11ffe48-8d5e-4096-ab82-90839fab3b81 where datastore-14 is the vSphere Datastore MoRef ID and a11ffe48-8d5e-4096-ab82-90839fab3b81 is the vCenter Server UUID.
Now that we understand how to find the associated vSphere Datastore from our vSphere Content Library, we can optimize the SQL query to to return everything that we need in a single command by providing just the name of the content library:
SELECT cl_storage.*, cl_library.id AS library_id FROM cl_library JOIN cl_library_storage ON cl_library.id = cl_library_storage.library_id JOIN cl_storage ON cl_library_storage.storage_id = cl_storage.id WHERE cl_library.name = 'my-content-library';
Note: The SQL query above was actually generated by using ChatGPT and simply by providing it the output from the three SQL queries and asking for the desired ouptupt which was cl_storage đŸ˜€ I did have to ask for it to also return library_id, so after amending my request, it generated the above.
As highlighted in the screenshot, 7093350f-cce7-49f6-973e-42e4cdecebdd is the storage ID which we use to filter and update the storageuri from the current value of Datastore:datastore-12:a11ffe48-8d5e-4096-ab82-90839fab3b81 to our new value which we will construct in Step 6 and Step 7 and b14c9fc4-c3ee-4053-bde1-20a99a3761a9 is content library ID.
Step 6 - Before we can update the value for storageuri field, we need to retrieve the Managed Object Reference (MoRef) ID for the vSphere Datastore that we plan to relocate the content library to. To do so, provide the name of the datastore and run the following command:
select id,name from vpx_datastore where name='datastore2';
As highlighted in the screenshot, datastore2 is associated with MoRef ID 14.
Step 7 - We can now update our content library to point to the new vSphere Datastore by running the following command which replaces the datastore MoRef ID with the one found in Step 6 and we filter it based on the storage id found Step 5.
update cl_storage set storageuri = 'Datastore:datastore-14:a11ffe48-8d5e-4096-ab82-90839fab3b81' where id = '7093350f-cce7-49f6-973e-42e4cdecebdd';
You can also re-run the query from Step 5 to confirm that storageuri has been updated successfully.
At this point we are done updating the VCDB and we can exit by running the following command:
\quit
Step 9 - Finally, login to the ESXi host via SSH and copy the entire content library folder which contains all the files from our source datastore (datastore1) to our destination datastore (datastore2). If you have ore than one content library configured, we can identify our content library by using the ID found in Step 3.
Note:Â If you are using a vSAN-backed datastore, instead of manually copying the directory, use the vSphere Datastore browser to perform the operation. In fact, this can be used for non-vSAN-backed datastores as well.
Step 10 - Once you have completed the directory copy, we can now log back into the VCSA and start the vCenter Server service by running the following command:
service-control --start vmware-vpxd
If everything was configured correctly, we should be able to login to our vCenter Server and observe that the vSphere Content Library is still functional (by deploying a workload or mounting an ISO) and that it is now backed by a different vSphere Datastore.
I have already shared this use case with the vSphere Content Library team and hopefully this is something that we can simplify for users in the future if you ever need to migrate an existing content library.
Ramon says
Good job @William Lam!!
We always are learning with you!!
Thanks!
David says
The number of times I've wanted this guide in the past! Great write up, thank you!
Kiran Basawaraj Zond says
We were running into this issue recently..but underlying issue may be different as we were not able to deploy vm with templates in CL as it was getting stuck at compute resources and file not found error..no idea what..we decided to changevthe stirage for CL..if any idea ro troubleshoot our issue would be great help..
Kaveh GOODARZEY says
You must be spying on me I just was talking about our need to do this with my team 2 days ago. Do you have a powercli script that does the same in a vmware supported way? Just for local published ones.
John says
What about moving a content library between two vSphere systems? As in, create a content library, then zip up the folder, move that folder to a different network/system/vCenter, then add the content library. I am aware of how to download individual images and import them into a library, but it would be much faster/easier if I could do it all at once.
William Lam says
As mentioned in article, it’s not just content but metadata which lives in VC, that would be very difficult to export/import
Justin says
There is a way to migrate items using the 'Clone Item' option and then delete the old CL once all the items are cloned to the new CL backed by new datastore.
Create the new CL. Go to the old cl, select the items. Right-click > clone item > Select the new CL. The summary page of the CL shows the size and number of items.
Scott says
Thanks for the great write-up.
Question: It appears that there is some level of dedupe/compression that is used when updating items in a content library. Is there a way to preserve that dedupe/compression when copying the data to the new datastore? We use subscriber CL in other data centers to the primary CL. How will the subscriber CL datastores be affected if the dedupe/compression cannot be preserved?