Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
24.44% covered (danger)
24.44%
11 / 45
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecificAliasValidator
24.44% covered (danger)
24.44%
11 / 45
40.00% covered (danger)
40.00%
2 / 5
112.05
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 updateIndices
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
90
 updateFreeIndices
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 swapAliases
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 shouldRemoveFromAlias
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace CirrusSearch\Maintenance\Validators;
4
5use CirrusSearch\Maintenance\Printer;
6use CirrusSearch\Maintenance\Reindexer;
7use Elastica\Client;
8use RawMessage;
9use Status;
10
11class SpecificAliasValidator extends IndexAliasValidator {
12    /**
13     * @var Reindexer
14     */
15    private $reindexer;
16
17    /**
18     * @var array
19     */
20    private $reindexParams;
21
22    /**
23     * @var Validator[]
24     */
25    private $reindexValidators;
26
27    /**
28     * @var bool
29     */
30    private $reindexAndRemoveOk;
31
32    /**
33     * @param Client $client
34     * @param string $aliasName
35     * @param string $specificIndexName
36     * @param bool $startOver
37     * @param Reindexer $reindexer
38     * @param array $reindexParams
39     * @param Validator[] $reindexValidators
40     * @param bool $reindexAndRemoveOk
41     * @param Printer|null $out
42     */
43    public function __construct(
44        Client $client,
45        $aliasName,
46        $specificIndexName,
47        $startOver,
48        Reindexer $reindexer,
49        array $reindexParams,
50        array $reindexValidators,
51        $reindexAndRemoveOk,
52        Printer $out = null
53    ) {
54        // @todo: this constructor takes too many arguments - refactor!
55
56        parent::__construct( $client, $aliasName, $specificIndexName, $startOver, $out );
57
58        $this->reindexer = $reindexer;
59        $this->reindexParams = $reindexParams;
60        $this->reindexValidators = $reindexValidators;
61        $this->reindexAndRemoveOk = $reindexAndRemoveOk;
62    }
63
64    /**
65     * @param string[] $add
66     * @param string[] $remove
67     * @return Status
68     */
69    protected function updateIndices( array $add, array $remove ) {
70        if ( !$remove ) {
71            return $this->updateFreeIndices( $add );
72        }
73
74        if ( !$this->reindexAndRemoveOk ) {
75            $this->output( "cannot correct!\n" );
76            return Status::newFatal( new RawMessage(
77                "The alias is held by another index which means it might be actively serving\n" .
78                "queries.  You can solve this problem by running this program again with\n" .
79                "--reindexAndRemoveOk.  Make sure you understand the consequences of either\n" .
80                "choice." ) );
81        }
82
83        try {
84            $this->output( "is taken...\n" );
85            $this->outputIndented( "\tReindexing...\n" );
86            $this->reindexer->reindex( ...$this->reindexParams );
87            # Expecting this to usually be a noop, index should have been created with
88            # appropriate settings and reindexer should restore all the settings it
89            # changed, but it couldn't hurt to check again.
90            foreach ( $this->reindexValidators as $validator ) {
91                $status = $validator->validate();
92                if ( !$status->isOK() ) {
93                    return $status;
94                }
95            }
96            // Validators might have changed replica counts, wait for everything to
97            // get to green.
98            $this->reindexer->waitForGreen();
99        } catch ( \Exception $e ) {
100            return Status::newFatal( new RawMessage( $e->getMessage() ) );
101        }
102
103        // now add alias & remove indices for real
104        $status = Status::newGood();
105        $status->merge( $this->swapAliases( $add ) );
106        $toRemove = [];
107        foreach ( $remove as $indexToRemove ) {
108            $resp = $this->client->request( $indexToRemove . '/_alias', 'GET' );
109            if ( !$resp->isOk() ) {
110                return Status::newFatal( "Cannot fetch aliases of the old index $indexToRemove" );
111            }
112            if ( count( $resp->getData()[$indexToRemove]['aliases'] ?? [] ) > 0 ) {
113                $this->outputIndented( "\t$indexToRemove still have active aliases, cannot remove.\n" );
114            } else {
115                $toRemove[] = $indexToRemove;
116            }
117        }
118        $status->merge( parent::updateIndices( [], $toRemove ) );
119        return $status;
120    }
121
122    /**
123     * @param string[] $add
124     * @return Status
125     */
126    public function updateFreeIndices( array $add ) {
127        $this->output( "alias is free..." );
128
129        foreach ( $add as $indexName ) {
130            $index = $this->client->getIndex( $indexName );
131            $index->addAlias( $this->aliasName, false );
132        }
133
134        $this->output( "corrected\n" );
135
136        return Status::newGood();
137    }
138
139    /**
140     * @param array $add
141     * @return Status
142     */
143    public function swapAliases( array $add ) {
144        $this->outputIndented( "\tSwapping alias..." );
145
146        foreach ( $add as $indexName ) {
147            $index = $this->client->getIndex( $indexName );
148            $index->addAlias( $this->aliasName, true );
149        }
150
151        $this->output( "done\n" );
152
153        return Status::newGood();
154    }
155
156    /**
157     * @param string $name
158     * @return bool
159     */
160    protected function shouldRemoveFromAlias( $name ) {
161        return true;
162    }
163}