Able to access Elasticsearch with Python's Requests but not with official client

12/17/2021

I have an Elasticsearch DB running on Kubernetes exposed to my_domain.com/elastic as an Istio virtual service, which I have no problem accessing via the browser (as in I get to login successfully to the endpoint). I can also query the DB with Python's Requests. But I can't access the DB with the official python client if I use my_domain.com/elastic. The LoadBalancer IP works perfectly well even with the client. What am I missing? I have SSL certificates set up for my_domain.com via Cert-Manager and CloudFlare.

This works:

import requests
import os
data = ' { "query": { "match_all": {} } }'
headers = {'Content-Type': 'application/json'}
auth= ('elastic', os.environ['ELASTIC_PASSWORD']) 
response = requests.post('https://mydomain.cloud/elastic/_search', auth=auth,  data=data, headers=headers)
print(response.text)

This doesn't work (I have tried a number of different parameters):

from datetime import datetime
import os
from elasticsearch import Elasticsearch, RequestsHttpConnection


es = Elasticsearch(,
   [{'host': 'mydomain.cloud', 'port': 443, 'url_prefix': 'elastic', 'use_ssl': True}],
    http_auth=('elastic', os.environ['ELASTIC_PASSWORD']), # 1Password or kubectl get secret elastic-cluster-es-elastic-user -o go-template='{{.data.elastic | base64decode}}' -n elastic-system
    schema='https'#, verify_certs=False,
    # use_ssl=True,
    # connection_class = RequestsHttpConnection,
    # port=443,
)

# if not es.ping():
#     raise ValueError("Connection failed")

doc = {
    'author': 'kimchy',
    'text': 'Elasticsearch: cool. bonsai cool.',
    'timestamp': datetime.now(),
}
res = es.index(index="test-index", id=1, document=doc)
print(res['result'])

res = es.get(index="test-index", id=1)
print(res['_source'])

es.indices.refresh(index="test-index")

res = es.search(index="test-index", query={"match_all": {}})
print("Got %d Hits:" % res['hits']['total']['value'])
for hit in res['hits']['hits']:
    print("%(timestamp)s %(author)s: %(text)s" % hit["_source"])

The resulting error:

elasticsearch.exceptions.RequestError: RequestError(400, 'no handler found for uri [//test-index/_doc/1] and method [PUT]', 'no handler found for uri [//test-index/_doc/1] and method [PUT]') 

cluster.yaml

apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elastic-cluster
  namespace: elastic-system
spec:
  version: 7.15.2
  http:
    # tls:
    #   selfSignedCertificate:
    #      disabled: true
    service:
      spec:
        type: LoadBalancer
  nodeSets:
  - name: master-nodes
    count: 2
    config:
      node.roles: ["master"]
    volumeClaimTemplates:
    - metadata:
        name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 5Gi
        storageClassName: local-storage
  - name: data-nodes
    count: 2
    config:
      node.roles: ["data"]
    volumeClaimTemplates:
    - metadata:
        name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 10Gi
        storageClassName: local-storage
    podTemplate:
      # metadata:
      #   annotations:
      #     traffic.sidecar.istio.io/includeInboundPorts: "*"
      #     traffic.sidecar.istio.io/excludeOutboundPorts: "9300" 
      #     traffic.sidecar.istio.io/excludeInboundPorts: "9300"
      spec:
        # automountServiceAccountToken: true
        containers:
        - name: elasticsearch
          resources:
            requests:
              memory: 4Gi
              cpu: 3
            limits:
              memory: 4Gi
              cpu: 3

virtual-service.yaml

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: elastic-vts
  namespace: elastic-system
spec:
  hosts:
  - "mydomain.cloud"
  gateways:
  - istio-system/gateway
  http:
  - match:
    - port: 443
    - uri:
        prefix: /elastic
    rewrite:
      uri: /
    route:
    - destination:
        host: elastic-cluster-es-http.elastic-system.svc.cluster.local
        port:
          number: 9200

destination-rule.yaml

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: elastic-destination-rule
  namespace: elastic-system
spec:
  host: elastic-cluster-es-http.elastic-system.svc.cluster.local
  trafficPolicy:
    tls:
      mode: SIMPLE

gateway.yaml

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - 'mydomain.cloud'
    tls:
      httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
      - 'mydomain.cloud'
    tls:
      mode: SIMPLE
      credentialName: letsencrypt-staging-tls
     
-- Minsky
elasticsearch
http
istio
kubernetes

1 Answer

12/30/2021

I have reproduced your problem and the solution is as follows. First, pay attention to your yaml file:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: elastic-vts
  namespace: elastic-system
spec:
  hosts:
  - "mydomain.cloud"
  gateways:
  - istio-system/gateway
  http:
  - match:
    - port: 443
    - uri:
        prefix: /elastic   <---- here is the problem
    rewrite:
      uri: /
      ...

The error that appears looks like this:

elasticsearch.exceptions.RequestError: RequestError(400, 'no handler found for uri [//test-index/_doc/1] and method [PUT]', 'no handler found for uri [//test-index/_doc/1] and method [PUT]')

The problem is right there: [//test-index/_doc/1] (it's about a duplicate / character). I think it's a similar problem to the problem mentioned here. To fix this, I suggest adding the / to the line prefix: /elastic and your yaml will be like this example:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: elastic-vts
  namespace: elastic-system
spec:
  hosts:
  - "mydomain.cloud"
  gateways:
  - istio-system/gateway
  http:
  - match:
    - port: 443
    - uri:
        prefix: /elastic/ <---- here
    rewrite:
      uri: /
      ...

In this moment the answer from Elastic looks like:

Got 1 Hits:
2021-12-30T09:20:12.038004 kimchy: Elasticsearch: cool. bonsai cool.
-- Mikołaj Głodziak
Source: StackOverflow