dataflow-core 2.0.9__py3-none-any.whl → 2.0.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dataflow-core might be problematic. Click here for more details.

@@ -1,22 +1,22 @@
1
- from flask import redirect, request
1
+ from flask import redirect, request, jsonify
2
2
  from flask_appbuilder.security.views import AuthDBView
3
- from superset.security import SupersetSecurityManager
4
3
  from flask_appbuilder.security.views import expose
5
4
  from flask_login import login_user
6
- from .package.configuration import ConfigurationManager
7
- from .package.models.database import DatabaseManager
8
- from .package.models import (
9
- user as m_user,
10
- session as m_session
11
- )
5
+ from flask_jwt_extended import (
6
+ create_access_token
7
+ )
8
+ from flask_appbuilder.const import (
9
+ API_SECURITY_ACCESS_TOKEN_KEY
10
+ )
11
+ from superset.security import SupersetSecurityManager
12
12
  from dataflow.dataflow import Dataflow
13
13
 
14
- class CustomAuthDBView(AuthDBView):
14
+ class DataflowAuthDBView(AuthDBView):
15
15
  def __init__(self):
16
16
  self.dataflow = Dataflow()
17
17
 
18
18
  @expose('/login/', methods=['GET'])
19
- def login(self):
19
+ def login_redirect(self):
20
20
  try:
21
21
  session_id = request.cookies.get('dataflow_session')
22
22
 
@@ -30,8 +30,7 @@ class CustomAuthDBView(AuthDBView):
30
30
  first_name=user_details.get("first_name", ""),
31
31
  last_name=user_details.get("last_name", ""),
32
32
  email=user_details.get("email", ""),
33
- role=self.appbuilder.sm.find_role('Admin'),
34
- password=""
33
+ role=self.appbuilder.sm.find_role('Admin')
35
34
  )
36
35
  if user:
37
36
  login_user(user, remember=False)
@@ -41,8 +40,27 @@ class CustomAuthDBView(AuthDBView):
41
40
  except Exception as e:
42
41
  return super().login()
43
42
 
43
+ @expose("/login", methods=["POST"])
44
+ def login_token(self):
45
+ login_payload = request.get_json()
46
+ user = self.appbuilder.sm.find_user(username=login_payload["user_name"])
44
47
 
45
- class CustomSecurityManager(SupersetSecurityManager):
46
- authdbview = CustomAuthDBView
48
+ if not user:
49
+ user = self.appbuilder.sm.add_user(
50
+ username=login_payload["user_name"],
51
+ first_name=login_payload.get("first_name", ""),
52
+ last_name=login_payload.get("last_name", ""),
53
+ email=login_payload.get("email", ""),
54
+ role=self.appbuilder.sm.find_role('Admin')
55
+ )
56
+
57
+ resp = dict()
58
+ resp[API_SECURITY_ACCESS_TOKEN_KEY] = create_access_token(
59
+ identity=str(user.id), fresh=True
60
+ )
61
+ return jsonify(resp)
62
+
63
+ class DataflowSecurityManager(SupersetSecurityManager):
64
+ authdbview = DataflowAuthDBView
47
65
  def __init__(self, appbuilder):
48
- super(CustomSecurityManager, self).__init__(appbuilder)
66
+ super(DataflowSecurityManager, self).__init__(appbuilder)
@@ -1,5 +1,5 @@
1
1
  """models.py"""
2
- from sqlalchemy import Column, Integer, String, LargeBinary, Enum
2
+ from sqlalchemy import Column, Integer, String, LargeBinary, Enum, Boolean
3
3
  from sqlalchemy.ext.declarative import declarative_base
4
4
 
5
5
  #instance for create declarative base
@@ -17,7 +17,6 @@ class User(Base):
17
17
  first_name = Column(String)
18
18
  last_name = Column(String)
19
19
  email = Column(String, unique=True)
20
- role = Column(Enum('admin', 'user', name='role_field'), nullable=False)
21
20
  image = Column(LargeBinary)
22
21
  active = Column(Enum('N', 'Y', name='active_field'), nullable=False, server_default=str("N"))
23
22
  password = Column(String, nullable=False)
dataflow/dataflow.py CHANGED
@@ -1,9 +1,7 @@
1
- import os, requests, shutil, subprocess, datetime
1
+ import os, requests
2
2
  from .models.database import DatabaseManager
3
- from .models.environment import JobLogs
4
- from sqlalchemy.inspection import inspect
5
3
  from .utils.aws_secrets_manager import SecretsManagerClient
6
- import json, asyncio, pkg_resources
4
+ import json
7
5
  from authenticator.package.configuration import ConfigurationManager
8
6
 
9
7
 
@@ -38,26 +36,101 @@ class Dataflow:
38
36
  return e
39
37
 
40
38
  def variable(self, variable_name: str):
41
- """Get variable value from secrets manager."""
39
+ """
40
+ Get variable value from UI API.
41
+ """
42
42
  try:
43
- host_name = os.environ["HOSTNAME"]
44
- user_name = host_name.replace("jupyter-","")
45
-
46
- vault_path = "variables"
47
- variable_data = self.secrets_manager.get_secret_by_key(vault_path, user_name, variable_name)
48
- return variable_data['value']
49
-
43
+ host_name = os.environ.get("HOSTNAME", "")
44
+ user_name = host_name.replace("jupyter-", "") if host_name.startswith("jupyter-") else host_name
45
+ runtime = os.environ.get("RUNTIME")
46
+ slug = os.environ.get("SLUG")
47
+
48
+ dataflow_config = ConfigurationManager('/dataflow/app/auth_config/dataflow_auth.cfg')
49
+ variable_api = dataflow_config.get_config_value("auth", "db_get_variables")
50
+ if not variable_api:
51
+ print("[Dataflow.variable] Variable Unreachable")
52
+ return None
53
+
54
+ if runtime:
55
+ query_params = {
56
+ "variable_key": variable_name,
57
+ "runtime": runtime,
58
+ "slug": slug
59
+ }
60
+ response = requests.get(variable_api, params=query_params)
61
+ if response.status_code == 200:
62
+ response_text = response.text.strip().strip('"')
63
+ return response_text
64
+
65
+ query_params["slug"] = "global"
66
+ response = requests.get(variable_api, params=query_params)
67
+ if response.status_code == 200:
68
+ response_text = response.text.strip().strip('"')
69
+ return response_text
70
+ else:
71
+ return None
72
+
73
+ query_params = {
74
+ "variable_key": variable_name,
75
+ "runtime": None,
76
+ "slug": None,
77
+ "created_by": user_name
78
+ }
79
+ response = requests.get(variable_api, params=query_params)
80
+ if response.status_code == 200:
81
+ response_text = response.text.strip().strip('"')
82
+ return response_text
83
+ else:
84
+ return None
50
85
  except Exception as e:
86
+ print(f"[Dataflow.variable] Exception occurred: {e}")
51
87
  return None
52
88
 
89
+ def secret(self, secret_name: str):
90
+ """Get secret value from secrets manager for Studio or Runtime."""
91
+ try:
92
+ host_name = os.environ.get("HOSTNAME", "")
93
+ user_name = host_name.replace("jupyter-", "") if host_name.startswith("jupyter-") else host_name
94
+ runtime = os.environ.get("RUNTIME")
95
+ slug = os.environ.get("SLUG")
96
+
97
+ dataflow_config = ConfigurationManager('/dataflow/app/auth_config/dataflow_auth.cfg')
98
+ secret_api = dataflow_config.get_config_value("auth", "db_get_secrets")
99
+ if not secret_api:
100
+ print("[Dataflow.secret] Secret API Unreachable")
101
+ return None
102
+
103
+ query_params = {
104
+ "secret_key": secret_name,
105
+ "created_by": user_name
106
+ }
107
+
108
+ if runtime:
109
+ query_params["runtime"] = runtime
110
+ if slug:
111
+ query_params["slug"] = slug
112
+
113
+ response = requests.get(secret_api, params=query_params)
114
+
115
+ if response.status_code == 200:
116
+ response_text = response.text.strip().strip('"')
117
+ return response_text
118
+ else:
119
+ return None
120
+ except Exception as e:
121
+ print(f"[Dataflow.secret] Exception occurred: {e}")
122
+ return None
123
+
53
124
  def connection(self, conn_id: str):
54
125
  """Get connection details from secrets manager."""
55
126
  try:
56
127
  host_name = os.environ["HOSTNAME"]
57
128
  user_name=host_name.replace("jupyter-","")
129
+ runtime = os.environ.get("RUNTIME")
130
+ slug = os.environ.get("SLUG")
58
131
 
59
132
  vault_path = "connections"
60
- secret = self.secrets_manager.get_secret_by_key(vault_path, user_name, conn_id)
133
+ secret = self.secrets_manager.get_secret_by_key(vault_path, user_name, conn_id, runtime, slug)
61
134
 
62
135
  conn_type = secret['conn_type'].lower()
63
136
  username = secret['login']
@@ -71,7 +144,7 @@ class Dataflow:
71
144
 
72
145
  connection_string = f"{conn_type}://{user_info}{host}:{port}{db_info}"
73
146
 
74
- extra = secret.get('extra', '')
147
+ extra = secret.get('extra', '')
75
148
  if extra:
76
149
  try:
77
150
  extra_params = json.loads(extra)
dataflow/environment.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import os, shutil, subprocess, datetime
2
- from .models.database import DatabaseManager
3
2
  from .models.environment import JobLogs, Environment
4
3
  import json, asyncio, pkg_resources
5
4
  from sqlalchemy.orm import Session
@@ -1,6 +1,7 @@
1
1
  import boto3
2
2
  from botocore.exceptions import ClientError, EndpointConnectionError, NoCredentialsError
3
3
  import json
4
+ from .json_handler import JsonHandler
4
5
 
5
6
  class SecretsManagerClient:
6
7
  """
@@ -11,6 +12,7 @@ class SecretsManagerClient:
11
12
  json_handler: An instance of JsonHandler for handling JSON operations.
12
13
  """
13
14
  def __init__(self):
15
+ self.json_handler = JsonHandler()
14
16
  try:
15
17
  self.client = boto3.client('secretsmanager')
16
18
  except EndpointConnectionError as e:
@@ -21,14 +23,16 @@ class SecretsManagerClient:
21
23
  raise Exception(f"Failed to initialize SecretsManagerClient: No AWS credentials found. {e}")
22
24
 
23
25
 
24
- def get_secret_by_key(self, vault_path, user_name, secret_key: str):
26
+ def get_secret_by_key(self, vault_path, user_name, conn_id: str, runtime, slug):
25
27
  """
26
- Get information about a specific secret.
28
+ Get information about a specific secret using a dynamically constructed vault path.
27
29
 
28
30
  Args:
29
- vault_path (str): The vault path.
31
+ vault_path (str): The base vault path.
30
32
  user_name (str): The user name.
31
- secret_key (str): The key of the secret to retrieve.
33
+ conn_id (str): The key of the secret to retrieve.
34
+ runtime (str, optional): The runtime environment. Defaults to None.
35
+ slug (str, optional): The slug identifier. Defaults to None.
32
36
 
33
37
  Returns:
34
38
  str: Information about the secret in JSON format.
@@ -37,25 +41,17 @@ class SecretsManagerClient:
37
41
  Exception: If the operation fails.
38
42
  """
39
43
  try:
40
- if not user_name:
41
- raise Exception("user_name is required when secret_key is provided")
42
-
43
- secret_name = f"{user_name}/{vault_path}/{secret_key}"
44
+ if runtime and slug:
45
+ secret_name = f"{runtime}/{slug}/{vault_path}/{conn_id}"
46
+ else:
47
+ secret_name = f"{user_name}/{vault_path}/{conn_id}"
48
+
44
49
  response = self.client.get_secret_value(SecretId=secret_name)
45
- secret_metadata = self.client.describe_secret(SecretId=secret_name)
46
50
  secret_data = json.loads(response.get('SecretString'))
47
51
 
48
- if secret_data.get('is_active') == 'Y':
49
- secret_info={
50
- "Name": secret_key,
51
- "Description": secret_metadata.get('Description')
52
- }
53
- secret_info.update(secret_data)
54
- return secret_info
55
- else:
56
- raise Exception(f"Secret named '{secret_key}' is not active")
52
+ return secret_data
57
53
  except ClientError as e:
58
54
  if e.response['Error']['Code'] == 'ResourceNotFoundException':
59
- raise Exception(f"Secret named '{secret_key}' not found")
55
+ raise Exception(f"Secret named '{conn_id}' not found with path '{secret_name}'")
60
56
  else:
61
- raise Exception(f"Failed to get secret '{secret_key}': {e}")
57
+ raise Exception(f"Failed to get secret '{conn_id}': {e}")
@@ -0,0 +1,33 @@
1
+ import json
2
+
3
+ class JsonHandler:
4
+ """
5
+ Helper class for handling JSON serialization and deserialization.
6
+ """
7
+
8
+ def __init__(self):
9
+ pass
10
+
11
+ def dict_to_json(self, data_dict):
12
+ """
13
+ Serialize a dictionary to JSON string.
14
+
15
+ Args:
16
+ data_dict (dict): The dictionary to serialize.
17
+
18
+ Returns:
19
+ str: The JSON string representation of the dictionary.
20
+ """
21
+ return json.dumps(data_dict)
22
+
23
+ def json_to_dict(self, json_string):
24
+ """
25
+ Deserialize a JSON string to dictionary.
26
+
27
+ Args:
28
+ json_string (str): The JSON string to deserialize.
29
+
30
+ Returns:
31
+ dict: The dictionary representation of the JSON string.
32
+ """
33
+ return json.loads(json_string)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataflow-core
3
- Version: 2.0.9
3
+ Version: 2.0.11
4
4
  Summary: Dataflow core package
5
5
  Author: Dataflow
6
6
  Author-email:
@@ -1,26 +1,27 @@
1
1
  authenticator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  authenticator/dataflowairflowauthenticator.py,sha256=PcGlL2cq5EA9RdtClyrOupvNXxk6h54UPQcQ-g4VQtA,3117
3
3
  authenticator/dataflowhubauthenticator.py,sha256=m7ef84WfAjQ0IM8bg-1JhPs75rMNwKq3B0ZB5XF-07w,3403
4
- authenticator/dataflowsupersetauthenticator.py,sha256=M2pNpIdmWwzJVuMQ6trXLWQT4HpcYT84bC93uOSm0fQ,1772
4
+ authenticator/dataflowsupersetauthenticator.py,sha256=Qx8hUGSOfUTgffRCaVf88vmE9bFGNBvd9mEMHcpD488,2463
5
5
  authenticator/package/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  authenticator/package/configuration.py,sha256=7To6XwH1eESiYp39eqPcswXWwrdBUdPF6xN6WnazOF0,663
7
7
  authenticator/package/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  authenticator/package/models/database.py,sha256=y09pqnglsBBtDZlyhvqDAlpUSFovwAzBAi6jOYl_XNk,896
9
9
  authenticator/package/models/session.py,sha256=j6PhbrTMJxEkeDT4Vf5SqGtM_LI_vZy9O4vxn6LtIbc,495
10
- authenticator/package/models/user.py,sha256=IYogp_vt0yDBG5i936uNPjgTis77VYPzITn9XpQUIyw,788
10
+ authenticator/package/models/user.py,sha256=fxaQeDssWLXqh4XeKdbr3LPG_cbkjP2LjJOnsM6ZCOE,721
11
11
  dataflow/__init__.py,sha256=WTRg8HMpMWSgxYJ9ZGVldx4k07fAbta3mBmZ1hG9mWE,30
12
12
  dataflow/configuration.py,sha256=7To6XwH1eESiYp39eqPcswXWwrdBUdPF6xN6WnazOF0,663
13
- dataflow/dataflow.py,sha256=YDARgW2-wdmOQveClU4NhTf2eC15seLWrCQWDQ4gQP8,3488
14
- dataflow/environment.py,sha256=9_4wgpESP_a3DBT3yaqZHfCOZ4ZBOKCzt9W32gb0biE,19648
13
+ dataflow/dataflow.py,sha256=_5f4nObBiXf8GfgIAyTTR05UTNZ65S7jNQAJkB7FN2E,6392
14
+ dataflow/environment.py,sha256=-wnkgjpX5CaYH44JxDt8fgkNv2JZVu7qM-pW_xf7pUY,19603
15
15
  dataflow/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  dataflow/models/database.py,sha256=y09pqnglsBBtDZlyhvqDAlpUSFovwAzBAi6jOYl_XNk,896
17
17
  dataflow/models/environment.py,sha256=kJ4yRAX0ulh7YZsIVMWHkGLrptHbKOMVYtaWtsejVds,2157
18
18
  dataflow/scripts/clone_environment.sh,sha256=PJfMWPgiWSkvY-x98WmjeAkRREjC9824JzTazHe2iQQ,390
19
19
  dataflow/scripts/create_environment.sh,sha256=ams50MD1r53cHRYDfpAvmEAMsCaCFvlL0cmnRVXhFgY,496
20
20
  dataflow/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- dataflow/utils/aws_secrets_manager.py,sha256=FddITacFOYnj6bvlU2Y27gOrQdeUJMOKIX1zhsPAhHY,2486
22
- dataflow_core-2.0.9.dist-info/METADATA,sha256=Pnun0GuJwlKpojnebVwRIwziUWlamY4Pd9rm2_aGLPA,301
23
- dataflow_core-2.0.9.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
24
- dataflow_core-2.0.9.dist-info/entry_points.txt,sha256=ppj_EIbYrJJwCPg1kfdsZk5q1N-Ejfis1neYrnjhO8o,117
25
- dataflow_core-2.0.9.dist-info/top_level.txt,sha256=SZsUOpSCK9ntUy-3Tusxzf5A2e8ebwD8vouPb1dPt_8,23
26
- dataflow_core-2.0.9.dist-info/RECORD,,
21
+ dataflow/utils/aws_secrets_manager.py,sha256=A_fNs9VNah9dDdl9NhqizJamYU7xr2v_GXlw9InEDFk,2380
22
+ dataflow/utils/json_handler.py,sha256=5_7WdypegRBDe2HSqBXyrJAdd92wsha8qRcmQvCj1TA,782
23
+ dataflow_core-2.0.11.dist-info/METADATA,sha256=MeQcg0yFee-f1Vdo0MOC_5u14E_G1aOIw_4O_LiTpFo,302
24
+ dataflow_core-2.0.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ dataflow_core-2.0.11.dist-info/entry_points.txt,sha256=ppj_EIbYrJJwCPg1kfdsZk5q1N-Ejfis1neYrnjhO8o,117
26
+ dataflow_core-2.0.11.dist-info/top_level.txt,sha256=SZsUOpSCK9ntUy-3Tusxzf5A2e8ebwD8vouPb1dPt_8,23
27
+ dataflow_core-2.0.11.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5