Skip to content

Commit f125061

Browse files
committed
Improve zabbix_proxy type
It is now possible to manage individual `zabbix_proxy` resource properties. The type has been improved to do enhanced validation of all properties. Switching between active and passive proxies (and vice-versa) is now supported.
1 parent f7c1060 commit f125061

File tree

4 files changed

+315
-53
lines changed

4 files changed

+315
-53
lines changed

lib/puppet/provider/zabbix.rb

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,6 @@ def check_host(host)
7676
false
7777
end
7878

79-
# Check if proxy exists. When error raised, return false.
80-
def check_proxy(host)
81-
zbx.proxies.get_id(host: host)
82-
rescue Puppet::ExecutionFailure
83-
false
84-
end
85-
8679
# Get the template id from the name.
8780
def get_template_id(zbx, template)
8881
return template if a_number?(template)

lib/puppet/provider/zabbix_proxy/ruby.rb

Lines changed: 171 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,16 @@
22
Puppet::Type.type(:zabbix_proxy).provide(:ruby, parent: Puppet::Provider::Zabbix) do
33
confine feature: :zabbixapi
44

5-
def self.instances
6-
proxies = zbx.query(
7-
method: 'proxy.get',
8-
params: {
9-
output: 'extend',
10-
selectInterface: %w[interfaceid type main ip port useip]
11-
}
12-
)
5+
def initialize(value = {})
6+
super(value)
7+
@property_flush = {}
8+
end
9+
10+
mk_resource_methods
1311

12+
def self.instances
1413
proxies.map do |p|
15-
# p['interface'] is an Array if the host is a active proxy
16-
# p['interface'] is a Hash if the host is a passive proxy
17-
new(
18-
ensure: :present,
19-
name: p['host'],
20-
ipaddress: p['interface'].is_a?(Hash) ? p['interface']['ip'] : nil,
21-
use_ip: p['interface'].is_a?(Hash) ? p['interface']['use_ip'] : nil,
22-
mode: p['status'].to_i - 5,
23-
port: p['interface'].is_a?(Hash) ? p['interface']['port'] : nil
24-
)
14+
new(proxy_properties_hash(p))
2515
end
2616
end
2717

@@ -33,39 +23,178 @@ def self.prefetch(resources)
3323
end
3424
end
3525

26+
def self.proxies(proxyids = nil)
27+
zbx.query(
28+
method: 'proxy.get',
29+
params: {
30+
proxyids: proxyids,
31+
output: 'extend',
32+
selectInterface: %w[interfaceid type main ip port useip]
33+
}.compact
34+
)
35+
end
36+
37+
# Convert from proxy hash returned by API into a resource properties hash
38+
def self.proxy_properties_hash(p)
39+
{
40+
ensure: :present,
41+
# Proxy object properties
42+
proxyid: p['proxyid'].to_i,
43+
name: p['host'],
44+
mode: status_to_mode(p['status']),
45+
# Proxy Interface object properties
46+
interfaceid: p['interface'].is_a?(Hash) ? p['interface']['interfaceid'] : nil,
47+
ipaddress: p['interface'].is_a?(Hash) ? p['interface']['ip'] : nil,
48+
use_ip: if p['interface'].is_a?(Hash) then p['interface']['useip'] == '1' ? :true : :false end,
49+
port: p['interface'].is_a?(Hash) ? p['interface']['port'].to_i : nil
50+
}
51+
end
52+
3653
def create
37-
# Set some vars
38-
host = @resource[:hostname]
39-
ipaddress = @resource[:ipaddress]
40-
41-
# Normally 0 is active and 1 is passive, in the API, its 5 and 6
42-
proxy_mode = @resource[:mode] + 5
43-
44-
use_ip = @resource[:use_ip]
45-
port = @resource[:port]
46-
47-
# Check if we need to connect via ip or fqdn
48-
use_ip = use_ip ? 1 : 0
49-
50-
zbx.proxies.create_or_update(
51-
host: host,
52-
status: proxy_mode,
53-
interfaces: [
54-
ip: ipaddress,
55-
dns: host,
56-
useip: use_ip,
57-
port: port
58-
]
54+
mode = @resource[:mode] || :active
55+
56+
if mode == :passive
57+
useip = if @resource[:use_ip].nil?
58+
1
59+
else
60+
@resource[:use_ip] == :true ? 1 : 0
61+
end
62+
interface = {
63+
ip: @resource[:ipaddress] || '127.0.0.1',
64+
dns: @resource[:hostname],
65+
useip: useip,
66+
port: @resource[:port] || 10_051
67+
}
68+
else
69+
interface = nil
70+
end
71+
72+
zbx.proxies.create(
73+
{
74+
host: @resource[:hostname],
75+
status: self.class.mode_to_status(mode),
76+
interface: interface
77+
}.compact
5978
)
79+
@property_flush[:created] = true
6080
end
6181

6282
def exists?
63-
check_proxy(@resource[:hostname])
83+
@property_hash[:ensure] == :present
6484
end
6585

6686
def destroy
6787
zbx.proxies.delete([zbx.proxies.get_id(host: @resource[:hostname])].flatten)
88+
@property_flush[:destroyed] = true
6889
end
6990

70-
mk_resource_methods
91+
def flush
92+
update unless @property_flush[:created] || @property_flush[:destroyed]
93+
94+
# Update @property_hash so that the output of puppet resource is correct
95+
if @property_flush[:destroyed]
96+
@property_hash.clear
97+
@property_hash[:ensure] = :absent
98+
else
99+
proxy = self.class.proxies(@property_hash[:proxyid]).find { |p| p['host'] == @resource[:hostname] }
100+
@property_hash = self.class.proxy_properties_hash(proxy)
101+
end
102+
end
103+
104+
def mode=(value)
105+
@property_flush[:mode] = value
106+
end
107+
108+
def change_to_passive_proxy
109+
Puppet.debug("We're changing to a passive proxy")
110+
# We need to call zbx.proxies.update with an `interface` hash.
111+
112+
useip = if @resource[:use_ip].nil?
113+
1 # Default to true
114+
else
115+
@resource[:use_ip] == :true ? 1 : 0
116+
end
117+
118+
interface = {
119+
ip: @resource[:ipaddress] || @property_hash[:ipaddress] || '127.0.0.1',
120+
dns: @resource[:hostname], # This is the namevar and will always exist
121+
useip: useip,
122+
port: @resource[:port] || @property_hash[:port] || 10_051
123+
}
124+
125+
zbx.proxies.update(
126+
{
127+
proxyid: @property_hash[:proxyid],
128+
status: self.class.mode_to_status(:passive),
129+
interface: interface
130+
},
131+
true
132+
)
133+
end
134+
135+
def change_to_active_proxy
136+
Puppet.debug("We're changing to an active proxy")
137+
zbx.proxies.update(
138+
{
139+
proxyid: @property_hash[:proxyid],
140+
status: self.class.mode_to_status(:active)
141+
},
142+
true
143+
)
144+
end
145+
146+
def update_interface_properties
147+
useip = if @resource[:use_ip].nil?
148+
nil # Don't provide a default. Keep use_ip unmanaged.
149+
else
150+
@resource[:use_ip] == :true ? 1 : 0
151+
end
152+
153+
interface = {
154+
interfaceid: @property_hash[:interfaceid],
155+
ip: @resource[:ipaddress],
156+
useip: useip,
157+
port: @resource[:port]
158+
}.compact
159+
160+
zbx.proxies.update(
161+
{
162+
proxyid: @property_hash[:proxyid],
163+
interface: interface
164+
},
165+
true
166+
)
167+
end
168+
169+
def update
170+
if @property_flush[:mode] == :passive
171+
change_to_passive_proxy
172+
return
173+
end
174+
175+
if @property_flush[:mode] == :active
176+
change_to_active_proxy
177+
return
178+
end
179+
180+
# At present, the only properties other than mode that can be updated are the interface properties applicable to passive proxies only.
181+
raise Puppet::Error, "Can't update proxy interface properties for an active proxy" unless @property_hash[:mode] == :passive
182+
update_interface_properties
183+
end
184+
185+
def self.status_to_mode(status)
186+
case status.to_i
187+
when 5
188+
:active
189+
when 6
190+
:passive
191+
else
192+
raise Puppet::Error, 'zabbix API returned invalid value for `status`'
193+
end
194+
end
195+
196+
def self.mode_to_status(mode)
197+
return 5 if mode == :active
198+
6
199+
end
71200
end

lib/puppet/type/zabbix_proxy.rb

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,91 @@
44
defaultto :present
55
end
66

7+
def munge_boolean_to_symbol(value)
8+
# insync? doesn't work with actual booleans
9+
# see https://tickets.puppetlabs.com/browse/PUP-2368
10+
value = value.downcase if value.respond_to? :downcase
11+
12+
case value
13+
when true, :true, 'true', :yes, 'yes'
14+
:true
15+
when false, :false, 'false', :no, 'no'
16+
:false
17+
else
18+
raise ArgumentError, 'expected a boolean value'
19+
end
20+
end
21+
22+
# Standard properties
723
newparam(:hostname, namevar: true) do
8-
desc 'FQDN of the machine.'
24+
desc 'FQDN of the proxy.'
25+
end
26+
27+
newproperty(:mode) do
28+
desc 'The kind of mode the proxy running. Active (0) or passive (1).'
29+
30+
newvalues(:active, :passive, 0, 1, '0', '1')
31+
32+
munge do |value|
33+
case value
34+
when 0, '0'
35+
:active
36+
when 1, '1'
37+
:passive
38+
else
39+
super(value)
40+
end
41+
end
42+
end
43+
44+
newproperty(:proxyid) do
45+
desc '(readonly) ID of the proxy'
46+
validate { |_val| raise Puppet::Error, 'proxyid is read-only' }
947
end
1048

49+
# Interface properties (applicable to passive proxies)
1150
newproperty(:ipaddress) do
1251
desc 'The IP address of the machine running zabbix proxy.'
52+
53+
validate do |value|
54+
require 'ipaddr'
55+
56+
begin
57+
IPAddr.new(value)
58+
rescue => e
59+
raise Puppet::Error, e.to_s
60+
end
61+
end
1362
end
1463

1564
newproperty(:use_ip) do
1665
desc 'Using ipadress instead of dns to connect. Is used by the zabbix-api command.'
17-
end
1866

19-
newproperty(:mode) do
20-
desc 'The kind of mode the proxy running. Active (0) or passive (1).'
67+
munge { |value| @resource.munge_boolean_to_symbol(value) }
2168
end
2269

2370
newproperty(:port) do
2471
desc 'The port that the zabbix proxy is listening on.'
72+
73+
validate do |value|
74+
if value.is_a?(String)
75+
raise Puppet::Error, 'invalid port' unless value =~ %r{^\d+$}
76+
raise Puppet::Error, 'invalid port' unless value.to_i.between?(1, 65_535)
77+
return
78+
end
79+
if value.is_a?(Integer)
80+
raise Puppet::Error, 'invalid port' unless value.between?(1, 65_535)
81+
return
82+
end
83+
raise Puppet::Error, 'invalid port'
84+
end
85+
86+
munge(&:to_i)
87+
end
88+
89+
newproperty(:interfaceid) do
90+
desc '(readonly) ID of the interface'
91+
validate { |_val| raise Puppet::Error, 'interfaceid is read-only' }
2592
end
2693

2794
autorequire(:file) { '/etc/zabbix/api.conf' }

0 commit comments

Comments
 (0)