iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
Odoo

Odoo 部署策略系列 第 24

(重新)自動化 odoo 設定:用 Python 腳本完成資料庫初始化

  • 分享至 

  • xImage
  •  

在上一章中,我們發現無法直接從 odoo CLI 進行資料庫的初始化,但我又不想每次都手動設定。因此,我決定寫一個 Python 腳本,透過發送 POST 請求來取代在網頁上手動設定的步驟。並且這個腳本設計可以在主機上對著容器執行,也可以放在容器內自行執行,方便完成資料庫初始化。


資料庫初始化腳本

原本預期這個腳本應該很簡單,不知道為什麼寫完後變得這麼長 XD,大概是因為有從檔案中讀取 admin_passwd 之類的功能。

這個腳本的預設值都是從 odoo 容器中直接創建資料庫的值,像是 localhost:8069,還有從 /etc/odoo/odoo.conf 讀取密碼,但也可以使用參數的方式覆蓋這些連線設定。

import argparse
import requests
import urllib3
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import configparser
import os
import sys

def read_master_password_from_file(conf_file):
    """從 odoo.conf 檔案中讀取 master password。"""
    if not os.path.exists(conf_file):
        # 檔案不存在,拋出錯誤
        raise FileNotFoundError(f"The file {conf_file} does not exist.")

    config = configparser.ConfigParser()
    with open(conf_file, 'r') as f:
        content = f.read()

    # 檢查檔案是否包含 section header
    if not any(line.strip().startswith('[') and line.strip().endswith(']') for line in content.splitlines()):
        # 沒有 section header,加入一個假 section
        content = '[dummy_section]\n' + content
        config.read_string(content)
        section = 'dummy_section'
    else:
        # 檔案有 section,正常讀取
        config.read_string(content)
        # 嘗試找到包含 'admin_passwd' 的 section
        section = None
        for sect in config.sections():
            if config.has_option(sect, 'admin_passwd'):
                section = sect
                break
        if not section:
            # 找不到 'admin_passwd',拋出錯誤
            raise ValueError(f"Master password (admin_passwd) not found in any section of {conf_file}.")

    try:
        # 從對應 section 中取得 master password
        master_pwd = config.get(section, 'admin_passwd')
        return master_pwd
    except configparser.NoOptionError:
        # 無法取得 admin_passwd,拋出錯誤
        raise ValueError(f"Master password (admin_passwd) not found in section '{section}' of {conf_file}.")

def create_odoo_db(master_pwd, db_name, login, password, lang, country_code, phone, url, ignore_ssl):
    # 如果選擇忽略 SSL 驗證,關閉 SSL 警告
    if ignore_ssl:
        urllib3.disable_warnings(InsecureRequestWarning)

    # 確保 URL 以正確的格式結尾
    if not url.startswith('http'):
        # 如果未指定協議,預設為 http
        url = f'http://{url}'

    # 將 URL 末端補上正確的路徑
    if not url.endswith('/web/database/create'):
        url = f'{url.rstrip("/")}/web/database/create'

    # 準備要發送的 POST 請求資料
    payload = {
        'master_pwd': master_pwd,  # 使用者的 master password
        'name': db_name,  # 要建立的資料庫名稱
        'login': login,  # 新資料庫的管理員帳號
        'password': password,  # 管理員的密碼
        'lang': lang,  # 資料庫的語言
        'country_code': country_code,  # 資料庫的國家代碼
        'phone': phone  # 管理員的電話號碼
    }

    # 透過 POST 發送請求
    try:
        response = requests.post(url, data=payload, verify=not ignore_ssl)

        # 檢查請求是否成功
        if response.status_code == 200:
            # 如果 response 包含錯誤訊息,判斷是否是因為密碼錯誤
            if "Database creation error: Access Denied" in response.text:
                print("Database creation failed: Access Denied. The master password is incorrect.")
            else:
                print("Database created successfully!")
        else:
            print(f"Failed to create database. Status code: {response.status_code}")
            # 顯示伺服器回應的錯誤內容
            print(f"Response: {response.text}")
    except requests.exceptions.SSLError as ssl_error:
        print(f"SSL error occurred: {ssl_error}")

if __name__ == '__main__':
    # 設定參數解析器
    parser = argparse.ArgumentParser(description="Create an Odoo database using curl.")

    # Master password 的設定,可以直接提供或從檔案中讀取
    parser.add_argument('-m', '--mpwd', help="Master Password for the Odoo instance. Cannot be used with --mpwd_file.")
    parser.add_argument('-f', '--mpwd_file', help="Path to the odoo.conf file containing the Master Password. Cannot be used with --mpwd.")
    
    # 其他參數:資料庫名稱、管理員帳號、管理員密碼、語言、國家代碼、電話
    parser.add_argument('--db_name', default='odoo', help="Database name to create (default: 'odoo')")
    parser.add_argument('--login', default='admin', help="Admin login for the new database (default: 'admin')")
    parser.add_argument('--password', default='admin', help="Admin Password for the new database (default: 'admin')")
    parser.add_argument('--lang', default='en_US', help="Language for the new database (default: 'en_US')")
    parser.add_argument('--country_code', default='tw', help="Country code for the new database (default: 'tw')")
    parser.add_argument('--phone', default='+886987654321', help="Phone number for the admin user (default: '+886987654321')")

    # 更新 URL 的說明,允許指定 http 或 https
    parser.add_argument('-u', '--url', default='localhost:8069',
                        help="Base URL for Odoo (default: 'localhost:8069'). You can provide the URL in the format 'localhost:8069' "
                             "and the script will convert it to 'http://localhost:8069/web/database/create'. If you want to use https, "
                             "provide the URL like 'https://localhost:443', and it will go to 'https://localhost:443/web/database/create'.")

    # 忽略 SSL 驗證錯誤的選項
    parser.add_argument('--ignore_ssl', action='store_true',
                        help="Ignore SSL certificate verification errors. Use this if you encounter certificate errors when using HTTPS.")

    args = parser.parse_args()

    # 確保不能同時使用 --mpwd 和 --mpwd_file
    if args.mpwd and args.mpwd_file:
        print("Error: --mpwd and --mpwd_file cannot be used at the same time.")
        sys.exit(1)

    # 判斷要使用的 master password
    if args.mpwd:
        master_pwd = args.mpwd
    else:
        if not args.mpwd_file:
            args.mpwd_file = "/etc/odoo/odoo.conf" # 預設的 odoo.conf 路徑
        try:
            master_pwd = read_master_password_from_file(args.mpwd_file)
        except Exception as e:
            print(f"Error reading master password from file: {e}")
            sys.exit(1)

    # 呼叫建立資料庫的函數
    create_odoo_db(master_pwd, args.db_name, args.login, args.password, args.lang, args.country_code, args.phone, args.url, args.ignore_ssl)

將腳本添加到容器中

完成這個腳本後,我們需要將它放入容器中。由於我之前為了實驗編寫了一些其他腳本,於是決定將它們連同 check-db-status.py 一起放入 utils 資料夾,然後一併複製到容器中:

COPY ./utils /usr/local/bin/

別忘了修改權限為 +x,並在腳本的第一行添加 #! /usr/bin/env python3。這樣一來,容器啟動後,當等待使用者輸入資料庫資訊時,我們可以使用 docker-compose exec [odoo_container] create-odoo-db.py 來直接完成資料庫的設定。


上一篇
勘誤:Timeout 設定與資料庫自動初始化邏輯修正
下一篇
將 odoo 靜態資源交給反向代理:效能與 XSS 防護的雙重提升
系列文
Odoo 部署策略30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言