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';
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';
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';
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';
At this point we are done updating the VCDB and we can exit by running the following command:
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.