Chef Cookbook中Ruby函数:为YUM仓库添加包排除规则报错解决
Chef Cookbook Ruby函数:为YUM仓库所有repo段添加包排除规则
先解决那个TypeError
你碰到的TypeError (can't convert Integer into Array),大概率是代码里把行号(整数类型)当成数组操作了——比如遍历行时误拿了索引值而非行内容,或者在数组插入/拼接时用错了变量类型。举个例子,如果写了lines[i] << 'exclude=...'但i是整数、lines[i]没取到正确的行字符串,就会触发这个错误。
正确的实现代码
下面是符合需求的Chef Ruby代码实现,用ruby_block资源执行(适合在Chef运行时处理文件修改):
ruby_block 'add_exclude_to_all_repos' do block do repo_file = '/etc/yum.repos.d/your-target-repo.repo' exclude_line = 'exclude=zabbix*' # 读取文件所有行,保留原换行符避免格式混乱 lines = File.readlines(repo_file, chomp: false) in_repo_section = false current_repo_lines = [] output_lines = [] lines.each do |line| # 识别repo段的起始标记 if line.strip.start_with?('[') && line.strip.end_with?(']') # 先处理上一个未完成的repo段 if in_repo_section # 检查当前段是否已有exclude规则 has_exclude = current_repo_lines.any? { |l| l.strip.start_with?('exclude=') } unless has_exclude # 找到段内最后一个非空行的位置 last_non_empty_idx = current_repo_lines.rindex { |l| !l.strip.empty? } if last_non_empty_idx current_repo_lines.insert(last_non_empty_idx + 1, "#{exclude_line}\n") else # 段内全是空行,直接把规则加在开头 current_repo_lines.unshift("#{exclude_line}\n") end end # 将处理好的段加入输出列表 output_lines.concat(current_repo_lines) current_repo_lines = [] end in_repo_section = true end # 收集当前repo段的行,非repo段的行直接加入输出 if in_repo_section current_repo_lines << line else output_lines << line end end # 处理最后一个repo段(循环结束后可能还有未处理的) if in_repo_section has_exclude = current_repo_lines.any? { |l| l.strip.start_with?('exclude=') } unless has_exclude last_non_empty_idx = current_repo_lines.rindex { |l| !l.strip.empty? } if last_non_empty_idx current_repo_lines.insert(last_non_empty_idx + 1, "#{exclude_line}\n") else current_repo_lines.unshift("#{exclude_line}\n") end end output_lines.concat(current_repo_lines) end # 将修改后的内容写回文件 File.write(repo_file, output_lines.join) end # 添加not_if条件,避免重复执行(当所有repo段都已有exclude规则时跳过) not_if do repo_file = '/etc/yum.repos.d/your-target-repo.repo' next false unless File.exist?(repo_file) lines = File.readlines(repo_file) in_repo = false all_repos_have_exclude = true current_repo_has_exclude = false lines.each do |line| if line.strip.start_with?('[') && line.strip.end_with?(']') in_repo = true current_repo_has_exclude = false elsif in_repo && line.strip.start_with?('exclude=') current_repo_has_exclude = true elsif in_repo && line.strip != '' && !line.start_with?('#') # 遇到repo段内的其他配置行,若还没找到exclude则标记为未满足 all_repos_have_exclude = false unless current_repo_has_exclude in_repo = false end end # 检查最后一个repo段的状态 all_repos_have_exclude && current_repo_has_exclude end end
代码说明
- 用
File.readlines(chomp: false)保留原文件的换行符,避免修改后格式错乱 - 逐行遍历识别
[repo]段的范围,分段处理确保每个repo段都被检查 - 对无exclude规则的段,精准插入到最后一个非空行之后,保持原文件格式整洁
- 通过
not_if条件判断是否需要执行,避免重复修改浪费资源
输入输出示例
输入文件(仅最后一段有exclude)
[repo1] name=Repo 1 baseurl=http://repo1.example.com enabled=1 [repo2] name=Repo 2 baseurl=http://repo2.example.com enabled=1 [repo3] name=Repo 3 baseurl=http://repo3.example.com enabled=1 exclude=zabbix*
输出文件(所有段都添加了exclude)
[repo1] name=Repo 1 baseurl=http://repo1.example.com enabled=1 exclude=zabbix* [repo2] name=Repo 2 baseurl=http://repo2.example.com enabled=1 exclude=zabbix* [repo3] name=Repo 3 baseurl=http://repo3.example.com enabled=1 exclude=zabbix*
内容的提问来源于stack exchange,提问作者ariva
相关产品推荐
相关产品推荐

