This file is indexed.

/usr/lib/python3/dist-packages/searchlightclient/osc/v1/search.py is in python3-searchlightclient 1.3.0-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#   Licensed under the Apache License, Version 2.0 (the "License"); you may
#   not use this file except in compliance with the License. You may obtain
#   a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#   License for the specific language governing permissions and limitations
#   under the License.
#

"""Searchlight v1 Search action implementations"""

import json
import logging

from osc_lib.command import command
from osc_lib import utils


class SearchResource(command.Lister):
    """Search Searchlight resource."""

    log = logging.getLogger(__name__ + ".SearchResource")

    def get_parser(self, prog_name):
        parser = super(SearchResource, self).get_parser(prog_name)
        parser.add_argument(
            "query",
            metavar="<query>",
            help="Query resources by Elasticsearch query string or json "
                 "format DSL. Query string example: 'name: cirros AND "
                 "updated_at: [now-1y TO now]'. DSL example: "
                 "'{\"term\": {\"name\": \"cirros\"}}'. "
                 "See Elasticsearch DSL or Searchlight documentation for "
                 "more detail."
        )
        parser.add_argument(
            "--json",
            action='store_true',
            default=False,
            help="Treat the query argument as a JSON formatted DSL query."
        )
        parser.add_argument(
            "--type",
            nargs='*',
            metavar="<resource-type>",
            help="One or more types to search. Uniquely identifies resource "
                 "types. Example: --type OS::Glance::Image "
                 "OS::Nova::Server"
        )
        parser.add_argument(
            "--all-projects",
            action='store_true',
            default=False,
            help="By default searches are restricted to the current project "
                 "unless all_projects is set"
        )
        parser.add_argument(
            "--source",
            nargs='?',
            const='all_sources',
            metavar="[<field>,...]",
            help="Whether to display the json source. If not specified, "
                 "it will not be displayed. If specified with no argument, "
                 "the full source will be displayed. Otherwise, specify the "
                 "fields combined with ',' to return the fields you want. "
                 "It is recommended that you use the --max-width argument "
                 "with this option."
        )
        return parser

    def take_action(self, parsed_args):
        self.log.debug("take_action(%s)", parsed_args)

        search_client = self.app.client_manager.search
        mapping = {"_score": "score", "_type": "type", "_id": "id",
                   "_index": "index", "_source": "source"}

        params = {
            "type": parsed_args.type,
            "all_projects": parsed_args.all_projects
        }
        source = parsed_args.source
        if source:
            columns = ("ID", "Score", "Type", "Source")
            if source != "all_sources":
                params["_source"] = (["id"] +
                    [s for s in source.split(",") if s != 'id'])
        else:
            columns = ("ID", "Name", "Score", "Type", "Updated")
            # Only return the required fields when source not specified.
            params["_source"] = ["id", "name", "updated_at"]

        if parsed_args.query:
            if parsed_args.json:
                query = json.loads(parsed_args.query)
            else:
                try:
                    json.loads(parsed_args.query)
                    print("You should use the --json flag when specifying "
                          "a JSON object.")
                    exit(1)
                except Exception:
                    qs = self._modify_query_string(parsed_args.query)
                    query = {"query_string": {"query": qs}}

            params['query'] = query

        data = search_client.search.search(**params)
        result = []
        for r in data.hits['hits']:
            converted = {}
            extra = {}
            # hit._id may include extra information appended after _,
            # so use r['_source']['id'] for safe.
            r['_id'] = r.get('_source', {}).get('id')
            for k, v in r.items():
                map_key = mapping.get(k)
                if map_key is not None:
                    converted[map_key] = v
                    if k == "_source" and not parsed_args.source:
                        converted["name"] = v.get("name")
                        converted["updated"] = v.get("updated_at")
                else:
                    extra[k] = v
            if extra:
                self.log.debug("extra info returned: %s", extra)
            result.append(utils.get_dict_properties(converted, columns))
        return (columns, result)

    def _modify_query_string(self, query_string):
        return query_string.replace('/', '\/')