Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F107904551
hpc_syncusers
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Apr 11, 16:38
Size
8 KB
Mime Type
text/x-perl
Expires
Sun, Apr 13, 16:38 (2 d)
Engine
blob
Format
Raw Data
Handle
25495224
Attached To
rSLURMACCOUNTS slurm-accounts
hpc_syncusers
View Options
#!/usr/bin/perl -w
# hpc_syncusers - synchronise slurm user and account data with group memberships and YAML account definitions.
# - create/delete/modify slurm associations and scratch data
#
# Author : EPFL-SCITAS
# Date : March 2016
use
strict
;
use
FindBin
;
use
lib
"$FindBin::RealBin/../lib/blib"
;
use
HPCUsers
;
use
Slurm
;
use
Scratch
;
use
Cmd
;
use
ParseAccounts
;
use
Cwd
'abs_path'
;
# -----------------------------------------------------------------------------
# Command line options
#
my
%opt
;
my
$account_def_file
=
"accounts.yaml"
;
my
$cluster
=
""
;
sub
print_usage
()
{
print
STDERR
<<
"EOF"
;
Synchronize
SCITAS
cluster
users
with
their
group
membership
and
account
definitions:
-
set
slurm
associations
accordingly
-
create
scratch
directory
-
read
account
definitions
in
file
$account_def_file
-
log
commands
in
$
Log::
logfile
By
default
,
does
a
dry
run
by
only
printing
the
commands
required
to
bring
users
in
sync
.
usage:
$0
[
-
f
]
[
-
g
]
[
-
h
]
OPTIONS
-
g
:
go
for
real
by
applying
the
required
modifications
,
and
log
output
.
-
f
:
also
free
ressources
of
users
having
no
more
access
to
the
cluster
,
i
.
e
.
delete
slurm
accounts
and
scratch
data
-
h
:
this
(
help
)
message
example:
$0
-
g
EOF
exit
;
}
# array_diff(A,B) : return an array with all of the elements in A not being in B
sub
array_diff
(\@\@)
{
my
%a
=
map
{
$_
=>
1
}
@
{
$_
[
1
]};
return
grep
(
!
exists
(
$a
{
$_
}),
@
{
$_
[
0
]});
}
# return an array with no dupplicate
sub
array_unique
(@)
{
return
keys
%
{{
map
{
$_
=>
1
}
@_
}};
}
sub
init
()
{
use
Getopt::
Std
;
my
$opt_string
=
'fhg'
;
getopts
(
"$opt_string"
,
\
%opt
)
or
print_usage
();
# pathname of logfile
$cluster
=
Slurm::
get_cluster_name
();
my
$logdir
=
"$FindBin::RealBin/../var/"
;
if
(
$cluster
ne
""
&&
-
e
"$logdir"
)
{
$
Log::
logfile
=
abs_path
(
$logdir
.
$cluster
.
"_"
.
$
Log::
logfile
);
}
else
{
$
Log::
logfile
=
"/var/log/"
.
$
Log::
logfile
;
}
# pathname of account definition file
my
$pathname
=
abs_path
(
"$FindBin::RealBin/../etc/"
.
$account_def_file
);
if
(
defined
(
$pathname
)
&&
-
e
"$pathname"
)
{
$account_def_file
=
$pathname
;
}
else
{
$account_def_file
=
abs_path
(
"$FindBin::RealBin/"
.
$account_def_file
);
}
print_usage
()
if
$opt
{
h
};
$
Cmd::
dry_run
=
1
;
if
(
$opt
{
g
})
{
$
Cmd::
dry_run
=
0
;
}
print_usage
()
if
(
scalar
@ARGV
>
1
);
}
sub
check_modify_user_associations
($)
{
my
(
$username
)
=
@_
;
my
@tmp
=
();
my
@existing_accounts
=
array_unique
(
sort
(
Slurm::
user_accounts
(
$username
)));
foreach
my
$groupname
(
HPCUsers::
member_of
(
$username
))
{
push
(
@tmp
,
ParseAccounts::
group_to_slurm_accounts
(
$groupname
));
}
my
@required_accounts
=
array_unique
(
sort
(
@tmp
));
my
@to_add
=
array_diff
(
@required_accounts
,
@existing_accounts
);
my
@to_remove
=
array_diff
(
@existing_accounts
,
@required_accounts
);
if
(
scalar
(
@to_add
)
>
0
||
scalar
(
@to_remove
)
>
0
)
{
Log::
log_message
(
sprintf
(
"modify user %s (%s)"
,
$username
,
HPCUsers::
user_to_string
(
$username
)));
Log::
append_msg
(
$
Log::
log_str
)
if
!
$
Cmd::
dry_run
;
print
$
Log::
log_str
,
"\n"
;
# add new associations
foreach
my
$account
(
@to_add
)
{
Log::
output_last_cmd_result
()
if
Slurm::
create_user_assoc
(
$username
,
$account
);
}
# remove obsolete associations
foreach
my
$account
(
@to_remove
)
{
Log::
output_last_cmd_result
()
if
Slurm::
delete_user_assoc
(
$username
,
$account
);
}
# reset defaut account if necessary
if
(
!
grep
{
$_
eq
Slurm::
default_account
(
$username
)}
@required_accounts
)
{
# set default account to first account of @required_accounts
Log::
output_last_cmd_result
()
if
Slurm::
set_default_account
(
$username
,
$required_accounts
[
0
]);
}
}
}
# User is new, create the slurm association(s) and private scratch directory
sub
new_user
($)
{
my
(
$username
)
=
@_
;
Log::
log_message
(
sprintf
(
"new user %s (%s)"
,
$username
,
HPCUsers::
user_to_string
(
$username
)));
Log::
append_msg
(
$
Log::
log_str
)
if
!
$
Cmd::
dry_run
;
print
$
Log::
log_str
,
"\n"
;
$
Log::
log_str
=
""
;
# get the user accounts from the unix groups the user belongs to
my
@groups
=
HPCUsers::
member_of
(
$username
);
# print HPCUsers::groups_to_string($username), "\n";
my
@accounts
=
();
foreach
my
$groupname
(
@groups
)
{
push
(
@accounts
,
ParseAccounts::
group_to_slurm_accounts
(
$groupname
));
}
# print $username, ":", Log::array_to_string(@accounts), "\n";
# Create slurm association(s)
foreach
my
$accountname
(
@accounts
)
{
Log::
output_last_cmd_result
()
if
Slurm::
create_user_assoc
(
$username
,
$accountname
);
}
# Create scratch dir
Log::
output_last_cmd_result
()
if
Scratch::
create_user_scratch_dir
(
$username
,
HPCUsers::
gid
(
$username
));
}
# User has no more access to SCITAS clusters:
# - delete the user from slurm dbd, along with all of its association(s)
# - delete its private scratch directory
sub
free_user
($)
{
my
(
$username
)
=
@_
;
return
if
((
$username
eq
"query"
||
$username
eq
"root"
));
Log::
log_message
(
sprintf
(
"free user %s (%s)"
,
$username
,
HPCUsers::
user_to_string
(
$username
)));
Log::
append_msg
(
$
Log::
log_str
)
if
!
$
Cmd::
dry_run
;
print
$
Log::
log_str
,
"\n"
;
# delete slurm data
Log::
output_last_cmd_result
()
if
Slurm::
delete_user
(
$username
);
# delete, or move scratch directory
Log::
output_last_cmd_result
()
if
Scratch::
delete_user_scratch_dir
(
$username
);
}
sub
scan_users
()
{
foreach
my
$username
(
HPCUsers::
all_users
())
{
next
if
(
$username
eq
"scitasbuild"
);
if
(
!
HPCUsers::
is_in_hpc_group
(
$username
)
||
!
HPCUsers::
is_accredited
(
$username
))
{
# if user has no more access to the cluster, we can remove it's account and data
free_user
(
$username
)
if
(
$opt
{
f
}
&&
Scratch::
user_scratch_dir_exists
(
$username
));
}
elsif
(
!
Scratch::
user_scratch_dir_exists
(
$username
))
{
# we assume that's a new user, because his private scratch directory doesn't exist
new_user
(
$username
);
}
else
{
check_modify_user_associations
(
$username
);
}
}
}
# Scan and update slurm accounts with definitions found in account YAML file
sub
scan_accounts
()
{
my
$modified
;
my
$nb_iterations
=
0
;
rescan:
return
if
++
$nb_iterations
>
25
;
# we never know, to avoid infinite loop
$modified
=
0
;
foreach
my
$account
(
ParseAccounts::
all_accounts_tree
())
{
my
$parent
=
ParseAccounts::
account_parent
(
$account
);
my
$share
=
ParseAccounts::
account_share
(
$account
);
if
(
!
Slurm::
account_exists
(
$account
))
{
# print "NOT EXISTS ", $account, " parent=", $parent, " share=", $share, "\n";
Log::
output_last_cmd_result
()
if
(
Slurm::
create_account
(
$account
,
$parent
,
$share
));
}
# check and set acount parent
if
(
Slurm::
set_account_parent
(
$account
,
$parent
))
{
Log::
output_last_cmd_result
();
# if slurm account depedence tree is modified, we need to rescan accounts from scratch
goto
rescan
if
(
$
Cmd::
result
{
status
}
eq
"reinitialized"
);
}
# check and set fairshare value
Log::
output_last_cmd_result
()
if
(
Slurm::
set_account_share
(
$account
,
$share
));
# check and set maxwall value
if
(
Slurm::
set_account_maxwall
(
$account
,
ParseAccounts::
account_maxwall
(
$account
)))
{
Log::
output_last_cmd_result
();
$modified
=
1
if
$
Cmd::
result
{
status
}
eq
"reinitialized"
;
}
# check and set maxnodes value
if
(
Slurm::
set_account_maxnodes
(
$account
,
ParseAccounts::
account_maxnodes
(
$account
)))
{
Log::
output_last_cmd_result
();
$modified
=
1
if
$
Cmd::
result
{
status
}
eq
"reinitialized"
;
}
# if slurm data has been modified enough, it's safer to rescan all accounts from scratch
goto
rescan
if
(
$modified
);
}
}
# -----------------------------------------------------------------------------
init
();
HPCUsers::
init
();
# search all groups to be able to associate users to accounts
HPCUsers::
search_scoldap_for_groups
();
# For debugging
# HPCUsers::print_users();
# Slurm::print_accounts();
# parse YAML account definition file
ParseAccounts::
init
(
$cluster
,
$account_def_file
);
#ParseAccounts::print();
# first scan, modify the accounts
scan_accounts
();
# then add, delete user associations
scan_users
();
Event Timeline
Log In to Comment