You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 22:40:59