]>
Commit | Line | Data |
---|---|---|
eb32152f DM |
1 | package PVE::Status::Graphite; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
fa6f3716 | 5 | |
eb32152f | 6 | use PVE::Status::Plugin; |
2c927f11 | 7 | use IO::Socket::Timeout; |
eb32152f DM |
8 | |
9 | # example config (/etc/pve/status.cfg) | |
10 | #graphite: | |
58541b94 | 11 | # server test |
567bb543 | 12 | # port 2003 |
2c927f11 | 13 | # proto udp |
567bb543 | 14 | # path proxmox.mycluster |
eb32152f DM |
15 | # disable 0 |
16 | # | |
17 | ||
18 | use base('PVE::Status::Plugin'); | |
19 | ||
20 | sub type { | |
21 | return 'graphite'; | |
22 | } | |
23 | ||
24 | sub properties { | |
25 | return { | |
567bb543 | 26 | path => { |
5c90e08a | 27 | type => 'string', format => 'graphite-path', |
567bb543 | 28 | description => "root graphite path (ex: proxmox.mycluster.mykey)", |
eb32152f | 29 | }, |
2c927f11 MV |
30 | timeout => { |
31 | type => 'integer', | |
c44a0c01 | 32 | description => "graphite tcp socket timeout (default=1)", |
2c927f11 MV |
33 | optional => 1 |
34 | }, | |
35 | proto => { | |
36 | type => 'string', | |
37 | enum => ['udp', 'tcp'], | |
38 | description => "send graphite data using tcp or udp (default)", | |
39 | optional => 1, | |
40 | }, | |
eb32152f DM |
41 | }; |
42 | } | |
43 | ||
44 | sub options { | |
45 | return { | |
58541b94 | 46 | server => {}, |
567bb543 | 47 | port => { optional => 1 }, |
2c927f11 MV |
48 | proto => { optional => 1 }, |
49 | timeout => { optional => 1 }, | |
567bb543 | 50 | path => { optional => 1 }, |
eb32152f | 51 | disable => { optional => 1 }, |
5c90e08a | 52 | }; |
eb32152f DM |
53 | } |
54 | ||
5a5aed73 DC |
55 | # we do not want boolean/state information to export to graphite |
56 | my $key_blacklist = { | |
57 | 'template' => 1, | |
58 | 'pid' => 1, | |
59 | 'agent' => 1, | |
60 | 'serial' => 1, | |
61 | }; | |
62 | ||
eb32152f DM |
63 | # Plugin implementation |
64 | sub update_node_status { | |
567bb543 AD |
65 | my ($class, $plugin_config, $node, $data, $ctime) = @_; |
66 | ||
67 | write_graphite_hash($plugin_config, $data, $ctime, "nodes.$node"); | |
eb32152f | 68 | |
eb32152f DM |
69 | } |
70 | ||
71 | sub update_qemu_status { | |
09f19204 | 72 | my ($class, $plugin_config, $vmid, $data, $ctime, $nodename) = @_; |
567bb543 | 73 | write_graphite_hash($plugin_config, $data, $ctime, "qemu.$vmid"); |
eb32152f DM |
74 | } |
75 | ||
76 | sub update_lxc_status { | |
09f19204 | 77 | my ($class, $plugin_config, $vmid, $data, $ctime, $nodename) = @_; |
eb32152f | 78 | |
567bb543 | 79 | write_graphite_hash($plugin_config, $data, $ctime, "lxc.$vmid"); |
eb32152f DM |
80 | } |
81 | ||
82 | sub update_storage_status { | |
567bb543 AD |
83 | my ($class, $plugin_config, $nodename, $storeid, $data, $ctime) = @_; |
84 | ||
85 | write_graphite_hash($plugin_config, $data, $ctime, "storages.$nodename.$storeid"); | |
86 | } | |
87 | ||
88 | sub write_graphite_hash { | |
89 | my ($plugin_config, $d, $ctime, $object) = @_; | |
90 | ||
58541b94 | 91 | my $host = $plugin_config->{server}; |
dd4268e5 TL |
92 | my $port = $plugin_config->{port} || 2003; |
93 | my $path = $plugin_config->{path} // 'proxmox'; | |
94 | my $proto = $plugin_config->{proto} || 'udp'; | |
c44a0c01 | 95 | my $timeout = $plugin_config->{timeout} // 1; |
567bb543 AD |
96 | |
97 | my $carbon_socket = IO::Socket::IP->new( | |
5c90e08a DC |
98 | PeerAddr => $host, |
99 | PeerPort => $port, | |
2c927f11 MV |
100 | Proto => $proto, |
101 | Timeout => $timeout, | |
f014da61 | 102 | ) || die "couldn't create carbon socket [$host]:$port - $@\n"; |
567bb543 | 103 | |
2c927f11 MV |
104 | if ( $proto eq 'tcp' ) { |
105 | IO::Socket::Timeout->enable_timeouts_on($carbon_socket); | |
106 | $carbon_socket->read_timeout($timeout); | |
107 | $carbon_socket->write_timeout($timeout); | |
108 | } | |
567bb543 AD |
109 | write_graphite($carbon_socket, $d, $ctime, $path.".$object"); |
110 | ||
111 | $carbon_socket->close() if $carbon_socket; | |
eb32152f | 112 | |
eb32152f DM |
113 | } |
114 | ||
567bb543 AD |
115 | sub write_graphite { |
116 | my ($carbon_socket, $d, $ctime, $path) = @_; | |
117 | ||
118 | for my $key (keys %$d) { | |
119 | ||
5c90e08a DC |
120 | my $value = $d->{$key}; |
121 | my $oldpath = $path; | |
122 | $key =~ s/\./-/g; | |
123 | $path .= ".$key"; | |
567bb543 | 124 | |
5c90e08a DC |
125 | if ( defined $value ) { |
126 | if ( ref $value eq 'HASH' ) { | |
127 | write_graphite($carbon_socket, $value, $ctime, $path); | |
5a5aed73 | 128 | } elsif ($value =~ m/^[+-]?[0-9]*\.?[0-9]+$/ && |
5c90e08a | 129 | !$key_blacklist->{$key}) { |
5a5aed73 DC |
130 | $carbon_socket->send( "$path $value $ctime\n" ); |
131 | } else { | |
132 | # do not send blacklisted or non-numeric values | |
133 | } | |
5c90e08a DC |
134 | } |
135 | $path = $oldpath; | |
567bb543 AD |
136 | } |
137 | } | |
138 | ||
139 | PVE::JSONSchema::register_format('graphite-path', \&pve_verify_graphite_path); | |
140 | sub pve_verify_graphite_path { | |
141 | my ($path, $noerr) = @_; | |
142 | ||
143 | my $regex = "([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)"; | |
144 | ||
145 | if ($path !~ /^(${regex}\.)*${regex}$/) { | |
5c90e08a DC |
146 | return undef if $noerr; |
147 | die "value does not look like a valid graphite path\n"; | |
567bb543 AD |
148 | } |
149 | ||
150 | return $path; | |
151 | } | |
152 | ||
153 | ||
eb32152f | 154 | 1; |