express42 / zabbixapi

Ruby wrapper to Zabbix API
MIT License
132 stars 128 forks source link

get_id() is not specific enough for template items when doing create_or_update() #57

Closed jrbeilke closed 7 years ago

jrbeilke commented 7 years ago

We're using zabbixapi to keep our Zabbix templates in-sync and up-to-date, but we're having an issue when trying to use create_or_update() on templated items.

Here's the code we're using to create/update one of the items on our templates:

templateid = zabbixapi.templates.create_or_update(
  :host => 'zabbix-templates_aws_ec2-metadata',
  :groups => [:groupid => @zabbixapi.hostgroups.get_or_create(:name => 'zabbix-templates')]
)

zabbixapi.items.create_or_update(
  :name => 'ami-id',
  :description => 'Captures the AMI ID from AWS and adds it to the host inventory under the "OS (Short)" tag.',
  :key_ => 'curl[http://169.254.169.254/latest/meta-data/ami-id]',
  :delay => 60,
  :type => 7, #Zabbix agent (active)
  :value_type => 1, #Character
  :history => 7,
  :trends => 365,
  :inventory_link => 7, #OS (Short)
  :hostid => templateid,
  :applications => [@zabbixapi.applications.get_or_create(:name => 'EC2', :hostid => templateid)]
)

Looks like create_or_update() makes a call to get_id() to find the itemid, but the filter on that query is not specific enough to only pull the itemid attached to the template. Instead get_id() pulls the itemid from one of the hosts linked to the template instead, since the item gets copied to the hosts using that template.

  result = @client.api_request(
    :method => "#{method_name}.get",
    :params => {
      :filter => {
        indentify.to_sym => name
      },
      :output => [key, indentify]
    }
  )
  id = nil
  result.each { |item| id = item[key].to_i if item[indentify] == data[indentify.to_sym] }
  id
jrbeilke commented 7 years ago

So it's not just items that are affected by this, but anything that requires more than a single field to be identified properly in Zabbix when using templates, like:

The Graphs class already overrides create_or_update() to be more specific, so it seems like we need something similar added to the other classes.

def create_or_update(data)
  graphid = get_id(:name => data[:name], :templateid => data[:templateid])
  graphid ? _update(data.merge(:graphid => graphid)) : create(data)
end