Skip to content

Commit ce54130

Browse files
author
DEFERME Bert
committed
Zabbix role (and role rules) provider
1 parent a048911 commit ce54130

File tree

2 files changed

+223
-0
lines changed

2 files changed

+223
-0
lines changed
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../zabbix'
4+
Puppet::Type.type(:zabbix_role).provide(:ruby, parent: Puppet::Provider::Zabbix) do
5+
confine feature: :zabbixapi
6+
7+
def initialize(value = {})
8+
super(value)
9+
@property_flush = {}
10+
end
11+
12+
def get_id(rolename)
13+
zbx.roles.get_id(name: rolename)
14+
end
15+
16+
def get_role_by_name(name)
17+
api_role = zbx.roles.get_raw(output: 'extend', selectRules: 'extend', filter: { name: name })
18+
if api_role.empty?
19+
nil
20+
else
21+
{
22+
name: api_role[0]['name'],
23+
type: api_role[0]['type'],
24+
readonly: api_role[0]['readonly'],
25+
rules: api_role[0]['rules'],
26+
}
27+
end
28+
end
29+
30+
def role
31+
@role ||= get_role_by_name(@resource[:name])
32+
@role
33+
end
34+
35+
attr_writer :role
36+
37+
def name
38+
role[:name]
39+
end
40+
41+
def name=(value)
42+
@property_flush[:name] = value
43+
end
44+
45+
def type
46+
role[:type]
47+
end
48+
49+
def type=(value)
50+
@property_flush[:type] = value
51+
end
52+
53+
def readonly
54+
role[:readonly]
55+
end
56+
57+
def readonly=(value)
58+
@property_flush[:readonly] = value
59+
end
60+
61+
def rules
62+
role[:rules]
63+
end
64+
65+
def rules=(hash)
66+
@property_flush[:rules] = hash
67+
end
68+
69+
# Defining all rules is cumbersome, this allows for defining just the needed rules, keeping all others to be the zabbix default
70+
def check_rules
71+
# Merge 'IS' (role[:rules]) with 'SHOULD' (resource[:rules])
72+
merged = role[:rules].merge(@resource[:rules]) do |_key, oldval, newval|
73+
if oldval.is_a?(Array)
74+
# structure:
75+
# ui => [ {"name" => "something", value => "something"} ]
76+
# In case of an array we want uniqueness by hash-name with 'newval' taking precedence
77+
# we also sort by hash-name to making comparing easy
78+
(newval + oldval).uniq { |h| h['name'] }.sort_by { |h| h['name'] }
79+
else
80+
# not an array: use the new value
81+
newval
82+
end
83+
end
84+
# make sure the 'IS' (role[:rules]) is sorted to make comparing easy
85+
is_sorted = role[:rules].map { |k, v| v.is_a?(Array) ? [k, v.sort_by { |h| h['name'] }] : [k, v] }.to_h
86+
# if merged equals is_sorted it means that 'should' is contained in 'in' and no action is needed
87+
# otherwise the value is either wrong or missing so action is needed
88+
merged == is_sorted
89+
end
90+
91+
def flush
92+
if @property_flush[:ensure] == :absent
93+
delete_role
94+
return
95+
end
96+
97+
update_role unless @property_flush.empty?
98+
end
99+
100+
def update_role
101+
zbx.query(
102+
method: 'role.update',
103+
params: @property_flush.merge({ roleid: get_id(@resource[:name]) })
104+
)
105+
end
106+
107+
def delete_role
108+
zbx.roles.delete(get_id(@resource[:name]))
109+
end
110+
111+
def create
112+
params = {}
113+
params[:name] = @resource[:name]
114+
params[:type] = @resource[:type]
115+
params[:readonly] = @resource[:readonly] unless @resource[:readonly].nil?
116+
params[:rules] = @resource[:rules] unless @resource[:rules].nil?
117+
118+
zbx.roles.create(params)
119+
end
120+
121+
def exists?
122+
role
123+
end
124+
125+
def destroy
126+
@property_flush[:ensure] = :absent
127+
end
128+
end

lib/puppet/type/zabbix_role.rb

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# frozen_string_literal: true
2+
3+
Puppet::Type.newtype(:zabbix_role) do
4+
@doc = %q("Manage zabbix role objects
5+
6+
zabbix_role { 'My custom role':
7+
ensure => present,
8+
type => 'Admin',
9+
readonly => false,
10+
rules => {
11+
'ui'=> [
12+
{
13+
'name' => 'configuration.actions',
14+
'status' => '1'
15+
},
16+
{
17+
'name' => 'configuration.discovery',
18+
'status'=>'0'
19+
},
20+
],
21+
'ui.default_access' => '1',
22+
'services.read.mode' => '1',
23+
'services.write.mode' => '0',
24+
'modules.default_access' => '0',
25+
'api.access' => '0',
26+
}
27+
}")
28+
29+
ensurable do
30+
defaultvalues
31+
defaultto :present
32+
end
33+
34+
newparam(:name, namevar: true) do
35+
desc 'the name of the role'
36+
validate do |value|
37+
raise ArgumentError, "role must be a valid string, \"#{value}\" is not" unless value.is_a?(String)
38+
end
39+
end
40+
41+
newproperty(:type) do
42+
desc 'role type'
43+
newvalues('User', 'Admin', 'Super admin')
44+
defaultto 'User'
45+
46+
type_values = {
47+
'User' => 1,
48+
'Admin' => 2,
49+
'Super admin' => 3,
50+
}
51+
52+
munge do |value|
53+
type_values[value]
54+
end
55+
end
56+
57+
newproperty(:readonly, boolean: true) do
58+
desc 'Whether the role is readonly'
59+
newvalues(true, false)
60+
defaultto false
61+
munge do |value|
62+
value ? 1 : 0
63+
end
64+
end
65+
66+
newproperty(:rules) do
67+
desc 'The role rules'
68+
69+
def insync?(_is)
70+
provider.check_rules
71+
end
72+
73+
def change_to_s(currentvalue, newvalue)
74+
md5_cur = Digest::MD5.hexdigest currentvalue.to_s
75+
md5_new = Digest::MD5.hexdigest newvalue.to_s
76+
Puppet.debug("OLD rules: #{currentvalue}")
77+
Puppet.debug("NEW rules: #{newvalue}")
78+
"changed #{md5_cur} to #{md5_new}"
79+
end
80+
81+
def is_to_s(currentvalue)
82+
Digest::MD5.hexdigest currentvalue.to_s
83+
end
84+
85+
def should_to_s(newvalue)
86+
Digest::MD5.hexdigest newvalue.to_s
87+
end
88+
89+
validate do |value|
90+
raise ArgumentError, 'rules must be a hash' unless value.is_a?(Hash)
91+
end
92+
end
93+
94+
autorequire(:file) { '/etc/zabbix/api.conf' }
95+
end

0 commit comments

Comments
 (0)