[VCFA 9.X] Forcer la suppression d'une Content Library

Comment supprimer de force une Content Library de son infrastructure à la suite d’un bug ou d’une mauvaise manipulation côté vCenter ?

[VCFA 9.X] Forcer la suppression d'une Content Library

Ce post fait suite à un souci que j’ai rencontré sur mon infrastructure VCFA 9 qui, rappelons-le, est depuis cette version un mélange de deux anciens produits VMware : VMware Cloud Director et VMware Aria Automation.

Symptômes

Les symptômes sont les suivants :

  • La Content Library apparaît avec le statut Failed depuis le tenant client.
  • Un message indique de contacter l’administrateur.

image.png

Plusieurs causes peuvent expliquer ce message :

  • Un problème de refresh entre VCFA et vCenter. Dans certains cas, un simple nouveau refresh suffit à résoudre le problème.
  • Une Content Library supprimée ou modifiée directement dans vCenter au lieu de passer par VCFA. La synchronisation ne peut alors plus se faire correctement.

Dans mon cas, il s’agissait d’une erreur d’administration : la Content Library avait été supprimée directement depuis vCenter au lieu de VCFA.

Diagnostic côté administrateur

Dans un premier temps, j’ai donc suivi le message d’erreur et je me suis connecté au tenant en tant qu’administrateur.

J’ai alors obtenu le message suivant :

[ 75f3e97 ] Erreur interne du serveur

NotFound (com.vmware.vapi.std.errors.not_found) => {
    messages = [
        LocalizableMessage (com.vmware.vapi.std.localizable_message) => {
            id = com.vmware.vdcs.cls-main.library_not_found,
            defaultMessage = Library 3fd not found.,
            args = [],
            params = ,
            localized =
        }
    ],
    data = ,
    errorType = NOT_FOUND
}

image-1.png

L’erreur est ici plutôt claire : VCFA ne retrouve plus la Content Library côté vCenter.

Première tentative : passer par l’API

Pour nettoyer la configuration côté VCFA, mon premier réflexe a été de tenter de passer par l’API du Provider.

Malheureusement, celle-ci refuse l’opération, car la Content Library se trouve dans un état qui ne lui convient pas.

Je vais donc devoir passer directement par la base de données PostgreSQL de mon instance VCFA.

Deuxième tentative : passer par la base de données

⚠️ Attention : les étapes suivantes peuvent avoir un impact important sur votre infrastructure.

Soyez conscients des risques avant d’effectuer des modifications directement dans la base de données.

Une petite snapshot ou un backup avant de commencer ne fait jamais de mal !

Connexion SSH à un nœud VCFA

La première étape consiste à se connecter en SSH sur l’un des nœuds VCFA avec l’utilisateur vmware-system-user et le mot de passe défini lors du déploiement.

Dans mon cas, j’utilise PuTTY :

login as: vmware-system-user
Pre-authentication banner message from server:
| Welcome to Photon 5.0 (\m) - Kernel \r (\l)
End of banner message from server
Keyboard-interactive authentication prompts from server:
| Password:
End of keyboard-interactive prompts from server
Last login: Tue Aug  4 13:29:13 2026 from 10.7.50.188
vmware-system-user@vcfalab-ddza2 [ ~ ]$

Passage en root

Il faut ensuite élever ses privilèges afin de passer en root avec la commande suivante :

sudo -s

Ce qui donne :

vmware-system-user@vcfalab-ddza2 [ ~ ]$ sudo -s
root [ /home/vmware-system-user ]#

Configuration de kubectl

Nous devons ensuite exporter le fichier de configuration Kubernetes afin de pouvoir utiliser kubectl :

export KUBECONFIG=/etc/kubernetes/admin.conf

Dans mon cas :

root [ /home/vmware-system-user ]# export KUBECONFIG=/etc/kubernetes/admin.conf

Recherche du pod PostgreSQL

Une fois cela fait, nous pouvons lister les pods afin de trouver les pods PostgreSQL qui nous intéressent :

kubectl get pods -n prelude | grep -I postgres

La commande retourne dans mon environnement :

root [ /home/vmware-system-user ]# kubectl get pods -n prelude | grep -I postgres
vcfapostgres-0                                        2/2     Running     3 (75d ago)   130d
vcfapostgres-1                                        2/2     Running     3 (75d ago)   130d
vcfapostgres-2                                        2/2     Running     4 (72d ago)   130d
vcfapostgres-pooler-qs7b9558c-mcq2c                   1/1     Running     1 (75d ago)   130d
vcfapostgres-pooler-qs7b9558c-r6xts                   1/1     Running     2             130d

Dans notre cas, le pod qui nous intéresse est le premier : vcfapostgres-0.

Nous allons donc nous connecter directement à l’intérieur de celui-ci :

kubectl -n prelude -it exec vcfapostgres-0 -- bash

Ce qui donne :

root [ /home/vmware-system-user ]# kubectl -n prelude -it exec vcfapostgres-0 -- bash
Defaulted container "postgres" out of: postgres, metrics-exporter

This container is managed by runit, when stopping/starting services use sv

Examples:

sv stop cron
sv restart patroni

Current status: (sv status /etc/service/*)

run: /etc/service/cron: (pid 34) 6480061s
run: /etc/service/etcd: (pid 33) 6480061s
run: /etc/service/patroni: (pid 30) 6480061s
run: /etc/service/pgbouncer: (pid 32) 6480061s
run: /etc/service/pgqd: (pid 31) 6480061s
root [ /home/postgres ]#

Passage sur l’utilisateur PostgreSQL

Une fois à l’intérieur du conteneur, nous devons basculer sur l’utilisateur postgres :

su - postgres

Ce qui donne :

root [ /home/postgres ]# su - postgres
postgres@vcfapostgres-0 [ ~ ]$

Connexion à PostgreSQL

Nous pouvons maintenant lancer le client psql :

psql

Dans mon environnement :

postgres@vcfapostgres-0 [ ~ ]$ psql
psql (16.10, server 14.19)
Type "help" for help.

postgres=#

Connexion à la base tenantmanager

Nous allons tout d’abord activer l’Expanded Display de psql, ce qui rendra les résultats beaucoup plus lisibles :

\x

Puis nous nous connectons à la base de données tenantmanager :

\c tenantmanager

Ce qui donne :

postgres=# \x
Expanded display is on.

postgres=# \c tenantmanager
psql (16.10, server 14.19)
You are now connected to database "tenantmanager" as user "postgres".

tenantmanager=#

Recherche de la Content Library en erreur

Une fois connectés à la base tenantmanager, nous allons lister les différentes Content Libraries présentes dans la table catalog :

SELECT * FROM catalog;

Dans mon cas, la requête retourne notamment les deux entrées suivantes :

-[ RECORD 1 ]---------------+--------------------------------------------------------------------------------------------------
id                          | 21eadd65-fdb0-4867-a774-ea9980dd0b7f
name                        | Test-toto
description                 |
user_id                     | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
org_id                      | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
shared_count                | 0
date_created                | 2026-08-11 13:26:26.032
version_number              | 1
is_published_external       | f
upload_access               | f
delete_access               | f
library_publish_url         |
password                    |
subscription_location       |
subscription_password       |
subscription_local_copy     | f
subscribed_to_ext_feeds     | f
domain_name                 |
deleted                     | f
is_cache_enabled            | f
preserve_identity_info_flag | f
org_publishing_level        | NONE
distributed_catalog_id      |
distributed_catalog_name    |
bound_access_level          |
on_delete_action            |
is_vcf_image_library        | t
is_provider_content_library | f
auto_attach                 | t
status                      | READY

-[ RECORD 2 ]---------------+--------------------------------------------------------------------------------------------------
id                          | 72d61656-e867-4b9f-a363-265370b64fd2
name                        | Test-titi
description                 |
user_id                     | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
org_id                      | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
shared_count                | 0
date_created                | 2026-08-11 13:26:40.495
version_number              | 1
is_published_external       | f
upload_access               | f
delete_access               | f
library_publish_url         |
password                    |
subscription_location       |
subscription_password       |
subscription_local_copy     | f
subscribed_to_ext_feeds     | f
domain_name                 |
deleted                     | f
is_cache_enabled            | f
preserve_identity_info_flag | f
org_publishing_level        | NONE
distributed_catalog_id      |
distributed_catalog_name    |
bound_access_level          |
on_delete_action            |
is_vcf_image_library        | t
is_provider_content_library | f
auto_attach                 | t
status                      | NOT_READY

tenantmanager=#

Nous retrouvons donc bien nos deux Content Libraries :

  • Test-toto, avec le statut READY
  • Test-titi, avec le statut NOT_READY

C’est donc Test-titi qui nous intéresse.

Son ID est le suivant :

72d61656-e867-4b9f-a363-265370b64fd2

Suppression de l’entrée dans la base

Nous pouvons maintenant construire la requête SQL permettant de supprimer cette entrée de la table catalog :

DELETE FROM catalog
WHERE id = '72d61656-e867-4b9f-a363-265370b64fd2';

La suppression est bien prise en compte :

tenantmanager=# DELETE FROM catalog WHERE id = '72d61656-e867-4b9f-a363-265370b64fd2';
DELETE 1
tenantmanager=#

Et voilà ! La Content Library a bien été supprimée du tenant VCFA.

⚠️ À noter

Cette procédure s’applique uniquement aux Content Libraries côté tenant et non aux Content Libraries côté Provider.

Elle n’effectue également aucun nettoyage côté vCenter. Il vous appartient donc de vérifier l’état des objets correspondants dans vCenter et d’effectuer le nettoyage nécessaire.