/** * WPML compatibility functions * * @global array $duplicated_posts Array to store the posts being duplicated. * * @package Yoast\WP\Duplicate_Post * @since 3.2 */ add_action( 'admin_init', 'duplicate_post_wpml_init' ); /** * Add handlers for WPML compatibility. */ function duplicate_post_wpml_init() { if ( defined( 'ICL_SITEPRESS_VERSION' ) ) { add_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'shutdown', 'duplicate_wpml_string_packages', 11 ); } } global $duplicated_posts; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: Renaming a global variable is a BC break. $duplicated_posts = []; /** * Copy post translations. * * @global SitePress $sitepress Instance of the Main WPML class. * @global array $duplicated_posts Array of duplicated posts. * * @param int $post_id ID of the copy. * @param WP_Post $post Original post object. * @param string $status Status of the new post. */ function duplicate_post_wpml_copy_translations( $post_id, $post, $status = '' ) { global $sitepress; global $duplicated_posts; remove_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10 ); remove_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10 ); $current_language = $sitepress->get_current_language(); $trid = $sitepress->get_element_trid( $post->ID ); if ( ! empty( $trid ) ) { $translations = $sitepress->get_element_translations( $trid ); $new_trid = $sitepress->get_element_trid( $post_id ); foreach ( $translations as $code => $details ) { if ( $code !== $current_language ) { if ( $details->element_id ) { $translation = get_post( $details->element_id ); if ( ! $translation ) { continue; } $new_post_id = duplicate_post_create_duplicate( $translation, $status ); if ( ! is_wp_error( $new_post_id ) ) { $sitepress->set_element_language_details( $new_post_id, 'post_' . $translation->post_type, $new_trid, $code, $current_language ); } } } } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: see above. $duplicated_posts[ $post->ID ] = $post_id; } } /** * Duplicate string packages. * * @global array() $duplicated_posts Array of duplicated posts. */ function duplicate_wpml_string_packages() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: renaming the function would be a BC-break. global $duplicated_posts; foreach ( $duplicated_posts as $original_post_id => $duplicate_post_id ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $original_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $original_post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $new_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $duplicate_post_id ); if ( is_array( $original_string_packages ) ) { foreach ( $original_string_packages as $original_string_package ) { $translated_original_strings = $original_string_package->get_translated_strings( [] ); foreach ( $new_string_packages as $new_string_package ) { $cache = new WPML_WP_Cache( 'WPML_Package' ); $cache->flush_group_cache(); $new_strings = $new_string_package->get_package_strings(); foreach ( $new_strings as $new_string ) { if ( isset( $translated_original_strings[ $new_string->name ] ) ) { foreach ( $translated_original_strings[ $new_string->name ] as $language => $translated_string ) { do_action( // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. 'wpml_add_string_translation', $new_string->id, $language, $translated_string['value'], $translated_string['status'] ); } } } } } } } } Re:全体マニュフェスト – Raqqa

Re:全体マニュフェスト

# =========================
# 0) Namespace
# =========================
apiVersion: v1
kind: Namespace
metadata:
  name: portal-dev
---
# =========================
# 1) Shared Postgres (one instance, two DBs: odoo & portal)
#    - Superuser: POSTGRES_USER=postgres
#    - Creates users/DBs: odoo / portal
# =========================
apiVersion: v1
kind: Secret
metadata:
  name: postgres-auth
  namespace: portal-dev
type: Opaque
stringData:
  POSTGRES_PASSWORD: "change-super-pass"   # superuser
  ODOO_DB_USER: odoo
  ODOO_DB_PASSWORD: "change-odoo-pass"
  PORTAL_DB_USER: portal
  PORTAL_DB_PASSWORD: "change-portal-pass"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgres-init
  namespace: portal-dev
data:
  init-multi-db.sh: |
    #!/usr/bin/env bash
    set -euo pipefail
    echo "Initializing multiple DBs (odoo, portal)..."
    psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-SQL
      DO \$\$
      BEGIN
        IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname='${ODOO_DB_USER}') THEN
          CREATE ROLE ${ODOO_DB_USER} LOGIN PASSWORD '${ODOO_DB_PASSWORD}';
        END IF;
        IF NOT EXISTS (SELECT FROM pg_database WHERE datname='odoo') THEN
          CREATE DATABASE odoo OWNER ${ODOO_DB_USER};
        END IF;

        IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname='${PORTAL_DB_USER}') THEN
          CREATE ROLE ${PORTAL_DB_USER} LOGIN PASSWORD '${PORTAL_DB_PASSWORD}';
        END IF;
        IF NOT EXISTS (SELECT FROM pg_database WHERE datname='portal') THEN
          CREATE DATABASE portal OWNER ${PORTAL_DB_USER};
        END IF;
      END
      \$\$;
SQL
    echo "Enable common extensions in portal DB..."
    psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -d portal <<-SQL
      CREATE EXTENSION IF NOT EXISTS pgcrypto;
      CREATE EXTENSION IF NOT EXISTS postgres_fdw;
SQL
    echo "Enable useful extensions in odoo DB..."
    psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -d odoo <<-SQL
      CREATE EXTENSION IF NOT EXISTS pgcrypto;
SQL
    echo "Done."
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: portal-dev
spec:
  serviceName: postgres
  replicas: 1
  selector: { matchLabels: { app: postgres } }
  template:
    metadata: { labels: { app: postgres } }
    spec:
      containers:
        - name: db
          image: postgres:16
          ports: [{ containerPort: 5432, name: pg }]
          env:
            - name: POSTGRES_USER
              value: postgres
            - name: POSTGRES_PASSWORD
              valueFrom: { secretKeyRef: { name: postgres-auth, key: POSTGRES_PASSWORD } }
            - name: ODOO_DB_USER
              valueFrom: { secretKeyRef: { name: postgres-auth, key: ODOO_DB_USER } }
            - name: ODOO_DB_PASSWORD
              valueFrom: { secretKeyRef: { name: postgres-auth, key: ODOO_DB_PASSWORD } }
            - name: PORTAL_DB_USER
              valueFrom: { secretKeyRef: { name: postgres-auth, key: PORTAL_DB_USER } }
            - name: PORTAL_DB_PASSWORD
              valueFrom: { secretKeyRef: { name: postgres-auth, key: PORTAL_DB_PASSWORD } }
          volumeMounts:
            - { name: data, mountPath: /var/lib/postgresql/data }
            - { name: init, mountPath: /docker-entrypoint-initdb.d }
      volumes:
        - name: init
          configMap:
            name: postgres-init
            defaultMode: 0755
  volumeClaimTemplates:
    - metadata: { name: data }
      spec:
        accessModes: ["ReadWriteOnce"]
        resources: { requests: { storage: 20Gi } }
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: portal-dev
spec:
  selector: { app: postgres }
  ports: [{ name: pg, port: 5432, targetPort: 5432 }]
---
# =========================
# 2) Odoo (uses DB=odoo on same Postgres)
# =========================
apiVersion: v1
kind: ConfigMap
metadata:
  name: odoo-config
  namespace: portal-dev
data:
  ODOO_DB_NAME: odoo
  ODOO_DB_HOST: postgres
  ODOO_DB_PORT: "5432"
  ODOO_PROXY_MODE: "true"
  ODOO_DB_FILTER: "^odoo$"
  ODOO_LOG_LEVEL: info
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: odoo
  namespace: portal-dev
spec:
  replicas: 1
  selector: { matchLabels: { app: odoo } }
  template:
    metadata: { labels: { app: odoo } }
    spec:
      containers:
        - name: odoo
          image: odoo:16.0
          ports: [{ containerPort: 8069, name: http }]
          envFrom:
            - configMapRef: { name: odoo-config }
          env:
            - name: ODOO_DB_USER
              valueFrom: { secretKeyRef: { name: postgres-auth, key: ODOO_DB_USER } }
            - name: ODOO_DB_PASSWORD
              valueFrom: { secretKeyRef: { name: postgres-auth, key: ODOO_DB_PASSWORD } }
          volumeMounts:
            - { name: filestore, mountPath: /var/lib/odoo }
          readinessProbe:
            httpGet: { path: /web, port: http }
            initialDelaySeconds: 20
            periodSeconds: 5
          livenessProbe:
            httpGet: { path: /web, port: http }
            initialDelaySeconds: 60
            periodSeconds: 10
          resources:
            requests: { cpu: "250m", memory: "512Mi" }
            limits:   { cpu: "1000m", memory: "2Gi" }
      volumes:
        - name: filestore
          persistentVolumeClaim: { claimName: odoo-filestore }
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: odoo-filestore
  namespace: portal-dev
spec:
  accessModes: ["ReadWriteOnce"]
  resources: { requests: { storage: 20Gi } }
---
apiVersion: v1
kind: Service
metadata:
  name: odoo
  namespace: portal-dev
spec:
  selector: { app: odoo }
  ports: [{ name: http, port: 80, targetPort: 8069 }]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: odoo
  namespace: portal-dev
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: odoo.dev.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend: { service: { name: odoo, port: { number: 80 } } }
---
# =========================
# 3) Portal API (uses DB=portal on same Postgres)
# =========================
apiVersion: v1
kind: ConfigMap
metadata:
  name: api-config
  namespace: portal-dev
data:
  APP_ENV: dev
  LOG_LEVEL: info
  API_PORT: "8080"
  DB_HOST: postgres
  DB_PORT: "5432"
  DB_NAME: portal
  # Odoo FDW DSN hint (optional)
  ODOO_FDW_HOST: postgres
  ODOO_FDW_PORT: "5432"
  ODOO_FDW_DB: odoo
  # Chroma
  CHROMA_HOST: chroma
  CHROMA_PORT: "8000"
  CHROMA_COLLECTION_FIELD_JA: portal_field_ja
  CHROMA_COLLECTION_VIEW_JA: portal_view_common_ja
---
apiVersion: v1
kind: Secret
metadata:
  name: api-auth
  namespace: portal-dev
type: Opaque
stringData:
  DB_USER: portal
  DB_PASSWORD: "change-portal-pass"          # mirror of postgres-auth PORTAL_DB_PASSWORD
  API_BEARER_TOKEN: "dev-token"              # CronJobs use this to call API
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: portal-api
  namespace: portal-dev
spec:
  replicas: 2
  selector: { matchLabels: { app: portal-api } }
  template:
    metadata: { labels: { app: portal-api } }
    spec:
      containers:
        - name: api
          image: your-registry/portal-api:0.1.0
          ports: [{ containerPort: 8080, name: http }]
          envFrom:
            - configMapRef: { name: api-config }
            - secretRef: { name: api-auth }
          readinessProbe:
            httpGet: { path: /healthz, port: http }
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            httpGet: { path: /livez, port: http }
            initialDelaySeconds: 10
            periodSeconds: 10
          startupProbe:
            httpGet: { path: /startupz, port: http }
            failureThreshold: 30
            periodSeconds: 2
          resources:
            requests: { cpu: "200m", memory: "256Mi" }
            limits:   { cpu: "1",    memory: "1Gi" }
---
apiVersion: v1
kind: Service
metadata:
  name: portal-api
  namespace: portal-dev
spec:
  selector: { app: portal-api }
  ports: [{ name: http, port: 80, targetPort: 8080 }]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: portal-api
  namespace: portal-dev
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: api.dev.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend: { service: { name: portal-api, port: { number: 80 } } }
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: portal-api
  namespace: portal-dev
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: portal-api
  minReplicas: 2
  maxReplicas: 8
  metrics:
    - type: Resource
      resource: { name: cpu, target: { type: Utilization, averageUtilization: 60 } }
---
# =========================
# 4) ChromaDB (dev用)
# =========================
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: chroma
  namespace: portal-dev
spec:
  serviceName: chroma
  replicas: 1
  selector: { matchLabels: { app: chroma } }
  template:
    metadata: { labels: { app: chroma } }
    spec:
      containers:
        - name: chroma
          image: chromadb/chroma:latest
          ports: [{ containerPort: 8000, name: http }]
          env:
            - { name: CHROMA_SERVER_HOST, value: "0.0.0.0" }
            - { name: CHROMA_SERVER_HTTP_PORT, value: "8000" }
          volumeMounts: [{ name: data, mountPath: /chroma/chroma }]
  volumeClaimTemplates:
    - metadata: { name: data }
      spec:
        accessModes: ["ReadWriteOnce"]
        resources: { requests: { storage: 20Gi } }
---
apiVersion: v1
kind: Service
metadata:
  name: chroma
  namespace: portal-dev
spec:
  selector: { app: chroma }
  ports: [{ name: http, port: 8000, targetPort: 8000 }]
---
# =========================
# 5) DB Migration Job (apply DDL to portal DB)
# =========================
apiVersion: batch/v1
kind: Job
metadata:
  name: portal-db-migrate
  namespace: portal-dev
spec:
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: migrate
          image: your-registry/portal-api:0.1.0
          envFrom:
            - configMapRef: { name: api-config }
            - secretRef:    { name: api-auth }
          command: ["sh", "-c"]
          args:
            - >
              python -m scripts.apply_sql /app/sql/000_extensions.sql &&
              python -m scripts.apply_sql /app/sql/010_portal_core.sql &&
              python -m scripts.apply_sql /app/sql/020_portal_translate.sql &&
              python -m scripts.apply_sql /app/sql/030_portal_chroma_doc.sql
---
# =========================
# 6) FDW + ir_*_src Rebuild (Portal DB ←→ Odoo DB on same Postgres)
# =========================
apiVersion: batch/v1
kind: CronJob
metadata:
  name: ir-src-rebuild
  namespace: portal-dev
spec:
  schedule: "0 * * * *"   # hourly
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: psql
              image: postgres:16
              envFrom:
                - configMapRef: { name: api-config }   # DB_HOST/DB_NAME=portal
              env:
                - name: DB_USER
                  valueFrom: { secretKeyRef: { name: api-auth, key: DB_USER } }
                - name: DB_PASSWORD
                  valueFrom: { secretKeyRef: { name: api-auth, key: DB_PASSWORD } }
                - name: ODOO_DB_USER
                  valueFrom: { secretKeyRef: { name: postgres-auth, key: ODOO_DB_USER } }
                - name: ODOO_DB_PASSWORD
                  valueFrom: { secretKeyRef: { name: postgres-auth, key: ODOO_DB_PASSWORD } }
              command: ["bash", "-lc"]
              args:
                - |
                  export PGPASSWORD="$DB_PASSWORD";
                  psql "host=$DB_HOST dbname=$DB_NAME user=$DB_USER" -v ON_ERROR_STOP=1 <<'SQL'
                  CREATE EXTENSION IF NOT EXISTS postgres_fdw;
                  DO $$
                  BEGIN
                    IF NOT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname='odoo_server') THEN
                      CREATE SERVER odoo_server FOREIGN DATA WRAPPER postgres_fdw
                        OPTIONS (host 'postgres', dbname 'odoo', port '5432');
                    END IF;
                  END$$;
                  CREATE SCHEMA IF NOT EXISTS odoo_fdw;
                  -- User mapping for portal app user to access odoo DB
                  DO $$
                  BEGIN
                    IF NOT EXISTS (
                      SELECT 1 FROM pg_user_mappings
                      WHERE srvname='odoo_server' AND umuser = (SELECT usesysid FROM pg_user WHERE usename = current_user)
                    ) THEN
                      CREATE USER MAPPING FOR CURRENT_USER SERVER odoo_server
                        OPTIONS (user :'odoo_user', password :'odoo_pass');
                    END IF;
                  END$$;
                  -- Optional IMPORT FOREIGN SCHEMA (run initially / on schema change)
                  -- IMPORT FOREIGN SCHEMA public LIMIT TO
                  --   (ir_model, ir_model_fields, ir_ui_view, ir_act_window, ir_act_window_view, ir_model_data)
                  --   FROM SERVER odoo_server INTO odoo_fdw;

                  -- ===== Your action-centric rebuild SQL here =====
                  -- Drops & recreates public.ir_model_src / ir_field_src / ir_view_src
                  -- (貼り付け推奨:既に共有いただいた action-centric 版)
                  -- ================================================

SQL
              # Pass env to psql heredoc
              env:
                - name: odoo_user
                  valueFrom: { secretKeyRef: { name: postgres-auth, key: ODOO_DB_USER } }
                - name: odoo_pass
                  valueFrom: { secretKeyRef: { name: postgres-auth, key: ODOO_DB_PASSWORD } }
---
# =========================
# 7) Pipeline CronJobs (call Portal API)
# =========================
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cj-extract-view
  namespace: portal-dev
spec:
  schedule: "*/30 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: curl
              image: curlimages/curl:8.8.0
              env:
                - name: TOKEN
                  valueFrom: { secretKeyRef: { name: api-auth, key: API_BEARER_TOKEN } }
              args:
                - >
                  -sS -X POST
                  -H "Authorization: Bearer $(TOKEN)"
                  -H "Content-Type: application/json"
                  --data '{"action_xmlids":[],"targets":["ai_purpose","help"],"mode":"upsert_if_changed"}'
                  http://portal-api.portal-dev.svc.cluster.local/extract/view_common
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cj-extract-field
  namespace: portal-dev
spec:
  schedule: "15 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: curl
              image: curlimages/curl:8.8.0
              env:
                - name: TOKEN
                  valueFrom: { secretKeyRef: { name: api-auth, key: API_BEARER_TOKEN } }
              args:
                - >
                  -sS -X POST
                  -H "Authorization: Bearer $(TOKEN)"
                  -H "Content-Type: application/json"
                  --data '{"models":[],"fields":[],"mode":"upsert_if_changed"}'
                  http://portal-api.portal-dev.svc.cluster.local/extract/field
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cj-translate-run
  namespace: portal-dev
spec:
  schedule: "*/20 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: curl
              image: curlimages/curl:8.8.0
              env:
                - name: TOKEN
                  valueFrom: { secretKeyRef: { name: api-auth, key: API_BEARER_TOKEN } }
              args:
                - >
                  -sS -X POST
                  -H "Authorization: Bearer $(TOKEN)"
                  -H "Content-Type: application/json"
                  --data '{"limit":200,"source_lang":"ja_JP","target_lang":"en_US","entities":["field","view_common"]}'
                  http://portal-api.portal-dev.svc.cluster.local/translate/run
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cj-chroma-package
  namespace: portal-dev
spec:
  schedule: "*/30 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: curl
              image: curlimages/curl:8.8.0
              env:
                - name: TOKEN
                  valueFrom: { secretKeyRef: { name: api-auth, key: API_BEARER_TOKEN } }
              args:
                - >
                  -sS -X POST
                  -H "Authorization: Bearer $(TOKEN)"
                  -H "Content-Type: application/json"
                  --data '{"entities":["field","view_common"],"lang":"ja","collections":{"field":"portal_field_ja","view_common":"portal_view_common_ja"},"limit":500}'
                  http://portal-api.portal-dev.svc.cluster.local/chroma/package
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cj-chroma-upsert
  namespace: portal-dev
spec:
  schedule: "*/15 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: curl
              image: curlimages/curl:8.8.0
              env:
                - name: TOKEN
                  valueFrom: { secretKeyRef: { name: api-auth, key: API_BEARER_TOKEN } }
              args:
                - >
                  -sS -X POST
                  -H "Authorization: Bearer $(TOKEN)"
                  -H "Content-Type: application/json"
                  --data '{"collections":["portal_field_ja","portal_view_common_ja"],"limit":1000,"dry_run":false}'
                  http://portal-api.portal-dev.svc.cluster.local/chroma/upsert

Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です