]>
git.proxmox.com Git - pmg-api.git/blob - src/PMG/API2/Nodes.pm
259f8f3992572b653546fc9c14220450706001d8
1 package PMG
::API2
::NodeInfo
;
5 use Time
::Local
qw(timegm_nocheck);
11 use PVE
::JSONSchema
qw(get_standard_option);
12 use PMG
::RESTEnvironment
;
19 use PMG
::API2
::Subscription
;
22 use PMG
::API2
::Services
;
23 use PMG
::API2
::Network
;
24 use PMG
::API2
::ClamAV
;
25 use PMG
::API2
::SpamAssassin
;
26 use PMG
::API2
::Postfix
;
27 use PMG
::API2
::MailTracker
;
28 use PMG
::API2
::Backup
;
29 use PMG
::API2
::PBS
::Job
;
31 use base
qw(PVE::RESTHandler);
33 __PACKAGE__-
>register_method ({
34 subclass
=> "PMG::API2::Postfix",
38 __PACKAGE__-
>register_method ({
39 subclass
=> "PMG::API2::ClamAV",
43 __PACKAGE__-
>register_method ({
44 subclass
=> "PMG::API2::SpamAssassin",
45 path
=> 'spamassassin',
48 __PACKAGE__-
>register_method ({
49 subclass
=> "PMG::API2::Network",
53 __PACKAGE__-
>register_method ({
54 subclass
=> "PMG::API2::Tasks",
58 __PACKAGE__-
>register_method ({
59 subclass
=> "PMG::API2::Services",
63 __PACKAGE__-
>register_method ({
64 subclass
=> "PMG::API2::Subscription",
65 path
=> 'subscription',
68 __PACKAGE__-
>register_method ({
69 subclass
=> "PMG::API2::APT",
73 __PACKAGE__-
>register_method ({
74 subclass
=> "PMG::API2::MailTracker",
78 __PACKAGE__-
>register_method ({
79 subclass
=> "PMG::API2::Backup",
83 __PACKAGE__-
>register_method ({
84 subclass
=> "PMG::API2::PBS::Job",
88 __PACKAGE__-
>register_method ({
92 permissions
=> { user
=> 'all' },
93 description
=> "Node index.",
95 additionalProperties
=> 0,
97 node
=> get_standard_option
('pve-node'),
106 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
113 { name
=> 'backup' },
115 { name
=> 'clamav' },
116 { name
=> 'spamassassin' },
117 { name
=> 'postfix' },
118 { name
=> 'services' },
119 { name
=> 'syslog' },
120 { name
=> 'journal' },
122 { name
=> 'tracker' },
124 { name
=> 'report' },
125 { name
=> 'status' },
126 { name
=> 'subscription' },
127 { name
=> 'termproxy' },
128 { name
=> 'rrddata' },
134 __PACKAGE__-
>register_method({
140 permissions
=> { check
=> [ 'admin', 'audit' ] },
141 description
=> "Gather various system information about a node",
143 additionalProperties
=> 0,
145 node
=> get_standard_option
('pve-node'),
152 return PMG
::Report
::generate
();
155 __PACKAGE__-
>register_method({
159 protected
=> 1, # fixme: can we avoid that?
161 permissions
=> { check
=> [ 'admin', 'audit' ] },
162 description
=> "Read node RRD statistics",
164 additionalProperties
=> 0,
166 node
=> get_standard_option
('pve-node'),
168 description
=> "Specify the time frame you are interested in.",
170 enum
=> [ 'hour', 'day', 'week', 'month', 'year' ],
173 description
=> "The RRD consolidation function",
175 enum
=> [ 'AVERAGE', 'MAX' ],
190 return PMG
::Utils
::create_rrd_data
(
191 "pmg-node-v1.rrd", $param->{timeframe
}, $param->{cf
});
195 __PACKAGE__-
>register_method({
199 description
=> "Read system log",
202 permissions
=> { check
=> [ 'admin', 'audit' ] },
204 additionalProperties
=> 0,
206 node
=> get_standard_option
('pve-node'),
219 pattern
=> '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$',
220 description
=> "Display all log since this date-time string.",
225 pattern
=> '^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$',
226 description
=> "Display all log until this date-time string.",
230 description
=> "Service ID",
243 description
=> "Line number",
247 description
=> "Line text",
256 my $restenv = PMG
::RESTEnvironment-
>get();
258 my $service = $param->{service
};
259 $service = PMG
::Utils
::lookup_real_service_name
($service)
262 my ($count, $lines) = PVE
::Tools
::dump_journal
(
263 $param->{start
}, $param->{limit
},
264 $param->{since
}, $param->{'until'}, $service);
266 $restenv->set_result_attrib('total', $count);
271 __PACKAGE__-
>register_method({
275 description
=> "Read Journal",
277 permissions
=> { check
=> [ 'admin', 'audit' ] },
280 additionalProperties
=> 0,
282 node
=> get_standard_option
('pve-node'),
284 description
=> "Display all log since this UNIX epoch. Conflicts with 'startcursor'.",
290 description
=> "Display all log until this UNIX epoch. Conflicts with 'endcursor'.",
296 description
=> "Limit to the last X lines. Conflicts with a range.",
302 description
=> "Start after the given Cursor. Conflicts with 'since'.",
307 description
=> "End before the given Cursor. Conflicts with 'until'.",
322 my $cmd = ["/usr/bin/mini-journalreader"];
323 push @$cmd, '-n', $param->{lastentries
} if $param->{lastentries
};
324 push @$cmd, '-b', $param->{since
} if $param->{since
};
325 push @$cmd, '-e', $param->{until} if $param->{until};
326 push @$cmd, '-f', $param->{startcursor
} if $param->{startcursor
};
327 push @$cmd, '-t', $param->{endcursor
} if $param->{endcursor
};
330 my $parser = sub { push @$lines, shift };
332 PVE
::Tools
::run_command
($cmd, outfunc
=> $parser);
338 __PACKAGE__-
>register_method ({
342 permissions
=> { check
=> [ 'admin' ] },
344 description
=> "Creates a Terminal proxy.",
346 additionalProperties
=> 0,
348 node
=> get_standard_option
('pve-node'),
351 description
=> "Run 'apt-get dist-upgrade' instead of normal shell.",
358 additionalProperties
=> 0,
360 user
=> { type
=> 'string' },
361 ticket
=> { type
=> 'string' },
362 port
=> { type
=> 'integer' },
363 upid
=> { type
=> 'string' },
369 my $node = $param->{node
};
371 if ($node ne PVE
::INotify
::nodename
()) {
372 die "termproxy to remote node not implemented";
375 my $authpath = "/nodes/$node";
377 my $restenv = PMG
::RESTEnvironment-
>get();
378 my $user = $restenv->get_user();
380 raise_perm_exc
('user != root@pam') if $param->{upgrade
} && $user ne 'root@pam';
382 my $ticket = PMG
::Ticket
::assemble_vnc_ticket
($user, $authpath);
384 my $family = PVE
::Tools
::get_host_address_family
($node);
385 my $port = PVE
::Tools
::next_vnc_port
($family);
389 if ($user eq 'root@pam') {
390 if ($param->{upgrade
}) {
391 my $upgradecmd = "pmgupgrade --shell";
392 # $upgradecmd = PVE::Tools::shellquote($upgradecmd) if $remip;
393 $shcmd = [ '/bin/bash', '-c', $upgradecmd ];
395 $shcmd = [ '/bin/login', '-f', 'root' ];
398 $shcmd = [ '/bin/login' ];
401 my $cmd = ['/usr/bin/termproxy', $port, '--path', $authpath,
407 syslog
('info', "starting termproxy $upid\n");
409 my $cmdstr = join (' ', @$cmd);
410 syslog
('info', "launch command: $cmdstr");
412 PVE
::Tools
::run_command
($cmd);
417 my $upid = $restenv->fork_worker('termproxy', "", $user, $realcmd);
419 PVE
::Tools
::wait_for_vnc_port
($port);
429 __PACKAGE__-
>register_method({
430 name
=> 'vncwebsocket',
431 path
=> 'vncwebsocket',
433 permissions
=> { check
=> [ 'admin' ] },
434 description
=> "Opens a weksocket for VNC traffic.",
436 additionalProperties
=> 0,
438 node
=> get_standard_option
('pve-node'),
440 description
=> "Ticket from previous call to vncproxy.",
445 description
=> "Port number returned by previous vncproxy call.",
455 port
=> { type
=> 'string' },
461 my $authpath = "/nodes/$param->{node}";
463 my $restenv = PMG
::RESTEnvironment-
>get();
464 my $user = $restenv->get_user();
466 PMG
::Ticket
::verify_vnc_ticket
($param->{vncticket
}, $user, $authpath);
468 my $port = $param->{port
};
470 return { port
=> $port };
473 __PACKAGE__-
>register_method({
477 description
=> "Read DNS settings.",
479 permissions
=> { check
=> [ 'admin', 'audit' ] },
481 additionalProperties
=> 0,
483 node
=> get_standard_option
('pve-node'),
488 additionalProperties
=> 0,
491 description
=> "Search domain for host-name lookup.",
496 description
=> 'First name server IP address.',
501 description
=> 'Second name server IP address.',
506 description
=> 'Third name server IP address.',
515 my $res = PVE
::INotify
::read_file
('resolvconf');
520 __PACKAGE__-
>register_method({
521 name
=> 'update_dns',
524 description
=> "Write DNS settings.",
528 additionalProperties
=> 0,
530 node
=> get_standard_option
('pve-node'),
532 description
=> "Search domain for host-name lookup.",
536 description
=> 'First name server IP address.',
537 type
=> 'string', format
=> 'ip',
541 description
=> 'Second name server IP address.',
542 type
=> 'string', format
=> 'ip',
546 description
=> 'Third name server IP address.',
547 type
=> 'string', format
=> 'ip',
552 returns
=> { type
=> "null" },
556 PVE
::INotify
::update_file
('resolvconf', $param);
562 __PACKAGE__-
>register_method({
566 description
=> "Read server time and time zone settings.",
568 permissions
=> { check
=> [ 'admin', 'audit' ] },
570 additionalProperties
=> 0,
572 node
=> get_standard_option
('pve-node'),
577 additionalProperties
=> 0,
580 description
=> "Time zone",
584 description
=> "Seconds since 1970-01-01 00:00:00 UTC.",
586 minimum
=> 1297163644,
589 description
=> "Seconds since 1970-01-01 00:00:00 (local time)",
591 minimum
=> 1297163644,
599 my $ltime = timegm_nocheck
(localtime($ctime));
601 timezone
=> PVE
::INotify
::read_file
('timezone'),
609 __PACKAGE__-
>register_method({
610 name
=> 'set_timezone',
613 description
=> "Set time zone.",
617 additionalProperties
=> 0,
619 node
=> get_standard_option
('pve-node'),
621 description
=> "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.",
626 returns
=> { type
=> "null" },
630 PVE
::INotify
::write_file
('timezone', $param->{timezone
});
635 __PACKAGE__-
>register_method({
639 description
=> "Read server status. This is used by the cluster manager to test the node health.",
641 permissions
=> { check
=> [ 'admin', 'qmanager', 'audit' ] },
644 additionalProperties
=> 0,
646 node
=> get_standard_option
('pve-node'),
651 additionalProperties
=> 1,
654 description
=> "Seconds since 1970-01-01 00:00:00 UTC.",
656 minimum
=> 1297163644,
659 description
=> "The uptime of the system in seconds.",
664 description
=> "Database is synced with other nodes.",
672 my $restenv = PMG
::RESTEnvironment-
>get();
673 my $cinfo = $restenv->{cinfo
};
677 my $res = { time => $ctime, insync
=> 1 };
679 my $si = PMG
::DBTools
::cluster_sync_status
($cinfo);
680 foreach my $cid (keys %$si) {
681 my $lastsync = $si->{$cid};
682 my $sdiff = $ctime - $lastsync;
683 $sdiff = 0 if $sdiff < 0;
684 $res->{insync
} = 0 if $sdiff > (60*3);
687 my ($uptime, $idle) = PVE
::ProcFSTools
::read_proc_uptime
();
688 $res->{uptime
} = $uptime;
690 my ($avg1, $avg5, $avg15) = PVE
::ProcFSTools
::read_loadavg
();
691 $res->{loadavg
} = [ $avg1, $avg5, $avg15];
693 my ($sysname, $nodename, $release, $version, $machine) = POSIX
::uname
();
695 $res->{kversion
} = "$sysname $release $version";
697 $res->{cpuinfo
} = PVE
::ProcFSTools
::read_cpuinfo
();
699 my $stat = PVE
::ProcFSTools
::read_proc_stat
();
700 $res->{cpu
} = $stat->{cpu
};
701 $res->{wait} = $stat->{wait};
703 my $meminfo = PVE
::ProcFSTools
::read_meminfo
();
705 free
=> $meminfo->{memfree
},
706 total
=> $meminfo->{memtotal
},
707 used
=> $meminfo->{memused
},
711 free
=> $meminfo->{swapfree
},
712 total
=> $meminfo->{swaptotal
},
713 used
=> $meminfo->{swapused
},
716 $res->{pmgversion
} = PMG
::pmgcfg
::package() . "/" .
717 PMG
::pmgcfg
::version_text
();
719 my $dinfo = df
('/', 1); # output is bytes
722 total
=> $dinfo->{blocks
},
723 avail
=> $dinfo->{bavail
},
724 used
=> $dinfo->{used
},
725 free
=> $dinfo->{blocks
} - $dinfo->{used
},
728 if (my $subinfo = PVE
::INotify
::read_file
('subscription')) {
729 if (my $level = $subinfo->{level
}) {
730 $res->{level
} = $level;
737 __PACKAGE__-
>register_method({
741 permissions
=> { check
=> [ 'admin' ] },
743 description
=> "Reboot or shutdown a node.",
746 additionalProperties
=> 0,
748 node
=> get_standard_option
('pve-node'),
750 description
=> "Specify the command.",
752 enum
=> [qw(reboot shutdown)],
756 returns
=> { type
=> "null" },
760 if ($param->{command
} eq 'reboot') {
761 system ("(sleep 2;/sbin/reboot)&");
762 } elsif ($param->{command
} eq 'shutdown') {
763 system ("(sleep 2;/sbin/poweroff)&");
769 package PMG
::API2
::Nodes
;
774 use PVE
::RESTHandler
;
775 use PVE
::JSONSchema
qw(get_standard_option);
777 use PMG
::RESTEnvironment
;
779 use base
qw(PVE::RESTHandler);
781 __PACKAGE__-
>register_method ({
782 subclass
=> "PMG::API2::NodeInfo",
786 __PACKAGE__-
>register_method ({
790 permissions
=> { user
=> 'all' },
791 description
=> "Cluster node index.",
793 additionalProperties
=> 0,
802 links
=> [ { rel
=> 'child', href
=> "{node}" } ],
807 my $nodename = PVE
::INotify
::nodename
();
809 my $res = [ { node
=> $nodename } ];
813 $done->{$nodename} = 1;
815 my $restenv = PMG
::RESTEnvironment-
>get();
816 my $cinfo = $restenv->{cinfo
};
818 foreach my $ni (values %{$cinfo->{ids
}}) {
819 push @$res, { node
=> $ni->{name
} } if !$done->{$ni->{name
}};
820 $done->{$ni->{name
}} = 1;