Merge branch 'storageareas' into fugro
commit
5792021ee3
|
@ -2,3 +2,6 @@
|
|||
path = web/api/app/Plugin/Crud
|
||||
url = https://github.com/FriendsOfCake/crud.git
|
||||
branch = 3.0
|
||||
[submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"]
|
||||
path = web/api/app/Plugin/CakePHP-Enum-Behavior
|
||||
url = https://github.com/asper/CakePHP-Enum-Behavior.git
|
||||
|
|
|
@ -647,13 +647,13 @@ if(NOT ZM_NO_LIBVLC)
|
|||
endif(LIBVLC_LIBRARIES)
|
||||
endif(NOT ZM_NO_LIBVLC)
|
||||
|
||||
find_package(Boost 1.36.0)
|
||||
if(Boost_FOUND)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
set(CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIRS}")
|
||||
list(APPEND ZM_BIN_LIBS "${Boost_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
#find_package(Boost 1.36.0)
|
||||
#if(Boost_FOUND)
|
||||
#include_directories(${Boost_INCLUDE_DIRS})
|
||||
##set(CMAKE_REQUIRED_INCLUDES "${Boost_INCLUDE_DIRS}")
|
||||
#list(APPEND ZM_BIN_LIBS "${Boost_LIBRARIES}")
|
||||
#endif()
|
||||
#
|
||||
# *** END OF LIBRARY CHECKS ***
|
||||
|
||||
# Check for gnutls or crypto
|
||||
|
|
|
@ -209,11 +209,62 @@ CREATE TABLE `Events` (
|
|||
`StateId` int(10) unsigned NOT NULL,
|
||||
`Orientation` enum('0','90','180','270','hori','vert') NOT NULL default '0',
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`Id`,`MonitorId`),
|
||||
KEY `MonitorId` (`MonitorId`),
|
||||
KEY `StartTime` (`StartTime`),
|
||||
KEY `Frames` (`Frames`),
|
||||
KEY `Archived` (`Archived`)
|
||||
PRIMARY KEY (`Id`),
|
||||
KEY `Events_MonitorId_idx` (`MonitorId`),
|
||||
KEY `Events_StorageId_idx` (`StorageId`),
|
||||
KEY `Events_StartTime_idx` (`StartTime`),
|
||||
KEY `Events_EndTime_DiskSpace` (`EndTime`,`DiskSpace`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
DROP TABLE IF EXISTS `Events_Hour`;
|
||||
CREATE TABLE `Events_Hour` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`StartTime` datetime default NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Hour_MonitorId_StartTime_idx` (`MonitorId`,`StartTime`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
DROP TABLE IF EXISTS `Events_Day`;
|
||||
CREATE TABLE `Events_Day` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`StartTime` datetime default NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Day_MonitorId_StartTime_idx` (`MonitorId`,`StartTime`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `Events_Week`;
|
||||
CREATE TABLE `Events_Week` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`StartTime` datetime default NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Week_MonitorId_StartTime_idx` (`MonitorId`,`StartTime`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
DROP TABLE IF EXISTS `Events_Month`;
|
||||
CREATE TABLE `Events_Month` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`StartTime` datetime default NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Month_MonitorId_StartTime_idx` (`MonitorId`,`StartTime`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `Events_Archived`;
|
||||
CREATE TABLE `Events_Archived` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Month_MonitorId_idx` (`MonitorId`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
--
|
||||
|
@ -285,8 +336,8 @@ CREATE TABLE `Groups_Monitors` (
|
|||
PRIMARY KEY (`Id`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
CREATE INDEX `Groups_Monitors_GroupId_idx` ON `Groups` (`GroupId`);
|
||||
CREATE INDEX `Groups_Monitors_MonitorId_idx` ON `Groups` (`MonitorId`);
|
||||
CREATE INDEX `Groups_Monitors_GroupId_idx` ON `Groups_Monitors` (`GroupId`);
|
||||
CREATE INDEX `Groups_Monitors_MonitorId_idx` ON `Groups_Monitors` (`MonitorId`);
|
||||
|
||||
--
|
||||
-- Table structure for table `Logs`
|
||||
|
@ -501,6 +552,9 @@ CREATE TABLE `Servers` (
|
|||
`FreeMem` bigint unsigned default null,
|
||||
`TotalSwap` bigint unsigned default null,
|
||||
`FreeSwap` bigint unsigned default null,
|
||||
`zmstats.pl` BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
`zmaudit.pl` BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
`zmtrigger.pl` BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY (`Id`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
|
@ -639,14 +693,15 @@ CREATE TABLE `Storage` (
|
|||
`Name` varchar(64) NOT NULL default '',
|
||||
`Type` enum('local','s3fs') NOT NULL default 'local',
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
`Scheme enum('Deep','Medium','Shallow') NOT NULL default 'Medium',
|
||||
`Scheme` enum('Deep','Medium','Shallow') NOT NULL default 'Medium',
|
||||
`ServerId` int(10) unsigned,
|
||||
PRIMARY KEY (`Id`)
|
||||
) ENGINE=@ZM_MYSQL_ENGINE@;
|
||||
|
||||
--
|
||||
-- Create a default storage location
|
||||
--
|
||||
insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL );
|
||||
insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL, 'Medium', 0 );
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
|
@ -668,7 +723,25 @@ insert into Users VALUES (NULL,'admin',password('admin'),'',1,'View','Edit','Edi
|
|||
--
|
||||
-- Add a sample filter to purge the oldest 100 events when the disk is 95% full
|
||||
--
|
||||
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',0,0,0,0,0,0,'',1,0,1,0);
|
||||
`Id` int(10) unsigned NOT NULL auto_increment,
|
||||
`Name` varchar(64) NOT NULL default '',
|
||||
`Query` text NOT NULL,
|
||||
`AutoArchive` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoVideo` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoUpload` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoEmail` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoMessage` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoExecute` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoExecuteCmd` tinytext,
|
||||
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoMove` tinyint(3) unsigned NOT NULL default '0',
|
||||
`AutoMoveTo` smallint(5) unsigned NOT NULL default 0,
|
||||
`UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0',
|
||||
`Background` tinyint(1) unsigned NOT NULL default '0',
|
||||
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
|
||||
|
||||
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',0/*AutoArchive*/,0/*AutoVideo*/,0/*AutoUpload*/,0/*AutoEmail*/,0/*AutoMessage*/,0/*AutoExecute*/,'',1/*AutoDelete*/,0/*AutoMove*/,0/*MoveTo*/,0/*UpdateDiskSpace*/,1/*Background*/,0/*Concurrent*/);
|
||||
insert into Filters values (NULL,'Update DiskSpace','{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}',0,0,0,0,0,0,'',0,0,0,1,1,0);
|
||||
|
||||
--
|
||||
-- Add in some sample control protocol definitions
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Storage'
|
||||
AND column_name = 'ServerId'
|
||||
) > 0,
|
||||
"SELECT 'Column ServerId already exists in Storage'",
|
||||
"ALTER TABLE Storage ADD `ServerId` int(10) unsigned AFTER `Scheme`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM Filters WHERE Name = 'Update DiskSpace'
|
||||
AND Query = '{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}'
|
||||
) > 0,
|
||||
"SELECT 'Update Disk Space Filter already exists.'",
|
||||
"INSERT INTO Filters (Name,Query,UpdateDiskSpace,Background) values ('Update DiskSpace','{\"terms\":[{\"attr\":\"DiskSpace\",\"op\":\"IS\",\"val\":\"NULL\"}]}',1,1)"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
|
@ -0,0 +1,123 @@
|
|||
drop procedure if exists update_storage_stats;
|
||||
|
||||
delimiter //
|
||||
|
||||
create procedure update_storage_stats(IN StorageId smallint(5), IN space BIGINT)
|
||||
|
||||
sql security invoker
|
||||
|
||||
deterministic
|
||||
|
||||
begin
|
||||
|
||||
update Storage set DiskSpace = DiskSpace + space where Id = StorageId;
|
||||
|
||||
end;
|
||||
|
||||
//
|
||||
|
||||
delimiter ;
|
||||
|
||||
drop trigger if exists event_update_trigger;
|
||||
|
||||
delimiter //
|
||||
|
||||
create trigger event_update_trigger
|
||||
|
||||
after update
|
||||
|
||||
on Events
|
||||
|
||||
for each row
|
||||
|
||||
begin
|
||||
declare diff BIGINT default 0;
|
||||
|
||||
set diff = NEW.DiskSpace - OLD.DiskSpace;
|
||||
IF ( NEW.StorageId = OLD.StorageID ) THEN
|
||||
|
||||
IF ( diff ) THEN
|
||||
call update_storage_stats(OLD.StorageId, diff);
|
||||
END IF;
|
||||
ELSE
|
||||
IF ( NEW.DiskSpace ) THEN
|
||||
call update_storage_stats(NEW.StorageId, NEW.DiskSpace);
|
||||
END IF;
|
||||
IF ( OLD.DiskSpace ) THEN
|
||||
call update_storage_stats(OLD.StorageId, -OLD.DiskSpace);
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
end;
|
||||
|
||||
//
|
||||
|
||||
delimiter ;
|
||||
|
||||
drop trigger if exists event_insert_trigger;
|
||||
|
||||
delimiter //
|
||||
/*
|
||||
create trigger event_insert_trigger
|
||||
|
||||
after insert
|
||||
|
||||
on Events
|
||||
|
||||
for each row
|
||||
|
||||
begin
|
||||
|
||||
call update_storage_stats(NEW.StorageId, NEW.DiskSpace);
|
||||
|
||||
end;
|
||||
*/
|
||||
//
|
||||
|
||||
delimiter ;
|
||||
|
||||
|
||||
drop trigger if exists event_delete_trigger;
|
||||
|
||||
delimiter //
|
||||
|
||||
create trigger event_delete_trigger
|
||||
|
||||
before delete
|
||||
|
||||
on Events
|
||||
|
||||
for each row
|
||||
|
||||
begin
|
||||
|
||||
call update_storage_stats(OLD.StorageId, -OLD.DiskSpace);
|
||||
|
||||
end;
|
||||
|
||||
//
|
||||
|
||||
delimiter ;
|
||||
|
||||
set @exist := (select count(*) from information_schema.statistics where table_name = 'Events' and index_name = 'Archived' and table_schema = database());
|
||||
set @sqlstmt := if( @exist > 0, 'DROP INDEX Archived ON Events', "SELECT 'Archived INDEX is already removed.'");
|
||||
PREPARE stmt FROM @sqlstmt;
|
||||
EXECUTE stmt;
|
||||
|
||||
set @exist := (select count(*) from information_schema.statistics where table_name = 'Events' and index_name = 'Frames' and table_schema = database());
|
||||
set @sqlstmt := if( @exist > 0, 'DROP INDEX Frames ON Events', "SELECT 'Frames INDEX is already removed.'");
|
||||
PREPARE stmt FROM @sqlstmt;
|
||||
EXECUTE stmt;
|
||||
|
||||
set @exist := (select count(*) from information_schema.statistics where table_name = 'Events' and index_name = 'Events_StorageId_idx' and table_schema = database());
|
||||
set @sqlstmt := if( @exist > 0, "SELECT 'Index Events_StorageId_idx already exists.'", 'CREATE INDEX Events_StorageId_idx on Events (StorageId)');
|
||||
PREPARE stmt FROM @sqlstmt;
|
||||
EXECUTE stmt;
|
||||
|
||||
set @exist := (select count(*) from information_schema.statistics where table_name = 'Events' and index_name = 'Events_EndTime_DiskSpace_idx' and table_schema = database());
|
||||
set @sqlstmt := if( @exist > 0, "SELECT 'Index Events_EndTime_DiskSpace_idx already exists.'", 'CREATE INDEX Events_EndTime_DiskSpace_idx on Events (EndTime, DiskSpace)');
|
||||
PREPARE stmt FROM @sqlstmt;
|
||||
EXECUTE stmt;
|
||||
|
||||
UPDATE Storage SET DiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE StorageId=Storage.Id);
|
||||
|
|
@ -15,6 +15,3 @@ SET @s = (SELECT IF(
|
|||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
INSERT INTO `Controls` VALUES (28,'Floureon 1080P','Ffmpeg','Floureon',0,0,0,1,0,0,0,1,1,18,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,0,1,1,1,0,0,0,1,1,0,0,0,0,1,1,8,0,0,1,0,0,0,0,1,1,8,0,0,0,0);
|
||||
|
||||
|
|
|
@ -0,0 +1,275 @@
|
|||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE table_name = 'Events_Hour'
|
||||
AND table_schema = DATABASE()
|
||||
) > 0,
|
||||
"SELECT 'Events_Hour table exists'",
|
||||
"
|
||||
CREATE TABLE `Events_Hour` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`StartTime` datetime default NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Hour_MonitorId_StartTime_idx` (`MonitorId`,`StartTime`)
|
||||
);
|
||||
"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE table_name = 'Events_Day'
|
||||
AND table_schema = DATABASE()
|
||||
) > 0,
|
||||
"SELECT 'Events_Day table exists'",
|
||||
"
|
||||
CREATE TABLE `Events_Day` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`StartTime` datetime default NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Day_MonitorId_StartTime_idx` (`MonitorId`,`StartTime`)
|
||||
);
|
||||
"));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE table_name = 'Events_Week'
|
||||
AND table_schema = DATABASE()
|
||||
) > 0,
|
||||
"SELECT 'Events_Week table exists'",
|
||||
"
|
||||
CREATE TABLE `Events_Week` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`StartTime` datetime default NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Week_MonitorId_StartTime_idx` (`MonitorId`,`StartTime`)
|
||||
);
|
||||
"));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE table_name = 'Events_Month'
|
||||
AND table_schema = DATABASE()
|
||||
) > 0,
|
||||
"SELECT 'Events_Month table exists'",
|
||||
"
|
||||
CREATE TABLE `Events_Month` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`StartTime` datetime default NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Month_MonitorId_StartTime_idx` (`MonitorId`,`StartTime`)
|
||||
);
|
||||
"));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE table_name = 'Events_Archived'
|
||||
AND table_schema = DATABASE()
|
||||
) > 0,
|
||||
"SELECT 'Events_Archived table exists'",
|
||||
"
|
||||
CREATE TABLE `Events_Archived` (
|
||||
`EventId` int(10) unsigned NOT NULL,
|
||||
`MonitorId` int(10) unsigned NOT NULL,
|
||||
`DiskSpace` bigint unsigned default NULL,
|
||||
PRIMARY KEY (`EventId`),
|
||||
KEY `Events_Month_MonitorId_idx` (`MonitorId`)
|
||||
);
|
||||
"));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
drop trigger if exists event_update_trigger;
|
||||
|
||||
delimiter //
|
||||
|
||||
CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
declare diff BIGINT default 0;
|
||||
|
||||
set diff = NEW.DiskSpace - OLD.DiskSpace;
|
||||
IF ( NEW.StorageId = OLD.StorageID ) THEN
|
||||
IF ( diff ) THEN
|
||||
call update_storage_stats(OLD.StorageId, diff);
|
||||
END IF;
|
||||
ELSE
|
||||
IF ( NEW.DiskSpace ) THEN
|
||||
call update_storage_stats(NEW.StorageId, NEW.DiskSpace);
|
||||
END IF;
|
||||
IF ( OLD.DiskSpace ) THEN
|
||||
call update_storage_stats(OLD.StorageId, -OLD.DiskSpace);
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
UPDATE Events_Hour SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id;
|
||||
UPDATE Events_Day SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id;
|
||||
UPDATE Events_Week SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id;
|
||||
UPDATE Events_Month SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id;
|
||||
IF ( NEW.Archived != OLD.Archived ) THEN
|
||||
IF ( NEW.Archived ) THEN
|
||||
INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace);
|
||||
UPDATE Monitors SET ArchivedEvents = ArchivedEvents+1, ArchivedEventDiskSpace = ArchivedEventDiskSpace + NEW.DiskSpace WHERE Id=NEW.MonitorId;
|
||||
ELSEIF ( OLD.Archived ) THEN
|
||||
DELETE FROM Events_Archived WHERE EventId=OLD.Id;
|
||||
UPDATE Monitors SET ArchivedEvents =ArchivedEvents-1, ArchivedEventDiskSpace = ArchivedEventDiskSpace - OLD.DiskSpace WHERE Id=OLD.MonitorId;
|
||||
ELSE
|
||||
IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN
|
||||
UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id;
|
||||
UPDATE Monitors SET
|
||||
ArchivedEventDiskSpace = ArchivedEventDiskSpace - OLD.DiskSpace + NEW.DiskSpace
|
||||
WHERE Id=OLD.MonitorId;
|
||||
END IF;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN
|
||||
UPDATE Monitors SET TotalEventDiskSpace = TotalEventDiskSpace - OLD.DiskSpace + NEW.DiskSpace WHERE Id=OLD.MonitorId;
|
||||
END IF;
|
||||
|
||||
END;
|
||||
|
||||
//
|
||||
|
||||
delimiter ;
|
||||
|
||||
DROP TRIGGER IF EXISTS event_insert_trigger;
|
||||
|
||||
delimiter //
|
||||
create trigger event_insert_trigger after insert on Events
|
||||
for each row
|
||||
begin
|
||||
|
||||
INSERT INTO Events_Hour (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0);
|
||||
INSERT INTO Events_Day (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0);
|
||||
INSERT INTO Events_Week (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0);
|
||||
INSERT INTO Events_Month (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0);
|
||||
end;
|
||||
//
|
||||
|
||||
delimiter ;
|
||||
|
||||
|
||||
drop trigger if exists event_delete_trigger;
|
||||
|
||||
delimiter //
|
||||
|
||||
CREATE TRIGGER event_delete_trigger BEFORE DELETe on Events
|
||||
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
call update_storage_stats(OLD.StorageId, -OLD.DiskSpace);
|
||||
DELETE FROM Events_Hour WHERE EventId=OLD.Id;
|
||||
DELETE FROM Events_Day WHERE EventId=OLD.Id;
|
||||
DELETE FROM Events_Week WHERE EventId=OLD.Id;
|
||||
DELETE FROM Events_Month WHERE EventId=OLD.Id;
|
||||
IF ( OLD.Archived ) THEN
|
||||
DELETE FROM Events_Archived WHERE EventId=OLD.Id;
|
||||
UPDATE Monitors SET
|
||||
ArchivedEvents = ArchivedEvents - 1,
|
||||
ArchivedEventDiskSpace = ArchivedEventDiskSpace - OLD.DiskSpace,
|
||||
TotalEvents = TotalEvents - 1,
|
||||
TotalEventDiskSpace = TotalEventDiskSpace - OLD.DiskSpace
|
||||
WHERE Id=OLD.MonitorId;
|
||||
ELSE
|
||||
UPDATE Monitors SET
|
||||
TotalEvents = TotalEvents-1,
|
||||
TotalEventDiskSpace=TotalEventDiskSpace-OLD.DiskSpace
|
||||
WHERE Id=OLD.MonitorId;
|
||||
END IF;
|
||||
END;
|
||||
|
||||
//
|
||||
|
||||
delimiter ;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Servers'
|
||||
AND column_name = 'zmstats.pl'
|
||||
) > 0,
|
||||
"SELECT 'Column zmstats.pl already exists in Servers'",
|
||||
"ALTER TABLE Servers ADD `zmstats.pl` BOOLEAN NOT NULL DEFAULT FALSE AFTER `FreeSwap`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Servers'
|
||||
AND column_name = 'zmaudit.pl'
|
||||
) > 0,
|
||||
"SELECT 'Column zmaudit.pl already exists in Servers'",
|
||||
"ALTER TABLE Servers ADD `zmaudit.pl` BOOLEAN NOT NULL DEFAULT FALSE AFTER `zmstats.pl`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
SET @s = (SELECT IF(
|
||||
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
|
||||
AND table_name = 'Servers'
|
||||
AND column_name = 'zmtrigger.pl'
|
||||
) > 0,
|
||||
"SELECT 'Column zmtrigger.pl already exists in Servers'",
|
||||
"ALTER TABLE Servers ADD `zmtrigger.pl` BOOLEAN NOT NULL DEFAULT FALSE AFTER `zmaudit.pl`"
|
||||
));
|
||||
|
||||
PREPARE stmt FROM @s;
|
||||
EXECUTE stmt;
|
||||
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId,
|
||||
COUNT(Id) AS TotalEvents,
|
||||
SUM(DiskSpace) AS TotalEventDiskSpace,
|
||||
SUM(IF(Archived,1,0)) AS ArchivedEvents,
|
||||
SUM(IF(Archived,DiskSpace,0)) AS ArchivedEventDiskSpace,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 hour),1,0)) AS HourEvents,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 hour),DiskSpace,0)) AS HourEventDiskSpace,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 day),1,0)) AS DayEvents,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 day),DiskSpace,0)) AS DayEventDiskSpace,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 week),1,0)) AS WeekEvents,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 week),DiskSpace,0)) AS WeekEventDiskSpace,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 month),1,0)) AS MonthEvents,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 month),DiskSpace,0)) AS MonthEventDiskSpace
|
||||
FROM Events GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.TotalEvents = E.TotalEvents,
|
||||
Monitors.TotalEventDiskSpace = E.TotalEventDiskSpace,
|
||||
Monitors.ArchivedEvents = E.ArchivedEvents,
|
||||
Monitors.ArchivedEventDiskSpace = E.ArchivedEventDiskSpace,
|
||||
Monitors.HourEvents = E.HourEvents,
|
||||
Monitors.HourEventDiskSpace = E.HourEventDiskSpace,
|
||||
Monitors.DayEvents = E.DayEvents,
|
||||
Monitors.DayEventDiskSpace = E.DayEventDiskSpace,
|
||||
Monitors.WeekEvents = E.WeekEvents,
|
||||
Monitors.WeekEventDiskSpace = E.WeekEventDiskSpace,
|
||||
Monitors.MonthEvents = E.MonthEvents,
|
||||
Monitors.MonthEventDiskSpace = E.MonthEventDiskSpace;
|
|
@ -31,9 +31,9 @@ if [ "$1" = "configure" ]; then
|
|||
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
||||
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
||||
# This creates the user.
|
||||
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
echo "grant lock tables, alter,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
else
|
||||
echo "grant lock tables, alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
echo "grant lock tables, alter,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
fi
|
||||
|
||||
zmupdate.pl --nointeractive
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
[Unit]
|
||||
Description=ZoneMinder CCTV recording and surveillance system
|
||||
After=network.target mysql.service
|
||||
Requires=mysql.service
|
||||
# Remarked out so that it will start ZM on machines that don't have mysql installed
|
||||
#Requires=mysql.service
|
||||
|
||||
[Service]
|
||||
#User=www-data
|
||||
|
@ -13,7 +14,10 @@ ExecStart=/usr/bin/zmpkg.pl start
|
|||
ExecReload=/usr/bin/zmpkg.pl restart
|
||||
ExecStop=/usr/bin/zmpkg.pl stop
|
||||
PIDFile=/var/run/zm/zm.pid
|
||||
Restart=on-abnormal
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
Environment=TZ=:/etc/localtime
|
||||
TimeoutSec=600
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -33,9 +33,9 @@ if [ "$1" = "configure" ]; then
|
|||
if ! $(echo quit | mysql --defaults-file=/etc/mysql/debian.cnf zm > /dev/null 2> /dev/null) ; then
|
||||
cat /usr/share/zoneminder/db/zm_create.sql | mysql --defaults-file=/etc/mysql/debian.cnf
|
||||
# This creates the user.
|
||||
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
echo "grant lock tables,alter,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
else
|
||||
echo "grant lock tables,alter,select,insert,update,delete,create,index on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
echo "grant lock tables,alter,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql
|
||||
fi
|
||||
|
||||
zmupdate.pl --nointeractive
|
||||
|
|
|
@ -17,6 +17,7 @@ PIDFile=/var/run/zm/zm.pid
|
|||
Restart=always
|
||||
RestartSec=10
|
||||
Environment=TZ=:/etc/localtime
|
||||
TimeoutSec=600
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
@ -14,6 +14,7 @@ configure_file(zmtrigger.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" @ONLY)
|
|||
configure_file(zmupdate.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" @ONLY)
|
||||
configure_file(zmvideo.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" @ONLY)
|
||||
configure_file(zmwatch.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" @ONLY)
|
||||
configure_file(zmstats.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmstats.pl" @ONLY)
|
||||
configure_file(zmcamtool.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" @ONLY)
|
||||
configure_file(zmsystemctl.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmsystemctl.pl" @ONLY)
|
||||
configure_file(zmtelemetry.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" @ONLY)
|
||||
|
@ -33,7 +34,7 @@ FOREACH(PERLSCRIPT ${perlscripts})
|
|||
ENDFOREACH(PERLSCRIPT ${perlscripts})
|
||||
|
||||
# Install the perl scripts
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmaudit.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcontrol.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmdc.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmfilter.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmpkg.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrack.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtrigger.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmupdate.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmvideo.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmwatch.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmcamtool.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmtelemetry.pl" "${CMAKE_CURRENT_BINARY_DIR}/zmstats.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
if(NOT ZM_NO_X10)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zmx10.pl" DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
endif(NOT ZM_NO_X10)
|
||||
|
|
|
@ -2399,6 +2399,17 @@ our @options = (
|
|||
type => $types{integer},
|
||||
category => 'system',
|
||||
},
|
||||
{
|
||||
name => 'ZM_STATS_UPDATE_INTERVAL',
|
||||
default => '60',
|
||||
description => 'How often to update the database statistics',
|
||||
help => q`
|
||||
The zmstats daemon performs various db queries that may take
|
||||
a long time in the background.
|
||||
`,
|
||||
type => $types{integer},
|
||||
category => 'system',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WATCH_CHECK_INTERVAL',
|
||||
default => '10',
|
||||
|
|
|
@ -200,6 +200,32 @@ sub RelativePath {
|
|||
return $$event{RelativePath};
|
||||
}
|
||||
|
||||
sub LinkPath {
|
||||
my $event = shift;
|
||||
if ( @_ ) {
|
||||
$$event{LinkPath} = $_[0];
|
||||
}
|
||||
|
||||
if ( ! $$event{LinkPath} ) {
|
||||
if ( $$event{Scheme} eq 'Deep' ) {
|
||||
if ( $event->Time() ) {
|
||||
$$event{LinkPath} = join('/',
|
||||
$event->{MonitorId},
|
||||
strftime( '%y/%m/%d',
|
||||
localtime($event->Time())
|
||||
),
|
||||
'.'.$$event{Id}
|
||||
);
|
||||
} else {
|
||||
Error("Event $$event{Id} has no value for Time(), unable to determine link path");
|
||||
$$event{LinkPath} = '';
|
||||
}
|
||||
} # end if Scheme
|
||||
} # end if ! Path
|
||||
|
||||
return $$event{LinkPath};
|
||||
} # end sub LinkPath
|
||||
|
||||
sub GenerateVideo {
|
||||
my ( $self, $rate, $fps, $scale, $size, $overwrite, $format ) = @_;
|
||||
|
||||
|
@ -292,10 +318,10 @@ sub delete {
|
|||
my $event = $_[0];
|
||||
if ( ! ( $event->{Id} and $event->{MonitorId} and $event->{StartTime} ) ) {
|
||||
my ( $caller, undef, $line ) = caller;
|
||||
Warning( "Can't Delete event $event->{Id} from Monitor $event->{MonitorId} $event->{StartTime} from $caller:$line\n" );
|
||||
Warning( "Can't Delete event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime} from $caller:$line\n" );
|
||||
return;
|
||||
}
|
||||
Info( "Deleting event $event->{Id} from Monitor $event->{MonitorId} $event->{StartTime}\n" );
|
||||
Info( "Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime}\n" );
|
||||
$ZoneMinder::Database::dbh->ping();
|
||||
# Do it individually to avoid locking up the table for new events
|
||||
my $sql = 'DELETE FROM Events WHERE Id=?';
|
||||
|
@ -337,50 +363,25 @@ sub delete_files {
|
|||
return;
|
||||
}
|
||||
|
||||
chdir( $storage_path );
|
||||
if ( ! $$event{MonitorId} ) {
|
||||
Error("No monitor id assigned to event $$event{Id}");
|
||||
return;
|
||||
}
|
||||
my $event_path = $event->Path();
|
||||
Debug("Deleting files for Event $$event{Id} from $event_path.");
|
||||
if ( $event_path ) {
|
||||
( $event_path ) = ( $event_path =~ /^(.*)$/ ); # De-taint
|
||||
my $command = "/bin/rm -rf $event_path";
|
||||
ZoneMinder::General::executeShellCommand( $command );
|
||||
}
|
||||
|
||||
if ( $$event{Scheme} eq 'Deep' ) {
|
||||
if ( ! $$event{MonitorId} ) {
|
||||
Error("No monitor id assigned to event $$event{Id}");
|
||||
return;
|
||||
my $link_path = $event->LinkPath();
|
||||
Debug("Deleting files for Event $$event{Id} from $storage_path/$link_path.");
|
||||
if ( $link_path ) {
|
||||
( $link_path ) = ( $link_path =~ /^(.*)$/ ); # De-taint
|
||||
unlink( $storage_path.'/'.$link_path ) or Error( "Unable to unlink '$storage_path/$link_path': $!" );
|
||||
}
|
||||
Debug("Deleting files for Event $$event{Id} from $storage_path.");
|
||||
my $link_path = $$event{MonitorId}.'/*/*/*/.'.$$event{Id};
|
||||
#Debug( "LP1:$link_path" );
|
||||
my @links = glob($link_path);
|
||||
#Debug( "L:".$links[0].": $!" );
|
||||
if ( @links ) {
|
||||
( $link_path ) = ( $links[0] =~ /^(.*)$/ ); # De-taint
|
||||
#Debug( "LP2:$link_path" );
|
||||
|
||||
( my $day_path = $link_path ) =~ s/\.\d+//;
|
||||
#Debug( "DP:$day_path" );
|
||||
my $event_path = $day_path.readlink( $link_path );
|
||||
( $event_path ) = ( $event_path =~ /^(.*)$/ ); # De-taint
|
||||
#Debug( "EP:$event_path" );
|
||||
my $command = "/bin/rm -rf $event_path";
|
||||
#Debug( "C:$command" );
|
||||
ZoneMinder::General::executeShellCommand( $command );
|
||||
|
||||
unlink( $link_path ) or Error( "Unable to unlink '$link_path': $!" );
|
||||
|
||||
my @path_parts = split( /\//, $event_path );
|
||||
for ( my $i = int(@path_parts)-2; $i >= 1; $i-- ) {
|
||||
my $delete_path = join( '/', @path_parts[0..$i] );
|
||||
#Debug( "DP$i:$delete_path" );
|
||||
my @has_files = glob( join('/', $storage_path,$delete_path,'*' ) );
|
||||
#Debug( "HF1:".$has_files[0] ) if ( @has_files );
|
||||
last if ( @has_files );
|
||||
@has_files = glob( join('/', $storage_path, $delete_path, '.[0-9]*' ) );
|
||||
#Debug( "HF2:".$has_files[0] ) if ( @has_files );
|
||||
last if ( @has_files );
|
||||
my $command = "/bin/rm -rf $storage_path/$delete_path";
|
||||
ZoneMinder::General::executeShellCommand( $command );
|
||||
}
|
||||
} # end if links
|
||||
} else {
|
||||
my $command = '/bin/rm -rf '. $storage_path . '/'. $event->RelativePath();
|
||||
ZoneMinder::General::executeShellCommand( $command );
|
||||
}
|
||||
} # end sub delete_files
|
||||
|
||||
|
@ -456,10 +457,11 @@ sub MoveTo {
|
|||
if ( @$err ) {
|
||||
for my $diag (@$err) {
|
||||
my ($file, $message) = %$diag;
|
||||
next if $message eq 'File exists';
|
||||
if ($file eq '') {
|
||||
$error .= "general error: $message\n";
|
||||
} else {
|
||||
$error .= "problem unlinking $file: $message\n";
|
||||
$error .= "problem making $file: $message\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,24 +133,25 @@ sub Sql {
|
|||
my $self = $_[0];
|
||||
if ( ! $$self{Sql} ) {
|
||||
my $filter_expr = ZoneMinder::General::jsonDecode( $self->{Query} );
|
||||
my $sql = "SELECT E.*,
|
||||
my $sql = 'SELECT E.*,
|
||||
unix_timestamp(E.StartTime) as Time,
|
||||
M.Name as MonitorName,
|
||||
M.DefaultRate,
|
||||
M.DefaultScale
|
||||
FROM Events as E
|
||||
INNER JOIN Monitors as M on M.Id = E.MonitorId
|
||||
";
|
||||
INNER JOIN Storage as S on S.Id = E.StorageId
|
||||
';
|
||||
$self->{Sql} = '';
|
||||
|
||||
if ( $filter_expr->{terms} ) {
|
||||
foreach my $term ( @{$filter_expr->{terms}} ) {
|
||||
|
||||
if ( exists($term->{cnj}) ) {
|
||||
$self->{Sql} .= ' '.$term->{cnj}." ";
|
||||
$self->{Sql} .= ' '.$term->{cnj}.' ';
|
||||
}
|
||||
if ( exists($term->{obr}) ) {
|
||||
$self->{Sql} .= ' '.str_repeat( "(", $term->{obr} )." ";
|
||||
$self->{Sql} .= ' '.str_repeat( '(', $term->{obr} ).' ';
|
||||
}
|
||||
my $value = $term->{val};
|
||||
my @value_list;
|
||||
|
@ -159,7 +160,7 @@ sub Sql {
|
|||
my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/;
|
||||
$self->{Sql} .= 'M.'.$temp_attr_name;
|
||||
} elsif ( $term->{attr} =~ /^Server/ ) {
|
||||
$self->{Sql} .= 'M.'.$term->{attr};
|
||||
$self->{Sql} .= 'S.'.$term->{attr};
|
||||
|
||||
# StartTime options
|
||||
} elsif ( $term->{attr} eq 'DateTime' ) {
|
||||
|
@ -171,9 +172,9 @@ sub Sql {
|
|||
} elsif ( $term->{attr} eq 'StartDate' ) {
|
||||
$self->{Sql} .= 'to_days( E.StartTime )';
|
||||
} elsif ( $term->{attr} eq 'Time' ) {
|
||||
$self->{Sql} .= "extract( hour_second from E.StartTime )";
|
||||
$self->{Sql} .= 'extract( hour_second from E.StartTime )';
|
||||
} elsif ( $term->{attr} eq 'Weekday' ) {
|
||||
$self->{Sql} .= "weekday( E.StartTime )";
|
||||
$self->{Sql} .= 'weekday( E.StartTime )';
|
||||
|
||||
# EndTIme options
|
||||
} elsif ( $term->{attr} eq 'EndDateTime' ) {
|
||||
|
@ -181,7 +182,7 @@ sub Sql {
|
|||
} elsif ( $term->{attr} eq 'EndDate' ) {
|
||||
$self->{Sql} .= 'to_days( E.EndTime )';
|
||||
} elsif ( $term->{attr} eq 'EndTime' ) {
|
||||
$self->{Sql} .= "extract( hour_second from E.EndTime )";
|
||||
$self->{Sql} .= 'extract( hour_second from E.EndTime )';
|
||||
} elsif ( $term->{attr} eq 'EndWeekday' ) {
|
||||
$self->{Sql} .= "weekday( E.EndTime )";
|
||||
|
||||
|
@ -212,6 +213,8 @@ sub Sql {
|
|||
$value = "'$ZoneMinder::Config::Config{ZM_SERVER_ID}'";
|
||||
# This gets used later, I forget for what
|
||||
$$self{Server} = new ZoneMinder::Server( $ZoneMinder::Config::Config{ZM_SERVER_ID} );
|
||||
} elsif ( $temp_value eq 'NULL' ) {
|
||||
$value = $temp_value;
|
||||
} else {
|
||||
$value = "'$temp_value'";
|
||||
# This gets used later, I forget for what
|
||||
|
|
|
@ -172,7 +172,6 @@ MAIN: while( $loop ) {
|
|||
|
||||
foreach my $Storage (
|
||||
ZoneMinder::Storage->find( ($Config{ZM_SERVER_ID} ? ( ServerId => $Config{ZM_SERVER_ID} ) : () ) ),
|
||||
new ZoneMinder::Storage(),
|
||||
) {
|
||||
Debug('Checking events in ' . $Storage->Path() );
|
||||
if ( ! chdir( $Storage->Path() ) ) {
|
||||
|
@ -238,8 +237,13 @@ MAIN: while( $loop ) {
|
|||
} elsif ( $$Storage{Scheme} eq 'Medium' ) {
|
||||
foreach my $event_dir ( glob("$monitor_dir/*/*") ) {
|
||||
next if ! -d $event_dir;
|
||||
my $Event = $fs_events->{$event} = new ZoneMinder::Event();
|
||||
$$Event{Id} = $event;
|
||||
my ( $date, $event_id ) = $event_dir =~ /^$monitor_dir\/(\d{4}\-\d{2}\-\d{2})\/(\d\+)$/;
|
||||
if ( ! $event_id ) {
|
||||
Debug("Unable to parse date/event_id from $event_dir");
|
||||
next;
|
||||
}
|
||||
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
|
||||
$$Event{Id} = $event_id;
|
||||
$$Event{Path} = $event_dir;
|
||||
$Event->MonitorId( $monitor_dir );
|
||||
$Event->StorageId( $Storage->Id() );
|
||||
|
@ -357,8 +361,18 @@ Debug("Event $db_event is not in fs.");
|
|||
}
|
||||
next;
|
||||
}
|
||||
if ( ! $Event->EndTime() ) {
|
||||
Debug("Event $$Event{Id} has no end time. deleting it.");
|
||||
if ( $age > $Config{ZM_AUDIT_MIN_AGE} ) {
|
||||
if ( confirm() ) {
|
||||
$Event->delete();
|
||||
$cleaned = 1;
|
||||
}
|
||||
next;
|
||||
}
|
||||
}
|
||||
if ( $Event->check_for_in_filesystem() ) {
|
||||
Debug('Database events apparently exists at ' . $Event->Path() );
|
||||
Debug("Database event $$Event{Id} apparently exists at " . $Event->Path() );
|
||||
} else {
|
||||
if ( $age > $Config{ZM_AUDIT_MIN_AGE} ) {
|
||||
aud_print( "Database event '$db_monitor/$db_event' does not exist at " . $Event->Path().' in filesystem' );
|
||||
|
@ -588,6 +602,26 @@ Debug("Event $db_event is not in fs.");
|
|||
} # end if ZM_LOG_DATABASE_LIMIT
|
||||
$loop = $continuous;
|
||||
|
||||
my $eventcounts_sql = q`
|
||||
UPDATE Monitors SET
|
||||
TotalEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id),
|
||||
TotalEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND DiskSpace IS NOT NULL),
|
||||
HourEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB( NOW(), INTERVAL 1 hour) ),
|
||||
HourEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 hour) AND DiskSpace IS NOT NULL),
|
||||
DayEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 day)),
|
||||
DayEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 day) AND DiskSpace IS NOT NULL),
|
||||
WeekEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 week)),
|
||||
WeekEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 week) AND DiskSpace IS NOT NULL),
|
||||
MonthEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB( NOW(), INTERVAL 1 month)),
|
||||
MonthEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 month) AND DiskSpace IS NOT NULL),
|
||||
ArchivedEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1),
|
||||
ArchivedEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1 AND DiskSpace IS NOT NULL)
|
||||
`;
|
||||
|
||||
my $eventcounts_sth = $dbh->prepare_cached( $eventcounts_sql );
|
||||
$eventcounts_sth->execute();
|
||||
$eventcounts_sth->finish();
|
||||
|
||||
sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ) if $continuous;
|
||||
};
|
||||
|
||||
|
|
|
@ -69,8 +69,6 @@ use POSIX;
|
|||
use Socket;
|
||||
use IO::Handle;
|
||||
use Time::HiRes qw(usleep);
|
||||
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
||||
use Sys::CpuLoad;
|
||||
|
||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||
#use Data::Dumper;
|
||||
|
@ -101,6 +99,7 @@ my @daemons = (
|
|||
'zmx10.pl',
|
||||
'zmwatch.pl',
|
||||
'zmupdate.pl',
|
||||
'zmstats.pl',
|
||||
'zmtrack.pl',
|
||||
'zmtelemetry.pl'
|
||||
);
|
||||
|
@ -149,8 +148,11 @@ socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" );
|
|||
|
||||
my $saddr = sockaddr_un( SOCK_FILE );
|
||||
my $server_up = connect( CLIENT, $saddr );
|
||||
|
||||
if ( ! $server_up ) {
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
||||
use Sys::CpuLoad;
|
||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
||||
'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
||||
Error("Failed Updating status of Server record to Not RUnning for Id=$Config{ZM_SERVER_ID}" . $dbh->errstr());
|
||||
|
@ -234,6 +236,7 @@ use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
|||
use Sys::CpuLoad;
|
||||
#use Data::Dumper;
|
||||
|
||||
# We count 100 of these, so total timeout is this value *100.
|
||||
use constant KILL_DELAY => 100*1000; # 1/10th of a second
|
||||
|
||||
our %cmd_hash;
|
||||
|
@ -281,14 +284,29 @@ sub run {
|
|||
my $win = $rin;
|
||||
my $ein = $win;
|
||||
my $timeout = 1;
|
||||
my $Server = undef;
|
||||
my $secs_count = 0;
|
||||
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
require ZoneMinder::Server;
|
||||
dPrint( ZoneMinder::Logger::INFO, 'Loading Server record' );
|
||||
$Server = new ZoneMinder::Server( $Config{ZM_SERVER_ID} );
|
||||
dPrint( ZoneMinder::Logger::INFO, 'Loading Server record have ' . $$Server{Name} );
|
||||
}
|
||||
|
||||
while( 1 ) {
|
||||
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
$dbh = zmDbConnect() if ! $dbh->ping();
|
||||
my @cpuload = Sys::CpuLoad::load();
|
||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
||||
if ( $secs_count % 60 ) {
|
||||
$dbh = zmDbConnect() if ! $dbh->ping();
|
||||
my @cpuload = Sys::CpuLoad::load();
|
||||
dPrint( ZoneMinder::Logger::INFO, 'Updating Server record' );
|
||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
||||
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
||||
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
|
||||
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
|
||||
}
|
||||
}
|
||||
$secs_count += 1;
|
||||
}
|
||||
my $nfound = select( my $rout = $rin, undef, undef, $timeout );
|
||||
if ( $nfound > 0 ) {
|
||||
|
@ -296,12 +314,16 @@ sub run {
|
|||
my $paddr = accept( CLIENT, SERVER );
|
||||
my $message = <CLIENT>;
|
||||
|
||||
next if ( !$message );
|
||||
next if !$message;
|
||||
|
||||
my ( $command, $daemon, @args ) = split( /;/, $message );
|
||||
|
||||
if ( $command eq 'start' ) {
|
||||
start( $daemon, @args );
|
||||
if ( $Server and exists $$Server{$daemon} and ! $$Server{$daemon} ) {
|
||||
Debug("Not running $daemon because it is turned off for this server.");
|
||||
} else {
|
||||
start( $daemon, @args );
|
||||
}
|
||||
} elsif ( $command eq 'stop' ) {
|
||||
stop( $daemon, @args );
|
||||
} elsif ( $command eq 'restart' ) {
|
||||
|
@ -505,7 +527,7 @@ sub kill_until_dead {
|
|||
my $blockset = POSIX::SigSet->new(SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, $blockset, $sigset ) or die "dying at block...\n";
|
||||
while( $process and $$process{pid} and kill( 0, $$process{pid} ) ) {
|
||||
if ( $count++ > 50 ) {
|
||||
if ( $count++ > 100 ) {
|
||||
dPrint( ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at "
|
||||
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||
.". Sending KILL to pid $$process{pid}\n"
|
||||
|
@ -526,7 +548,6 @@ sub _stop {
|
|||
my $pid = send_stop( $final, $process );
|
||||
return if ! $pid;
|
||||
delete( $cmd_hash{$$process{command}} );
|
||||
|
||||
kill_until_dead( $process );
|
||||
}
|
||||
|
||||
|
@ -578,7 +599,8 @@ sub reload {
|
|||
sub logrot {
|
||||
logReinit();
|
||||
foreach my $process ( values( %pid_hash ) ) {
|
||||
if ( $process->{pid} && $process->{command} =~ /^zm.*\.pl/ ) {
|
||||
if ( $process->{pid} ) {
|
||||
# && $process->{command} =~ /^zm.*\.pl/ ) {
|
||||
kill( 'HUP', $process->{pid} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,24 +219,18 @@ sub getFilters {
|
|||
) ORDER BY Name';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Unable to prepare '$sql': ".$dbh->errstr() );
|
||||
my $res;
|
||||
if ( $filter_name ) {
|
||||
$res = $sth->execute( $filter_name )
|
||||
or Fatal( "Unable to execute '$sql': ".$sth->errstr() );
|
||||
} else {
|
||||
$res = $sth->execute()
|
||||
or Fatal( "Unable to execute '$sql': ".$sth->errstr() );
|
||||
}
|
||||
my $res = $sth->execute( @sql_values )
|
||||
or Fatal( "Unable to execute '$sql': ".$sth->errstr() );
|
||||
FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) {
|
||||
my $filter = new ZoneMinder::Filter( $$db_filter{Id}, $db_filter );
|
||||
Debug( "Found filter '$db_filter->{Name}'\n" );
|
||||
my $sql = $filter->Sql();
|
||||
my $filter_sql = $filter->Sql();
|
||||
|
||||
if ( ! $sql ) {
|
||||
if ( ! $filter_sql ) {
|
||||
Error( "Error parsing Sql. skipping filter '$db_filter->{Name}'\n" );
|
||||
next FILTER;
|
||||
}
|
||||
push( @filters, $filter );
|
||||
push @filters, $filter;
|
||||
}
|
||||
$sth->finish();
|
||||
if ( ! @filters ) {
|
||||
|
@ -245,7 +239,7 @@ FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) {
|
|||
Debug( "Got " . @filters . " filters" );
|
||||
}
|
||||
|
||||
return( @filters );
|
||||
return @filters;
|
||||
} # end sub getFilters
|
||||
|
||||
sub checkFilter {
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
#!/usr/bin/perl -wT
|
||||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder WatchDog Script, $Date$, $Revision$
|
||||
# Copyright (C) 2001-2008 Philip Coombes
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zmwatch.pl - ZoneMinder Stats Updating Script
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zmstats.pl
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This does background updating various stats in the db like event counts, diskspace, etc.
|
||||
|
||||
=cut
|
||||
use strict;
|
||||
use bytes;
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# These are the elements you can edit to suit your installation
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
use constant START_DELAY => 30; # To give everything else time to start
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# Don't change anything below here
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
@EXTRA_PERL_LIB@
|
||||
use ZoneMinder;
|
||||
use ZoneMinder::Storage;
|
||||
use POSIX;
|
||||
use DBI;
|
||||
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||
|
||||
$| = 1;
|
||||
|
||||
$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin';
|
||||
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
|
||||
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
||||
|
||||
logInit();
|
||||
logSetSignal();
|
||||
|
||||
Info( "Stats Daemon starting in ".START_DELAY." seconds\n" );
|
||||
sleep( START_DELAY );
|
||||
|
||||
my $dbh = zmDbConnect();
|
||||
|
||||
my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'SELECT * FROM Monitors';
|
||||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
|
||||
my $eventcounts_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId,
|
||||
COUNT(Id) AS TotalEvents,
|
||||
SUM(DiskSpace) AS TotalEventDiskSpace,
|
||||
SUM(IF(Archived,1,0)) AS ArchivedEvents,
|
||||
SUM(IF(Archived,DiskSpace,0)) AS ArchivedEventDiskSpace,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 hour),1,0)) AS HourEvents,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 hour),DiskSpace,0)) AS HourEventDiskSpace,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 day),1,0)) AS DayEvents,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 day),DiskSpace,0)) AS DayEventDiskSpace,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 week),1,0)) AS WeekEvents,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 week),DiskSpace,0)) AS WeekEventDiskSpace,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 month),1,0)) AS MonthEvents,
|
||||
SUM(IF(StartTime > DATE_SUB(NOW(), INTERVAL 1 month),DiskSpace,0)) AS MonthEventDiskSpace
|
||||
FROM Events GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.TotalEvents = E.TotalEvents,
|
||||
Monitors.TotalEventDiskSpace = E.TotalEventDiskSpace,
|
||||
Monitors.ArchivedEvents = E.ArchivedEvents,
|
||||
Monitors.ArchivedEventDiskSpace = E.ArchivedEventDiskSpace,
|
||||
Monitors.HourEvents = E.HourEvents,
|
||||
Monitors.HourEventDiskSpace = E.HourEventDiskSpace,
|
||||
Monitors.DayEvents = E.DayEvents,
|
||||
Monitors.DayEventDiskSpace = E.DayEventDiskSpace,
|
||||
Monitors.WeekEvents = E.WeekEvents,
|
||||
Monitors.WeekEventDiskSpace = E.WeekEventDiskSpace,
|
||||
Monitors.MonthEvents = E.MonthEvents,
|
||||
Monitors.MonthEventDiskSpace = E.MonthEventDiskSpace
|
||||
`;
|
||||
|
||||
|
||||
my $eventcounts_hour_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId, COUNT(*) AS HourEvents, SUM(DiskSpace) AS HourEventDiskSpace
|
||||
FROM Events_Hour GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.HourEvents = E.HourEvents,
|
||||
Monitors.HourEventDiskSpace = E.HourEventDiskSpace
|
||||
`;
|
||||
|
||||
|
||||
my $eventcounts_day_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId, COUNT(*) AS DayEvents, SUM(DiskSpace) AS DayEventDiskSpace
|
||||
FROM Events_Day GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.DayEvents = E.DayEvents,
|
||||
Monitors.DayEventDiskSpace = E.DayEventDiskSpace
|
||||
`;
|
||||
|
||||
my $eventcounts_week_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId, COUNT(*) AS WeekEvents, SUM(DiskSpace) AS WeekEventDiskSpace
|
||||
FROM Events_Week GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.WeekEvents = E.WeekEvents,
|
||||
Monitors.WeekEventDiskSpace = E.WeekEventDiskSpace
|
||||
`;
|
||||
|
||||
my $eventcounts_month_sql = q`
|
||||
UPDATE Monitors INNER JOIN (
|
||||
SELECT MonitorId, COUNT(*) AS MonthEvents, SUM(DiskSpace) AS MonthEventDiskSpace
|
||||
FROM Events_Month GROUP BY MonitorId
|
||||
) AS E ON E.MonitorId=Monitors.Id SET
|
||||
Monitors.MonthEvents = E.MonthEvents,
|
||||
Monitors.MonthEventDiskSpace = E.MonthEventDiskSpace
|
||||
`;
|
||||
|
||||
|
||||
my $eventcounts_sth = $dbh->prepare_cached( $eventcounts_sql );
|
||||
my $eventcounts_hour_sth = $dbh->prepare_cached( $eventcounts_hour_sql );
|
||||
my $eventcounts_day_sth = $dbh->prepare_cached( $eventcounts_day_sql );
|
||||
my $eventcounts_week_sth = $dbh->prepare_cached( $eventcounts_week_sql );
|
||||
my $eventcounts_month_sth = $dbh->prepare_cached( $eventcounts_month_sql );
|
||||
|
||||
while( 1 ) {
|
||||
$dbh->ping();
|
||||
|
||||
$dbh->do('DELETE FROM Events_Hour WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 hour)');
|
||||
$dbh->do('DELETE FROM Events_Day WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 day)');
|
||||
$dbh->do('DELETE FROM Events_Week WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 week)');
|
||||
$dbh->do('DELETE FROM Events_Month WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 month)');
|
||||
$eventcounts_hour_sth->execute( ) or Error( "Can't execute: ".$eventcounts_sth->errstr() );
|
||||
$eventcounts_day_sth->execute( ) or Error( "Can't execute: ".$eventcounts_sth->errstr() );
|
||||
$eventcounts_week_sth->execute( ) or Error( "Can't execute: ".$eventcounts_sth->errstr() );
|
||||
$eventcounts_month_sth->execute( ) or Error( "Can't execute: ".$eventcounts_sth->errstr() );
|
||||
|
||||
sleep( $Config{ZM_STATS_CHECK_INTERVAL} );
|
||||
} # end while (1)
|
||||
|
||||
Info( "Stats Daemon exiting\n" );
|
||||
exit();
|
||||
1;
|
||||
__END__
|
|
@ -932,17 +932,44 @@ sub patchDB {
|
|||
my $dbh = shift;
|
||||
my $version = shift;
|
||||
|
||||
my $file = ( $updateDir ? $updateDir : $Config{ZM_PATH_DATA}.'/db' ) . "/zm_update-$version.sql";
|
||||
my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
||||
my $command = 'mysql';
|
||||
if ( defined($portOrSocket) ) {
|
||||
if ( $portOrSocket =~ /^\// ) {
|
||||
$command .= ' -S'.$portOrSocket;
|
||||
} else {
|
||||
$command .= ' -h'.$host.' -P'.$portOrSocket;
|
||||
}
|
||||
} else {
|
||||
$command .= ' -h'.$host;
|
||||
}
|
||||
if ( $dbUser ) {
|
||||
$command .= ' -u'.$dbUser;
|
||||
$command .= ' -p"'.$dbPass.'"' if $dbPass;
|
||||
}
|
||||
$command .= ' '.$Config{ZM_DB_NAME}.' < ';
|
||||
if ( $updateDir ) {
|
||||
$command .= $updateDir;
|
||||
} else {
|
||||
$command .= $Config{ZM_PATH_DATA}.'/db';
|
||||
}
|
||||
$command .= '/zm_update-'.$version.'.sql';
|
||||
|
||||
open( my $fh, '<', $file ) or die "Unable to open $file $!";
|
||||
$/ = undef;
|
||||
my $sql = <$fh>;
|
||||
close $fh;
|
||||
$dbh->do($sql) or die $dbh->errstr();
|
||||
print( "Executing '$command'\n" ) if ( logDebugging() );
|
||||
my $output = qx($command);
|
||||
my $status = $? >> 8;
|
||||
if ( $status || logDebugging() ) {
|
||||
chomp( $output );
|
||||
print( "Output: $output\n" );
|
||||
}
|
||||
if ( $status ) {
|
||||
die( "Command '$command' exited with status: $status\n" );
|
||||
}
|
||||
print( "\nDatabase successfully upgraded to version $version.\n" );
|
||||
$sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'";
|
||||
my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'";
|
||||
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() );
|
||||
$sth->finish();
|
||||
}
|
||||
|
||||
sub migratePaths {
|
||||
|
|
|
@ -79,31 +79,12 @@ my $sql = $Config{ZM_SERVER_ID} ? 'SELECT * FROM Monitors WHERE ServerId=?' : 'S
|
|||
my $sth = $dbh->prepare_cached( $sql )
|
||||
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||
|
||||
my $eventcounts_sql = q`
|
||||
UPDATE Monitors SET
|
||||
TotalEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id),
|
||||
TotalEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND DiskSpace IS NOT NULL),
|
||||
HourEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB( NOW(), INTERVAL 1 hour) ),
|
||||
HourEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 hour) AND DiskSpace IS NOT NULL),
|
||||
DayEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 day)),
|
||||
DayEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 day) AND DiskSpace IS NOT NULL),
|
||||
WeekEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 week)),
|
||||
WeekEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 week) AND DiskSpace IS NOT NULL),
|
||||
MonthEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB( NOW(), INTERVAL 1 month)),
|
||||
MonthEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND StartTime > DATE_SUB(NOW(), INTERVAL 1 month) AND DiskSpace IS NOT NULL),
|
||||
ArchivedEvents=(SELECT COUNT(Id) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1),
|
||||
ArchivedEventDiskSpace=(SELECT SUM(DiskSpace) FROM Events WHERE MonitorId=Monitors.Id AND Archived=1 AND DiskSpace IS NOT NULL)
|
||||
WHERE Id=?`;
|
||||
|
||||
my $eventcounts_sth = $dbh->prepare_cached( $eventcounts_sql );
|
||||
|
||||
while( 1 ) {
|
||||
|
||||
my $res = $sth->execute( $Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID} : () )
|
||||
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||
while( my $monitor = $sth->fetchrow_hashref() ) {
|
||||
|
||||
$eventcounts_sth->execute( $$monitor{Id} ) or Error( "Can't execute: ".$eventcounts_sth->errstr() );
|
||||
|
||||
my $now = time();
|
||||
next if $monitor->{Function} eq 'None';
|
||||
my $restart = 0;
|
||||
|
@ -196,25 +177,13 @@ while( 1 ) {
|
|||
} # end if check analysis daemon
|
||||
# Prevent open handles building up if we have connect to shared memory
|
||||
zmMemInvalidate( $monitor ); # Close our file handle to the zmc process we are about to end
|
||||
|
||||
|
||||
} # end foreach monitor
|
||||
$eventcounts_sth->finish();
|
||||
|
||||
my $diskspace_sql = 'UPDATE Storage SET DiskSpace =(SELECT SUM(DiskSpace) FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL)';
|
||||
my $diskspace_sth = $dbh->prepare_cached( $diskspace_sql )
|
||||
or Fatal( "Can't prepare '$diskspace_sql': ".$dbh->errstr() );
|
||||
foreach my $Storage ( ZoneMinder::Storage->find() ) {
|
||||
Debug("Updating disk space for $$Storage{Name} was $$Storage{DiskSpace}");
|
||||
$diskspace_sth->execute( $$Storage{Id} ) or Error( "Can't execute: ".$diskspace_sth->errstr() );
|
||||
$Storage->load();
|
||||
Debug("Updated disk space for $$Storage{Name} to $$Storage{DiskSpace}");
|
||||
}
|
||||
$diskspace_sth->finish();
|
||||
sleep( $Config{ZM_WATCH_CHECK_INTERVAL} );
|
||||
} # end while (1)
|
||||
|
||||
Info( "Watchdog exiting\n" );
|
||||
exit();
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
|
|
@ -77,10 +77,24 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream
|
|||
Debug(4, "Looking at packet with stream index (%d) with keyframe (%d), frames_to_keep is (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), frames_to_keep );
|
||||
|
||||
// Want frames_to_keep video keyframes. Otherwise, we may not have enough
|
||||
if ( ( av_packet->stream_index == stream_id) && ( av_packet->flags & AV_PKT_FLAG_KEY ) ) {
|
||||
if ( ( av_packet->stream_index == stream_id) ) {
|
||||
//&& ( av_packet->flags & AV_PKT_FLAG_KEY ) ) {
|
||||
frames_to_keep --;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we start on a keyframe
|
||||
for ( ; it != pktQueue.rend(); ++it ) {
|
||||
ZMPacket *zm_packet = *it;
|
||||
AVPacket *av_packet = &(zm_packet->packet);
|
||||
|
||||
Debug(4, "Looking for keyframe at packet with stream index (%d) with keyframe (%d), frames_to_keep is (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), frames_to_keep );
|
||||
|
||||
// Want frames_to_keep video keyframes. Otherwise, we may not have enough
|
||||
if ( ( av_packet->stream_index == stream_id) && ( av_packet->flags & AV_PKT_FLAG_KEY ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( frames_to_keep ) {
|
||||
Debug(3, "Hit end of queue, still need (%d) video keyframes", frames_to_keep );
|
||||
}
|
||||
|
|
|
@ -313,6 +313,7 @@ bool VideoStore::open() {
|
|||
if (ret < 0) {
|
||||
Error("Could not open out file '%s': %s\n", filename,
|
||||
av_make_error_string(ret).c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -346,68 +347,83 @@ bool VideoStore::open() {
|
|||
}
|
||||
|
||||
VideoStore::~VideoStore() {
|
||||
if (audio_out_codec) {
|
||||
// The codec queues data. We need to send a flush command and out
|
||||
// whatever we get. Failures are not fatal.
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
|
||||
while (1) {
|
||||
if ( oc->pb ) {
|
||||
|
||||
if (audio_out_codec) {
|
||||
// The codec queues data. We need to send a flush command and out
|
||||
// whatever we get. Failures are not fatal.
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
|
||||
while (1) {
|
||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||
// Put encoder into flushing mode
|
||||
avcodec_send_frame(audio_out_ctx, NULL);
|
||||
ret = avcodec_receive_packet(audio_out_ctx, &pkt);
|
||||
if (ret < 0) {
|
||||
if (AVERROR_EOF != ret) {
|
||||
Error("ERror encoding audio while flushing (%d) (%s)", ret,
|
||||
// Put encoder into flushing mode
|
||||
avcodec_send_frame(audio_out_ctx, NULL);
|
||||
ret = avcodec_receive_packet(audio_out_ctx, &pkt);
|
||||
if (ret < 0) {
|
||||
if (AVERROR_EOF != ret) {
|
||||
Error("ERror encoding audio while flushing (%d) (%s)", ret,
|
||||
av_err2str(ret));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
int got_packet = 0;
|
||||
ret =
|
||||
int got_packet = 0;
|
||||
ret =
|
||||
avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet);
|
||||
if (ret < 0) {
|
||||
Error("ERror encoding audio while flushing (%d) (%s)", ret,
|
||||
if (ret < 0) {
|
||||
Error("ERror encoding audio while flushing (%d) (%s)", ret,
|
||||
av_err2str(ret));
|
||||
break;
|
||||
}
|
||||
Debug(1, "Have audio encoder, need to flush it's out");
|
||||
if (!got_packet) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Debug(1, "Have audio encoder, need to flush it's out");
|
||||
if (!got_packet) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts,
|
||||
Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts,
|
||||
pkt.dts, pkt.duration);
|
||||
pkt.pts = audio_next_pts;
|
||||
pkt.dts = audio_next_dts;
|
||||
pkt.pts = audio_next_pts;
|
||||
pkt.dts = audio_next_dts;
|
||||
|
||||
if (pkt.duration > 0)
|
||||
pkt.duration =
|
||||
if (pkt.duration > 0)
|
||||
pkt.duration =
|
||||
av_rescale_q(pkt.duration, audio_out_ctx->time_base,
|
||||
audio_out_stream->time_base);
|
||||
audio_next_pts += pkt.duration;
|
||||
audio_next_dts += pkt.duration;
|
||||
audio_out_stream->time_base);
|
||||
audio_next_pts += pkt.duration;
|
||||
audio_next_dts += pkt.duration;
|
||||
|
||||
Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts,
|
||||
Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts,
|
||||
pkt.dts, pkt.duration);
|
||||
pkt.stream_index = audio_out_stream->index;
|
||||
av_interleaved_write_frame(oc, &pkt);
|
||||
zm_av_packet_unref(&pkt);
|
||||
} // while have buffered frames
|
||||
} // end if audio_out_codec
|
||||
pkt.stream_index = audio_out_stream->index;
|
||||
av_interleaved_write_frame(oc, &pkt);
|
||||
zm_av_packet_unref(&pkt);
|
||||
} // while have buffered frames
|
||||
} // end if audio_out_codec
|
||||
|
||||
// Flush Queues
|
||||
av_interleaved_write_frame(oc, NULL);
|
||||
// Flush Queues
|
||||
av_interleaved_write_frame(oc, NULL);
|
||||
|
||||
/* Write the trailer before close */
|
||||
if (int rc = av_write_trailer(oc)) {
|
||||
Error("Error writing trailer %s", av_err2str(rc));
|
||||
} else {
|
||||
Debug(3, "Sucess Writing trailer");
|
||||
/* Write the trailer before close */
|
||||
if (int rc = av_write_trailer(oc)) {
|
||||
Error("Error writing trailer %s", av_err2str(rc));
|
||||
} else {
|
||||
Debug(3, "Sucess Writing trailer");
|
||||
}
|
||||
|
||||
// WHen will be not using a file ?
|
||||
if ( !(out_format->flags & AVFMT_NOFILE) ) {
|
||||
/* Close the out file. */
|
||||
Debug(2, "Closing");
|
||||
if (int rc = avio_close(oc->pb)) {
|
||||
oc->pb = NULL;
|
||||
Error("Error closing avio %s", av_err2str(rc));
|
||||
}
|
||||
} else {
|
||||
Debug(3, "Not closing avio because we are not writing to a file.");
|
||||
}
|
||||
}
|
||||
|
||||
// I wonder if we should be closing the file first.
|
||||
// I also wonder if we really need to be doing all the ctx
|
||||
// allocation/de-allocation constantly, or whether we can just re-use it.
|
||||
|
@ -463,16 +479,6 @@ VideoStore::~VideoStore() {
|
|||
#endif
|
||||
}
|
||||
|
||||
// WHen will be not using a file ?
|
||||
if (!(out_format->flags & AVFMT_NOFILE)) {
|
||||
/* Close the out file. */
|
||||
if (int rc = avio_close(oc->pb)) {
|
||||
Error("Error closing avio %s", av_err2str(rc));
|
||||
}
|
||||
} else {
|
||||
Debug(3, "Not closing avio because we are not writing to a file.");
|
||||
}
|
||||
|
||||
/* free the stream */
|
||||
avformat_free_context(oc);
|
||||
}
|
||||
|
|
|
@ -168,6 +168,8 @@ int main( int argc, char *argv[] ) {
|
|||
|
||||
if ( zm_reload ) {
|
||||
monitor->Reload();
|
||||
logTerm();
|
||||
logInit( log_id_string );
|
||||
zm_reload = false;
|
||||
}
|
||||
sigprocmask( SIG_UNBLOCK, &block_set, 0 );
|
||||
|
|
|
@ -313,6 +313,14 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
} // end foreach n_monitors
|
||||
sigprocmask(SIG_UNBLOCK, &block_set, 0);
|
||||
if ( zm_reload ) {
|
||||
for ( int i = 0; i < n_monitors; i++ ) {
|
||||
monitors[i]->Reload();
|
||||
}
|
||||
logTerm();
|
||||
logInit( log_id_string );
|
||||
zm_reload = false;
|
||||
}
|
||||
} // end while ! zm_terminate
|
||||
for ( int i = 0; i < n_monitors; i++ ) {
|
||||
delete monitors[i];
|
||||
|
|
|
@ -70,6 +70,7 @@ Cache::config('default', array('engine' => 'Apc'));
|
|||
*
|
||||
*/
|
||||
CakePlugin::load('Crud');
|
||||
CakePlugin::load('CakePHP-Enum-Behavior');
|
||||
|
||||
/**
|
||||
* You can attach event listeners to the request lifecycle as Dispatcher Filter. By default CakePHP bundles two filters:
|
||||
|
@ -142,6 +143,27 @@ foreach( $configvals as $key => $value) {
|
|||
Configure::write( $key, $value );
|
||||
}
|
||||
|
||||
// For Human-readability, use ZM_SERVER_HOST or ZM_SERVER_NAME in zm.conf, and convert it here to a ZM_SERVER_ID
|
||||
if ( ! defined('ZM_SERVER_ID') ) {
|
||||
App::uses('ClassRegistry', 'Utility');
|
||||
$ServerModel = ClassRegistry::init('Server');
|
||||
if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) {
|
||||
$Server = $ServerModel->find( 'first', array( 'conditions'=>array('Name'=>ZM_SERVER_NAME) ) );
|
||||
if ( ! $Server ) {
|
||||
Error('Invalid Multi-Server configration detected. ZM_SERVER_NAME set to ' . ZM_SERVER_NAME . ' in zm.conf, but no corresponding entry found in Servers table.');
|
||||
} else {
|
||||
define( 'ZM_SERVER_ID', $Server['Server']['Id'] );
|
||||
}
|
||||
} else if ( defined('ZM_SERVER_HOST') and ZM_SERVER_HOST ) {
|
||||
$Server = $ServerModel->find( 'first', array( 'conditions'=>array('Name'=>ZM_SERVER_HOST) ) );
|
||||
if ( ! $Server ) {
|
||||
Error('Invalid Multi-Server configration detected. ZM_SERVER_HOST set to ' . ZM_SERVER_HOST . ' in zm.conf, but no corresponding entry found in Servers table.');
|
||||
} else {
|
||||
define( 'ZM_SERVER_ID', $Server['Server']['Id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function process_configfile($configFile) {
|
||||
if ( is_readable( $configFile ) ) {
|
||||
$configvals = array();
|
||||
|
|
|
@ -13,12 +13,15 @@ class MonitorsController extends AppController {
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public $components = array('Paginator', 'RequestHandler');
|
||||
public $components = array('Paginator', 'RequestHandler');
|
||||
|
||||
public function beforeRender() {
|
||||
$this->set($this->Monitor->enumValues());
|
||||
}
|
||||
public function beforeFilter() {
|
||||
parent::beforeFilter();
|
||||
$canView = $this->Session->Read('monitorPermission');
|
||||
if ($canView =='None') {
|
||||
if ($canView == 'None') {
|
||||
throw new UnauthorizedException(__('Insufficient Privileges'));
|
||||
return;
|
||||
}
|
||||
|
@ -29,21 +32,21 @@ class MonitorsController extends AppController {
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function index() {
|
||||
public function index() {
|
||||
$this->Monitor->recursive = 0;
|
||||
|
||||
if ($this->request->params['named']) {
|
||||
$this->FilterComponent = $this->Components->load('Filter');
|
||||
//$conditions = $this->FilterComponent->buildFilter($this->request->params['named']);
|
||||
$conditions = $this->request->params['named'];
|
||||
} else {
|
||||
$conditions = array();
|
||||
}
|
||||
if ($this->request->params['named']) {
|
||||
$this->FilterComponent = $this->Components->load('Filter');
|
||||
//$conditions = $this->FilterComponent->buildFilter($this->request->params['named']);
|
||||
$conditions = $this->request->params['named'];
|
||||
} else {
|
||||
$conditions = array();
|
||||
}
|
||||
|
||||
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
|
||||
if (!empty($allowedMonitors)) {
|
||||
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
|
||||
if (!empty($allowedMonitors)) {
|
||||
$conditions['Monitor.Id' ] = $allowedMonitors;
|
||||
}
|
||||
}
|
||||
$find_array = array('conditions'=>$conditions,'contain'=>array('Group'));
|
||||
|
||||
if ( isset( $conditions['GroupId'] ) ) {
|
||||
|
@ -70,7 +73,7 @@ class MonitorsController extends AppController {
|
|||
'monitors' => $monitors,
|
||||
'_serialize' => array('monitors')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* view method
|
||||
|
@ -79,51 +82,57 @@ class MonitorsController extends AppController {
|
|||
* @param string $id
|
||||
* @return void
|
||||
*/
|
||||
public function view($id = null) {
|
||||
$this->Monitor->recursive = 0;
|
||||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
|
||||
if (!empty($allowedMonitors)) {
|
||||
$restricted = array('Monitor.' . $this->Monitor->primaryKey => $allowedMonitors);
|
||||
} else {
|
||||
$restricted = '';
|
||||
}
|
||||
|
||||
$options = array('conditions' => array(
|
||||
array('Monitor.' . $this->Monitor->primaryKey => $id),
|
||||
$restricted
|
||||
)
|
||||
);
|
||||
$monitor = $this->Monitor->find('first', $options);
|
||||
$this->set(array(
|
||||
'monitor' => $monitor,
|
||||
'_serialize' => array('monitor')
|
||||
));
|
||||
}
|
||||
public function view($id = null) {
|
||||
$this->Monitor->recursive = 0;
|
||||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
$allowedMonitors=preg_split ('@,@', $this->Session->Read('allowedMonitors'),NULL, PREG_SPLIT_NO_EMPTY);
|
||||
if (!empty($allowedMonitors)) {
|
||||
$restricted = array('Monitor.' . $this->Monitor->primaryKey => $allowedMonitors);
|
||||
} else {
|
||||
$restricted = '';
|
||||
}
|
||||
|
||||
$options = array('conditions' => array(
|
||||
array('Monitor.' . $this->Monitor->primaryKey => $id),
|
||||
$restricted
|
||||
)
|
||||
);
|
||||
$monitor = $this->Monitor->find('first', $options);
|
||||
$this->set(array(
|
||||
'monitor' => $monitor,
|
||||
'_serialize' => array('monitor')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* add method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add() {
|
||||
if ($this->request->is('post')) {
|
||||
public function add() {
|
||||
if ( $this->request->is('post') ) {
|
||||
|
||||
if ($this->Session->Read('systemPermission') != 'Edit')
|
||||
{
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
if ( $this->Session->Read('systemPermission') != 'Edit' ) {
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->Monitor->create();
|
||||
if ($this->Monitor->save($this->request->data)) {
|
||||
$this->daemonControl($this->Monitor->id, 'start');
|
||||
return $this->flash(__('The monitor has been saved.'), array('action' => 'index'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->Monitor->create();
|
||||
if ($this->Monitor->save($this->request->data)) {
|
||||
$this->daemonControl($this->Monitor->id, 'start');
|
||||
//return $this->flash(__('The monitor has been saved.'), array('action' => 'index'));
|
||||
$message = 'Saved';
|
||||
} else {
|
||||
$message = 'Error';
|
||||
}
|
||||
$this->set(array(
|
||||
'message' => $message,
|
||||
'_serialize' => array('message')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* edit method
|
||||
|
@ -132,40 +141,38 @@ class MonitorsController extends AppController {
|
|||
* @param string $id
|
||||
* @return void
|
||||
*/
|
||||
public function edit($id = null) {
|
||||
$this->Monitor->id = $id;
|
||||
public function edit($id = null) {
|
||||
$this->Monitor->id = $id;
|
||||
|
||||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
if ($this->Session->Read('monitorPermission') != 'Edit')
|
||||
{
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
if ($this->Monitor->save($this->request->data)) {
|
||||
$message = 'Saved';
|
||||
} else {
|
||||
$message = 'Error';
|
||||
}
|
||||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
if ($this->Session->Read('monitorPermission') != 'Edit') {
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
if ($this->Monitor->save($this->request->data)) {
|
||||
$message = 'Saved';
|
||||
} else {
|
||||
$message = 'Error';
|
||||
}
|
||||
|
||||
$this->set(array(
|
||||
'message' => $message,
|
||||
'_serialize' => array('message')
|
||||
));
|
||||
$this->set(array(
|
||||
'message' => $message,
|
||||
'_serialize' => array('message')
|
||||
));
|
||||
|
||||
// - restart or stop this monitor after change
|
||||
// - restart or stop this monitor after change
|
||||
$func = $this->Monitor->find('first', array(
|
||||
'fields' => array('Function'),
|
||||
'conditions' => array('Id' => $id)
|
||||
))['Monitor']['Function'];
|
||||
// We don't pass the request data as the monitor object because it may be a subset of the full monitor array
|
||||
if ( $func == 'None' ) {
|
||||
$this->daemonControl( $this->Monitor->id, 'stop' );
|
||||
} else {
|
||||
$this->daemonControl( $this->Monitor->id, 'restart' );
|
||||
$this->daemonControl( $this->Monitor->id, 'stop' );
|
||||
if ( ( $func != 'None' ) and ( $this->Monitor->ServerId == ZM_SERVER_ID ) ) {
|
||||
$this->daemonControl( $this->Monitor->id, 'start' );
|
||||
}
|
||||
}
|
||||
} // end function edit
|
||||
|
||||
/**
|
||||
* delete method
|
||||
|
@ -174,196 +181,183 @@ class MonitorsController extends AppController {
|
|||
* @param string $id
|
||||
* @return void
|
||||
*/
|
||||
public function delete($id = null) {
|
||||
$this->Monitor->id = $id;
|
||||
if (!$this->Monitor->exists()) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
if ($this->Session->Read('systemPermission') != 'Edit')
|
||||
{
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
$this->request->allowMethod('post', 'delete');
|
||||
public function delete($id = null) {
|
||||
$this->Monitor->id = $id;
|
||||
if (!$this->Monitor->exists()) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
if ($this->Session->Read('systemPermission') != 'Edit') {
|
||||
throw new UnauthorizedException(__('Insufficient privileges'));
|
||||
return;
|
||||
}
|
||||
$this->request->allowMethod('post', 'delete');
|
||||
|
||||
$this->daemonControl($this->Monitor->id, 'stop');
|
||||
$this->daemonControl($this->Monitor->id, 'stop');
|
||||
|
||||
if ($this->Monitor->delete()) {
|
||||
return $this->flash(__('The monitor has been deleted.'), array('action' => 'index'));
|
||||
} else {
|
||||
return $this->flash(__('The monitor could not be deleted. Please, try again.'), array('action' => 'index'));
|
||||
}
|
||||
}
|
||||
if ($this->Monitor->delete()) {
|
||||
return $this->flash(__('The monitor has been deleted.'), array('action' => 'index'));
|
||||
} else {
|
||||
return $this->flash(__('The monitor could not be deleted. Please, try again.'), array('action' => 'index'));
|
||||
}
|
||||
}
|
||||
|
||||
public function sourceTypes() {
|
||||
$sourceTypes = $this->Monitor->query("describe Monitors Type;");
|
||||
public function sourceTypes() {
|
||||
$sourceTypes = $this->Monitor->query("describe Monitors Type;");
|
||||
|
||||
preg_match('/^enum\((.*)\)$/', $sourceTypes[0]['COLUMNS']['Type'], $matches);
|
||||
foreach( explode(',', $matches[1]) as $value ) {
|
||||
$enum[] = trim( $value, "'" );
|
||||
}
|
||||
preg_match('/^enum\((.*)\)$/', $sourceTypes[0]['COLUMNS']['Type'], $matches);
|
||||
foreach( explode(',', $matches[1]) as $value ) {
|
||||
$enum[] = trim( $value, "'" );
|
||||
}
|
||||
|
||||
$this->set(array(
|
||||
'sourceTypes' => $enum,
|
||||
'_serialize' => array('sourceTypes')
|
||||
));
|
||||
}
|
||||
$this->set(array(
|
||||
'sourceTypes' => $enum,
|
||||
'_serialize' => array('sourceTypes')
|
||||
));
|
||||
}
|
||||
|
||||
// arm/disarm alarms
|
||||
// expected format: http(s):/portal-api-url/monitors/alarm/id:M/command:C.json
|
||||
// where M=monitorId
|
||||
// where C=on|off|status
|
||||
public function alarm()
|
||||
{
|
||||
$id = $this->request->params['named']['id'];
|
||||
$cmd = strtolower($this->request->params['named']['command']);
|
||||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
if ( $cmd != 'on' && $cmd != 'off' && $cmd != 'status')
|
||||
{
|
||||
throw new BadRequestException(__('Invalid command'));
|
||||
}
|
||||
$zm_path_bin = Configure::read('ZM_PATH_BIN');
|
||||
// arm/disarm alarms
|
||||
// expected format: http(s):/portal-api-url/monitors/alarm/id:M/command:C.json
|
||||
// where M=monitorId
|
||||
// where C=on|off|status
|
||||
public function alarm() {
|
||||
$id = $this->request->params['named']['id'];
|
||||
$cmd = strtolower($this->request->params['named']['command']);
|
||||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
if ( $cmd != 'on' && $cmd != 'off' && $cmd != 'status' ) {
|
||||
throw new BadRequestException(__('Invalid command'));
|
||||
}
|
||||
$zm_path_bin = Configure::read('ZM_PATH_BIN');
|
||||
|
||||
switch ($cmd)
|
||||
{
|
||||
case "on":
|
||||
$q = '-a';
|
||||
$verbose = "-v";
|
||||
break;
|
||||
case "off":
|
||||
$q = "-c";
|
||||
$verbose = "-v";
|
||||
break;
|
||||
case "status":
|
||||
$verbose = ""; // zmu has a bug - gives incorrect verbose output in this case
|
||||
$q = "-s";
|
||||
break;
|
||||
}
|
||||
switch ($cmd) {
|
||||
case 'on':
|
||||
$q = '-a';
|
||||
$verbose = '-v';
|
||||
break;
|
||||
case 'off':
|
||||
$q = '-c';
|
||||
$verbose = '-v';
|
||||
break;
|
||||
case 'status':
|
||||
$verbose = ''; // zmu has a bug - gives incorrect verbose output in this case
|
||||
$q = '-s';
|
||||
break;
|
||||
}
|
||||
|
||||
// form auth key based on auth credentials
|
||||
$this->loadModel('Config');
|
||||
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH'));
|
||||
// form auth key based on auth credentials
|
||||
$this->loadModel('Config');
|
||||
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH'));
|
||||
$config = $this->Config->find('first', $options);
|
||||
$zmOptAuth = $config['Config']['Value'];
|
||||
$zmOptAuth = $config['Config']['Value'];
|
||||
|
||||
|
||||
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_RELAY'));
|
||||
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_RELAY'));
|
||||
$config = $this->Config->find('first', $options);
|
||||
$zmAuthRelay = $config['Config']['Value'];
|
||||
|
||||
$auth="";
|
||||
if ($zmOptAuth)
|
||||
{
|
||||
if ($zmAuthRelay == 'hashed')
|
||||
{
|
||||
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_SECRET'));
|
||||
$config = $this->Config->find('first', $options);
|
||||
$zmAuthHashSecret = $config['Config']['Value'];
|
||||
$zmAuthRelay = $config['Config']['Value'];
|
||||
|
||||
$auth='';
|
||||
if ( $zmOptAuth ) {
|
||||
if ( $zmAuthRelay == 'hashed' ) {
|
||||
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_SECRET'));
|
||||
$config = $this->Config->find('first', $options);
|
||||
$zmAuthHashSecret = $config['Config']['Value'];
|
||||
|
||||
$time = localtime();
|
||||
$ak = $zmAuthHashSecret.$this->Session->Read('username').$this->Session->Read('passwordHash').$time[2].$time[3].$time[4].$time[5];
|
||||
$ak = md5($ak);
|
||||
$auth = " -A ".$ak;
|
||||
}
|
||||
elseif ($zmAuthRelay == 'plain')
|
||||
{
|
||||
$auth = " -U " .$this->Session->Read('username')." -P ".$this->Session->Read('password');
|
||||
|
||||
}
|
||||
elseif ($zmAuthRelay == 'none')
|
||||
{
|
||||
$auth = " -U " .$this->Session->Read('username');
|
||||
}
|
||||
}
|
||||
|
||||
$shellcmd = escapeshellcmd("$zm_path_bin/zmu $verbose -m$id $q $auth");
|
||||
$status = exec ($shellcmd);
|
||||
$time = localtime();
|
||||
$ak = $zmAuthHashSecret.$this->Session->Read('username').$this->Session->Read('passwordHash').$time[2].$time[3].$time[4].$time[5];
|
||||
$ak = md5($ak);
|
||||
$auth = ' -A '.$ak;
|
||||
} else if ( $zmAuthRelay == 'plain' ) {
|
||||
$auth = ' -U ' .$this->Session->Read('username').' -P '.$this->Session->Read('password');
|
||||
|
||||
} else if ( $zmAuthRelay == 'none' ) {
|
||||
$auth = ' -U ' .$this->Session->Read('username');
|
||||
}
|
||||
}
|
||||
|
||||
$shellcmd = escapeshellcmd("$zm_path_bin/zmu $verbose -m$id $q $auth");
|
||||
$status = exec ($shellcmd);
|
||||
|
||||
$this->set(array(
|
||||
'status' => $status,
|
||||
'_serialize' => array('status'),
|
||||
));
|
||||
$this->set(array(
|
||||
'status' => $status,
|
||||
'_serialize' => array('status'),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// Check if a daemon is running for the monitor id
|
||||
public function daemonStatus() {
|
||||
$id = $this->request->params['named']['id'];
|
||||
$daemon = $this->request->params['named']['daemon'];
|
||||
|
||||
// Check if a daemon is running for the monitor id
|
||||
public function daemonStatus() {
|
||||
$id = $this->request->params['named']['id'];
|
||||
$daemon = $this->request->params['named']['daemon'];
|
||||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
|
||||
if (!$this->Monitor->exists($id)) {
|
||||
throw new NotFoundException(__('Invalid monitor'));
|
||||
}
|
||||
$monitor = $this->Monitor->find('first', array(
|
||||
'fields' => array('Id', 'Type', 'Device'),
|
||||
'conditions' => array('Id' => $id)
|
||||
));
|
||||
|
||||
$monitor = $this->Monitor->find('first', array(
|
||||
'fields' => array('Id', 'Type', 'Device'),
|
||||
'conditions' => array('Id' => $id)
|
||||
));
|
||||
// Clean up the returned array
|
||||
$monitor = Set::extract('/Monitor/.', $monitor);
|
||||
|
||||
// Clean up the returned array
|
||||
$monitor = Set::extract('/Monitor/.', $monitor);
|
||||
// Pass -d for local, otherwise -m
|
||||
if ($monitor[0]['Type'] == 'Local') {
|
||||
$args = '-d '. $monitor[0]['Device'];
|
||||
} else {
|
||||
$args = '-m '. $monitor[0]['Id'];
|
||||
}
|
||||
|
||||
// Pass -d for local, otherwise -m
|
||||
if ($monitor[0]['Type'] == 'Local') {
|
||||
$args = "-d ". $monitor[0]['Device'];
|
||||
} else {
|
||||
$args = "-m ". $monitor[0]['Id'];
|
||||
}
|
||||
// Build the command, and execute it
|
||||
$zm_path_bin = Configure::read('ZM_PATH_BIN');
|
||||
$command = escapeshellcmd("$zm_path_bin/zmdc.pl status $daemon $args");
|
||||
$status = exec( $command );
|
||||
|
||||
// Build the command, and execute it
|
||||
$zm_path_bin = Configure::read('ZM_PATH_BIN');
|
||||
$command = escapeshellcmd("$zm_path_bin/zmdc.pl status $daemon $args");
|
||||
$status = exec( $command );
|
||||
// If 'not' is present, the daemon is not running, so return false
|
||||
// https://github.com/ZoneMinder/ZoneMinder/issues/799#issuecomment-108996075
|
||||
// Also sending back the status text so we can check if the monitor is in pending
|
||||
// state which means there may be an error
|
||||
$statustext = $status;
|
||||
$status = (strpos($status, 'not')) ? false : true;
|
||||
|
||||
// If 'not' is present, the daemon is not running, so return false
|
||||
// https://github.com/ZoneMinder/ZoneMinder/issues/799#issuecomment-108996075
|
||||
// Also sending back the status text so we can check if the monitor is in pending
|
||||
// state which means there may be an error
|
||||
$statustext = $status;
|
||||
$status = (strpos($status, 'not')) ? false : true;
|
||||
$this->set(array(
|
||||
'status' => $status,
|
||||
'statustext' => $statustext,
|
||||
'_serialize' => array('status','statustext'),
|
||||
));
|
||||
}
|
||||
|
||||
$this->set(array(
|
||||
'status' => $status,
|
||||
'statustext' => $statustext,
|
||||
'_serialize' => array('status','statustext'),
|
||||
));
|
||||
}
|
||||
public function daemonControl($id, $command, $monitor=null, $daemon=null) {
|
||||
$args = '';
|
||||
$daemons = array();
|
||||
|
||||
public function daemonControl($id, $command, $monitor=null, $daemon=null) {
|
||||
$args = '';
|
||||
$daemons = array();
|
||||
if (!$monitor) {
|
||||
// Need to see if it is local or remote
|
||||
$monitor = $this->Monitor->find('first', array(
|
||||
'fields' => array('Type', 'Function'),
|
||||
'conditions' => array('Id' => $id)
|
||||
));
|
||||
$monitor = $monitor['Monitor'];
|
||||
}
|
||||
|
||||
if (!$monitor) {
|
||||
// Need to see if it is local or remote
|
||||
$monitor = $this->Monitor->find('first', array(
|
||||
'fields' => array('Type', 'Function'),
|
||||
'conditions' => array('Id' => $id)
|
||||
));
|
||||
$monitor = $monitor['Monitor'];
|
||||
}
|
||||
if ($monitor['Type'] == 'Local') {
|
||||
$args = '-d ' . $monitor['Device'];
|
||||
} else {
|
||||
$args = '-m ' . $id;
|
||||
}
|
||||
|
||||
if ($monitor['Type'] == 'Local') {
|
||||
$args = "-d " . $monitor['Device'];
|
||||
} else {
|
||||
$args = "-m " . $id;
|
||||
}
|
||||
if ($monitor['Function'] == 'Monitor') {
|
||||
array_push($daemons, 'zmc');
|
||||
} else {
|
||||
array_push($daemons, 'zmc', 'zma');
|
||||
}
|
||||
|
||||
$zm_path_bin = Configure::read('ZM_PATH_BIN');
|
||||
|
||||
if ($monitor['Function'] == 'Monitor') {
|
||||
array_push($daemons, 'zmc');
|
||||
} else {
|
||||
array_push($daemons, 'zmc', 'zma');
|
||||
}
|
||||
|
||||
$zm_path_bin = Configure::read('ZM_PATH_BIN');
|
||||
|
||||
foreach ($daemons as $daemon) {
|
||||
$shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args");
|
||||
$status = exec( $shellcmd );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
foreach ($daemons as $daemon) {
|
||||
$shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args");
|
||||
$status = exec( $shellcmd );
|
||||
}
|
||||
}
|
||||
|
||||
} // end class MonitorsController
|
||||
|
|
|
@ -86,10 +86,10 @@ class Monitor extends AppModel {
|
|||
);
|
||||
|
||||
/**
|
||||
* * hasMany associations
|
||||
* *
|
||||
* * @var array
|
||||
* */
|
||||
* hasMany associations
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $hasAndBelongsToMany = array(
|
||||
'Group' => array(
|
||||
'className' => 'Group',
|
||||
|
@ -108,5 +108,16 @@ class Monitor extends AppModel {
|
|||
'counterQuery' => ''
|
||||
),
|
||||
);
|
||||
public $actsAs = array(
|
||||
'CakePHP-Enum-Behavior.Enum' => array(
|
||||
'Type' => array('Local','Remote','File','Ffmpeg','Libvlc','cURL'),
|
||||
'Function' => array('None','Monitor','Modect','Record','Mocord','Nodect'),
|
||||
'Orientation' => array('0','90','180','270','hori','vert'),
|
||||
'OutputCodec' => array('h264','mjpeg','mpeg1','mpeg2'),
|
||||
'OutputContainer' => array('auto','mp4','mkv'),
|
||||
'DefaultView' => array('Events','Control'),
|
||||
'Status' => array('Unknown','NotRunning','Running','NoSignal','Signal'),
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7108489f218c54d36d235d3af91d6da2f8311237
|
|
@ -0,0 +1,2 @@
|
|||
echo json_encode($message);
|
||||
echo json_encode($monitor);
|
|
@ -0,0 +1,2 @@
|
|||
$xml = Xml::fromArray(array('response' => $message));
|
||||
echo $xml->asXML();
|
|
@ -293,8 +293,8 @@ private $control_fields = array(
|
|||
}
|
||||
return $filters;
|
||||
}
|
||||
public function save( $new_values = null ) {
|
||||
|
||||
public function save( $new_values = null ) {
|
||||
|
||||
if ( $new_values ) {
|
||||
foreach ( $new_values as $k=>$v ) {
|
||||
|
@ -302,8 +302,10 @@ private $control_fields = array(
|
|||
}
|
||||
}
|
||||
|
||||
$sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, array_keys( $this->defaults ) ) ) . ' WHERE Id=?';
|
||||
$values = array_map( function($field){return $this->{$field};}, $this->fields );
|
||||
$fields = array_keys( $this->defaults );
|
||||
|
||||
$sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . ' WHERE Id=?';
|
||||
$values = array_map( function($field){return $this->{$field};}, $fields );
|
||||
$values[] = $this->{'Id'};
|
||||
dbQuery( $sql, $values );
|
||||
} // end function save
|
||||
|
|
|
@ -70,15 +70,38 @@ class Storage {
|
|||
Warning( "Unknown function call Storage->$fn from $file:$line" );
|
||||
}
|
||||
}
|
||||
public static function find_all() {
|
||||
$storage_areas = array();
|
||||
$result = dbQuery( 'SELECT * FROM Storage ORDER BY Name');
|
||||
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage' );
|
||||
foreach ( $results as $row => $obj ) {
|
||||
$storage_areas[] = $obj;
|
||||
$storage_cache[$obj->Id()] = $obj;
|
||||
public static function find_all( $parameters = null, $options = null ) {
|
||||
$filters = array();
|
||||
$sql = 'SELECT * FROM Storage ';
|
||||
$values = array();
|
||||
|
||||
if ( $parameters ) {
|
||||
$fields = array();
|
||||
$sql .= 'WHERE ';
|
||||
foreach ( $parameters as $field => $value ) {
|
||||
if ( $value == null ) {
|
||||
$fields[] = $field.' IS NULL';
|
||||
} else if ( is_array( $value ) ) {
|
||||
$func = function(){return '?';};
|
||||
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
|
||||
$values += $value;
|
||||
|
||||
} else {
|
||||
$fields[] = $field.'=?';
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
$sql .= implode(' AND ', $fields );
|
||||
}
|
||||
return $storage_areas;
|
||||
if ( $options and isset($options['order']) ) {
|
||||
$sql .= ' ORDER BY ' . $options['order'];
|
||||
}
|
||||
$result = dbQuery($sql, $values);
|
||||
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage');
|
||||
foreach ( $results as $row => $obj ) {
|
||||
$filters[] = $obj;
|
||||
}
|
||||
return $filters;
|
||||
}
|
||||
public function disk_usage_percent() {
|
||||
$path = $this->Path();
|
||||
|
@ -95,11 +118,8 @@ class Storage {
|
|||
Error("disk_total_space returned false for " . $path );
|
||||
return 0;
|
||||
}
|
||||
$free = disk_free_space( $path );
|
||||
if ( ! $free ) {
|
||||
Error("disk_free_space returned false for " . $path );
|
||||
}
|
||||
$usage = round(($total - $free) / $total * 100);
|
||||
$used = $this->disk_used_space();
|
||||
$usage = round( ($used / $total) * 100);
|
||||
return $usage;
|
||||
}
|
||||
public function disk_total_space() {
|
||||
|
|
|
@ -1280,6 +1280,7 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
|
|||
$filter['sql'] .= ' not regexp '.$value;
|
||||
break;
|
||||
case '=[]' :
|
||||
case 'IN' :
|
||||
$filter['sql'] .= ' in ('.join( ',', $valueList ).')';
|
||||
break;
|
||||
case '![]' :
|
||||
|
|
|
@ -333,7 +333,10 @@ if ($reload == 'reload') ob_start();
|
|||
}
|
||||
$func = function($S){ return '<span title="'.human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()).'">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; };
|
||||
#$func = function($S){ return '<span title="">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; };
|
||||
echo implode( ', ', array_map ( $func, $storage_areas ) );
|
||||
if ( count($storage_areas) >= 4 )
|
||||
$storage_areas = Storage::find_all( array('ServerId'=>null) );
|
||||
if ( count($storage_areas) < 4 )
|
||||
echo implode( ', ', array_map ( $func, $storage_areas ) );
|
||||
echo ' ' . ZM_PATH_MAP .': '. getDiskPercent(ZM_PATH_MAP).'%';
|
||||
?></li>
|
||||
</ul>
|
||||
|
|
|
@ -175,7 +175,7 @@ xhtmlHeaders( __FILE__, translate('Console') );
|
|||
?>
|
||||
<th class="colZones"><a href="<?php echo $_SERVER['PHP_SELF'] ?>?view=zones_overview"><?php echo translate('Zones') ?></a></th>
|
||||
<?php if ( canEdit('Monitors') ) { ?>
|
||||
<th class="colMark"><input type="checkbox" name="toggleCheck" value="1" onclick="toggleCheckbox( this, 'markMids[]' );"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/> <?php echo translate('All') ?></th>
|
||||
<th class="colMark"><input type="checkbox" name="toggleCheck" value="1" onclick="toggleCheckbox(this, 'markMids[]');setButtonStates(this);"<?php if ( !canEdit( 'Monitors' ) ) { ?> disabled="disabled"<?php } ?>/> <?php echo translate('All') ?></th>
|
||||
<?php } ?>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
|
@ -210,16 +210,16 @@ while ( $event_row = dbFetchNext( $results ) ) {
|
|||
?>
|
||||
<td class="colThumbnail">
|
||||
<?php
|
||||
if ( file_exists( $event->Path().'/snapshot.jpg' ) ) {
|
||||
Warning("Using snapshot");
|
||||
if ( ( $event->SaveJPEGs() == 4 ) and file_exists($event->Path().'/snapshot.jpg') ) {
|
||||
Logger::Debug("Using snapshot");
|
||||
$imgSrc = '?view=image&eid='.$event->Id().'&fid=snapshot&width='.$thumbData['Width'].'&height='.$thumbData['Height'];
|
||||
} else {
|
||||
Warning("Not Using snapshot" . $event->Path().'/snapshot.jpg' );
|
||||
Logger::Debug("Not Using snapshot" . $event->Path().'/snapshot.jpg' );
|
||||
$imgSrc = '?view=image&eid='.$event->Id().'&fid='.$thumbData['FrameId'].'&width='.$thumbData['Width'].'&height='.$thumbData['Height'];
|
||||
}
|
||||
$streamSrc = $event->getStreamSrc( array( 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single') );
|
||||
|
||||
$imgHtml = '<img id="thumbnail'.$event->id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($thumbData['Width']) .'px;height:'. validInt( $thumbData['Height'] ).'px;" onmouseover="this.src=\''.$streamSrc.'\';" onmouseout="this.src=\''.$imgSrc.'\';"/>';
|
||||
$imgHtml = '<img id="thumbnail'.$event->id().'" src="'.$imgSrc.'" alt="'. validHtmlStr('Event '.$event->Id()) .'" style="width:'. validInt($thumbData['Width']) .'px;height:'. validInt($thumbData['Height']).'px;" onmouseover="this.src=\''.$streamSrc.'\';" onmouseout="this.src=\''.$imgSrc.'\';"/>';
|
||||
|
||||
echo makePopupLink(
|
||||
'?view=frame&eid='.$event->Id().'&fid='.$thumbData['FrameId'],
|
||||
|
|
|
@ -142,6 +142,7 @@ foreach ( dbFetchAll( 'SELECT Id,Name FROM States ORDER BY lower(Name) ASC' ) as
|
|||
}
|
||||
$servers = array();
|
||||
$servers['ZM_SERVER_ID'] = 'Current Server';
|
||||
$servers['NULL'] = 'No Server';
|
||||
foreach ( dbFetchAll( 'SELECT Id,Name FROM Servers ORDER BY lower(Name) ASC' ) as $server ) {
|
||||
$servers[$server['Id']] = $server['Name'];
|
||||
}
|
||||
|
|
|
@ -55,7 +55,17 @@ function SetImageSource( monId, time ) {
|
|||
if ( eMonId[i] == monId && time >= eStartSecs[i] && time <= eEndSecs[i] ) {
|
||||
var duration = eEndSecs[i]-eStartSecs[i];
|
||||
var frame = parseInt((time - eStartSecs[i])/(duration)*eventFrames[i])+1;
|
||||
console.log("SetImageSource: " + time + " duration: " + duration + " frame: " + frame );
|
||||
var storage = Storage[eStorageId[i]];
|
||||
if ( storage.ServerId ) {
|
||||
var server = Servers[storage.ServerId];
|
||||
if ( server ) {
|
||||
console.log( server.Hostname + " for event " + eId[i] );
|
||||
return location.protocol + '//' + server.Hostname + '/index.php?view=image&eid=' + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height;
|
||||
} else {
|
||||
console.log("No server found for " + storage.ServerId );
|
||||
}
|
||||
}
|
||||
console.log("No storage found for " + eStorageId[i] );
|
||||
return "index.php?view=image&eid=" + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height;
|
||||
}
|
||||
} // end for
|
||||
|
@ -465,7 +475,6 @@ function setSpeed( speed_index ) {
|
|||
currentSpeed = parseFloat(speeds[speed_index]);
|
||||
speedIndex = speed_index;
|
||||
playSecsperInterval = Math.floor( 1000 * currentSpeed * currentDisplayInterval ) / 1000000;
|
||||
console.log("playSecsPerInterval: " + playSecsperInterval + " = currentspeed:" + currentSpeed + " * " + currentDisplayInterval + " /1000");
|
||||
showSpeed(speed_index);
|
||||
if ( timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ var imageLoadTimesNeeded=15; // and how many we need
|
|||
var timeLabelsFractOfRow = 0.9;
|
||||
var eMonId = [];
|
||||
var eId = [];
|
||||
var eStorageId = [];
|
||||
var eStartSecs = [];
|
||||
var eEndSecs = [];
|
||||
var eventFrames = []; // this is going to presume all frames equal durationlength
|
||||
|
@ -43,7 +44,6 @@ $index = 0;
|
|||
$anyAlarms = false;
|
||||
|
||||
if ( ! $initialModeIsLive ) {
|
||||
Warning($eventsSql);
|
||||
$result = dbQuery( $eventsSql );
|
||||
if ( ! $result ) {
|
||||
Fatal('SQL-ERR');
|
||||
|
@ -56,6 +56,7 @@ Warning($eventsSql);
|
|||
if ( $maxTimeSecs < $event['CalcEndTimeSecs'] ) $maxTimeSecs = $event['CalcEndTimeSecs'];
|
||||
echo "
|
||||
eMonId[$index]=" . $event['MonitorId'] . ";
|
||||
eStorageId[$index]=".$event['StorageId'] . ";
|
||||
eId[$index]=" . $event['Id'] . ";
|
||||
eStartSecs[$index]=" . $event['StartTimeSecs'] . ";
|
||||
eEndSecs[$index]=" . $event['CalcEndTimeSecs'] . ";
|
||||
|
@ -146,7 +147,17 @@ if ( $mId > 0 ) {
|
|||
|
||||
echo "var maxScore=$maxScore;\n"; // used to skip frame load if we find no alarms.
|
||||
} // end if initialmodeislive
|
||||
echo "var monitorName = [];\n";
|
||||
|
||||
echo "var Storage = []\n";
|
||||
foreach ( Storage::find_all() as $Storage ) {
|
||||
echo 'Storage[' . $Storage->Id() . '] = ' . json_encode($Storage). ";\n";
|
||||
}
|
||||
echo "var Servers = []\n";
|
||||
foreach ( Server::find_all() as $Server ) {
|
||||
echo 'Servers[' . $Server->Id() . '] = ' . json_encode($Server). ";\n";
|
||||
}
|
||||
echo "
|
||||
var monitorName = [];\n";
|
||||
echo "var monitorLoading = [];\n";
|
||||
echo "var monitorImageObject = [];\n";
|
||||
echo "var monitorImageURL = [];\n";
|
||||
|
|
|
@ -94,7 +94,7 @@ if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($display
|
|||
// Note we round up just a bit on the end time as otherwise you get gaps, like 59.78 to 00 in the next second, which can give blank frames when moved through slowly.
|
||||
|
||||
$eventsSql = '
|
||||
SELECT E.Id,E.Name,UNIX_TIMESTAMP(E.StartTime) AS StartTimeSecs,
|
||||
SELECT E.Id,E.Name,E.StorageId,UNIX_TIMESTAMP(E.StartTime) AS StartTimeSecs,
|
||||
CASE WHEN E.EndTime IS NULL THEN (SELECT UNIX_TIMESTAMP(DATE_ADD(E.StartTime, Interval max(Delta)+0.5 Second)) FROM Frames F WHERE F.EventId=E.Id)
|
||||
ELSE UNIX_TIMESTAMP(E.EndTime)
|
||||
END AS CalcEndTimeSecs, E.Length,
|
||||
|
|
|
@ -194,7 +194,7 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
|||
</div>
|
||||
</form>
|
||||
<?php
|
||||
} else if ( $tab == "servers" ) { ?>
|
||||
} else if ( $tab == 'servers' ) { ?>
|
||||
<form name="serversForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
|
||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
|
||||
|
@ -210,11 +210,16 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
|||
<th class="colCpuLoad"><?php echo translate('CpuLoad') ?></th>
|
||||
<th class="colMemory"><?php echo translate('Free').'/'.translate('Total') . ' ' . translate('Memory') ?></th>
|
||||
<th class="colSwap"><?php echo translate('Free').'/'.translate('Total') . ' ' . translate('Swap') ?></th>
|
||||
<th class="colStats"><?php echo translate('RunStats') ?></th>
|
||||
<th class="colAudit"><?php echo translate('RunAudit') ?></th>
|
||||
<th class="colTrigger"><?php echo translate('RunTrigger') ?></th>
|
||||
<th class="colMark"><?php echo translate('Mark') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach( dbFetchAll( 'SELECT *,(SELECT COUNT(Id) FROM Monitors WHERE ServerId=Servers.Id) AS MonitorCount FROM Servers' ) as $row ) { ?>
|
||||
<?php
|
||||
foreach( dbFetchAll( 'SELECT *,(SELECT COUNT(Id) FROM Monitors WHERE ServerId=Servers.Id) AS MonitorCount FROM Servers ORDER BY Id' ) as $row ) {
|
||||
?>
|
||||
<tr>
|
||||
<td class="colName"><?php echo makePopupLink( '?view=server&id='.$row['Id'], 'zmServer', 'server', validHtmlStr($row['Name']), $canEdit ) ?></td>
|
||||
<td class="colHostname"><?php echo makePopupLink( '?view=server&id='.$row['Id'], 'zmServer', 'server', validHtmlStr($row['Hostname']), $canEdit ) ?></td>
|
||||
|
@ -223,6 +228,9 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
|||
<td class="colCpuLoad"><?php echo makePopupLink( '?view=server&id='.$row['Id'], 'zmServer', 'server',$row['CpuLoad'], $canEdit ) ?></td>
|
||||
<td class="colMemory"><?php echo makePopupLink( '?view=server&id='.$row['Id'], 'zmServer', 'server', human_filesize($row['FreeMem']) . ' / ' . human_filesize($row['TotalMem']), $canEdit ) ?></td>
|
||||
<td class="colSwap"><?php echo makePopupLink( '?view=server&id='.$row['Id'], 'zmServer', 'server', human_filesize($row['FreeSwap']) . ' / ' . human_filesize($row['TotalSwap']) , $canEdit ) ?></td>
|
||||
<td class="colStats"><?php echo makePopupLink( '?view=server&id='.$row['Id'], 'zmServer', 'server', $row['zmstats.pl'] ? 'yes' : 'no', $canEdit ) ?></td>
|
||||
<td class="colAudit"><?php echo makePopupLink( '?view=server&id='.$row['Id'], 'zmServer', 'server', $row['zmaudit.pl'] ? 'yes' : 'no', $canEdit ) ?></td>
|
||||
<td class="colTrigger"><?php echo makePopupLink( '?view=server&id='.$row['Id'], 'zmServer', 'server', $row['zmtrigger.pl'] ? 'yes' : 'no', $canEdit ) ?></td>
|
||||
|
||||
<td class="colMark"><input type="checkbox" name="markIds[]" value="<?php echo $row['Id'] ?>" onclick="configureDeleteButton( this );"<?php if ( !$canEdit ) { ?> disabled="disabled"<?php } ?>/></td>
|
||||
</tr>
|
||||
|
@ -249,6 +257,7 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
|||
<th class="colPath"><?php echo translate('path') ?></th>
|
||||
<th class="colType"><?php echo translate('Type') ?></th>
|
||||
<th class="colScheme"><?php echo translate('StorageScheme') ?></th>
|
||||
<th class="colServer"><?php echo translate('Server') ?></th>
|
||||
<th class="colMark"><?php echo translate('Mark') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -260,6 +269,9 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
|||
<td class="colPath"><?php echo makePopupLink( '?view=storage&id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Path']), $canEdit ) ?></td>
|
||||
<td class="colType"><?php echo makePopupLink( '?view=storage&id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Type']), $canEdit ) ?></td>
|
||||
<td class="colScheme"><?php echo makePopupLink( '?view=storage&id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Scheme']), $canEdit ) ?></td>
|
||||
<td class="colServer"><?php
|
||||
$Server = new Server($row['ServerId']);
|
||||
echo makePopupLink( '?view=storage&id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($Server->Name()), $canEdit ) ?></td>
|
||||
<td class="colMark"><input type="checkbox" name="markIds[]" value="<?php echo $row['Id'] ?>" onclick="configureDeleteButton(this);"<?php if ( !$canEdit ) { ?> disabled="disabled"<?php } ?>/></td>
|
||||
</tr>
|
||||
<?php } #end foreach Server ?>
|
||||
|
|
|
@ -58,6 +58,27 @@ xhtmlHeaders(__FILE__, translate('Server').' - '.$newServer['Name'] );
|
|||
<th scope="row"><?php echo translate('Hostname') ?></th>
|
||||
<td><input type="text" name="newServer[Hostname]" value="<?php echo $newServer['Hostname'] ?>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('RunStats') ?></th>
|
||||
<td>
|
||||
<input type="radio" name="newServer[zmstats.pl]" value="1"<?php echo $newServer['zmstats.pl'] ? ' checked="checked"' : '' ?>/> Yes
|
||||
<input type="radio" name="newServer[zmstats.pl]" value="0"<?php echo $newServer['zmstats.pl'] ? '' : ' checked="checked"' ?>/> No
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('RunAudit') ?></th>
|
||||
<td>
|
||||
<input type="radio" name="newServer[zmaudit.pl]" value="1"<?php echo $newServer['zmaudit.pl'] ? ' checked="checked"' : '' ?>/> Yes
|
||||
<input type="radio" name="newServer[zmaudit.pl]" value="0"<?php echo $newServer['zmaudit.pl'] ? '' : ' checked="checked"' ?>/> No
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('RunTrigger') ?></th>
|
||||
<td>
|
||||
<input type="radio" name="newServer[zmtrigger.pl]" value="1"<?php echo $newServer['zmtrigger.pl'] ? ' checked="checked"' : '' ?>/> Yes
|
||||
<input type="radio" name="newServer[zmtrigger.pl]" value="0"<?php echo $newServer['zmtrigger.pl'] ? '' : ' checked="checked"' ?>/> No
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="contentButtons">
|
||||
|
|
|
@ -27,6 +27,7 @@ if ( $_REQUEST['id'] ) {
|
|||
if ( !($newStorage = dbFetchOne('SELECT * FROM Storage WHERE Id=?', NULL, ARRAY($_REQUEST['id'])) ) ) {
|
||||
$view = 'error';
|
||||
return;
|
||||
$newStorage['ServerId'] = '';
|
||||
}
|
||||
} else {
|
||||
$newStorage = array();
|
||||
|
@ -43,6 +44,11 @@ $scheme_options = array(
|
|||
'Shallow' => translate('Shallow'),
|
||||
);
|
||||
|
||||
$servers = Server::find_all();
|
||||
$ServersById = array();
|
||||
foreach ( $servers as $S ) {
|
||||
$ServersById[$S->Id()] = $S;
|
||||
}
|
||||
$focusWindow = true;
|
||||
|
||||
xhtmlHeaders(__FILE__, translate('Storage')." - ".$newStorage['Name'] );
|
||||
|
@ -67,6 +73,10 @@ xhtmlHeaders(__FILE__, translate('Storage')." - ".$newStorage['Name'] );
|
|||
<th scope="row"><?php echo translate('Path') ?></th>
|
||||
<td><input type="text" name="newStorage[Path]" value="<?php echo $newStorage['Path'] ?>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Server') ?></th>
|
||||
<td><?php echo htmlSelect( 'newStorage[ServerId]', array('','Remote') + $ServersById, $newStorage['ServerId'] ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Type') ?></th>
|
||||
<td><?php echo htmlSelect( 'newStorage[Type]', $type_options, $newStorage['Type'] ); ?></td>
|
||||
|
|
Loading…
Reference in New Issue