Skip to content
Snippets Groups Projects
Commit 379ed2b8 authored by Robert Anderson's avatar Robert Anderson Committed by Nigel Kukard
Browse files

Provide user data storage with cache support

Added new data_set() and data_get() userdb functions for setting and fetching user data. New table users_data stores user data as Name => Value. Updated UPGRADING file with upgrading instructions.
parent a3da3513
No related branches found
No related tags found
No related merge requests found
2011-03-22:
Add users_data table for various functions
CREATE TABLE @PREFIX@users_data (
ID @SERIAL_TYPE@,
UserID @INT_UNSIGNED@,
LastUpdated DATETIME,
Name VARCHAR(255),
Value VARCHAR(255),
UNIQUE (UserID,Name)
);
2011-01-11: 2011-01-11:
Move configuration file item "use_packet_timestamp=" to "[radius]" section Move configuration file item "use_packet_timestamp=" to "[radius]" section
......
...@@ -264,3 +264,20 @@ CREATE TABLE @PREFIX@accounting_summary ( ...@@ -264,3 +264,20 @@ CREATE TABLE @PREFIX@accounting_summary (
TotalOutput @INT_UNSIGNED@ TotalOutput @INT_UNSIGNED@
) @CREATE_TABLE_SUFFIX@; ) @CREATE_TABLE_SUFFIX@;
/* Users data */
CREATE TABLE @PREFIX@users_data (
ID @SERIAL_TYPE@,
UserID @INT_UNSIGNED@,
LastUpdated DATETIME,
Name VARCHAR(255),
Value VARCHAR(255),
UNIQUE (UserID,Name)
) @CREATE_TABLE_SUFFIX@;
...@@ -22,6 +22,7 @@ use warnings; ...@@ -22,6 +22,7 @@ use warnings;
# Modules we need # Modules we need
use smradius::constants; use smradius::constants;
use awitpt::cache;
use smradius::logging; use smradius::logging;
use awitpt::db::dblayer; use awitpt::db::dblayer;
use smradius::util; use smradius::util;
...@@ -46,6 +47,10 @@ our $pluginInfo = { ...@@ -46,6 +47,10 @@ our $pluginInfo = {
# User database # User database
User_find => \&find, User_find => \&find,
User_get => \&get, User_get => \&get,
# Users data
Users_data_set => \&data_set,
Users_data_get => \&data_get
}; };
# Module config # Module config
...@@ -92,10 +97,62 @@ sub init ...@@ -92,10 +97,62 @@ sub init
FROM FROM
@TP@user_attributes @TP@user_attributes
WHERE WHERE
UserID = %{userdb.ID} UserID = %{userdb.id}
AND Disabled = 0 AND Disabled = 0
'; ';
$config->{'users_data_set_query'} = '
INSERT INTO
@TP@users_data (UserID, LastUpdated, Name, Value)
VALUES
(
%{userdb.id},
%{query.LastUpdated},
%{query.Name},
%{query.Value}
)
';
$config->{'users_data_update_query'} = '
UPDATE
@TP@users_data
SET
LastUpdated = %{query.LastUpdated},
Value = %{query.Value}
WHERE
UserID = %{userdb.id}
AND Name = %{query.Name}
';
$config->{'users_data_get_query'} = '
SELECT
LastUpdated, Name, Value
FROM
@TP@users_data
WHERE
UserID = %{userdb.id}
AND Name > %{query.Name}
';
$config->{'users_data_delete_query'} = '
DELETE FROM
@TP@users_data
WHERE
UserID = %{userdb.id}
AND Name = %{query.Name}
';
$config->{'users_data_cleanup_query'} = '
DELETE FROM
@TP@users_data
WHERE UserID NOT IN
(
SELECT ID FROM users
)
';
# Default cache time for user data
$config->{'userdb_data_cache_time'} = 300;
# Setup SQL queries # Setup SQL queries
if (defined($scfg->{'mod_userdb_sql'})) { if (defined($scfg->{'mod_userdb_sql'})) {
...@@ -130,6 +187,76 @@ sub init ...@@ -130,6 +187,76 @@ sub init
$scfg->{'mod_userdb_sql'}->{'userdb_get_user_attributes_query'}; $scfg->{'mod_userdb_sql'}->{'userdb_get_user_attributes_query'};
} }
} }
if (defined($scfg->{'mod_userdb_sql'}->{'users_data_set_query'}) &&
$scfg->{'mod_userdb_sql'}->{'users_data_set_query'} ne "") {
if (ref($scfg->{'mod_userdb_sql'}->{'users_data_set_query'}) eq "ARRAY") {
$config->{'users_data_set_query'} = join(' ',
@{$scfg->{'mod_userdb_sql'}->{'users_data_set_query'}});
} else {
$config->{'users_data_set_query'} = $scfg->{'mod_userdb_sql'}->{'users_data_set_query'};
}
}
if (defined($scfg->{'mod_userdb_sql'}->{'users_data_update_query'}) &&
$scfg->{'mod_userdb_sql'}->{'users_data_update_query'} ne "") {
if (ref($scfg->{'mod_userdb_sql'}->{'users_data_update_query'}) eq "ARRAY") {
$config->{'users_data_update_query'} = join(' ',
@{$scfg->{'mod_userdb_sql'}->{'users_data_update_query'}});
} else {
$config->{'users_data_update_query'} = $scfg->{'mod_userdb_sql'}->{'users_data_update_query'};
}
}
if (defined($scfg->{'mod_userdb_sql'}->{'users_data_get_query'}) &&
$scfg->{'mod_userdb_sql'}->{'users_data_get_query'} ne "") {
if (ref($scfg->{'mod_userdb_sql'}->{'users_data_get_query'}) eq "ARRAY") {
$config->{'users_data_get_query'} = join(' ',
@{$scfg->{'mod_userdb_sql'}->{'users_data_get_query'}});
} else {
$config->{'users_data_get_query'} = $scfg->{'mod_userdb_sql'}->{'users_data_get_query'};
}
}
if (defined($scfg->{'mod_userdb_sql'}->{'users_data_delete_query'}) &&
$scfg->{'mod_userdb_sql'}->{'users_data_delete_query'} ne "") {
if (ref($scfg->{'mod_userdb_sql'}->{'users_data_delete_query'}) eq "ARRAY") {
$config->{'users_data_delete_query'} = join(' ',
@{$scfg->{'mod_userdb_sql'}->{'users_data_delete_query'}});
} else {
$config->{'users_data_delete_query'} = $scfg->{'mod_userdb_sql'}->{'users_data_delete_query'};
}
}
if (defined($scfg->{'mod_userdb_sql'}->{'users_data_cleanup_query'}) &&
$scfg->{'mod_userdb_sql'}->{'users_data_cleanup_query'} ne "") {
if (ref($scfg->{'mod_userdb_sql'}->{'users_data_cleanup_query'}) eq "ARRAY") {
$config->{'users_data_cleanup_query'} = join(' ',
@{$scfg->{'mod_userdb_sql'}->{'users_data_cleanup_query'}});
} else {
$config->{'users_data_cleanup_query'} = $scfg->{'mod_userdb_sql'}->{'users_data_cleanup_query'};
}
}
if (defined($scfg->{'mod_userdb_sql'}->{'userdb_data_cache_time'})) {
if ($scfg->{'mod_userdb_sql'}{'userdb_data_cache_time'} =~ /^\s*(yes|true|1)\s*$/i) {
# Default?
} elsif ($scfg->{'mod_userdb_sql'}{'userdb_data_cache_time'} =~ /^\s*(no|false|0)\s*$/i) {
$config->{'mod_userdb_sql'}{'userdb_data_cache_time'} = undef;
} elsif ($scfg->{'mod_userdb_sql'}{'userdb_data_cache_time'} =~ /^[0-9]+$/) {
$config->{'mod_userdb_sql'}{'userdb_data_cache_time'} = $scfg->{'mod_userdb_sql'}{'userdb_data_cache_time'};
} else {
$server->log(LOG_NOTICE,"[MOD_USERDB_SQL] Value for 'userdb_data_cache_time' is invalid");
}
}
}
# Log this for info sake
if (defined($config->{'userdb_data_cache_time'})) {
$server->log(LOG_NOTICE,"[MOD_USERDB_SQL] Users data caching ENABLED, cache time is %ds.",
$config->{'userdb_data_cache_time'});
} else {
$server->log(LOG_NOTICE,"[MOD_USERDB_SQL] Users caching DISABLED");
} }
} }
...@@ -137,10 +264,11 @@ sub init ...@@ -137,10 +264,11 @@ sub init
# Try find a user # Try find a user
# #
# @param server Server object # @param server Server object
# @param user User # @param user SMRadius user hash
# @li Username Username of the user we want
# @param packet Radius packet # @param packet Radius packet
# #
# @return Result # @return UserDB hash of db query
sub find sub find
{ {
my ($server,$user,$packet) = @_; my ($server,$user,$packet) = @_;
...@@ -191,10 +319,12 @@ sub find ...@@ -191,10 +319,12 @@ sub find
# Try to get a user # Try to get a user
# #
# @param server Server object # @param server Server object
# @param user User # @param user UserDB hash we got from find()
# @param packet Radius packet # @param packet Radius packet
# #
# @return Result # @return User attributes hash
# @li Attributes Radius attribute hash
# @li VAttributes Radius vendor attribute hash
sub get sub get
{ {
my ($server,$user,$packet) = @_; my ($server,$user,$packet) = @_;
...@@ -220,7 +350,7 @@ sub get ...@@ -220,7 +350,7 @@ sub get
my $sth = DBSelect(@dbDoParams); my $sth = DBSelect(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"Failed to get group attributes: ".awitpt::db::dblayer::Error()); $server->log(LOG_ERR,"Failed to get group attributes: ".awitpt::db::dblayer::Error());
return -1; return RES_ERROR;
} }
# Loop with group attributes # Loop with group attributes
...@@ -238,7 +368,7 @@ sub get ...@@ -238,7 +368,7 @@ sub get
$sth = DBSelect(@dbDoParams); $sth = DBSelect(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"Failed to get user attributes: ".awitpt::db::dblayer::Error()); $server->log(LOG_ERR,"Failed to get user attributes: ".awitpt::db::dblayer::Error());
return -1; return RES_ERROR;
} }
# Loop with user attributes # Loop with user attributes
...@@ -256,5 +386,133 @@ sub get ...@@ -256,5 +386,133 @@ sub get
} }
## @data_set
# Set user data
#
# @param server Server object
# @param user UserDB hash we got from find()
# @param name Variable name
# @param value Variable value
#
# @return RES_OK on success, RES_ERROR on error
sub data_set
{
my ($server, $user, $name, $value) = @_;
# Build template
my $template;
# Last updated time would be now
$template->{'query'}->{'LastUpdated'} = $user->{'_Internal'}->{'Timestamp-Unix'};
$template->{'query'}->{'Name'} = $name;
$template->{'query'}->{'Value'} = $value;
# Add in userdb data
foreach my $item (keys %{$user->{'_UserDB_Data'}}) {
$template->{'userdb'}->{$item} = $user->{'_UserDB_Data'}->{$item};
}
# Replace template entries
my @dbDoParams = templateReplace($config->{'users_data_update_query'},$template);
# Query database
my $sth = DBDo(@dbDoParams);
if (!$sth) {
$server->log(LOG_ERR,"Failed to update users data: ".awitpt::db::dblayer::Error());
return RES_ERROR;
}
# If we updated *something* ...
if ($sth eq "0E0") {
@dbDoParams = templateReplace($config->{'users_data_set_query'},$template);
# Insert
$sth = DBDo(@dbDoParams);
if (!$sth) {
$server->log(LOG_ERR,"Failed to set users data: ".awitpt::db::dblayer::Error());
return RES_ERROR;
}
}
# If we using caching, cache the result of this set
if (defined($config->{'userdb_data_cache_time'})) {
# Build hash to store
my %data;
$data{'CachedUntil'} = $user->{'_Internal'}->{'Timestamp-Unix'} + $config->{'accounting_usage_cache_time'};
$data{'LastUpdated'} = $user->{'_Internal'}->{'Timestamp-Unix'};
$data{'Name'} = $name;
$data{'Value'} = $value;
# Cache the result
cacheStoreComplexKeyPair('mod_userdb_sql(data_get)',$user->{'UserID'}."/".$template->{'query'}->{'Name'},\%data);
}
return RES_OK;
}
## @data_get
# Get user data
#
# @param server Server object
# @param user UserDB hash we got from find()
# @param name Variable name
#
# @return Users data hash
# @li LastUpdated Time of last update
# @li Name Variable Name
# @li Value Variable Value
sub data_get
{
my ($server, $user, $name) = @_;
# Build template
my $template;
$template->{'query'}->{'Name'} = $name;
# Add in userdb data
foreach my $item (keys %{$user->{'_UserDB_Data'}}) {
$template->{'userdb'}->{$item} = $user->{'_UserDB_Data'}->{$item};
}
# If we using caching, check how old the result is
if (defined($config->{'userdb_data_cache_time'})) {
my ($res,$val) = cacheGetComplexKeyPair('mod_userdb_sql(data_get)',$user->{'UserID'}."/".$template->{'query'}->{'Name'});
if (defined($val) && $val->{'CachedUntil'} > $user->{'_Internal'}->{'Timestamp-Unix'}) {
return $val;
}
}
# Replace template entries
my @dbDoParams = templateReplace($config->{'user_data_get_query'},$template);
# Query database
my $sth = DBSelect(@dbDoParams);
if (!$sth) {
$server->log(LOG_ERR,"Failed to get users data: ".awitpt::db::dblayer::Error());
return RES_ERROR;
}
# Fetch user data
my $row = $sth->fetchrow_hashref();
my %data;
$data{'LastUpdated'} = $row->{'LastUpdated'};
$data{'Name'} = $row->{'Name'};
$data{'Value'} = $row->{'Value'};
# If we using caching and got here, it means that we must cache the result
if (defined($config->{'userdb_data_cache_time'})) {
$data{'CachedUntil'} = $user->{'_Internal'}->{'Timestamp-Unix'} + $config->{'userdb_data_cache_time'};
# Cache the result
cacheStoreComplexKeyPair('mod_userdb_sql(data_get)',$user->{'UserID'}."/".$template->{'query'}->{'Name'},\%data);
}
return \%data;
}
1; 1;
# vim: ts=4 # vim: ts=4
...@@ -447,6 +447,63 @@ userdb_get_user_attributes_query=<<EOT ...@@ -447,6 +447,63 @@ userdb_get_user_attributes_query=<<EOT
AND Disabled = 0 AND Disabled = 0
EOT EOT
users_data_set_query=<<EOT
INSERT INTO
@TP@users_data (UserID, LastUpdated, Name, Value)
VALUES
(
%{userdb.id},
%{query.LastUpdated},
%{query.Name},
%{query.Value}
)
EOT
users_data_update_query=<<EOT
UPDATE
@TP@users_data
SET
LastUpdated = %{query.LastUpdated},
Value = %{query.Value}
WHERE
UserID = %{userdb.id}
AND Name = %{query.Name}
EOT
users_data_get_query=<<EOT
SELECT
LastUpdated, Name, Value
FROM
@TP@users_data
WHERE
UserID = %{userdb.id}
AND Name > %{query.Name}
EOT
users_data_delete_query=<<EOT
DELETE FROM
@TP@users_data
WHERE
UserID = %{userdb.id}
AND Name = %{query.Name}
EOT
users_data_cleanup_query=<<EOT
DELETE FROM
@TP@users_data
WHERE UserID NOT IN
(
SELECT ID FROM users
)
EOT
# This is how long we going to cache the data query for
# Default: 300 (seconds)
#
# You can use "no", "0", "false" to disable, specify a number > 1, or use
# "yes", "1", "true" to enable with the default value
userdb_data_cache_time=300
# MOD_FEATURE_UPDATE_USER_STATS_SQL # MOD_FEATURE_UPDATE_USER_STATS_SQL
[mod_feature_update_user_stats_sql] [mod_feature_update_user_stats_sql]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment