FOSSology  4.4.0
Open Source License Compliance by Open Source Software
admin-dashboard-general.php
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2008-2013 Hewlett-Packard Development Company, L.P.
4  SPDX-FileCopyrightText: © 2015-2018 Siemens AG
5  SPDX-FileCopyrightText: © 2019 Orange
6 
7  SPDX-License-Identifier: GPL-2.0-only
8 */
9 
10 define("TITLE_DASHBOARD_GENERAL", _("Overview Dashboard"));
11 
13 
14 class dashboard extends FO_Plugin
15 {
16  public $pgVersion;
17 
19  private $dbManager;
20 
21  function __construct()
22  {
23  global $PG_CONN;
24  $this->Name = "dashboard";
25  $this->Title = TITLE_DASHBOARD_GENERAL;
26  $this->MenuList = "Admin::Dashboards::Overview";
27  $this->DBaccess = PLUGIN_DB_ADMIN;
28  parent::__construct();
29  $this->dbManager = $GLOBALS['container']->get('db.manager');
30  $this->pgVersion = pg_version($PG_CONN);
31  }
32 
37  function DatabaseContentsRow($TableName, $TableLabel, $fromRest = false)
38  {
39  $row = $this->dbManager->getSingleRow(
40  "select sum(reltuples) as val from pg_class where relname like $1 and reltype !=0",
41  array($TableName),
42  __METHOD__);
43  $item_count = $row['val'];
44 
45  $V = "<tr><td>$TableLabel</td>";
46  $V .= "<td align='right'>" . number_format($item_count,0,"",",") . "</td>";
47 
48  $LastVacTime = $this->GetLastVacTime($TableName);
49  if (empty($LastVacTime)) {
50  $mystyle = "style=background-color:red";
51  } else {
52  $mystyle = "";
53  }
54  $V .= "<td $mystyle>" . substr($LastVacTime, 0, 16) . "</td>";
55 
56  $LastAnalyzeTime = $this->GetLastAnalyzeTime($TableName);
57  if (empty($LastAnalyzeTime)) {
58  $mystyle = "style=background-color:red";
59  } else {
60  $mystyle = "";
61  }
62  $V .= "<td $mystyle>" . substr($LastAnalyzeTime, 0, 16) . "</td>";
63 
64  $V .= "</tr>\n";
65 
66  if ($fromRest) {
67  return [
68  "metric" => $TableLabel,
69  "total" => intval($item_count),
70  "lastVacuum" => $LastVacTime,
71  "lastAnalyze" => $LastAnalyzeTime
72  ];
73  }
74  return $V;
75  }
76 
81  function DatabaseContents()
82  {
83  $V = "<table border=1>\n";
84 
85  $head1 = _("Metric");
86  $head2 = _("Total");
87  $head3 = _("Last<br>Vacuum");
88  $head4 = _("Last<br>Analyze");
89  $V .= "<tr><th>$head1</th><th>$head2</th><th>$head3</th><th>$head4</th></tr>\n";
90 
91  /**** Users ****/
92  $V .= $this->DatabaseContentsRow("users", _("Users"));
93 
94  /**** Uploads ****/
95  $V .= $this->DatabaseContentsRow("upload", _("Uploads"));
96 
97  /**** Unique pfiles ****/
98  $V .= $this->DatabaseContentsRow("pfile", _("Unique files referenced in repository"));
99 
100  /**** uploadtree recs ****/
101  $V .= $this->DatabaseContentsRow("uploadtree_%", _("Individual Files"));
102 
103  /**** License recs ****/
104  $V .= $this->DatabaseContentsRow("license_file", _("Discovered Licenses"));
105 
106  /**** Copyright recs ****/
107  $V .= $this->DatabaseContentsRow("copyright", _("Copyrights/URLs/Emails"));
108 
109  $V .= "</table>\n";
110 
111  return $V;
112  }
113 
114  function GetLastAnalyzeTimeOrVacTime($queryPart,$TableName)
115  {
116  $sql = "select greatest($queryPart) as lasttime from pg_stat_all_tables where schemaname = 'public' and relname like $1";
117  $row = $this->dbManager->getSingleRow($sql, array($TableName), __METHOD__);
118 
119  return $row["lasttime"];
120  }
121 
122  function GetLastVacTime($TableName)
123  {
124  return $this->GetLastAnalyzeTimeOrVacTime("last_vacuum, last_autovacuum",$TableName);
125  }
126 
127  function GetPHPInfoTable($fromRest = false)
128  {
129  $PHP_VERSION = phpversion();
130  $loadedModules = get_loaded_extensions();
131 
132  $restRes = [];
133 
134  $table = "
135 <table class='infoTable' border=1>
136  <tr>
137  <th>
138  Info
139  </th>
140  <th>
141  Value
142  </th>
143  </tr>
144  <tbody>
145  <tr>
146  <td>
147  PHP Version
148  </td>
149  <td>
150  $PHP_VERSION
151  </td>
152  </tr>
153  <tr>
154  <td>
155  Loaded Extensions
156  </td>
157  <td><div class='infoTable'>";
158 
159  $restRes['phpVersion'] = $PHP_VERSION;
160  $restRes['loadedExtensions'] = [];
161  foreach ($loadedModules as $currentExtensionName) {
162  $currentVersion = phpversion($currentExtensionName);
163  $table .= $currentExtensionName . ": " . $currentVersion . "<br />";
164  $restRes['loadedExtensions'][] = [
165  'name' => $currentExtensionName,
166  'version' => $currentVersion
167  ];
168  }
169 
170  $table .="</div></td>
171  </tr>
172  </tbody>
173 </table>
174 
175  ";
176 
177  if ($fromRest) {
178  return $restRes;
179  }
180  return $table;
181  }
182 
183  function GetLastAnalyzeTime($TableName)
184  {
185  return $this->GetLastAnalyzeTimeOrVacTime("last_analyze, last_autoanalyze",
186  $TableName);
187  }
188 
189 
194  function DatabaseMetrics($fromRest = false)
195  {
196  $restRes = [];
197  $V = "<table border=1>\n";
198  $text = _("Metric");
199  $text1 = _("Total");
200  $V .= "<tr><th>$text</th><th>$text1</th></tr>\n";
201 
202  /* Database size */
203  $sql = "SELECT pg_database_size('fossology') as val;";
204  $row = $this->dbManager->getSingleRow($sql, array(), __METHOD__."get_Size");
205  $Size = HumanSize($row['val']);
206  $text = _("FOSSology database size");
207  $V .= "<tr><td>$text</td>";
208  $V .= "<td align='right'> $Size </td></tr>\n";
209 
210  $restRes[] = [
211  "metric" => $text,
212  "total" => $row['val']
213  ];
214 
215  /**** Version ****/
216  $text = _("Postgresql version");
217  $V .= "<tr><td>$text</td>";
218  $V .= "<td align='right'> {$this->pgVersion['server']} </td></tr>\n";
219 
220  $restRes[] = [
221  "metric" => $text,
222  "total" => $this->pgVersion['server']
223  ];
224 
225  /**** Query stats ****/
226  // count current queries
227  $sql = "SELECT count(*) AS val FROM pg_stat_activity";
228  $row = $this->dbManager->getSingleRow($sql, array(), __METHOD__."get_connection_count");
229  $connection_count = $row['val'];
230 
231  /**** Active connection count ****/
232  $text = _("Active database connections");
233  $V .= "<tr><td>$text</td>";
234  $V .= "<td align='right'>" . number_format($connection_count,0,"",",") . "</td></tr>\n";
235 
236  $V .= "</table>\n";
237 
238  $restRes[] = [
239  "metric" => $text,
240  "total" => $connection_count
241  ];
242 
243  if ($fromRest) {
244  return $restRes;
245  }
246 
247  return $V;
248  }
249 
250 
256  function DatabaseQueries($fromRest = false)
257  {
258  $V = "<table border=1 id='databaseTable'>\n";
259  $head1 = _("PID");
260  $head2 = _("Query");
261  $head3 = _("Started");
262  $head4 = _("Elapsed");
263  $restRes = [];
264  $V .= "<tr><th>$head1</th><th>$head2</th><th>$head3</th><th>$head4</th></tr>\n";
265  $getCurrentVersion = explode(" ", $this->pgVersion['server']);
266  $currentVersion = str_replace(".", "", $getCurrentVersion[0]);
267  unset($getCurrentVersion);
268  $oldVersion = str_replace(".", "", "9.2");
269  $current_query = ($currentVersion >= $oldVersion) ? "state" : "current_query";
270  $procpid = ($currentVersion >= $oldVersion) ? "pid" : "procpid";
271  $sql = "SELECT $procpid processid, $current_query, query_start AT TIME ZONE 'UTC' AS query_start, now()-query_start AS elapsed FROM pg_stat_activity WHERE $current_query != '<IDLE>' AND datname = 'fossology' ORDER BY $procpid";
272 
273  $statementName = __METHOD__."queryFor_".$current_query."_orderBy_".$procpid;
274  $this->dbManager->prepare($statementName,$sql);
275  $result = $this->dbManager->execute($statementName, array());
276 
277  if (pg_num_rows($result) > 1) {
278  while ($row = pg_fetch_assoc($result)) {
279  if ($row[$current_query] == $sql) {
280  continue; // Don't display this query
281  }
282  $V .= "<tr>";
283  $V .= "<td class='dashboard'>$row[processid]</td>";
284  $V .= "<td class='dashboard'>" . htmlspecialchars($row[$current_query]) .
285  "</td>";
286  $StartTime = Convert2BrowserTime(substr($row['query_start'], 0, 19));
287  $V .= "<td class='dashboard'>$StartTime</td>";
288  $V .= "<td class='dashboard'>$row[elapsed]</td>";
289  $V .= "</tr>\n";
290  $dt = new DateTime($row['query_start'], new DateTimeZone("UTC"));
291  $restRes[] = [
292  "pid" => $row['processid'],
293  "query" => htmlspecialchars($row[$current_query]),
294  "startTime" => $dt->format("Y-m-d\\TH:i:s.v\\Z"),
295  "elapsed" => $row['elapsed']
296  ];
297  }
298  } else {
299  $V .= "<tr><td class='dashboard' colspan=4>There are no active FOSSology queries</td></tr>";
300  }
301 
302  pg_free_result($result);
303  $V .= "</table>\n";
304 
305  if ($fromRest) {
306  return $restRes;
307  }
308  return $V;
309  }
310 
311 
315  function DiskFree($fromRest = false)
316  {
317  global $SYSCONFDIR;
318  global $SysConf;
319 
320  $restRes = [];
321 
322  $Cmd = "df -hP";
323  $Buf = $this->DoCmd($Cmd);
324 
325  /* Separate lines */
326  $Lines = explode("\n",$Buf);
327 
328  /* Display results */
329  $V = "<table border=1>\n";
330  $head0 = _("Filesystem");
331  $head1 = _("Capacity");
332  $head2 = _("Used");
333  $head3 = _("Available");
334  $head4 = _("Percent Full");
335  $head5 = _("Mount Point");
336  $V .= "<tr><th>$head0</th><th>$head1</th><th>$head2</th><th>$head3</th><th>$head4</th><th>$head5</th></tr>\n";
337  $headerline = true;
338  foreach ($Lines as $L) {
339  // Skip top header line
340  if ($headerline) {
341  $headerline = false;
342  continue;
343  }
344 
345  if (empty($L)) {
346  continue;
347  }
348  $L = trim($L);
349  $L = preg_replace("/[[:space:]][[:space:]]*/", " ", $L);
350  $List = explode(" ", $L);
351 
352  // Skip some filesystems we are not interested in
353  if ($List[0] == 'tmpfs') {
354  continue;
355  }
356  if ($List[0] == 'udev') {
357  continue;
358  }
359  if ($List[0] == 'none') {
360  continue;
361  }
362  if ($List[5] == '/boot') {
363  continue;
364  }
365 
366  $V .= "<tr><td>" . htmlentities($List[0]) . "</td>";
367  $V .= "<td align='right' style='border-right:none'>$List[1]</td>";
368  $V .= "<td align='right' style='border-right:none'>$List[2]</td>";
369  $V .= "<td align='right' style='border-right:none'>$List[3]</td>";
370 
371  // Warn if running out of disk space
372  $PctFull = (int) $List[4];
373  $WarnAtPct = 90; // warn the user if they exceed this % full
374  if ($PctFull > $WarnAtPct) {
375  $mystyle = "style=border-right:none;background-color:red";
376  } else {
377  $mystyle = "style='border-right:none'";
378  }
379  $V .= "<td align='right' $mystyle>$List[4]</td>";
380 
381  $V .= "<td align='left'>" . htmlentities($List[5]) . "</td></tr>\n";
382 
383  $restRes["data"][] = [
384  "filesystem" => htmlentities($List[0]),
385  "capacity" => $List[1],
386  "used" => $List[2],
387  "available" => $List[3],
388  "percentFull" => $List[4],
389  "mountPoint" => htmlentities($List[5])
390  ];
391  }
392  $V .= "</table>\n";
393 
394  /*** Print out important file paths so users can interpret the above "df" ***/
395  $V .= _("Note:") . "<br>";
396  $Indent = "&nbsp;&nbsp;";
397 
398  // File path to the database
399  $V .= $Indent . _("Database"). ": " . "&nbsp;";
400  // Get the database data_directory. If we were the superuser we could
401  // just query the database with "show data_directory", but we are not.
402  // So try to get it from a ps and parse the -D argument
403  $Cmd = "ps -eo cmd | grep postgres | grep -- -D";
404  $Buf = $this->DoCmd($Cmd);
405  // Find the -D
406  $DargToEndOfStr = trim(substr($Buf, strpos($Buf, "-D") + 2 ));
407  $DargArray = explode(' ', $DargToEndOfStr);
408  $V .= $DargArray[0] . "<br>";
409 
410  // Repository path
411  $V .= $Indent . _("Repository") . ": " . $SysConf['FOSSOLOGY']['path'] . "<br>";
412 
413  // FOSSology config location
414  $V .= $Indent . _("FOSSology config") . ": " . $SYSCONFDIR . "<br>";
415 
416  $restRes["notes"] = [
417  "database" => $DargArray[0],
418  "repository" => $SysConf['FOSSOLOGY']['path'],
419  "fossologyConfig" => $SYSCONFDIR
420  ];
421 
422  if ($fromRest) {
423  return $restRes;
424  }
425  return ($V);
426  }
427 
428  public function Output()
429  {
430 
431  $V = "<table style='width: 100%;' border=0>\n";
432  $V .= "<tr>";
433  $V .= "<td valign='top'>\n";
434  $text = _("Database Contents");
435  $V .= "<h2>$text</h2>\n";
436  $V .= $this->DatabaseContents();
437  $V .= "</td>";
438 
439  $V .= "<td class='dashboard'>\n";
440  $text = _("Database Metrics");
441  $V .= "<h2>$text</h2>\n";
442  $V .= $this->DatabaseMetrics();
443  $V .= "</td>";
444  $V .= "</tr>";
445 
446  $V .= "<tr>";
447  $V .= "<td class='dashboard'>";
448  $text = _("Active FOSSology queries");
449  $V .= "<h2>$text</h2>\n";
450  $V .= $this->DatabaseQueries();
451  $V .= "</td>";
452 
453  $V .= "<td class='dashboard'>";
454  $text = _("PHP Info");
455  $V .= "<h2>$text</h2>\n";
456  $V .= $this->GetPHPInfoTable();
457  $V .= "</td>";
458  $V .= "</tr>";
459 
460  $V .= "<tr>";
461  $V .= "<td class='dashboard'>";
462  $text = _("Disk Space");
463  $V .= "<h2>$text</h2>\n";
464  $V .= $this->DiskFree();
465  $V .= "</td>";
466  $V .= "</tr>";
467 
468  $V .= "</table>\n";
469  $V .= "<br><br>";
470  return $V;
471  }
472 
478  protected function DoCmd($cmd)
479  {
480  $fin = popen($cmd, "r");
481  $buffer = "";
482  while (! feof($fin)) {
483  $buffer .= fread($fin, 8192);
484  }
485  pclose($fin);
486  return $buffer;
487  }
488 }
489 
490 $NewPlugin = new dashboard;
491 $NewPlugin->Initialize();
This is the Plugin class. All plugins should:
Definition: FO_Plugin.php:57
__construct()
base constructor. Most plugins will just use this
DatabaseContents()
Database Contents metrics.
DatabaseQueries($fromRest=false)
Database queries.
DatabaseMetrics($fromRest=false)
Database metrics.
DiskFree($fromRest=false)
Determine amount of free disk space.
DatabaseContentsRow($TableName, $TableLabel, $fromRest=false)
Return each html row for DatabaseContents()
Output()
This function is called when user output is requested. This function is responsible for content....
DoCmd($cmd)
execute a shell command
HumanSize( $bytes)
Translate a byte number to a proper type, xxx bytes to xxx B/KB/MB/GB/TB/PB.
Definition: common-ui.php:100
Convert2BrowserTime($server_time)
Convert the server time to browser time.
Definition: common-ui.php:312
char * trim(char *ptext)
Trimming whitespace.
Definition: fossconfig.c:690
#define PLUGIN_DB_ADMIN
Plugin requires admin level permission on DB.
Definition: libfossology.h:39
foreach($Options as $Option=> $OptVal) if(0==$reference_flag &&0==$nomos_flag) $PG_CONN
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16