Ruby nil:NilClass 的未定义方法“[]”

Ruby undefined method `[]' for nil:NilClass

我正在尝试让 nagios 检查 BBU(电池备份单元),我有一个名为 check_bbu

的 ruby 脚本
#!/usr/bin/ruby
require 'json'

output = %x{/usr/sbin/storcli /c0/bbu show j}

begin
        j = JSON.parse(output)
        result = j["Controllers"][0]["Command Status"]["Status"]
        status = j["Controllers"][0]["Response Data"]["BBU_Info"][0]["State"]
rescue Exception => e
        puts "CRITICAL: error reading BBU status: #{e}"
        exit 2
end

if result != 'Success'
        puts "CRITICAL: command not successful, result: #{result}"
        exit 2
end

if status != 'Optimal'
        puts "CRITICAL: BBU not optimal, status is #{status}"
        exit 2
end

puts "OK: BBU is optimal"

但是当我 运行 这个插件时,我遇到了以下错误,

$ ./check_nrpe -u -t 30 -H foo.example.com -c check_bbu
CRITICAL: error reading BBU status: undefined method `[]' for nil:NilClass

我做错了什么?

您的代码似乎在

中断
j = JSON.parse(output)
result = j["Controllers"][0]["Command Status"]["Status"]
status = j["Controllers"][0]["Response Data"]["BBU_Info"][0]["State"]

你应该检查哪一行

  1. j == nil,你想要j["Controllers"]
  2. result = j["Controllers"][0]["Command Status"]["Status"]
  3. status = j["Controllers"][0]["Response Data"]["BBU_Info"][0]["State"]

导致 undefined method '[]' for nil:NilClass 首先显示 j 值,并确保 json 格式与您的代码匹配。

j = JSON.parse(output)
p j # display value

更新:

您的 json 格式应与您的代码匹配,否则会引发错误。

例如:

{
  "Controllers": [
    {
      "Commandddd Status": { # format not match
        "Status": "success"
      }
    }
  ]
}

# code and json format not match
j["Controllers"][0]["Command Status"] # nil

j["Controllers"][0]["Command Status"]["Status"]
=> nil["Status"] #  boom!

例如我的评论,假设我们有正确的 JSON:

j = {"Controllers" => [{"Comand Status" => {"status" => 'ok'}}]}
=> {"Controllers"=>[{"Comand Status"=>{"status"=>"ok"}}]} 

所以通过输入第一行,应该 return 正确的结果:

> j["Controllers"][0]["Comand Status"]["status"]
=> "ok" 

但是也有可能写错JSON,例如:

j_e = {"Controllers" => []}

所以现在是 return 错误:

>j_e["Controllers"][0]["Comand Status"]["status"]
NoMethodError: undefined method `[]' for nil:NilClass

要解决它,你可以使用类似的东西:

def try data, keys # there we take arguments: data == j, and keys == array with keys
  return data if data.nil? # there we check: if data, that we send == nil, for example j = nil, array = ['first', etc..] we should stop this method and return nil as result
  value = data[keys.shift] # on this line we try to get some data from j ##keys.shift will delete first element from array that we send to this method and return as `key` for `data`, for example data['Controllers'] so keys now will looks like: [0, 'Comand Status', 'status']
  unless keys.empty? #on this line we check if on the pred line we was used the last key and keys now looks like: [] we: *return value and if it's not empty we just **call this method 1 more time
    try(value, keys) #**value = [{"Comand Status" => {"status" => 'ok'}}] and keys = [0, 'Comand Status', 'status']
  else
    value #*nil or value
  end
end



j = {"Controllers"=>[{"Comand Status"=>{"status"=>"ok"}}]}
try(j, ['Controllers', 0, 'Comand Status', 'status'])
>'ok'
try j, ['Controllers', 1, 'Comand Status', 'status']
> nil

在您的代码中,这应该如下所示:

require 'json'

def try data, keys
  return data if data.nil?
  value = data[keys.shift]  
  unless keys.empty?
    try(value, keys)
  else
    value
  end
end


output = %x{/usr/sbin/storcli /c0/bbu show j}
begin
  j = JSON.parse(output)
  result = try(j, ["Controllers", 0, "Command Status", "Status"])
  status = try(j, ["Controllers", 0, "Response Data", "BBU_Info", 0, "State"])
rescue Exception => e
  puts "CRITICAL: error reading BBU status: #{e}"
  exit 2
end

if result != 'Success'
  puts "CRITICAL: command not successful, result: #{result}"
  exit 2
end

if status != 'Optimal'
  puts "CRITICAL: BBU not optimal, status is #{status}"
  exit 2
end

puts "OK: BBU is optimal"

此外,对于 Ruby 2.3.0+

简单多了,只是:

j.dig("Controllers", 0, "Comand Status", "status")