static getESShards (req, res) {
    const options = ViewerUtils.addCluster(req.query.cluster, { flat_settings: true });
    Promise.all([
      Db.shards(options.cluster ? { cluster: options.cluster } : undefined),
      Db.getClusterSettingsCache(options)
    ]).then(([{ body: shards }, { body: settings }]) => {
      if (!Array.isArray(shards)) {
        return res.serverError(500, 'No results');
      }
      let ipExcludes = [];
      if (settings.persistent['cluster.routing.allocation.exclude._ip']) {
        ipExcludes = settings.persistent['cluster.routing.allocation.exclude._ip'].split(',');
      }

      let nodeExcludes = [];
      if (settings.persistent['cluster.routing.allocation.exclude._name']) {
        nodeExcludes = settings.persistent['cluster.routing.allocation.exclude._name'].split(',');
      }

      let regex;
      if (req.query.filter !== undefined) {
        try {
          regex = new RE2(req.query.filter.toLowerCase());
        } catch (e) {
          return res.serverError(500, `Regex Error: ${e}`);
        }
      }

      const result = {};
      const nodes = {};

      for (const shard of shards) {
        if (shard.node === null || shard.node === 'null') { shard.node = 'Unassigned'; }

        if (!(req.query.show === 'all' ||
          shard.state === req.query.show || //  Show only matching stage
          (shard.state !== 'STARTED' && req.query.show === 'notstarted'))) {
          continue;
        }

        if (regex && !shard.index.toLowerCase().match(regex) && !shard.node.toLowerCase().match(regex)) { continue; }

        if (result[shard.index] === undefined) {
          result[shard.index] = { name: shard.index, nodes: {} };
        }
        if (result[shard.index].nodes[shard.node] === undefined) {
          result[shard.index].nodes[shard.node] = [];
        }
        result[shard.index].nodes[shard.node].push(shard);
        nodes[shard.node] = { ip: shard.ip, ipExcluded: ipExcludes.includes(shard.ip), nodeExcluded: nodeExcludes.includes(shard.node) };

        result[shard.index].nodes[shard.node]
          .sort((a, b) => {
            return a.shard - b.shard;
          });

        delete shard.node;
        delete shard.index;
      }

      let indices = Object.keys(result).map((k) => result[k]);
      if (req.query.desc === 'true') {
        indices = indices.sort((a, b) => {
          return b.name.localeCompare(a.name);
        });
      } else {
        indices = indices.sort((a, b) => {
          return a.name.localeCompare(b.name);
        });
      }

      res.send({
        nodes,
        indices,
        nodeExcludes,
        ipExcludes
      });
    });
  }
GET - /api/esshards

Fetches all OpenSearch/Elasticsearch shards
@name /esshards
@param {string} filter - Search text to filter the list of OpenSearch/Elasticsearch shards by.
@param {string} show=all - Which types of shard to show. Options include:
     all - show all shards.
     notstarted - show unstarted shards.
     INITIALIZING - show initializing shards.
     RELOCATING - show relocating shards.
     UNASSIGNED - show unassigned shards.
@param {string} desc=false - Whether to return the results in descending order. Defaults to "false".
@returns {array} nodes - List of ES data nodes.
@returns {array} indices - List of ES indices.
@returns {array} nodeExcludes - List of node names that disallow the allocation of shards.
@returns {array} ipExcludes - List of node ips that disallow the allocation of shards.