Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clear Unknown Indices #1065

Merged
merged 8 commits into from
Dec 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions lib/MetaCPAN/Role/Script.pm
Original file line number Diff line number Diff line change
Expand Up @@ -364,17 +364,32 @@ sub await {

sub are_you_sure {
my ( $self, $msg ) = @_;
my $iconfirmed = 0;

if (is_interactive) {
print colored( ['bold red'], "*** Warning ***: $msg" ), "\n";
my $answer = prompt
'Are you sure you want to do this (type "YES" to confirm) ? ';
my $answer
= prompt colored( ['bold red'], "*** Warning ***: $msg" ) . "\n"
. 'Are you sure you want to do this (type "YES" to confirm) ? ';
if ( $answer ne 'YES' ) {
print "bye.\n";
exit 0;
log_error {"Confirmation incorrect: '$answer'"};
print "Operation will be interruped!\n";

#Set System Error: 125 - ECANCELED - Operation canceled
$self->exit_code(125);
$self->handle_error( 'Operation canceled on User Request', 1 );
}
else {
log_info {'Operation confirmed.'};
print "alright then...\n";
$iconfirmed = 1;
}
print "alright then...\n";
}
else {
print colored( ['bold yellow'], "*** Warning ***: $msg" ) . "\n";
$iconfirmed = 1;
}

return $iconfirmed;
}

1;
Expand Down Expand Up @@ -424,7 +439,7 @@ This method uses the
L<C<Search::Elasticsearch::Client::2_0::Direct::ping()>|https://metacpan.org/pod/Search::Elasticsearch::Client::2_0::Direct#ping()>
method to verify the service availabilty and wait for C<arg_await_timeout> seconds.
When the service does not become available within C<arg_await_timeout> seconds it re-throws the
Exception from the C<Search::Elasticsearch::Client> and sets C< $! > to C< 112 >.
Exception from the C<Search::Elasticsearch::Client> and sets B<Exit Code> to C< 112 >.
The C<Search::Elasticsearch::Client> generates a C<"Search::Elasticsearch::Error::NoNodes"> Exception.
When the service is available it will populate the C<cluster_info> C<HASH> structure with the basic information
about the cluster.
Expand Down Expand Up @@ -462,6 +477,9 @@ See L<Method C<await()>>

Requests the user to confirm the operation with "I< YES >"

B<Exceptions:> When the operator input does not match "I< YES >" it will exit the Script
with Exit Code [125] (C<125 - ECANCELED - Operation canceled>).

=item C<handle_error( error_message[, die_always ] )>

Logs the string C<error_message> with the log function as fatal error.
Expand Down
94 changes: 86 additions & 8 deletions lib/MetaCPAN/Script/Mapping.pm
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ has arg_deploy_mapping => (
documentation => 'delete index if it exists already',
);

has arg_delete_all => (
init_arg => 'all',
is => 'ro',
isa => Bool,
default => 0,
documentation =>
'delete ALL existing indices (only effective in combination with "--delete")',
);

has arg_verify_mapping => (
init_arg => 'verify',
is => 'ro',
Expand Down Expand Up @@ -146,15 +155,28 @@ has delete_from_type => (
sub run {
my $self = shift;

# Wait for the ElasticSearch Engine to become ready
if ( $self->await ) {
$self->delete_index if $self->arg_delete_index;
bodo-hugo-barwich marked this conversation as resolved.
Show resolved Hide resolved
$self->create_index if $self->arg_create_index;
$self->update_index if $self->arg_update_index;
$self->copy_type if $self->copy_to_index;
$self->empty_type if $self->delete_from_type;
$self->list_types if $self->arg_list_types;

if ( $self->arg_deploy_mapping ) {
if ( $self->arg_delete_index ) {
$self->delete_index;
}
elsif ( $self->arg_create_index ) {
$self->create_index;
}
elsif ( $self->arg_update_index ) {
$self->update_index;
}
elsif ( $self->copy_to_index ) {
$self->copy_type;
}
elsif ( $self->delete_from_type ) {
$self->empty_type;
}
elsif ( $self->arg_deploy_mapping ) {
if ( $self->arg_delete_all ) {
$self->check_health;
$self->delete_all;
}
unless ( $self->deploy_mapping ) {
$self->print_error("Indices Re-creation has failed!");
$self->exit_code(1);
Expand All @@ -172,6 +194,10 @@ sub run {
}
}

if ( $self->arg_list_types ) {
$self->list_types;
}

if ( $self->arg_cluster_info ) {
$self->check_health;
$self->show_info;
Expand Down Expand Up @@ -213,6 +239,39 @@ sub delete_index {
$self->_delete_index($name);
}

sub delete_all {
my $self = $_[0];
my $runtime_environment = 'production';
my $is_development = 0;

$runtime_environment = $ENV{'PLACK_ENV'}
if ( defined $ENV{'PLACK_ENV'} );
$runtime_environment = $ENV{'MOJO_MODE'}
if ( defined $ENV{'MOJO_MODE'} );

$is_development = 1
if ( $runtime_environment eq 'development'
|| $runtime_environment eq 'testing' );

if ($is_development) {
my $name = undef;

$self->are_you_sure("ALL Indices will be deleted !!!");

foreach $name ( keys %{ $self->indices_info } ) {
$self->_delete_index($name);
}
}
else {
#Set System Error: 1 - EPERM - Operation not permitted
$self->exit_code(1);
$self->print_error("Operation not permitted!");
$self->handle_error(
"Operation not permitted in environment: $runtime_environment",
1 );
}
}
bodo-hugo-barwich marked this conversation as resolved.
Show resolved Hide resolved

sub _delete_index {
my ( $self, $name ) = @_;

Expand Down Expand Up @@ -847,6 +906,7 @@ MetaCPAN::Script::Mapping - Script to set the index and mapping the types

# bin/metacpan mapping --show_cluster_info # show basic info about the cluster, indices and aliases
# bin/metacpan mapping --delete
# bin/metacpan mapping --delete --all # deletes ALL indices in the cluster
# bin/metacpan mapping --verify # compare deployed indices and aliases with project definitions
# bin/metacpan mapping --list_types
# bin/metacpan mapping --delete_index xxx
Expand Down Expand Up @@ -898,6 +958,24 @@ See L<Method C<mappings_valid()>>

See L<Method C<MetaCPAN::Role::Script::check_health()>>

=item Option C<--all>

This option is only effective in combination with Option C<--delete>.
It uses the information gathered by C<MetaCPAN::Role::Script::check_health()> to delete
B<ALL> indices in the I<ElasticSearch> Cluster.
This option is usefull to reconstruct a broken I<ElasticSearch> Cluster

bin/metacpan mapping --delete --all

B<Exceptions:> It will throw an exceptions when not performed in an development or
testing environment.

See L<Option C<--delete>>

See L<Method C<deploy_mapping()>>

See L<Method C<MetaCPAN::Role::Script::check_health()>>

=item Option C<--verify>

This option will request the index mappings from the I<ElasticSearch> Cluster and
Expand Down
2 changes: 1 addition & 1 deletion lib/MetaCPAN/Script/Runner.pm
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ sub run {

# Display Exception Message in red
print colored( ['bold red'],
"*** EXECPTION [ $EXIT_CODE ] ***: " . $ex->{'message'} ),
"*** EXCEPTION [ $EXIT_CODE ] ***: " . $ex->{'message'} ),
"\n";
};

Expand Down
105 changes: 105 additions & 0 deletions t/lib/MetaCPAN/TestServer.pm
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ sub setup {

$self->es_client;

# Run the Delete Index Tests before mapping deployment
$self->test_delete_mappings;

# Deploy project mappings
$self->put_mappings;
}
Expand Down Expand Up @@ -351,6 +354,108 @@ sub prepare_user_test_data {
);
}

sub test_delete_mappings {
my $self = $_[0];

$self->test_delete_fails;
$self->test_delete_all;
}

sub test_delete_fails {
my $self = $_[0];

my $iexitcode;
my $irunok;

subtest 'delete all not permitted' => sub {

# mapping script - delete indices
{
local @ARGV = qw(mapping --delete --all);
local %ENV = (%ENV);

print STDERR "test_delete_fails - PLACK_ENV: '" . $ENV{'PLACK_ENV'} . "'\n";
print STDERR "test_delete_fails - MOJO_MODE: '" . $ENV{'MOJO_MODE'} . "'\n";

delete $ENV{'PLACK_ENV'};
delete $ENV{'MOJO_MODE'};

$irunok = MetaCPAN::Script::Runner::run;
$iexitcode = $MetaCPAN::Script::Runner::EXIT_CODE;
}

ok( !$irunok, "delete all fails" );
is( $iexitcode, 1, "Exit Code '1' - Permission Error" );
};
}

sub test_delete_all {
my $self = $_[0];

subtest 'delete all deletes unknown index' => sub {
subtest 'create index' => sub {
my $smockindexjson = q({
"mock_index" : {
"properties" : {
"mock_field" : {
"index" : "not_analyzed",
"ignore_above" : 2048,
"type" : "string"
}
}
}
});

local @ARGV = (
'mapping', '--create_index',
'mock_index', '--patch_mapping',
$smockindexjson
);

ok(
MetaCPAN::Script::Runner::run,
"creation 'mock_index' succeeds"
);
is( $MetaCPAN::Script::Runner::EXIT_CODE,
0, "Exit Code '0' - No Error" );
};
subtest 'info shows unknonwn index' => sub {
local @ARGV = ( 'mapping', '--show_cluster_info' );
my $mapping = MetaCPAN::Script::Mapping->new_with_options(
$self->_config );

ok( $mapping->run, "show info succeeds" );
is( $mapping->exit_code, 0, "Exit Code '0' - No Error" );

ok( defined $mapping->indices_info, 'Index Info built' );
ok( defined $mapping->indices_info->{'mock_index'},
'Unknown Index printed' );
};
subtest 'delete all succeeds' => sub {
local @ARGV = qw(mapping --delete --all);

print STDERR "test_delete_all - PLACK_ENV: '" . $ENV{'PLACK_ENV'} . "'\n";
print STDERR "test_delete_all - MOJO_MODE: '" . $ENV{'MOJO_MODE'} . "'\n";

ok( MetaCPAN::Script::Runner::run, "delete all succeeds" );
is( $MetaCPAN::Script::Runner::EXIT_CODE,
0, "Exit Code '0' - No Error" );
};
subtest 'info does not show unknown index' => sub {
local @ARGV = ( 'mapping', '--show_cluster_info' );
my $mapping = MetaCPAN::Script::Mapping->new_with_options(
$self->_config );

ok( $mapping->run, "show info succeeds" );
is( $mapping->exit_code, 0, "Exit Code '0' - No Error" );

ok( defined $mapping->indices_info, 'Index Info built' );
ok( !defined $mapping->indices_info->{'mock_index'},
'Unknown Index printed' );
};
};
}

sub test_mappings {
my $self = $_[0];

Expand Down
54 changes: 54 additions & 0 deletions t/script/mapping.t
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,60 @@ use MetaCPAN::Script::Mapping;

my $config = MetaCPAN::Script::Runner::build_config;

subtest 'create, delete index' => sub {
subtest 'create index' => sub {
my $smockindexjson = q({
"mock_index" : {
"properties" : {
"mock_field" : {
"type" : "string",
"ignore_above" : 2048,
"index" : "not_analyzed"
}
}
}
});
local @ARGV = (
'mapping', '--create_index',
'mock_index', '--patch_mapping',
$smockindexjson
);
my $mapping = MetaCPAN::Script::Mapping->new_with_options($config);

ok( $mapping->run, "creation 'mock_index' succeeds" );
is( $mapping->exit_code, 0, "Exit Code '0' - No Error" );
};
subtest 'info shows new index' => sub {
local @ARGV = ( 'mapping', '--show_cluster_info' );
my $mapping = MetaCPAN::Script::Mapping->new_with_options($config);

ok( $mapping->run, "show info succeeds" );
is( $mapping->exit_code, 0, "Exit Code '0' - No Error" );

ok( defined $mapping->indices_info, 'Index Info built' );
ok( defined $mapping->indices_info->{'mock_index'},
'Created Index printed' );
};
subtest 'delete index' => sub {
local @ARGV = ( 'mapping', '--delete_index', 'mock_index' );
my $mapping = MetaCPAN::Script::Mapping->new_with_options($config);

ok( $mapping->run, "deletion 'mock_index' succeeds" );
is( $mapping->exit_code, 0, "Exit Code '0' - No Error" );
};
subtest 'info does not show deleted index' => sub {
local @ARGV = ( 'mapping', '--show_cluster_info' );
my $mapping = MetaCPAN::Script::Mapping->new_with_options($config);

ok( $mapping->run, "show info succeeds" );
is( $mapping->exit_code, 0, "Exit Code '0' - No Error" );

ok( defined $mapping->indices_info, 'Index Info printed' );
ok( !defined $mapping->indices_info->{'mock_index'},
'Deleted Index not printed' );
};
};

subtest 'mapping verification succeeds' => sub {
local @ARGV = ( 'mapping', '--verify' );
my $mapping = MetaCPAN::Script::Mapping->new_with_options($config);
Expand Down