Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FLOC-3521] Support mapping public IP addresses in API client #2230

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions flocker/apiclient/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,14 @@ class Node(PClass):
A node on which a Flocker agent is running.

:attr UUID uuid: The UUID of the node.
:attr IPAddress hostname: The cluster IP address of the node.
:attr IPAddress public_address: The public IP address of the node.
"""
uuid = field(type=UUID, mandatory=True)
hostname = field(
type=(IPv4Address, IPv6Address),
mandatory=True,
)
public_address = field(
type=(IPv4Address, IPv6Address),
mandatory=True,
Expand Down Expand Up @@ -421,19 +426,23 @@ class FlockerClient(object):
A client for the Flocker V1 REST API.
"""
def __init__(self, reactor, host, port,
ca_cluster_path, cert_path, key_path):
ca_cluster_path, cert_path, key_path,
public_addresses={}):
"""
:param reactor: Reactor to use for connections.
:param bytes host: Host to connect to.
:param int port: Port to connect to:
:param FilePath ca_cluster_path: Path to cluster's CA certificate.
:param FilePath cert_path: Path to user certificate.
:param FilePath key_path: Path to user private key.
:param dict public_addresses: Dictionary mapping cluster IPAddress to
public IPAddress.
"""
self._reactor = reactor
self._treq = treq_with_authentication(reactor, ca_cluster_path,
cert_path, key_path)
self._base_url = b"https://%s:%d/v1" % (host, port)
self._public_addresses = public_addresses

def _request(self, method, path, body, success_codes, error_codes=None):
"""
Expand Down Expand Up @@ -642,6 +651,18 @@ def list_containers_configuration(self):
)
return d

def _get_public_address(self, hostname):
"""
Convert the cluster's internal hostname to a public address. This uses
the dictionary provided to the constructor. If the hostname does not
exist in the dictionary, just return the hostname, and hope it is
public.

:param IPAddress hostname: Hostname for Flocker node.
:return IPAddress: Public IP address for node.
"""
return self._public_addresses.get(hostname, hostname)

def list_nodes(self):
request = self._request(
b"GET", b"/state/nodes", None, {OK}
Expand All @@ -653,9 +674,11 @@ def to_nodes(result):
"""
nodes = []
for node_dict in result:
hostname = IPAddress(node_dict['host'])
node = Node(
uuid=UUID(hex=node_dict['uuid'], version=4),
public_address=IPAddress(node_dict['host']),
hostname=hostname,
public_address=self._get_public_address(hostname),
)
nodes.append(node)
return nodes
Expand Down
17 changes: 13 additions & 4 deletions flocker/apiclient/test/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,13 @@ class InterfaceTests(TestCase):
def setUp(self):
self.node_1 = Node(
uuid=uuid4(),
public_address=IPAddress('10.0.0.1')
hostname=IPAddress('10.0.0.1'),
public_address=IPAddress('10.1.0.1'),
)
self.node_2 = Node(
uuid=uuid4(),
public_address=IPAddress('10.0.0.2')
hostname=IPAddress('10.0.0.2'),
public_address=IPAddress('10.1.0.2'),
)
self.client = self.create_client()

Expand Down Expand Up @@ -545,7 +547,7 @@ def create_client(self):
source=source,
changes=[
UpdateNodeStateEra(era=self.era, uuid=self.node_1.uuid)] + [
NodeState(uuid=node.uuid, hostname=node.public_address)
NodeState(uuid=node.uuid, hostname=node.hostname)
for node in [self.node_1, self.node_2]
],
)
Expand All @@ -568,10 +570,17 @@ def create_client(self):
self.addCleanup(api_service.stopService)

credential_set.copy_to(credentials_path, user=True)

public_addresses = {
self.node_1.hostname: self.node_1.public_address,
self.node_2.hostname: self.node_2.public_address,
}

return FlockerClient(reactor, b"127.0.0.1", self.port,
credentials_path.child(b"cluster.crt"),
credentials_path.child(b"user.crt"),
credentials_path.child(b"user.key"))
credentials_path.child(b"user.key"),
public_addresses=public_addresses)

def synchronize_state(self):
deployment = self.persistence_service.get()
Expand Down