nothing works when only externalURL available

Bug #1309180 reported by Sergey Skripnick
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
python-keystoneclient
Invalid
Medium
Unassigned

Bug Description

I have a deployment where adminURL and internalURL are both available from internal network only. When I try to connect from an "external" network, I see the this error:

>>> from keystoneclient.v2_0 import client
>>> USERNAME, PASSWORD, TENANT, AUTH_URL = 'eye', 'secret', 'rally', 'http://172.18.200.196:35357/v2.0'
>>> keystone = client.Client(username=USERNAME, password=PASSWORD, tenant_name=TENANT, auth_url=AUTH_URL)
>>> keystone.tenants.list()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "keystoneclient/v2_0/tenants.py", line 118, in list
    tenant_list = self._list("/tenants%s" % query, "tenants")
  File "keystoneclient/base.py", line 106, in _list
    resp, body = self.client.get(url)
  File "keystoneclient/httpclient.py", line 590, in get
    return self._cs_request(url, 'GET', **kwargs)
  File "keystoneclient/httpclient.py", line 582, in _cs_request
    return self.request(url, method, **kwargs)
  File "keystoneclient/httpclient.py", line 564, in request
    resp = super(HTTPClient, self).request(url, method, **kwargs)
  File "keystoneclient/baseclient.py", line 21, in request
    return self.session.request(url, method, **kwargs)
  File "keystoneclient/utils.py", line 318, in inner
    return func(*args, **kwargs)
  File "keystoneclient/session.py", line 253, in request
    resp = self._send_request(url, method, redirect, **kwargs)
  File "keystoneclient/session.py", line 282, in _send_request
    raise exceptions.ConnectionRefused(msg)
keystoneclient.openstack.common.apiclient.exceptions.ConnectionRefused: Unable to establish connection to http://192.168.0.2:35357/v2.0/tenants

172.18.200.192 is "external" network
192.168.0.0 is internal network

Tags: endpoint
Revision history for this message
Dolph Mathews (dolph) wrote :

That's by design. The :35357/v2.0/ is assumed to be a deployer-only management API on a secure network. In a real deployment, you should not assume that end users on the public internet should be able to access it, for example.

Changed in python-keystoneclient:
status: New → Invalid
Revision history for this message
Sergey Skripnick (eyerediskin) wrote :

Exactly the same when I trying to use port 5000:

from keystoneclient.v2_0 import client
USERNAME, PASSWORD, TENANT, AUTH_URL = 'rally', 'rally', 'rally', 'http://172.18.200.196:5000/v2.0'
keystone = client.Client(username=USERNAME, password=PASSWORD, tenant_name=TENANT, auth_url=AUTH_URL)
keystone.authenticate()
print keystone.tenants.list()

Traceback (most recent call last):
  File "/tmp/k.py", line 5, in <module>
    print keystone.tenants.list()
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/v2_0/tenants.py", line 118, in list
    tenant_list = self._list("/tenants%s" % query, "tenants")
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/base.py", line 106, in _list
    resp, body = self.client.get(url)
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/httpclient.py", line 590, in get
    return self._cs_request(url, 'GET', **kwargs)
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/httpclient.py", line 582, in _cs_request
    return self.request(url, method, **kwargs)
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/httpclient.py", line 564, in request
    resp = super(HTTPClient, self).request(url, method, **kwargs)
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/baseclient.py", line 21, in request
    return self.session.request(url, method, **kwargs)
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/utils.py", line 318, in inner
    return func(*args, **kwargs)
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/session.py", line 257, in request
    resp = self._send_request(url, method, redirect, **kwargs)
  File "/home/sskripnick/code/python-keystoneclient/keystoneclient/session.py", line 286, in _send_request
    raise exceptions.ConnectionRefused(msg)
keystoneclient.openstack.common.apiclient.exceptions.ConnectionRefused: Unable to establish connection to http://192.168.0.2:35357/v2.0/tenants

But all works fine when I add `endpoint' argument:

from keystoneclient.v2_0 import client
USERNAME, PASSWORD, TENANT, AUTH_URL = 'rally', 'rally', 'rally', 'http://172.18.200.196:5000/v2.0'
keystone = client.Client(username=USERNAME, password=PASSWORD, tenant_name=TENANT,
                         auth_url=AUTH_URL, endpoint=AUTH_URL)
keystone.authenticate()
print keystone.tenants.list()

With `endpoint' it works even with port 35357

Revision history for this message
Dolph Mathews (dolph) wrote :

What are you trying to accomplish with separate networks, if you're going to expose :35357 on both networks anyway?

Unless you should be calling a different client method (I can't recall if tenants.list() is overloaded somehow to call GET :5000/v2.0/tenants), the request in #2 looks like it should work - but I could be mistaken.

Changed in python-keystoneclient:
status: Invalid → Triaged
importance: Undecided → Medium
Revision history for this message
Sergey Skripnick (eyerediskin) wrote :

If it designed for not working from external net then why it is works when external `endpoint' is specified?

If it designed for working from external network then why it is trying to use internalURL/adminURL?

I can't find any documentation about `endpoint' and adminURL/internalURL/externalURL. Seems like this 3 urls are useless, and only one url can be used.

Revision history for this message
Dolph Mathews (dolph) wrote :

> If it designed for not working from external net then why it is works when external `endpoint' is specified?

See below - I'm assuming you mean "public" instead of "external" throughout this report, but some calls work on both interfaces (auth, etc), some calls work only one the public interface (see below), and the bulk of the API only works on the admin interface (but these are also the least frequently hit calls).

> If it designed for working from external network then why it is trying to use internalURL/adminURL?

It's trying to use the admin URL because you're trying to make an admin-only call. Most of the v2 API is non-public. The public API *does* support a GET :5000/v2.0/tenants call, but it's entirely different from the GET :35357/v2.0/tenants call, and may be exposed differently by the client library.

> I can't find any documentation about `endpoint' and adminURL/internalURL/externalURL. Seems like this 3 urls are useless, and only one url can be used.

There's actually not an "externalURL" defined anywhere - although that's an entirely appropriate name, it's defined by the specification as a "public" URL. The v3 API likely has the provides the definitions: https://github.com/openstack/identity-api/blob/master/openstack-identity-api/v3/src/markdown/identity-api-v3.md

Revision history for this message
Steve Martinelli (stevemar) wrote :

this is partly as designed and partly a very specific deployer issue. marking as invalid since there doesn't seem to be anything to fix here

Changed in python-keystoneclient:
status: Triaged → Invalid
Revision history for this message
Fernado Feng (fernado) wrote :

HI:
   I have the same situation. But I hijack the connection. And it works!

cloud_cic_ip = None

def patched_new_conn(self):
    extra_kw = {}
    if self.source_address:
        extra_kw['source_address'] = self.source_address
    if self.socket_options:
        extra_kw['socket_options'] = self.socket_options
    try:
        if self.host == "192.168.0.2" and self.port == 35357:
            self.host = cloud_cic_ip
            self.port = 5000

        conn = connection.create_connection(
            (my_resolver(self.host), self.port), self.timeout, **extra_kw)
    except SocketTimeout as e:
        raise ConnectTimeoutError(
            self, "Connection to %s timed out. (connect timeout=%s)" %
                  (self.host, self.timeout))
    except SocketError as e:
        raise NewConnectionError(
            self, "Failed to establish a new connection: %s" % e)
    return conn

cloud_cic_ip = getCloudCICip()
requests.packages.urllib3.disable_warnings()
    requests.packages.urllib3.connection.HTTPConnection._new_conn = patched_new_conn
    sys.modules['requests'] = requests

and Now below code works well

keystone = client.Client(username=USERNAME, password=PASSWORD, tenant_name=TENANT, auth_url=AUTH_URL)
keystone.tenants.list()

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.