本文目录导读:

在Python中生成Chef配置,可以通过以下几种方式实现:
使用模板引擎生成Chef资源文件
使用Jinja2模板
from jinja2 import Template
# 定义模板
template_str = """
package '{{ package_name }}' do
action :install
end
template '/etc/{{ config_name }}.conf' do
source '{{ template_name }}.erb'
owner 'root'
group 'root'
mode '0644'
variables(
:port => {{ port }},
:host => '{{ host }}'
)
end
service '{{ service_name }}' do
supports :status => true, :restart => true
action [:enable, :start]
end
"""
# 创建模板对象
template = Template(template_str)
# 填充数据
config = {
'package_name': 'nginx',
'config_name': 'nginx',
'template_name': 'nginx',
'port': 8080,
'host': 'localhost',
'service_name': 'nginx'
}
# 渲染配置
chef_config = template.render(config)
# 写入文件
with open('recipes/default.rb', 'w') as f:
f.write(chef_config)
print(chef_config)
使用Python内置字符串格式化
def generate_chef_config(service_name, package_name, config_values):
"""生成Chef配置"""
config_template = """
# Cookbook: {service_name}
# Recipe: default
package '{package_name}' do
action :install
version '{version}'
end
service '{service_name}' do
supports :status => true, :restart => true
action [:enable, :start]
end
# 配置文件管理
directory '/etc/{service_name}' do
owner 'root'
group 'root'
mode '0755'
recursive true
action :create
end
template '/etc/{service_name}/{service_name}.conf' do
source '{service_name}.erb'
owner 'root'
group 'root'
mode '0644'
variables(
:port => {port},
:host => '{host}',
:max_clients => {max_clients}
)
end
"""
return config_template.format(
service_name=service_name,
package_name=package_name,
version=config_values.get('version', 'latest'),
port=config_values.get('port', 80),
host=config_values.get('host', 'localhost'),
max_clients=config_values.get('max_clients', 100)
)
# 使用示例
config = {
'version': '1.18.0',
'port': 8080,
'host': 'web.example.com',
'max_clients': 500
}
chef_recipe = generate_chef_config('nginx', 'nginx', config)
print(chef_recipe)
# 保存到文件
with open('nginx_recipe.rb', 'w') as f:
f.write(chef_recipe)
使用自定义类生成复杂配置
class ChefConfigGenerator:
"""Chef配置生成器"""
def __init__(self, cookbook_name):
self.cookbook_name = cookbook_name
self.resources = []
def add_package(self, name, version=None, action='install'):
"""添加包资源"""
self.resources.append({
'type': 'package',
'name': name,
'version': version,
'action': action
})
def add_service(self, name, action=['enable', 'start'], supports=None):
"""添加服务资源"""
if supports is None:
supports = {'status': True, 'restart': True}
self.resources.append({
'type': 'service',
'name': name,
'action': action,
'supports': supports
})
def add_template(self, name, source, variables=None,
owner='root', group='root', mode='0644'):
"""添加模板资源"""
if variables is None:
variables = {}
self.resources.append({
'type': 'template',
'name': name,
'source': source,
'owner': owner,
'group': group,
'mode': mode,
'variables': variables
})
def add_directory(self, name, owner='root', group='root',
mode='0755', recursive=True):
"""添加目录资源"""
self.resources.append({
'type': 'directory',
'name': name,
'owner': owner,
'group': group,
'mode': mode,
'recursive': recursive
})
def generate_resource_code(self, resource):
"""生成资源代码"""
type_map = {
'package': self._generate_package,
'service': self._generate_service,
'template': self._generate_template,
'directory': self._generate_directory
}
generator = type_map.get(resource['type'])
if generator:
return generator(resource)
return ''
def _generate_package(self, resource):
code = f"package '{resource['name']}' do\n"
if resource['version']:
code += f" version '{resource['version']}'\n"
code += f" action :{resource['action']}\nend\n"
return code
def _generate_service(self, resource):
code = f"service '{resource['name']}' do\n"
supports = resource['supports']
code += f" supports :status => {supports.get('status', True)}, :restart => {supports.get('restart', True)}\n"
action_list = resource['action']
code += f" action [:{', :'.join(action_list)}]\nend\n"
return code
def _generate_template(self, resource):
code = f"template '{resource['name']}' do\n"
code += f" source '{resource['source']}'\n"
code += f" owner '{resource['owner']}'\n"
code += f" group '{resource['group']}'\n"
code += f" mode '{resource['mode']}'\n"
if resource['variables']:
code += " variables(\n"
for key, value in resource['variables'].items():
if isinstance(value, str):
code += f" :{key} => '{value}',\n"
else:
code += f" :{key} => {value},\n"
code += " )\n"
code += "end\n"
return code
def _generate_directory(self, resource):
code = f"directory '{resource['name']}' do\n"
code += f" owner '{resource['owner']}'\n"
code += f" group '{resource['group']}'\n"
code += f" mode '{resource['mode']}'\n"
if resource['recursive']:
code += " recursive true\n"
code += " action :create\nend\n"
return code
def generate_recipe(self):
"""生成完整食谱"""
header = f"# Cookbook: {self.cookbook_name}\n# Recipe: default\n\n"
body = "\n".join(self.generate_resource_code(r) for r in self.resources)
return header + body
# 使用示例
generator = ChefConfigGenerator('my_app')
generator.add_package('nginx', version='1.18.0')
generator.add_directory('/etc/nginx')
generator.add_template(
'/etc/nginx/nginx.conf',
'nginx.erb',
variables={'port': 8080, 'host': 'localhost'}
)
generator.add_service('nginx')
recipe = generator.generate_recipe()
print(recipe)
# 保存到文件
with open('recipes/default.rb', 'w') as f:
f.write(recipe)
从YAML/JSON配置生成Chef配置
import yaml
import json
def generate_chef_from_yaml(yaml_file):
"""从YAML文件生成Chef配置"""
with open(yaml_file, 'r') as f:
config = yaml.safe_load(f)
chef_code = []
chef_code.append(f"# Generated Chef Cookbook: {config.get('cookbook_name', 'default')}")
# 处理包安装
for package in config.get('packages', []):
chef_code.append(f"package '{package['name']}' do")
if 'version' in package:
chef_code.append(f" version '{package['version']}'")
chef_code.append(" action :install")
chef_code.append("end\n")
# 处理服务
for service in config.get('services', []):
chef_code.append(f"service '{service['name']}' do")
chef_code.append(" action [:enable, :start]")
chef_code.append("end\n")
# 处理模板
for template in config.get('templates', []):
chef_code.append(f"template '{template['path']}' do")
chef_code.append(f" source '{template['source']}'")
chef_code.append(f" owner '{template.get('owner', 'root')}'")
chef_code.append(f" group '{template.get('group', 'root')}'")
chef_code.append(f" mode '{template.get('mode', '0644')}'")
if 'variables' in template:
chef_code.append(" variables(")
for key, value in template['variables'].items():
chef_code.append(f" :{key} => '{value}',")
chef_code.append(" )")
chef_code.append("end\n")
return "\n".join(chef_code)
# YAML配置示例
yaml_config = """
cookbook_name: web_server
packages:
- name: nginx
version: 1.18.0
services:
- name: nginx
templates:
- path: /etc/nginx/nginx.conf
source: nginx.erb
owner: root
group: root
mode: '0644'
variables:
port: 8080
host: localhost
"""
# 使用示例
with open('config.yaml', 'w') as f:
f.write(yaml_config)
chef_config = generate_chef_from_yaml('config.yaml')
print(chef_config)
完整的自动化生成脚本示例
#!/usr/bin/env python3
"""
Chef配置一键生成工具
支持生成完整的Cookbook结构
"""
import os
import json
from pathlib import Path
class ChefCookbookGenerator:
def __init__(self, cookbook_name, cookbook_path='.'):
self.cookbook_name = cookbook_name
self.cookbook_path = Path(cookbook_path) / cookbook_name
def create_cookbook_structure(self):
"""创建Cookbook目录结构"""
directories = [
'recipes',
'templates/default',
'attributes',
'files/default',
'metadata.rb'
]
for directory in directories:
path = self.cookbook_path / directory
if '.' not in directory: # 不是文件
path.mkdir(parents=True, exist_ok=True)
def generate_metadata(self):
"""生成metadata.rb"""
metadata_content = f"""
name '{self.cookbook_name}'
maintainer 'Generated by Python'
maintainer_email 'admin@example.com'
license 'Apache-2.0'
description 'Installs/Configures {self.cookbook_name}'
version '0.1.0'
supports 'centos'
supports 'ubuntu'
depends 'yum'
depends 'systemd'
"""
with open(self.cookbook_path / 'metadata.rb', 'w') as f:
f.write(metadata_content.strip())
def generate_default_recipe(self, packages, services, config_templates):
"""生成默认食谱"""
recipe_content = [
"#",
f"# Cookbook:: {self.cookbook_name}",
"# Recipe:: default",
"#",
"",
"# Update package list",
"execute 'update_package_list' do",
" command 'apt-get update'",
" action :nothing",
"end",
""
]
# 添加包安装
for package in packages:
recipe_content.append(f"package '{package}' do")
recipe_content.append(" action :install")
recipe_content.append(" notifies :run, 'execute[update_package_list]', :immediately")
recipe_content.append("end")
recipe_content.append("")
# 添加配置文件
for template_name, template_config in config_templates.items():
recipe_content.append(f"template '{template_config['path']}' do")
recipe_content.append(f" source '{template_name}.erb'")
recipe_content.append(f" owner '{template_config.get('owner', 'root')}'")
recipe_content.append(f" group '{template_config.get('group', 'root')}'")
recipe_content.append(f" mode '{template_config.get('mode', '0644')}'")
if 'variables' in template_config:
recipe_content.append(" variables(")
for key, value in template_config['variables'].items():
recipe_content.append(f" :{key} => '{value}',")
recipe_content.append(" )")
recipe_content.append("end")
recipe_content.append("")
# 添加服务
for service_name, service_config in services.items():
recipe_content.append(f"service '{service_name}' do")
recipe_content.append(" supports :status => true, :restart => true, :reload => true")
recipe_content.append(f" action [:{', :'.join(service_config.get('actions', ['enable', 'start']))}]")
if 'notifies' in service_config:
for notification in service_config['notifies']:
recipe_content.append(f" notifies :{notification['action']}, '{notification['resource']}'")
recipe_content.append("end")
recipe_content.append("")
# 写入文件
recipe_path = self.cookbook_path / 'recipes' / 'default.rb'
with open(recipe_path, 'w') as f:
f.write('\n'.join(recipe_content))
def generate(self, config):
"""根据配置生成完整的Cookbook"""
self.create_cookbook_structure()
self.generate_metadata()
self.generate_default_recipe(
config.get('packages', []),
config.get('services', {}),
config.get('templates', {})
)
# 使用示例
if __name__ == '__main__':
# 配置
config = {
'packages': ['nginx', 'php-fpm', 'mysql-server'],
'services': {
'nginx': {
'actions': ['enable', 'start'],
'notifies': [
{'action': 'reload', 'resource': 'service[php-fpm]'}
]
},
'php-fpm': {
'actions': ['enable', 'start']
},
'mysql': {
'actions': ['enable', 'start']
}
},
'templates': {
'nginx': {
'path': '/etc/nginx/nginx.conf',
'owner': 'root',
'group': 'root',
'mode': '0644',
'variables': {
'server_name': 'example.com',
'document_root': '/var/www/html',
'port': 80
}
},
'php': {
'path': '/etc/php/7.4/fpm/pool.d/www.conf',
'owner': 'root',
'group': 'root',
'mode': '0644',
'variables': {
'user': 'www-data',
'group': 'www-data',
'listen_port': 9000
}
}
}
}
# 生成Cookbook
generator = ChefCookbookGenerator('web_cookbook', './cookbooks')
generator.generate(config)
print("Chef Cookbook 生成完成!")
print(f"路径: ./cookbooks/web_cookbook")
使用建议
-
选择合适的工具:
- 简单配置:使用字符串格式化
- 复杂配置:使用Jinja2模板
- 需要代码逻辑:使用面向对象方式
-
模板管理:
- 将常用的配置模板保存为文件
- 支持变量替换和条件逻辑
-
错误处理:
def safe_generate_chef_config(config_data): """安全的配置生成函数""" try: # 验证配置数据 if not config_data.get('name'): raise ValueError("Cookbook name is required") # 生成配置 chef_code = generate_config(config_data) # 验证生成的代码语法 # (可以集成Chef验证工具) return chef_code except Exception as e: print(f"生成配置失败: {e}") return None -
集成测试:
def test_generated_config(): """测试生成的配置""" test_config = { 'package_name': 'test-package', 'service_name': 'test-service' } result = generate_chef_config(test_config) # 验证配置包含必要元素 assert 'package' in result assert 'service' in result assert 'end' in result print("测试通过!")
这种方法可以自动化生成大量Chef配置,特别适合管理多个环境或需要批量生成配置文件的情况。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播