Skip to content

Commit 3a44c07

Browse files
authored
Merge pull request #591 from aperture-data/release-0.4.47
2 parents da53474 + 5d004b6 commit 3a44c07

File tree

8 files changed

+175
-83
lines changed

8 files changed

+175
-83
lines changed

aperturedb/Configuration.py

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44
import re
55
from base64 import b64encode, b64decode
66

7-
APERTURE_CLOUD = ".cloud.aperturedata.io"
8-
AD_CLOUD_SCHEME = "adbc://"
7+
APERTUREDB_CLOUD = ".cloud.aperturedata.io"
8+
APERTUREDB_KEY_VERSION = 1
9+
FLAG_USE_COMPRESSED_HOST = 4
10+
FLAG_USE_REST = 2
11+
FLAG_USE_SSL = 1
12+
DEFAULT_HTTP_PORT = 80
13+
DEFAULT_HTTPS_PORT = 443
14+
DEFAULT_TCP_PORT = 55555
915

1016

1117
@dataclass(repr=False)
@@ -34,16 +40,8 @@ def __repr__(self) -> str:
3440
return f"[{self.host}:{self.port} as {self.username} using {mode} with SSL={self.use_ssl} auth={auth_mode}]"
3541

3642
def deflate(self) -> list:
37-
deflate_version = 1
38-
host = self.host
39-
if host.endswith(APERTURE_CLOUD):
40-
host = "adbc://{}".format(host[:-1 * len(APERTURE_CLOUD)])
41-
as_list = [deflate_version, host, self.port, self.username, self.password, self.name, int(self.use_ssl),
42-
int(self.use_rest), int(self.use_keepalive),
43-
self.retry_interval_seconds, self.retry_max_attempts]
44-
simplified = json.dumps(as_list)
45-
encoded_key = b64encode(simplified.encode('utf-8')).decode('utf-8')
46-
return encoded_key
43+
return self.create_aperturedb_key(self.host, self.port, self.token,
44+
self.use_rest, self.use_ssl, self.username, self.password)
4745

4846
def has_user_keys(self) -> bool:
4947
return self.user_keys is not None
@@ -65,76 +63,90 @@ def set_user_keys(self, keys: dict) -> None:
6563
self.user_keys = keys
6664

6765
@classmethod
68-
def create_web_token(cls, host: str, port: int, token_string: str) -> None:
69-
if token_string.startswith("adbp_"):
66+
def config_to_key_type(cls, compressed_host: bool, use_rest: bool, use_ssl: bool):
67+
return (FLAG_USE_COMPRESSED_HOST if compressed_host else 0) + \
68+
(FLAG_USE_REST if use_rest else 0) + \
69+
(FLAG_USE_SSL if use_ssl else 0)
70+
71+
@classmethod
72+
def key_type_to_config(cls, key_type: int): \
73+
return [bool(key_type & FLAG_USE_COMPRESSED_HOST),
74+
bool(key_type & FLAG_USE_REST),
75+
bool(key_type & FLAG_USE_SSL)]
76+
77+
@classmethod
78+
def config_default_port(cls, use_rest: bool, use_ssl: bool):
79+
if use_rest:
80+
return DEFAULT_HTTPS_PORT if use_ssl else DEFAULT_HTTP_PORT
81+
else:
82+
return DEFAULT_TCP_PORT
83+
84+
@classmethod
85+
def create_aperturedb_key(cls, host: str, port: int, token_string: str,
86+
use_rest: bool, use_ssl: bool, username: str = None, password: str = None) -> None:
87+
compressed = False
88+
if token_string is not None and token_string.startswith("adbp_"):
7089
token_string = token_string[5:]
7190

72-
if host.endswith(APERTURE_CLOUD):
73-
host = host[:-1 * len(APERTURE_CLOUD)]
91+
if host.endswith(APERTUREDB_CLOUD):
92+
host = host[:-1 * len(APERTUREDB_CLOUD)]
7493
m = re.match("(.*)\.farm(\d+)$", host)
7594
if m is not None:
7695
host = "{}.{}".format(m.group(1), int(m.group(2)))
77-
78-
host = "a://{}".format(host)
79-
80-
if port == 55555:
81-
web_token_json = [2, host, token_string]
96+
compressed = True
97+
98+
key_type = cls.config_to_key_type(compressed, use_rest, use_ssl)
99+
default_port = cls.config_default_port(use_rest, use_ssl)
100+
if port != default_port:
101+
host = f"{host}:{port}"
102+
if token_string is not None:
103+
key_json = [APERTUREDB_KEY_VERSION, key_type, host, token_string]
82104
else:
83-
web_token_json = [2, host, port, token_string]
84-
simplified = json.dumps(web_token_json)
105+
key_json = [APERTUREDB_KEY_VERSION,
106+
key_type, host, username, password]
107+
simplified = json.dumps(key_json, separators=(',', ':'))
85108
encoded = b64encode(simplified.encode('utf-8')).decode('utf-8')
86109
return encoded
87110

88111
@classmethod
89112
def reinflate(cls, encoded_str: list) -> object:
113+
name = "default_key"
90114
try:
91115
decoded = b64decode(encoded_str.encode('utf-8'))
92116
as_list = json.loads(decoded.decode('utf-8'))
93117
except:
94118
raise Exception(
95119
"Unable to make configuration from the provided string")
96120
version = as_list[0]
97-
if version not in (1, 2):
121+
if version not in (APERTUREDB_KEY_VERSION,):
98122
raise ValueError("version identifier of configuration was"
99-
f"g{as_list[0]}, which is not supported")
100-
if version == 1:
101-
host, port, username, password, name, use_ssl, \
102-
use_rest, use_keepalive, retry_interval_seconds, \
103-
retry_max_attempts = as_list[1:]
104-
if host.startswith(AD_CLOUD_SCHEME):
105-
host = host[len(AD_CLOUD_SCHEME):] + APERTURE_CLOUD
106-
use_ssl = bool(use_ssl)
107-
use_rest = bool(use_rest)
108-
use_keepaliave = bool(use_keepalive)
109-
c = Configuration(
110-
host, port, username, password, name, use_ssl, use_rest, use_keepalive,
111-
retry_interval_seconds, retry_max_attempts)
112-
elif version == 2:
113-
host = as_list[1]
114-
if host.startswith("a://"):
115-
m = re.match("a://([^.]*)\.(\d+)", host)
116-
host = "{}.farm{:04d}.cloud.aperturedata.io".format(
117-
m.group(1), int(m.group(2)))
118-
119-
cur_arg = 2
120-
# second arg is port
121-
if isinstance(as_list[2], int):
122-
cur_arg = 3
123-
else:
124-
port = 55555
125-
126-
name = "default"
127-
128-
username = None
129-
password = None
130-
token = None
131-
# if 1 argument left, treat as token.
132-
if len(as_list) - cur_arg == 1:
133-
token = "adbp_" + as_list[cur_arg]
134-
else:
135-
username = as_list[cur_arg]
136-
password = as_list[cur_arg + 1]
137-
138-
c = Configuration(host, port, username,
139-
password, name, token = token)
123+
f"{version}, which is not supported")
124+
is_compressed, use_rest, use_ssl = cls.key_type_to_config(as_list[1])
125+
host = as_list[2]
126+
token = username = password = None
127+
if len(as_list) == 4:
128+
token = "adbp_" + as_list[3]
129+
elif len(as_list) == 5:
130+
username, password = as_list[3:]
131+
132+
port_match = re.match(".*:(\d+)$", host)
133+
if port_match is not None:
134+
port = int(port_match.group(1))
135+
host = host[:-1 * (len(port_match.group(1)) + 1)]
136+
else:
137+
port = cls.config_default_port(use_rest, use_ssl)
138+
139+
if is_compressed:
140+
try:
141+
first, second = host.split('.')
142+
host = "{}.farm{:04d}{}".format(
143+
first, int(second), APERTUREDB_CLOUD)
144+
except Exception as e:
145+
raise ValueError(
146+
f"Unable to parse compressed host: {host} Error: {e}")
147+
148+
c = Configuration(
149+
host, port, username, password, name, use_ssl, use_rest)
150+
if token:
151+
c.token = token
140152
return c

aperturedb/Connector.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ def __init__(self, host="localhost", port=55555,
130130

131131
if key is not None:
132132
self.config = Configuration.reinflate(key)
133+
self.host = self.config.host
134+
self.port = self.config.port
135+
self.use_ssl = self.config.use_ssl
136+
token = self.config.token
133137
elif config is None:
134138
self.host = host
135139
self.port = port
@@ -143,6 +147,7 @@ def __init__(self, host="localhost", port=55555,
143147
username=user,
144148
password=password,
145149
name="runtime",
150+
token=token,
146151
use_keepalive=use_keepalive,
147152
retry_interval_seconds=retry_interval_seconds,
148153
retry_max_attempts=retry_max_attempts
@@ -153,6 +158,7 @@ def __init__(self, host="localhost", port=55555,
153158
self.port = config.port
154159
self.use_ssl = config.use_ssl
155160
self.use_keepalive = config.use_keepalive
161+
token = config.token
156162

157163
self.conn = None
158164

@@ -530,13 +536,8 @@ def clone(self) -> Connector:
530536
Connector: Clone of original Connector
531537
"""
532538
return type(self)(
533-
self.host,
534-
self.port,
535-
self.config.username,
536-
self.config.password,
537-
self.token,
538-
use_ssl=self.use_ssl,
539-
shared_data=self.shared_data)
539+
shared_data=self.shared_data,
540+
config=self.config)
540541

541542
def create_new_connection(self):
542543
from aperturedb.CommonLibrary import issue_deprecation_warning

aperturedb/ConnectorRest.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,7 @@ def __init__(self, host="localhost", port=None,
9191
self.last_query_time = 0
9292

9393
self.url = ('https' if self.use_ssl else 'http') + \
94-
'://' + host + ':' + str(self.port) + '/api/'
95-
96-
self.token = token
94+
'://' + self.host + ':' + str(self.port) + '/api/'
9795

9896
def __del__(self):
9997
logger.info("Done with connector REST.")

aperturedb/ParallelQuery.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def worker(self, thid: int, generator, start: int, end: int, run_event) -> None:
241241
self.error_counter += 1
242242

243243
if self.stats:
244-
self.pb.update(self.batchsize)
244+
self.pb.update(batch_end - batch_start)
245245
logger.info(f"Worker {thid} executed {total_batches} batches")
246246

247247
def get_objects_existed(self) -> int:

aperturedb/Parallelizer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def batched_run(self, generator, batchsize: int, numthreads: int, stats: bool):
5959
else:
6060
self.total_actions = len(generator)
6161
self.pb = tqdm(total=self.total_actions, desc="Progress",
62-
unit="batches", unit_scale=True, dynamic_ncols=True)
62+
unit="items", unit_scale=True, dynamic_ncols=True)
6363
start_time = time.time()
6464

6565
if self.total_actions < batchsize:

aperturedb/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import signal
1111
import sys
1212

13-
__version__ = "0.4.46"
13+
__version__ = "0.4.47"
1414

1515
logger = logging.getLogger(__name__)
1616

aperturedb/cli/keys.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
from enum import Enum
21
from typing import Annotated
32

43
import typer
54

65
from aperturedb.cli.console import console
76
from aperturedb.Configuration import Configuration
87
from aperturedb.Connector import Connector
9-
from aperturedb.CommonLibrary import create_connector
10-
from aperturedb.Utils import Utils
118

129
app = typer.Typer()
1310

1411

1512
@app.command(help="Create Key for a user")
1613
def generate(user: Annotated[str, typer.Argument(help="The user to generate a key for")]):
14+
from aperturedb.CommonLibrary import create_connector
1715
conn = create_connector()
1816
key = generate_user_key(conn, user)
1917
console.log(f"Key for {user} is", key, highlight=False)
2018

2119

2220
def generate_user_key(conn: Connector, user: str):
21+
from aperturedb.Utils import Utils
2322
u = Utils(conn)
2423
token = u.generate_token()
2524
u.assign_token(user, token)
26-
key = Configuration.create_web_token(
27-
conn.config.host, conn.config.port, token)
25+
key = Configuration.create_aperturedb_key(
26+
conn.config.host, conn.config.port, token, conn.config.use_rest,
27+
conn.config.use_ssl)
2828
return key

test/test_Key.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import logging
2+
import typer
3+
4+
from aperturedb.Configuration import Configuration
5+
6+
logger = logging.getLogger(__name__)
7+
8+
key_pairs = {
9+
"WzEsMSwibG9jYWxob3N0IiwiYWRtaW4iLCJhZG1pbiJd":
10+
[1, 1, "localhost", "admin", "admin"],
11+
"WzEsMCwiMTI3LjAuMC4xOjU1NTU0IiwiWVFadVZVV2Zab0FkWjJrUUVMeFB5RnptZHJ3WXd0cjBBRGEiXQ==":
12+
[1, 0, "127.0.0.1:55554", "YQZuVUWfZoAdZ2kQELxPyFzmdrwYwtr0ADa"],
13+
"WzEsNywid29ya2Zsb3ctbG9hZGVkLWZvMWphdTN0LjAiLCJhZG1pbiIsIjEyMzRCVFFMUF8lMnR0Il0=":
14+
[1, 7, "workflow-loaded-fo1jau3t.farm0000.cloud.aperturedata.io",
15+
"admin", "1234BTQLP_%2tt"],
16+
"WzEsNSwidGVzdC0zcWpxdDZrcy40IiwiWVFadVZVV2Zab0FkWjJrUUVMeFB5RnptZHJ3WXd0cjBBRGEiXQ==":
17+
[1, 5, "test-3qjqt6ks.farm0004.cloud.aperturedata.io",
18+
"YQZuVUWfZoAdZ2kQELxPyFzmdrwYwtr0ADa"],
19+
"WzEsMiwiMTkyLjE2OC40LjEyOjU1NTU1IiwiYWRtaW4iLCJhZG1pbiJd":
20+
[1, 2, "192.168.4.12:55555", "admin", "admin"],
21+
"WzEsMywiYXBlcnR1cmVkYi5iaWdjb3JwLmlvOjE5MTgiLCJZUVp1VlVXZlpvQWRaMmtRRUx4UHlGem1kcndZd3RyMEFEYSJd":
22+
[1, 3, "aperturedb.bigcorp.io:1918", "YQZuVUWfZoAdZ2kQELxPyFzmdrwYwtr0ADa"],
23+
"WzEsNCwidGNwLTU1N2Vwbm4zLjkwOToxOTE4IiwiYWRtaW4iLCI4OTBFcE1uKyElMiRfIl0=":
24+
[1, 4, "tcp-557epnn3.farm0909.cloud.aperturedata.io:1918",
25+
"admin", "890EpMn+!%2$_"],
26+
"WzEsNiwiaHR0cC05MGpnM3pwcy4xMjo0NDMiLCJZUVp1VlVXZlpvQWRaMmtRRUx4UHlGem1kcndZd3RyMEFEYSJd":
27+
[1, 6, "http-90jg3zps.farm0012.cloud.aperturedata.io:443",
28+
"YQZuVUWfZoAdZ2kQELxPyFzmdrwYwtr0ADa"]
29+
}
30+
31+
32+
class TestApertureDBKey():
33+
34+
def test_encode_keys(self):
35+
for key, data in key_pairs.items():
36+
logger.info(f"Testing encoding of {key}")
37+
config_type = data[1]
38+
host = data[2]
39+
username = password = token = None
40+
comp, rest, ssl = Configuration.key_type_to_config(config_type)
41+
if host.rfind(':') != -1:
42+
port = int(host.split(':')[1])
43+
host = host.split(':')[0]
44+
else:
45+
port = Configuration.config_default_port(rest, ssl)
46+
if len(data) == 4:
47+
token = data[3]
48+
else:
49+
username = data[3]
50+
password = data[4]
51+
c = Configuration(host, port, username, password,
52+
"encoding test", use_rest=rest, use_ssl=ssl, token=token)
53+
deflated = c.deflate()
54+
assert deflated == key
55+
56+
def test_decode_keys(self):
57+
for key, data in key_pairs.items():
58+
logger.info(f"Testing decoding of {key}")
59+
config = Configuration.reinflate(key)
60+
config_type = data[1]
61+
host = data[2]
62+
if config_type == 0 or config_type == 4:
63+
assert not config.use_rest and not config.use_ssl
64+
if config_type == 1 or config_type == 5:
65+
assert not config.use_rest and config.use_ssl
66+
if config_type == 2 or config_type == 6:
67+
assert config.use_rest and not config.use_ssl
68+
if config_type == 3 or config_type == 7:
69+
assert config.use_rest and config.use_ssl
70+
71+
if host.rfind(':') != -1:
72+
port = int(host.split(':')[1])
73+
host = host.split(':')[0]
74+
assert config.port == port
75+
76+
if len(data) == 4:
77+
assert config.token == "adbp_" + data[3]
78+
else:
79+
assert config.username == data[3] and config.password == data[4]
80+
81+
assert(config.host == host)

0 commit comments

Comments
 (0)