2017-08-15 116 views
2

我有一个非常标准的码头工人,compose.yml,我需要以编程方式编辑数据库的密码。编辑泊坞窗,compose.yml与PyYAML

自YAML文件,我认为这将是简单的编辑和转储内容。 到目前为止,我尝试了PyYAML,它只是乱泊坞窗,撰写文件,我不知道为什么。

加载和倾倒相同的内容,它打破了结构。

内容泊坞窗,compose.yml的:

version: '2' 
services: 
    web: 
    container_name: xxx 
    ports: 
    - "80:80" 
    volumes: 
     - .:/xxx 
    depends_on: 
     - mysql 
    build: . 
    mysql: 
    ports: 
    - "32768:32768" 
    - "3306:3306" 
    container_name: xxx-mysql 
    restart: always 
    image: mariadb:latest 
    environment: 
     MYSQL_ROOT_PASSWORD: 'thiswillbechangeonsetupscript' 
     MYSQL_DATABASE: 'xxxdb' 
    volumes: 
    - ./database:/var/lib/mysql 
    ports: 
     - "3306:3306" 

这是我如何加载和倾倒内容:

import yaml 

with open("docker-compose.yml", 'r') as ymlfile: 
    docker_config = yaml.load(ymlfile) 

with open("docker-compose.yml", 'w') as newconf: 
    yaml.dump(docker_config, newconf) 

这是该文件的保存方式。

services: 
    mysql: 
    container_name: xxx-mysql 
    environment: {MYSQL_DATABASE: xxxdb, MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript} 
    image: mariadb:latest 
    ports: ['3306:3306'] 
    restart: always 
    volumes: ['./database:/var/lib/mysql'] 
    web: 
    build: . 
    container_name: xxx 
    depends_on: [mysql] 
    ports: ['80:80'] 
    volumes: ['.:/xxx'] 
version: '2' 

有没有更好的方法来做到这一点?我错过了什么?

回答

1

您需要添加default_flow_style=False当你写的YAML:

import yaml 

with open("docker-compose.yml", 'r') as ymlfile: 
    docker_config = yaml.load(ymlfile) 

with open("docker-compose_new.yml", 'w') as newconf: 
    yaml.dump(docker_config, newconf, default_flow_style=False) 

然后你会得到下面的输出,除了用字母顺序写的线条,类似于你输入:

services: 
    mysql: 
    container_name: xxx-mysql 
    environment: 
     MYSQL_DATABASE: xxxdb 
     MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript 
    image: mariadb:latest 
    ports: 
    - 3306:3306 
    restart: always 
    volumes: 
    - ./database:/var/lib/mysql 
    web: 
    build: . 
    container_name: xxx 
    depends_on: 
    - mysql 
    ports: 
    - 80:80 
    volumes: 
    - .:/xxx 
version: '2' 

请注意,在原始docker-compose.yaml您在声明ports变量的两倍,因此YAML解析器将只考虑最后一个变量。为了解决这个问题,删除以下行:

ports: 
    - "3306:3306" 

然后,运行写入操作如上所述给出以下输出中:

services: 
    mysql: 
    container_name: xxx-mysql 
    environment: 
     MYSQL_DATABASE: xxxdb 
     MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript 
    image: mariadb:latest 
    ports: 
    - 32768:32768 
    - 3306:3306 
    restart: always 
    volumes: 
    - ./database:/var/lib/mysql 
    web: 
    build: . 
    container_name: xxx 
    depends_on: 
    - mysql 
    ports: 
    - 80:80 
    volumes: 
    - .:/xxx 
version: '2' 
+0

它是相似的,但不一样。转储中缺少端口映射“32768:32768”,因为PyYAML错误地忽略了重复键。 – Anthon

+0

是的。我看到了2个端口......谢谢 –

1

为PyYAML缺省转储是使用流式的叶节点([....]的序列,{...}的映射),所以你应该做的最小值为指定yaml.dump(....., default_flow_style=False)

然后YAML规范状态,该键的顺序是没有保证的,和你请参阅PyYAML按排序顺序转储它们。

我可以推荐使用ruamel.yaml(免责声明:我是该软件包的作者),其具体目标是允许以最小的变化进行这种往返转换,而与输入相比通常没有变化。包括键排序,流量Vs块的风格,对字符串等报价

还有另外一个理由使用ruamel.yaml:如果您在输入运行这个程序:

import sys 
import ruamel.yaml 

yaml = ruamel.yaml.YAML() 
yaml.preserve_quotes = True 
yaml.indent(sequence=3, offset=1) 

with open("docker-compose.yml", 'r') as ymlfile: 
    data = yaml.load(ymlfile) 
yaml.dump(data, sys.stdout) 

,你会得到一个DuplicateKeyError

ruamel.yaml.constructor.DuplicateKeyError: while constructing a mapping 
    in "docker-compose.yml", line 13, column 5 
found duplicate key "ports" with value "[]" (original value: "[]") 
    in "docker-compose.yml", line 24, column 5 

因为ports发生两倍在于是密钥mysql的值的映射键。根据YAML规范(PyYAML处于休眠状态的旧1.1和较新的1.2),这是不允许的,但PyYAML默默地处理了第一个键值对,使端口32768未映射。

从您的输入删除最后两行后,该程序的输出是:

version: '2' 
services: 
    web: 
    container_name: xxx 
    ports: 
    - "80:80" 
    volumes: 
    - .:/xxx 
    depends_on: 
    - mysql 
    build: . 
    mysql: 
    ports: 
    - "32768:32768" 
    - "3306:3306" 
    container_name: xxx-mysql 
    restart: always 
    image: mariadb:latest 
    environment: 
     MYSQL_ROOT_PASSWORD: 'thiswillbechangeonsetupscript' 
     MYSQL_DATABASE: 'xxxdb' 
    volumes: 
    - ./database:/var/lib/mysql 

是希望为您的预期目的足够接近。

请注意,PyYAML删除引号中- "80:80",这是很好的,因为80:80不能被错误地解释为60进制,但如果你做的东西与25端口改变- 80:80- 25:25使用YAML 1.1解析器像PyYAML时更是千差万别(如docker-compose一样)从- "25:25" (the former equalling - 1525`)

在此基础上我做了一个实用ruamel.dcw,使用此功能预先处理泊坞窗撰写文件,并进行环境变量的默认值(在它们没有被设置的情况下)和其他一些技巧,写出一个临时文件,然后调用docker-compose -f tmpfile,你应该使用类似的技术,在运行后处理你的临时文件。