#!/usr/bin/env perl

use 5.12.0;
use warnings;

use Cpanel::JSON::XS;
use Data::Dumper;
use Disbatch::Roles;
use File::Slurp;
use Getopt::Long;
use MongoDB 1.0.4;
use Safe::Isa;
use Term::ReadKey;
use Try::Tiny::Retry;

my ($config_file, $plugin_perms_file, $additional_perms_file, $root_user, $create_root, $drop_roles);

GetOptions(
    'config=s' => \$config_file,
    'plugin_perms=s' => \$plugin_perms_file,
    'additional_perms=s' => \$additional_perms_file,
    'root_user=s' => \$root_user,
    'create_root' => \$create_root,
    'drop_roles' => \$drop_roles,
);

die "Must pass --config and --root_user" unless $config_file and $root_user;

$plugin_perms_file //= '/etc/disbatch/plugin-permissions.json';

my $config = Cpanel::JSON::XS->new->relaxed->decode(scalar read_file $config_file);
my $plugin_perms = Cpanel::JSON::XS->new->relaxed->decode(scalar read_file $plugin_perms_file);
my $additional_perms = Cpanel::JSON::XS->new->relaxed->decode(scalar read_file $additional_perms_file) if defined $additional_perms_file;

die "No mongohost name in $config_file" unless $config->{mongohost};
die "No database name in $config_file" unless $config->{database};
die "No auth hash in $config_file" unless $config->{auth} and ref $config->{auth} eq 'HASH';
for my $username (@Disbatch::Roles::usernames) {
     die "No auth.$username password in $config_file" unless $config->{auth}{$username};
}

print "Enter password for $root_user:";
ReadMode('noecho');
chomp(my $root_password = <STDIN>);
ReadMode(0);

if ($create_root // 0) {
    say "Creating user '$root_user' in database 'admin' with the root role";
    my $admin = MongoDB->connect($config->{mongohost}, $config->{attributes})->get_database('admin');
    $admin->run_command([createUser => $root_user, pwd => $root_password, roles => [ { role => 'root', db => 'admin' } ]]);
}

$config->{attributes}{username} = $root_user;
$config->{attributes}{password} = $root_password;

my $test_db_root = MongoDB->connect($config->{mongohost}, $config->{attributes})->get_database($config->{database});
my $roles = Disbatch::Roles->new(db => $test_db_root, plugin_perms => $plugin_perms, additional_perms => $additional_perms, %{$config->{auth}});
if ($drop_roles // 0) {
    say "Dropping the following roles and users in database '$config->{database}' on $config->{mongohost}: ", join ', ', sort keys %{$roles->{userroles}};
    $roles->drop_roles_and_users;
}
try {
    say "Creating the following roles and users in database '$config->{database}' on $config->{mongohost}: ", join ', ', sort keys %{$roles->{userroles}};
    $roles->create_roles_and_users;
    say "Successfully created roles and users.";
} catch {
    die "Failed: $_->{message}\n" if $_->$_isa('MongoDB::Error');
    die $_;
};

__END__

=encoding utf8

=head1 NAME

disbatch-create-users - create roles and users for Disbatch

=head1 VERSION

version 4.102

=head1 SYNOPSIS

  disbatch-create-users --config /etc/disbatch/config.json --root_user root

=head1 ARGUMENTS

=over 2

=item --config <string>

Path to the JSON Disbatch config file.

The config file must have keys for C<mongohost> and C<database>.

It must also have the key C<auth> which is a hash with keys C<disbatchd>, C<disbatch_web>, C<task_runner>, C<queuebalance>, and C<plugin> whose values are the passwords for those MongoDB disbatch users.

=item --root_user <string>

Username of the MongoDB root user.

=item --plugin_perms <string>

Path to the JSON config file for C<plugin> permissions. Default is C</etc/disbatch/plugin-permissions.json>.

No permissions are required, but note that L<Disbatch::Plugin::Demo> must be able to do C<insert> on the C<reports> collection.

=item --additional_perms <string>

Path to the JSON config file to set additional permissions for included roles. No default.

If you have L<Disbatch::Web> load additional routes via C<config.web_extensions>, you may need to add permissions here.

Format of the file is C<{ role_name: {collection_name: array_of_actions, ...}, ... }>.

See file C<etc/disbatch/additional-permissions.json-example>.

=item --create_root

Will first create the root user in the C<admin> database. Optional.

This only works if no other users have been created.

=item --drop_roles

Will drop Disbatch roles and users before creating them. Optional.

=back

=head1 SEE ALSO

L<Disbatch>

L<Disbatch::Web>

L<Disbatch::Roles>

L<Disbatch::Plugin::Demo>

L<disbatchd>

L<disbatch.pl>

L<task_runner>

=head1 AUTHORS

Ashley Willis <awillis@synacor.com>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2016, 2019 by Ashley Willis.

This is free software, licensed under:

  The Apache License, Version 2.0, January 2004
