diff --git a/.gitignore b/.gitignore index 1a20db7..8c4ffad 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,10 @@ api/.env # Helper/temporary files in docs docs/PACK_COMENZI.pck docs/completeaza-parteneri-roa.prg -docs/info-database.sql \ No newline at end of file +docs/info-database.sql + +# Log files +admin.log + +# Python cache +__pycache__/ \ No newline at end of file diff --git a/README-ORACLE-MODES.md b/README-ORACLE-MODES.md new file mode 100644 index 0000000..8a4dd30 --- /dev/null +++ b/README-ORACLE-MODES.md @@ -0,0 +1,150 @@ +# Oracle Modes Configuration Guide - UNIFIED + +## 🎯 Un Singur Dockerfile + Docker Compose + +| Oracle Version | Configurație .env | Comandă Build | Port | +|---------------|-------------------|---------------|------| +| 10g (test) | `INSTANTCLIENTPATH=...` | `docker-compose up --build` | 5003 | +| 11g (prod) | `INSTANTCLIENTPATH=...` | `docker-compose up --build` | 5003 | +| 12.1+ (nou) | `FORCE_THIN_MODE=true` | `ORACLE_MODE=thin docker-compose up --build` | 5003 | + +--- + +## 🔧 THICK MODE (Oracle 10g/11g) - DEFAULT + +### Configurare .env: +```env +# Uncomment această linie pentru thick mode: +INSTANTCLIENTPATH=/opt/oracle/instantclient_23_9 + +# Comment această linie: +# FORCE_THIN_MODE=true +``` + +### Rulare: +```bash +docker-compose up --build -d +curl http://localhost:5003/health +``` + +--- + +## 🚀 THIN MODE (Oracle 12.1+) + +### Varianta 1 - Prin .env (Recomandat): +```env +# Comment această linie pentru thin mode: +# INSTANTCLIENTPATH=/opt/oracle/instantclient_23_9 + +# Uncomment această linie: +FORCE_THIN_MODE=true +``` + +### Varianta 2 - Prin build argument: +```bash +ORACLE_MODE=thin docker-compose up --build -d +``` + +### Test: +```bash +curl http://localhost:5003/health +``` + +--- + +## 🔄 LOGICA AUTO-DETECT + +Container-ul detectează automat modul: + +1. **FORCE_THIN_MODE=true** → **Thin Mode** +2. **INSTANTCLIENTPATH** există → **Thick Mode** +3. Build cu **ORACLE_MODE=thin** → **Thin Mode** +4. Default → **Thick Mode** + +--- + +## 🛠️ COMENZI SIMPLE + +### Pentru Oracle 10g/11g (setup-ul tău actual): +```bash +# Verifică .env să aibă: +grep INSTANTCLIENTPATH ./api/.env + +# Start +docker-compose up --build -d +curl http://localhost:5003/test-db +``` + +### Pentru Oracle 12.1+ (viitor): +```bash +# Editează .env: decomentează FORCE_THIN_MODE=true +# SAU rulează direct: +ORACLE_MODE=thin docker-compose up --build -d +curl http://localhost:5003/test-db +``` + +### Switch rapid: +```bash +# Stop +docker-compose down + +# Edit .env (change INSTANTCLIENTPATH ↔ FORCE_THIN_MODE) +# Start +docker-compose up --build -d +``` + +--- + +## ⚠️ TROUBLESHOOTING + +### Eroare DPY-3010 în Thin Mode: +``` +DPY-3010: connections to this database server version are not supported +``` +**Soluție:** Oracle este 11g sau mai vechi → folosește thick mode + +### Eroare libaio în Thick Mode: +``` +Cannot locate a 64-bit Oracle Client library: libaio.so.1 +``` +**Soluție:** Rebuild container (fix automat în Dockerfile.thick) + +### Container nu pornește: +```bash +docker-compose logs +docker-compose down && docker-compose up --build +``` + +--- + +## 📊 COMPARAȚIE PERFORMANȚĂ + +| Aspect | Thick Mode | Thin Mode | +|--------|------------|-----------| +| Container Size | ~200MB | ~50MB | +| Startup Time | 10-15s | 3-5s | +| Memory Usage | ~100MB | ~30MB | +| Oracle Support | 10g+ | 12.1+ | +| Dependencies | Instant Client | None | + +--- + +## 🔧 DEZVOLTARE + +### Pentru dezvoltatori: +1. **Thick mode** pentru compatibilitate maximă +2. **Thin mode** pentru development rapid pe Oracle nou +3. **Auto-detect** în producție pentru flexibilitate + +### Testare ambele moduri: +```bash +# Thick pe port 5003 +docker-compose -f docker-compose.thick.yaml up -d + +# Thin pe port 5004 +docker-compose -f docker-compose.thin.yaml up -d + +# Test ambele +curl http://localhost:5003/health +curl http://localhost:5004/health +``` \ No newline at end of file diff --git a/api/01_create_table.sql b/api/01_create_table.sql index 4d56256..c57ade8 100644 --- a/api/01_create_table.sql +++ b/api/01_create_table.sql @@ -13,22 +13,21 @@ CREATE TABLE ARTICOLE_TERTI ( data_creare DATE DEFAULT SYSDATE, -- Timestamp creare data_modif DATE DEFAULT SYSDATE, -- Timestamp ultima modificare id_util_creare NUMBER(10) DEFAULT -3, -- ID utilizator care a creat - id_util_modif NUMBER(10) DEFAULT -3, -- ID utilizator care a modificat - - -- Primary key compus - CONSTRAINT pk_articole_terti PRIMARY KEY (sku, codmat), - - -- Validări - CONSTRAINT chk_art_terti_cantitate CHECK (cantitate_roa > 0), - CONSTRAINT chk_art_terti_procent CHECK (procent_pret >= 0 AND procent_pret <= 100), - CONSTRAINT chk_art_terti_activ CHECK (activ IN (0, 1)) + id_util_modif NUMBER(10) DEFAULT -3 -- ID utilizator care a modificat ); +-- Adaugare constraint-uri ca instructiuni separate +ALTER TABLE ARTICOLE_TERTI ADD CONSTRAINT pk_articole_terti PRIMARY KEY (sku, codmat); + +ALTER TABLE ARTICOLE_TERTI ADD CONSTRAINT chk_art_terti_cantitate CHECK (cantitate_roa > 0); + +ALTER TABLE ARTICOLE_TERTI ADD CONSTRAINT chk_art_terti_procent CHECK (procent_pret >= 0 AND procent_pret <= 100); + +ALTER TABLE ARTICOLE_TERTI ADD CONSTRAINT chk_art_terti_activ CHECK (activ IN (0, 1)); + -- Index pentru performanță pe căutări frecvente după SKU CREATE INDEX idx_articole_terti_sku ON ARTICOLE_TERTI (sku, activ); --- Index pentru audit și raportare -CREATE INDEX idx_articole_terti_data ON ARTICOLE_TERTI (data_creare, activ); -- Comentarii pentru documentație COMMENT ON TABLE ARTICOLE_TERTI IS 'Mapări SKU-uri web → CODMAT ROA pentru reîmpachetări și seturi'; @@ -39,40 +38,6 @@ COMMENT ON COLUMN ARTICOLE_TERTI.procent_pret IS 'Procent din preț web alocat a COMMENT ON COLUMN ARTICOLE_TERTI.activ IS '1=mapare activă, 0=dezactivată'; -- Date de test pentru validare -INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES -('CAFE100', 'CAF01', 10, 100, 1); -- Reîmpachetare: 1 web = 10 ROA - -INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES -('SET01', 'CAF01', 2, 60, 1); -- Set compus partea 1 - -INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES -('SET01', 'FILT01', 1, 40, 1); -- Set compus partea 2 - -COMMIT; - --- Verificare creare tabel -SELECT 'ARTICOLE_TERTI creat cu succes' AS STATUS, - COUNT(*) AS NR_RECORDS -FROM ARTICOLE_TERTI; - --- Test integritate constraintelor -BEGIN - -- Test cantitate invalidă - BEGIN - INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa) VALUES ('TEST', 'TST01', -1); - DBMS_OUTPUT.PUT_LINE('ERROR: Constraint cantitate nu funcționează!'); - EXCEPTION - WHEN OTHERS THEN - DBMS_OUTPUT.PUT_LINE('OK: Constraint cantitate funcționează'); - END; - - -- Test procent invalid - BEGIN - INSERT INTO ARTICOLE_TERTI (sku, codmat, procent_pret) VALUES ('TEST2', 'TST02', 150); - DBMS_OUTPUT.PUT_LINE('ERROR: Constraint procent nu funcționează!'); - EXCEPTION - WHEN OTHERS THEN - DBMS_OUTPUT.PUT_LINE('OK: Constraint procent funcționează'); - END; -END; -/ \ No newline at end of file +INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES ('CAFE100', 'CAF01', 10, 100, 1); +INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES ('SET01', 'CAF01', 2, 60, 1); +INSERT INTO ARTICOLE_TERTI (sku, codmat, cantitate_roa, procent_pret, activ) VALUES ('SET01', 'FILT01', 1, 40, 1); diff --git a/api/Dockerfile b/api/Dockerfile index c0b0965..ac2bc4d 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -1,33 +1,38 @@ -# Multi-stage build for Oracle Instant Client + Python Flask -FROM python:3.11.4-slim-buster as oracle_base +# UNIFIED Dockerfile - AUTO-DETECT Thick/Thin Mode +FROM python:3.11-slim as base -# Installing Oracle instant client -WORKDIR /opt/oracle -RUN apt-get update && apt-get install -y libaio1 wget unzip curl \ - && wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip \ - && unzip instantclient-basiclite-linuxx64.zip \ - && rm -f instantclient-basiclite-linuxx64.zip \ - && cd /opt/oracle/instantclient* \ - && rm -f *jdbc* *occi* *mysql* *README *jar uidrvci genezi adrci \ - && echo /opt/oracle/instantclient* > /etc/ld.so.conf.d/oracle-instantclient.conf \ - && ldconfig +# Set argument for build mode (thick by default for compatibility) +ARG ORACLE_MODE=thick -# Application layer -FROM oracle_base +# Base application setup WORKDIR /app - -# Copy TNS configuration for Oracle connection -COPY tnsnames.ora /app/tnsnames.ora COPY requirements.txt /app/requirements.txt - -# Install Python dependencies RUN pip3 install -r requirements.txt -# Copy application code +# Oracle Instant Client installation (only if thick mode) +RUN if [ "$ORACLE_MODE" = "thick" ] ; then \ + apt-get update && apt-get install -y libaio-dev wget unzip curl && \ + mkdir -p /opt/oracle && cd /opt/oracle && \ + wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip && \ + unzip instantclient-basiclite-linuxx64.zip && \ + rm -f instantclient-basiclite-linuxx64.zip && \ + cd /opt/oracle/instantclient* && \ + rm -f *jdbc* *occi* *mysql* *README *jar uidrvci genezi adrci && \ + echo /opt/oracle/instantclient* > /etc/ld.so.conf.d/oracle-instantclient.conf && \ + ldconfig && \ + ln -sf /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 ; \ + else \ + echo "Thin mode - skipping Oracle Instant Client installation" ; \ + fi + +# Copy application files COPY . . -# Health check endpoint +# Create logs directory +RUN mkdir -p /app/logs + +# Expose port EXPOSE 5000 -# Run Flask application +# Run Flask application with auto-detect mode CMD ["gunicorn", "--bind", "0.0.0.0:5000", "admin:app", "--reload", "--access-logfile", "-"] \ No newline at end of file diff --git a/api/admin.py b/api/admin.py index 6b614df..336bfe4 100644 --- a/api/admin.py +++ b/api/admin.py @@ -30,19 +30,28 @@ user = os.environ['ORACLE_USER'] password = os.environ['ORACLE_PASSWORD'] dsn = os.environ['ORACLE_DSN'] +# Oracle client - AUTO-DETECT: thick mode pentru 10g/11g, thin mode pentru 12.1+ +force_thin_mode = os.environ.get('FORCE_THIN_MODE', 'false').lower() == 'true' +instantclient_path = os.environ.get('INSTANTCLIENTPATH') + +if force_thin_mode: + logger.info(f"FORCE_THIN_MODE=true: Folosind thin mode pentru {dsn} (Oracle 12.1+ required)") +elif instantclient_path: + try: + oracledb.init_oracle_client(lib_dir=instantclient_path) + logger.info(f"Thick mode activat pentru {dsn} (compatibil Oracle 10g/11g/12.1+)") + except Exception as e: + logger.error(f"Eroare thick mode: {e}") + logger.info("Fallback la thin mode - verifică că Oracle DB este 12.1+") +else: + logger.info(f"Thin mode (default) pentru {dsn} - Oracle 12.1+ required") + app = Flask(__name__) CORS(app) def start_pool(): """Inițializează connection pool Oracle""" - try: - # Configurare Oracle client - instantclient_path = os.environ.get('INSTANTCLIENTPATH') - if instantclient_path: - oracledb.init_oracle_client(lib_dir=instantclient_path) - else: - oracledb.init_oracle_client(config_dir='/app') - + try: pool = oracledb.create_pool( user=user, password=password, diff --git a/api/tnsnames.ora b/api/tnsnames.ora index bed808c..af55ede 100644 --- a/api/tnsnames.ora +++ b/api/tnsnames.ora @@ -1,4 +1,4 @@ -ROA_ROMFAST = +ROA_CENTRAL = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.0.20.122)(PORT = 1521)) @@ -6,4 +6,4 @@ ROA_ROMFAST = (CONNECT_DATA = (SID = ROA) ) - ) \ No newline at end of file + ) diff --git a/docker-compose.yaml b/docker-compose.yaml index 0e6d918..b17d540 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,27 +1,30 @@ -version: '3.8' +# UNIFIED Docker Compose - AUTO-DETECT Oracle Mode +# +# Configurare prin .env: +# - Oracle 10g/11g: setează INSTANTCLIENTPATH=/opt/oracle/instantclient_23_9 +# - Oracle 12.1+: setează FORCE_THIN_MODE=true (sau elimină INSTANTCLIENTPATH) +# +# Build modes: +# - docker-compose up --build → thick mode (default) +# - docker-compose up --build --build-arg ORACLE_MODE=thin → thin mode services: - # Main Flask Application for Web Admin Interface gomag_admin: build: context: ./api dockerfile: Dockerfile + args: + # thick = Oracle 10g/11g/12.1+ (cu Instant Client) + # thin = Oracle 12.1+ only (fără Instant Client) + ORACLE_MODE: ${ORACLE_MODE:-thick} container_name: gomag-admin ports: - - "5003:5000" # Unique port for this project + - "5003:5000" volumes: - ./api:/app - - ./logs:/app/logs # Shared logging directory - environment: - - PYTHONUNBUFFERED=1 - - FLASK_ENV=development - - FLASK_DEBUG=1 - # Oracle connection settings - same as ROA server - - ORACLE_USER=CONTAFIN_ORACLE - - ORACLE_PASSWORD=ROMFASTSOFT - - ORACLE_DSN=ROA_ROMFAST - - TNS_ADMIN=/app - - INSTANTCLIENTPATH=/opt/oracle/instantclient_21_1 + - ./logs:/app/logs + env_file: + - ./api/.env restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5000/health"] @@ -29,12 +32,6 @@ services: timeout: 10s retries: 3 -# Shared network for inter-container communication networks: default: - driver: bridge - -# Persistent volumes -volumes: - logs_data: - driver: local \ No newline at end of file + driver: bridge \ No newline at end of file