Datos sobre los COMMON USERS en una arquitectura 'Mutitenant' en Oracle 12c

El principal objetivo de este articulo es mostrar de una manera practica como se comportan los usuarios denominados COMMON dentro de una arquitectura Multitenant, nueva característica en Oracle 12c.

Existen dos tipos de usuarios en una arquitectura Multitenant: LOCAL y COMMON. Los usuarios comunes (COMMON) son usuarios que deben ser creados en el contenedor o root. A partir de aquí los usuarios son replicados hacia todas las base de datos PLUGGABLE que pertenezcan al contenedor. Los esquemas pertenecientes a estos usuarios son independientes unos de otros dentro de cada pluggable database (PDB). Es decir pueden poseer privilegios y objetos diferentes en cada esquema en cada PDB.

Los casos que vamos a analizar son los siguientes:
  1. Qué pasa cuando creamos una nueva PDB?
  2. Qué pasa cuando creamos un COMMON user y las PDB están apagadas (mount)?
  3. Qué pasa cuando creamos un COMMON user y las PDB están en modo READ ONLY?
  4. Qué pasa cuando hacemos un 'UNPLUG' y 'PLUG' de una PDB en un nuevo Container?
Para la demostración de los casos voy a utilizar las vistas CDB_USERS y CDB_PDBS que contienen los detalles de usuarios y pluggable database's en nuestra instancia. Las columnas COMMON y CON_ID indican si el usuario es de tipo COMMON y el ID de la PDB a la que pertenecen respectivamente. Para una mejor definición de las vistas consultar CDB_USERS y CDB_PDBS

Caso 1: qué pasa con los usuarios COMMON cuando se crean nuevas PDB?

En el escenario inicial tenemos dos usuarios tipo COMMON y ninguna PDB.


SQL> select a.con_id, a.username, b.pdb_name from cdb_users a,

  2  cdb_pdbs b where a.con_id = b.con_id
  3  and a.common = 'YES' and username like 'C##%';

no rows selected

SQL> select con_id,username,common from cdb_users
  2  where common = 'YES' and username like 'C##%';

CON_ID      USERNAME              COMMON
---------- --------------------- -----------
1          C##_CDB2USER2         YES
1          C##_CDB2USER1         YES

creemos entonces una nueva PDB llamada PDB1:

SQL> create pluggable database pdb1 
  2  admin user pdb1admin identified by pdb1admin roles=(CONNECT);

Pluggable database created.

SQL> alter pluggable database pdb1 open;

Pluggable database altered.

La respuesta a la pregunta que plantea el caso seria: se crean en automático al abrir la nueva base de datos para su uso.  

SQL> select a.con_id, a.username, b.pdb_name from cdb_users a,
  2  cdb_pdbs b where a.con_id = b.con_id
  3  and a.common = 'YES' and username like ‘C##%’;

    CON_ID USERNAME                 PDB_NAME
---------- ------------------------ -------------------
3          C##_CDB2USER1            PDB1
3          C##_CDB2USER2            PDB1

Caso 2: qué pasa cuando creamos un COMMON user y la(s) PDB(s) están apagadas (mount)?


SQL> alter pluggable database pdb1 close;

Pluggable database altered.

SQL> create user c##_cdb2user3 
  2  identified by password container=all;

User created.

SQL> alter pluggable database pdb1 open;

Pluggable database altered.

SQL> select a.con_id, a.username, b.pdb_name from cdb_users a, 
cdb_pdbs b where a.con_id = b.con_id 
and a.common = 'YES' and username like 'C##%';  2    3  

    CON_ID USERNAME                 PDB_NAME
---------- ------------------------ --------------------
3          C##_CDB2USER1            PDB1
3          C##_CDB2USER3            PDB1
3          C##_CDB2USER2            PDB1

Sucede lo mismo que en el caso anterior, cuando abrimos la base de datos para comenzar a trabajar con ella (en modo READ WRITE), automáticamente se replican los usuarios COMMON desde la base de datos contenedor.

Caso 3: qué pasa cuando creamos un COMMON user y la(s) PDB(s) están en modo READ ONLY?


SQL> alter pluggable database pdb1 close;

Pluggable database altered.

SQL> create user c##_cdb2user4 identified by password container=all;

User created.

SQL> alter pluggable database pdb1 open read only;

Pluggable database altered.

SQL> select a.con_id, a.username, b.pdb_name from cdb_users a,
  2  cdb_pdbs b where a.con_id = b.con_id
  3  and a.common = 'YES' and username like 'C##%';

    CON_ID USERNAME                  PDB_NAME
---------- ------------------------- --------------------
3          C##_CDB2USER1             PDB1
3          C##_CDB2USER3             PDB1
3          C##_CDB2USER2             PDB1

Los usuarios no se replican hasta que la base de abra en modo READ WRITE, comprobemos esta hipótesis:

SQL> alter pluggable database pdb1 close;

Pluggable database altered.

SQL> alter pluggable database pdb1 open;

Pluggable database altered.

SQL> select a.con_id, a.username, b.pdb_name from cdb_users a,
  2  cdb_pdbs b where a.con_id = b.con_id
  3  and a.common = 'YES' and username like 'C##%';

    CON_ID USERNAME                  PDB_NAME
---------- ------------------------- -------------------
3          C##_CDB2USER1             PDB1
3          C##_CDB2USER4             PDB1
3          C##_CDB2USER3             PDB1
3          C##_CDB2USER2             PDB1

Es correcta, hasta que la base de datos este abierta en modo READ WRITE los usuarios se van a replicar.

Caso 4: qué sucede con los COMMON users en una operación de UNPLUG y PLUG de una PDB en un nuevo Container?

Para este caso voy a utilizar una PDB llamada pdb2 del contenedor CDB1 y la voy a colocar en el contenedor CDB2, la PDB contiene 3 COMMON users:


SQL> select a.con_id, a.username, b.pdb_name from cdb_users a,
  2  cdb_pdbs b where a.con_id = b.con_id
  3  and a.common = 'YES' and username like 'C##%';

    CON_ID USERNAME                 PDB_NAME
---------- ------------------------ -------------------
3          C##_CDB1USER3            PDB1
3          C##_CDB1USER2            PDB1
3          C##_CDB1USER1            PDB1
4          C##_CDB1USER3            PDB2
4          C##_CDB1USER2            PDB2
4          C##_CDB1USER1            PDB2

6 rows selected.

SQL> alter pluggable database pdb2
  2  unplug into '/tmp/pdb2desc.xml';

Pluggable database altered.

  
El siguiente paso es hacer un PLUG de esta PDB en el nuevo contenedor, por mejores practicas usamos el paquete DBMS_CHECK_COMPATIBILITY para verificar que la PDB sea compatible con el CDB2.

SQL> BEGIN
  2  IF dbms_pdb.check_plug_compatibility('/tmp/pdb2desc.xml', 'PDB2') THEN
  3  dbms_output.put_line('TRUE');
  4  ELSE
  5  dbms_output.put_line('FALSE');
  6  END IF;
  7  END;
  8  /
TRUE

PL/SQL procedure successfully completed.

SQL> create pluggable database pdb2 using '/tmp/pdb2desc.xml';

Pluggable database created.


SQL> select con_id, name,open_mode from v$pdbs;

    CON_ID  NAME                     OPEN_MODE
---------- ------------------------- ----------
2          PDB$SEED                  READ ONLY
3          PDB1                      READ WRITE
4          PDB2                      MOUNTED

SQL> alter pluggable database pdb2 open;

Pluggable database altered.

Verifiquemos ahora que sucedió con los COMMON users:

SQL> select a.con_id, a.username, b.pdb_name from cdb_users a,
  2  cdb_pdbs b where a.con_id = b.con_id
  3  and a.common = 'YES' and username like ‘C##%’;

    CON_ID USERNAME                  PDB_NAME
---------- ------------------------- -------------------
3          C##_CDB2USER1             PDB1
3          C##_CDB2USER4             PDB1
3          C##_CDB2USER3             PDB1
3          C##_CDB2USER2             PDB1
4          C##_CDB2USER1             PDB2
4          C##_CDB1USER2             PDB2
4          C##_CDB2USER3             PDB2
4          C##_CDB2USER2             PDB2
4          C##_CDB1USER3             PDB2
4          C##_CDB2USER4             PDB2
4          C##_CDB1USER1             PDB2

11 rows selected.


SQL> select username,account_status,con_id from cdb_users where username like ‘C##%’;

USERNAME                  ACCOUNT_STATUS     CON_ID
------------------------- ------------------ ----------
C##_CDB1USER1             LOCKED              4
C##_CDB2USER4             OPEN                4
C##_CDB1USER3             LOCKED              4
C##_CDB2USER2             OPEN                4
C##_CDB2USER3             OPEN                4
C##_CDB1USER2             LOCKED              4
C##_CDB2USER1             OPEN                4
C##_CDB2USER2             OPEN                3
C##_CDB2USER3             OPEN                3
C##_CDB2USER4             OPEN                3
C##_CDB2USER1             OPEN                3
C##_CDB2USER2             OPEN                1
C##_CDB2USER3             OPEN                1
C##_CDB2USER4             OPEN                1
C##_CDB2USER1             OPEN                1

15 rows selected.

Caso extraño:
  • Los COMMON users que ya existían en CDB2 se replicaron en la nueva PDB como era de esperarse.
  • Los COMMON users que eran propios de la PDB2 que se coloco siguen existiendo PERO, están en estado LOCKED.
  • Ademas, los usuarios COMMON solo existen en la PDB2 mas en ninguna otra PDB ni siquiera en el Contenedor CDB$ROOT.
Verifiquemos que pasa al desbloquear los usuarios:

Desde CDB$ROOT:


SQL> alter user C##_CDB1USER1 account unlock;

alter user C##_CDB1USER1 account unlock
           *
ERROR at line 1:
ORA-01918: user 'C##_CDB1USER1' does not exist

Desde PDB2:

SQL> alter session set container=pdb2;

SQL> alter user C##_CDB1USER1 account unlock;
alter user C##_CDB1USER1 account unlock
*
ERROR at line 1:
ORA-65146: account cannot be unlocked in a PDB while it is locked in the root

Este es un caso especial en el manejo de COMMON users en una arquitectura Multitenant y se espera resolver en parches posteriores a 12.1.0.1  según lo explica el articulo en Metalink (Doc ID 16712618.8).

Nota: Si los esquemas de los COMMON users contenían objetos y datos estos pueden seguir siendo utilizados, sin embargo los usuarios no pueden ser desbloqueados pues son considerados HUERFANOS. 


Comments

Popular posts from this blog

Cómo extraer Archive Logs desde un Backup Piece

Ejemplo práctico con SQL Tuning Advisor y SQL Access Advisor

Guía rápida de uso de Oracle ASMLib