dataflow-core 2.0.9__tar.gz → 2.0.11__tar.gz

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.

Files changed (33) hide show
  1. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/PKG-INFO +1 -1
  2. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/dataflowsupersetauthenticator.py +33 -15
  3. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/package/models/user.py +1 -2
  4. dataflow_core-2.0.11/dataflow/dataflow.py +162 -0
  5. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/environment.py +0 -1
  6. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/utils/aws_secrets_manager.py +16 -20
  7. dataflow_core-2.0.11/dataflow/utils/json_handler.py +33 -0
  8. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow_core.egg-info/PKG-INFO +1 -1
  9. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow_core.egg-info/SOURCES.txt +1 -0
  10. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/setup.py +1 -1
  11. dataflow_core-2.0.9/dataflow/dataflow.py +0 -89
  12. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/README.md +0 -0
  13. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/__init__.py +0 -0
  14. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/dataflowairflowauthenticator.py +0 -0
  15. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/dataflowhubauthenticator.py +0 -0
  16. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/package/__init__.py +0 -0
  17. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/package/configuration.py +0 -0
  18. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/package/models/__init__.py +0 -0
  19. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/package/models/database.py +0 -0
  20. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/authenticator/package/models/session.py +0 -0
  21. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/__init__.py +0 -0
  22. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/configuration.py +0 -0
  23. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/models/__init__.py +0 -0
  24. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/models/database.py +0 -0
  25. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/models/environment.py +0 -0
  26. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/scripts/clone_environment.sh +0 -0
  27. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/scripts/create_environment.sh +0 -0
  28. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow/utils/__init__.py +0 -0
  29. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow_core.egg-info/dependency_links.txt +0 -0
  30. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow_core.egg-info/entry_points.txt +0 -0
  31. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow_core.egg-info/requires.txt +0 -0
  32. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/dataflow_core.egg-info/top_level.txt +0 -0
  33. {dataflow_core-2.0.9 → dataflow_core-2.0.11}/setup.cfg +0 -0
@@ -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,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)
@@ -0,0 +1,162 @@
1
+ import os, requests
2
+ from .models.database import DatabaseManager
3
+ from .utils.aws_secrets_manager import SecretsManagerClient
4
+ import json
5
+ from authenticator.package.configuration import ConfigurationManager
6
+
7
+
8
+ class Dataflow:
9
+ def __init__(self):
10
+ self.secrets_manager = SecretsManagerClient()
11
+
12
+ def auth(self, session_id: str):
13
+ """Retrieve user information from the auth API."""
14
+ try:
15
+ dataflow_config = ConfigurationManager('/dataflow/app/auth_config/dataflow_auth.cfg')
16
+ auth_api = dataflow_config.get_config_value('auth', 'ui_auth_api')
17
+ response = requests.get(
18
+ auth_api,
19
+ cookies={"dataflow_session": session_id, "jupyterhub-hub-login": ""}
20
+ )
21
+
22
+ if response.status_code != 200:
23
+ return response.json()
24
+
25
+ user_data = response.json()
26
+ user_dict = {
27
+ "user_name": user_data["user_name"],
28
+ "first_name": user_data["first_name"],
29
+ "last_name": user_data["last_name"] if user_data.get("last_name") else "",
30
+ "email": user_data["email"],
31
+ "role": user_data["role"]
32
+ }
33
+ return user_dict
34
+
35
+ except Exception as e:
36
+ return e
37
+
38
+ def variable(self, variable_name: str):
39
+ """
40
+ Get variable value from UI API.
41
+ """
42
+ try:
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
85
+ except Exception as e:
86
+ print(f"[Dataflow.variable] Exception occurred: {e}")
87
+ return None
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
+
124
+ def connection(self, conn_id: str):
125
+ """Get connection details from secrets manager."""
126
+ try:
127
+ host_name = os.environ["HOSTNAME"]
128
+ user_name=host_name.replace("jupyter-","")
129
+ runtime = os.environ.get("RUNTIME")
130
+ slug = os.environ.get("SLUG")
131
+
132
+ vault_path = "connections"
133
+ secret = self.secrets_manager.get_secret_by_key(vault_path, user_name, conn_id, runtime, slug)
134
+
135
+ conn_type = secret['conn_type'].lower()
136
+ username = secret['login']
137
+ password = secret.get('password', '')
138
+ host = secret['host']
139
+ port = secret['port']
140
+ database = secret.get('schemas', '')
141
+
142
+ user_info = f"{username}:{password}@" if password else f"{username}@"
143
+ db_info = f"/{database}" if database else ""
144
+
145
+ connection_string = f"{conn_type}://{user_info}{host}:{port}{db_info}"
146
+
147
+ extra = secret.get('extra', '')
148
+ if extra:
149
+ try:
150
+ extra_params = json.loads(extra)
151
+ if extra_params:
152
+ extra_query = "&".join(f"{key}={value}" for key, value in extra_params.items())
153
+ connection_string += f"?{extra_query}"
154
+ except json.JSONDecodeError:
155
+ # If 'extra' is not valid JSON, skip adding extra parameters
156
+ pass
157
+
158
+ connection_instance = DatabaseManager(connection_string)
159
+ return next(connection_instance.get_session())
160
+
161
+ except Exception as e:
162
+ return None
@@ -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:
@@ -21,6 +21,7 @@ dataflow/scripts/clone_environment.sh
21
21
  dataflow/scripts/create_environment.sh
22
22
  dataflow/utils/__init__.py
23
23
  dataflow/utils/aws_secrets_manager.py
24
+ dataflow/utils/json_handler.py
24
25
  dataflow_core.egg-info/PKG-INFO
25
26
  dataflow_core.egg-info/SOURCES.txt
26
27
  dataflow_core.egg-info/dependency_links.txt
@@ -14,7 +14,7 @@ class PostInstall(install):
14
14
 
15
15
  setup(
16
16
  name="dataflow-core",
17
- version="2.0.9",
17
+ version="2.0.11",
18
18
  packages=find_packages(include=["dataflow", "dataflow.*", "authenticator", "authenticator.*"]),
19
19
  include_package_data=True,
20
20
  package_data={
@@ -1,89 +0,0 @@
1
- import os, requests, shutil, subprocess, datetime
2
- from .models.database import DatabaseManager
3
- from .models.environment import JobLogs
4
- from sqlalchemy.inspection import inspect
5
- from .utils.aws_secrets_manager import SecretsManagerClient
6
- import json, asyncio, pkg_resources
7
- from authenticator.package.configuration import ConfigurationManager
8
-
9
-
10
- class Dataflow:
11
- def __init__(self):
12
- self.secrets_manager = SecretsManagerClient()
13
-
14
- def auth(self, session_id: str):
15
- """Retrieve user information from the auth API."""
16
- try:
17
- dataflow_config = ConfigurationManager('/dataflow/app/auth_config/dataflow_auth.cfg')
18
- auth_api = dataflow_config.get_config_value('auth', 'ui_auth_api')
19
- response = requests.get(
20
- auth_api,
21
- cookies={"dataflow_session": session_id, "jupyterhub-hub-login": ""}
22
- )
23
-
24
- if response.status_code != 200:
25
- return response.json()
26
-
27
- user_data = response.json()
28
- user_dict = {
29
- "user_name": user_data["user_name"],
30
- "first_name": user_data["first_name"],
31
- "last_name": user_data["last_name"] if user_data.get("last_name") else "",
32
- "email": user_data["email"],
33
- "role": user_data["role"]
34
- }
35
- return user_dict
36
-
37
- except Exception as e:
38
- return e
39
-
40
- def variable(self, variable_name: str):
41
- """Get variable value from secrets manager."""
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
-
50
- except Exception as e:
51
- return None
52
-
53
- def connection(self, conn_id: str):
54
- """Get connection details from secrets manager."""
55
- try:
56
- host_name = os.environ["HOSTNAME"]
57
- user_name=host_name.replace("jupyter-","")
58
-
59
- vault_path = "connections"
60
- secret = self.secrets_manager.get_secret_by_key(vault_path, user_name, conn_id)
61
-
62
- conn_type = secret['conn_type'].lower()
63
- username = secret['login']
64
- password = secret.get('password', '')
65
- host = secret['host']
66
- port = secret['port']
67
- database = secret.get('schemas', '')
68
-
69
- user_info = f"{username}:{password}@" if password else f"{username}@"
70
- db_info = f"/{database}" if database else ""
71
-
72
- connection_string = f"{conn_type}://{user_info}{host}:{port}{db_info}"
73
-
74
- extra = secret.get('extra', '')
75
- if extra:
76
- try:
77
- extra_params = json.loads(extra)
78
- if extra_params:
79
- extra_query = "&".join(f"{key}={value}" for key, value in extra_params.items())
80
- connection_string += f"?{extra_query}"
81
- except json.JSONDecodeError:
82
- # If 'extra' is not valid JSON, skip adding extra parameters
83
- pass
84
-
85
- connection_instance = DatabaseManager(connection_string)
86
- return next(connection_instance.get_session())
87
-
88
- except Exception as e:
89
- return None
File without changes
File without changes