cornflow 1.2.3a5__py3-none-any.whl → 1.3.0rc1__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.
- cornflow/app.py +24 -8
- cornflow/cli/service.py +93 -43
- cornflow/commands/auxiliar.py +4 -1
- cornflow/commands/dag.py +7 -7
- cornflow/commands/permissions.py +13 -7
- cornflow/commands/views.py +3 -0
- cornflow/config.py +26 -6
- cornflow/endpoints/__init__.py +27 -0
- cornflow/endpoints/case.py +37 -21
- cornflow/endpoints/dag.py +5 -5
- cornflow/endpoints/data_check.py +8 -7
- cornflow/endpoints/example_data.py +4 -2
- cornflow/endpoints/execution.py +215 -127
- cornflow/endpoints/health.py +30 -11
- cornflow/endpoints/instance.py +3 -3
- cornflow/endpoints/login.py +9 -2
- cornflow/endpoints/permission.py +1 -2
- cornflow/endpoints/schemas.py +3 -3
- cornflow/endpoints/signup.py +17 -11
- cornflow/migrations/versions/999b98e24225.py +34 -0
- cornflow/migrations/versions/cef1df240b27_.py +34 -0
- cornflow/models/__init__.py +2 -1
- cornflow/models/dag.py +8 -9
- cornflow/models/dag_permissions.py +3 -3
- cornflow/models/execution.py +2 -3
- cornflow/models/permissions.py +1 -0
- cornflow/models/user.py +1 -1
- cornflow/schemas/execution.py +14 -1
- cornflow/schemas/health.py +1 -1
- cornflow/shared/authentication/auth.py +14 -1
- cornflow/shared/authentication/decorators.py +32 -2
- cornflow/shared/const.py +58 -1
- cornflow/shared/exceptions.py +2 -1
- cornflow/tests/base_test_execution.py +798 -0
- cornflow/tests/const.py +1 -0
- cornflow/tests/integration/test_commands.py +2 -2
- cornflow/tests/integration/test_cornflowclient.py +2 -1
- cornflow/tests/unit/test_apiview.py +7 -1
- cornflow/tests/unit/test_cases.py +1 -1
- cornflow/tests/unit/test_cli.py +6 -3
- cornflow/tests/unit/test_commands.py +7 -6
- cornflow/tests/unit/test_dags.py +3 -3
- cornflow/tests/unit/test_example_data.py +1 -1
- cornflow/tests/unit/test_executions.py +115 -535
- cornflow/tests/unit/test_get_resources.py +103 -0
- cornflow/tests/unit/test_health.py +84 -3
- cornflow/tests/unit/test_main_alarms.py +1 -1
- cornflow/tests/unit/test_roles.py +2 -1
- cornflow/tests/unit/test_schema_from_models.py +1 -1
- cornflow/tests/unit/test_schemas.py +1 -1
- cornflow/tests/unit/test_sign_up.py +181 -6
- cornflow/tests/unit/tools.py +93 -10
- {cornflow-1.2.3a5.dist-info → cornflow-1.3.0rc1.dist-info}/METADATA +3 -3
- {cornflow-1.2.3a5.dist-info → cornflow-1.3.0rc1.dist-info}/RECORD +57 -53
- {cornflow-1.2.3a5.dist-info → cornflow-1.3.0rc1.dist-info}/WHEEL +0 -0
- {cornflow-1.2.3a5.dist-info → cornflow-1.3.0rc1.dist-info}/entry_points.txt +0 -0
- {cornflow-1.2.3a5.dist-info → cornflow-1.3.0rc1.dist-info}/top_level.txt +0 -0
cornflow/app.py
CHANGED
@@ -4,6 +4,8 @@ Main file with the creation of the app logic
|
|
4
4
|
|
5
5
|
# Full imports
|
6
6
|
import os
|
7
|
+
from logging.config import dictConfig
|
8
|
+
|
7
9
|
import click
|
8
10
|
|
9
11
|
# Partial imports
|
@@ -13,9 +15,8 @@ from flask_apispec.extension import FlaskApiSpec
|
|
13
15
|
from flask_cors import CORS
|
14
16
|
from flask_migrate import Migrate
|
15
17
|
from flask_restful import Api
|
16
|
-
from logging.config import dictConfig
|
17
|
-
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
18
18
|
from werkzeug.exceptions import NotFound
|
19
|
+
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
19
20
|
|
20
21
|
# Module imports
|
21
22
|
from cornflow.commands import (
|
@@ -36,7 +37,14 @@ from cornflow.endpoints.login import LoginEndpoint, LoginOpenAuthEndpoint
|
|
36
37
|
from cornflow.endpoints.signup import SignUpEndpoint
|
37
38
|
from cornflow.shared import db, bcrypt
|
38
39
|
from cornflow.shared.compress import init_compress
|
39
|
-
from cornflow.shared.const import
|
40
|
+
from cornflow.shared.const import (
|
41
|
+
AUTH_DB,
|
42
|
+
AUTH_LDAP,
|
43
|
+
AUTH_OID,
|
44
|
+
CONDITIONAL_ENDPOINTS,
|
45
|
+
SIGNUP_WITH_AUTH,
|
46
|
+
SIGNUP_WITH_NO_AUTH,
|
47
|
+
)
|
40
48
|
from cornflow.shared.exceptions import initialize_errorhandlers, ConfigurationError
|
41
49
|
from cornflow.shared.log_config import log_config
|
42
50
|
|
@@ -95,13 +103,21 @@ def create_app(env_name="development", dataconn=None):
|
|
95
103
|
|
96
104
|
if auth_type == AUTH_DB:
|
97
105
|
signup_activated = int(app.config["SIGNUP_ACTIVATED"])
|
98
|
-
if signup_activated
|
99
|
-
api.add_resource(
|
100
|
-
|
106
|
+
if signup_activated in [SIGNUP_WITH_AUTH, SIGNUP_WITH_NO_AUTH]:
|
107
|
+
api.add_resource(
|
108
|
+
SignUpEndpoint, CONDITIONAL_ENDPOINTS["signup"], endpoint="signup"
|
109
|
+
)
|
110
|
+
api.add_resource(
|
111
|
+
LoginEndpoint, CONDITIONAL_ENDPOINTS["login"], endpoint="login"
|
112
|
+
)
|
101
113
|
elif auth_type == AUTH_LDAP:
|
102
|
-
api.add_resource(
|
114
|
+
api.add_resource(
|
115
|
+
LoginEndpoint, CONDITIONAL_ENDPOINTS["login"], endpoint="login"
|
116
|
+
)
|
103
117
|
elif auth_type == AUTH_OID:
|
104
|
-
api.add_resource(
|
118
|
+
api.add_resource(
|
119
|
+
LoginOpenAuthEndpoint, CONDITIONAL_ENDPOINTS["login"], endpoint="login"
|
120
|
+
)
|
105
121
|
else:
|
106
122
|
raise ConfigurationError(
|
107
123
|
error="Invalid authentication type",
|
cornflow/cli/service.py
CHANGED
@@ -36,6 +36,12 @@ from cornflow.shared.const import (
|
|
36
36
|
ADMIN_ROLE,
|
37
37
|
SERVICE_ROLE,
|
38
38
|
PLANNER_ROLE,
|
39
|
+
DATABRICKS_BACKEND,
|
40
|
+
AIRFLOW_BACKEND,
|
41
|
+
SIGNUP_WITH_AUTH,
|
42
|
+
OID_PROVIDER_AWS,
|
43
|
+
OID_PROVIDER_AZURE,
|
44
|
+
OID_OTHER,
|
39
45
|
)
|
40
46
|
from cornflow.shared import db
|
41
47
|
from cryptography.fernet import Fernet
|
@@ -82,13 +88,14 @@ def init_cornflow_service():
|
|
82
88
|
config["cornflow_service_email"],
|
83
89
|
config["cornflow_service_pwd"],
|
84
90
|
)
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
91
|
+
if config["cornflow_backend"] == AIRFLOW_BACKEND:
|
92
|
+
_sync_with_airflow(
|
93
|
+
config["airflow_url"],
|
94
|
+
config["airflow_user"],
|
95
|
+
config["airflow_pwd"],
|
96
|
+
config["open_deployment"],
|
97
|
+
external_app=False,
|
98
|
+
)
|
92
99
|
_start_application(external_application, environment)
|
93
100
|
|
94
101
|
elif external_application == 1:
|
@@ -114,14 +121,14 @@ def init_cornflow_service():
|
|
114
121
|
config["cornflow_service_email"],
|
115
122
|
config["cornflow_service_pwd"],
|
116
123
|
)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
if config["cornflow_backend"] == AIRFLOW_BACKEND:
|
125
|
+
_sync_with_airflow(
|
126
|
+
config["airflow_url"],
|
127
|
+
config["airflow_user"],
|
128
|
+
config["airflow_pwd"],
|
129
|
+
config["open_deployment"],
|
130
|
+
external_app=True,
|
131
|
+
)
|
125
132
|
_start_application(external_application, environment, external_app_module)
|
126
133
|
|
127
134
|
else:
|
@@ -135,14 +142,36 @@ def _setup_environment_variables():
|
|
135
142
|
environment = os.getenv("FLASK_ENV", "development")
|
136
143
|
os.environ["FLASK_ENV"] = environment
|
137
144
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
os.
|
143
|
-
os.environ["
|
144
|
-
|
145
|
-
|
145
|
+
###################################
|
146
|
+
# Global defaults and back-compat #
|
147
|
+
###################################
|
148
|
+
# cornflow backend selection
|
149
|
+
cornflow_backend = os.getenv("CORNFLOW_BACKEND", str(AIRFLOW_BACKEND))
|
150
|
+
os.environ["CORNFLOW_BACKEND"] = cornflow_backend
|
151
|
+
cornflow_backend = int(cornflow_backend)
|
152
|
+
# Airflow global default conn
|
153
|
+
if cornflow_backend == AIRFLOW_BACKEND:
|
154
|
+
airflow_user = os.getenv("AIRFLOW_USER", "admin")
|
155
|
+
airflow_pwd = os.getenv("AIRFLOW_PWD", "admin")
|
156
|
+
airflow_url = os.getenv("AIRFLOW_URL", "http://webserver:8080")
|
157
|
+
os.environ["AIRFLOW_USER"] = airflow_user
|
158
|
+
os.environ["AIRFLOW_PWD"] = airflow_pwd
|
159
|
+
os.environ["AIRFLOW_URL"] = airflow_url
|
160
|
+
elif cornflow_backend == DATABRICKS_BACKEND:
|
161
|
+
databricks_url = os.getenv("DATABRICKS_HOST")
|
162
|
+
databricks_auth_secret = os.getenv("DATABRICKS_CLIENT_SECRET")
|
163
|
+
databricks_token_endpoint = os.getenv("DATABRICKS_TOKEN_ENDPOINT")
|
164
|
+
databricks_ep_clusters = os.getenv("DATABRICKS_EP_CLUSTERS")
|
165
|
+
databricks_client_id = os.getenv("DATABRICKS_CLIENT_ID")
|
166
|
+
databricks_health_path = os.getenv("DATABRICKS_HEALTH_PATH")
|
167
|
+
os.environ["DATABRICKS_HEALTH_PATH"] = databricks_health_path
|
168
|
+
os.environ["DATABRICKS_HOST"] = databricks_url
|
169
|
+
os.environ["DATABRICKS_CLIENT_SECRET"] = databricks_auth_secret
|
170
|
+
os.environ["DATABRICKS_TOKEN_ENDPOINT"] = databricks_token_endpoint
|
171
|
+
os.environ["DATABRICKS_EP_CLUSTERS"] = databricks_ep_clusters
|
172
|
+
os.environ["DATABRICKS_CLIENT_ID"] = databricks_client_id
|
173
|
+
else:
|
174
|
+
raise Exception("Selected backend not among valid options")
|
146
175
|
# Cornflow app config
|
147
176
|
os.environ.setdefault("cornflow_url", "http://cornflow:5000")
|
148
177
|
os.environ["FLASK_APP"] = "cornflow.app"
|
@@ -155,6 +184,10 @@ def _setup_environment_variables():
|
|
155
184
|
|
156
185
|
# Platform auth config and service users
|
157
186
|
auth = int(os.getenv("AUTH_TYPE", AUTH_DB))
|
187
|
+
if auth == AUTH_OID:
|
188
|
+
oid_provider = int(os.getenv("OID_PROVIDER", OID_PROVIDER_AWS))
|
189
|
+
os.environ["OID_PROVIDER"] = str(oid_provider)
|
190
|
+
|
158
191
|
cornflow_admin_user = os.getenv("CORNFLOW_ADMIN_USER", "cornflow_admin")
|
159
192
|
cornflow_admin_email = os.getenv(
|
160
193
|
"CORNFLOW_ADMIN_EMAIL", "cornflow_admin@cornflow.com"
|
@@ -171,7 +204,7 @@ def _setup_environment_variables():
|
|
171
204
|
os.environ["CORNFLOW_LOGGING"] = cornflow_logging
|
172
205
|
open_deployment = os.getenv("OPEN_DEPLOYMENT", 1)
|
173
206
|
os.environ["OPEN_DEPLOYMENT"] = str(open_deployment)
|
174
|
-
signup_activated = os.getenv("SIGNUP_ACTIVATED",
|
207
|
+
signup_activated = os.getenv("SIGNUP_ACTIVATED", SIGNUP_WITH_AUTH)
|
175
208
|
os.environ["SIGNUP_ACTIVATED"] = str(signup_activated)
|
176
209
|
user_access_all_objects = os.getenv("USER_ACCESS_ALL_OBJECTS", 0)
|
177
210
|
os.environ["USER_ACCESS_ALL_OBJECTS"] = str(user_access_all_objects)
|
@@ -191,25 +224,42 @@ def _setup_environment_variables():
|
|
191
224
|
|
192
225
|
external_application = int(os.getenv("EXTERNAL_APP", 0))
|
193
226
|
external_app_module = os.getenv("EXTERNAL_APP_MODULE")
|
227
|
+
base_dict = {
|
228
|
+
"environment": environment,
|
229
|
+
"auth": auth,
|
230
|
+
"cornflow_db_conn": cornflow_db_conn,
|
231
|
+
"cornflow_admin_user": cornflow_admin_user,
|
232
|
+
"cornflow_admin_email": cornflow_admin_email,
|
233
|
+
"cornflow_admin_pwd": cornflow_admin_pwd,
|
234
|
+
"cornflow_service_user": cornflow_service_user,
|
235
|
+
"cornflow_service_email": cornflow_service_email,
|
236
|
+
"cornflow_service_pwd": cornflow_service_pwd,
|
237
|
+
"cornflow_logging": cornflow_logging,
|
238
|
+
"open_deployment": open_deployment,
|
239
|
+
"external_application": external_application,
|
240
|
+
"external_app_module": external_app_module,
|
241
|
+
"cornflow_backend": cornflow_backend,
|
242
|
+
}
|
243
|
+
if cornflow_backend == AIRFLOW_BACKEND:
|
244
|
+
base_dict["airflow_user"] = airflow_user
|
245
|
+
base_dict["airflow_pwd"] = airflow_pwd
|
246
|
+
base_dict["airflow_url"] = airflow_url
|
247
|
+
|
248
|
+
elif cornflow_backend == DATABRICKS_BACKEND:
|
249
|
+
base_dict["databricks_url"] = databricks_url
|
250
|
+
base_dict["databricks_auth_secret"] = databricks_auth_secret
|
251
|
+
base_dict["databricks_token_endpoint"] = databricks_token_endpoint
|
252
|
+
base_dict["databricks_ep_clusters"] = databricks_ep_clusters
|
253
|
+
base_dict["databricks_client_id"] = databricks_client_id
|
254
|
+
base_dict["databricks_health_path"] = databricks_health_path
|
255
|
+
|
256
|
+
else:
|
257
|
+
raise Exception("Selected backend not among valid options")
|
258
|
+
|
259
|
+
if auth == AUTH_OID:
|
260
|
+
base_dict["oid_provider"] = oid_provider
|
194
261
|
|
195
|
-
return
|
196
|
-
"environment": environment,
|
197
|
-
"auth": auth,
|
198
|
-
"airflow_user": airflow_user,
|
199
|
-
"airflow_pwd": airflow_pwd,
|
200
|
-
"airflow_url": airflow_url,
|
201
|
-
"cornflow_db_conn": cornflow_db_conn,
|
202
|
-
"cornflow_admin_user": cornflow_admin_user,
|
203
|
-
"cornflow_admin_email": cornflow_admin_email,
|
204
|
-
"cornflow_admin_pwd": cornflow_admin_pwd,
|
205
|
-
"cornflow_service_user": cornflow_service_user,
|
206
|
-
"cornflow_service_email": cornflow_service_email,
|
207
|
-
"cornflow_service_pwd": cornflow_service_pwd,
|
208
|
-
"cornflow_logging": cornflow_logging,
|
209
|
-
"open_deployment": open_deployment,
|
210
|
-
"external_application": external_application,
|
211
|
-
"external_app_module": external_app_module,
|
212
|
-
}
|
262
|
+
return base_dict
|
213
263
|
|
214
264
|
|
215
265
|
def _configure_logging(cornflow_logging):
|
@@ -377,4 +427,4 @@ def _register_key():
|
|
377
427
|
os.system(add_key)
|
378
428
|
return True
|
379
429
|
else:
|
380
|
-
return False
|
430
|
+
return False
|
cornflow/commands/auxiliar.py
CHANGED
@@ -3,7 +3,7 @@ from importlib import import_module
|
|
3
3
|
|
4
4
|
from flask import current_app
|
5
5
|
|
6
|
-
from cornflow.endpoints import
|
6
|
+
from cornflow.endpoints import alarms_resources, get_resources
|
7
7
|
from cornflow.models import RoleModel
|
8
8
|
from cornflow.shared.const import (
|
9
9
|
EXTRA_PERMISSION_ASSIGNATION,
|
@@ -17,6 +17,9 @@ def get_all_external(external_app):
|
|
17
17
|
Get all resources, extra permissions, and custom roles actions.
|
18
18
|
external_app: If provided, it will get the resources and extra permissions for the external app.
|
19
19
|
"""
|
20
|
+
# We get base and conditional resources
|
21
|
+
resources = get_resources()
|
22
|
+
|
20
23
|
if external_app is None:
|
21
24
|
resources_to_register = resources
|
22
25
|
extra_permissions = EXTRA_PERMISSION_ASSIGNATION
|
cornflow/commands/dag.py
CHANGED
@@ -10,7 +10,7 @@ def register_deployed_dags_command(
|
|
10
10
|
|
11
11
|
# Internal modules imports
|
12
12
|
from cornflow_client.airflow.api import Airflow
|
13
|
-
from cornflow.models import
|
13
|
+
from cornflow.models import DeployedWorkflow
|
14
14
|
from cornflow.shared import db
|
15
15
|
from cornflow.shared.const import AIRFLOW_NOT_REACHABLE_MSG
|
16
16
|
|
@@ -28,7 +28,7 @@ def register_deployed_dags_command(
|
|
28
28
|
current_app.logger.info(f"{AIRFLOW_NOT_REACHABLE_MSG}")
|
29
29
|
return False
|
30
30
|
|
31
|
-
dags_registered = [dag.id for dag in
|
31
|
+
dags_registered = [dag.id for dag in DeployedWorkflow.get_all_objects()]
|
32
32
|
|
33
33
|
response = af_client.get_model_dags()
|
34
34
|
dag_list = response.json()["dags"]
|
@@ -40,7 +40,7 @@ def register_deployed_dags_command(
|
|
40
40
|
}
|
41
41
|
|
42
42
|
processed_dags = [
|
43
|
-
|
43
|
+
DeployedWorkflow(
|
44
44
|
{
|
45
45
|
"id": dag["dag_id"],
|
46
46
|
"description": dag["description"],
|
@@ -76,15 +76,15 @@ def register_deployed_dags_command(
|
|
76
76
|
|
77
77
|
|
78
78
|
def register_deployed_dags_command_test(dags: list = None, verbose: bool = False):
|
79
|
-
from cornflow.models import
|
79
|
+
from cornflow.models import DeployedWorkflow
|
80
80
|
from flask import current_app
|
81
81
|
from cornflow_client import get_pulp_jsonschema, get_empty_schema
|
82
82
|
|
83
83
|
if dags is None:
|
84
|
-
dags = ["solve_model_dag", "gc", "timer"]
|
84
|
+
dags = ["solve_model_dag", "gc", "timer", "979073949072767"]
|
85
85
|
|
86
86
|
deployed_dag = [
|
87
|
-
|
87
|
+
DeployedWorkflow(
|
88
88
|
{
|
89
89
|
"id": "solve_model_dag",
|
90
90
|
"description": None,
|
@@ -96,7 +96,7 @@ def register_deployed_dags_command_test(dags: list = None, verbose: bool = False
|
|
96
96
|
}
|
97
97
|
)
|
98
98
|
] + [
|
99
|
-
|
99
|
+
DeployedWorkflow(
|
100
100
|
{
|
101
101
|
"id": dag,
|
102
102
|
"description": None,
|
cornflow/commands/permissions.py
CHANGED
@@ -8,6 +8,7 @@ from cornflow.commands.auxiliar import (
|
|
8
8
|
from cornflow.models import ViewModel, PermissionViewRoleModel
|
9
9
|
from cornflow.shared import db
|
10
10
|
from cornflow.shared.const import ALL_DEFAULT_ROLES, GET_ACTION
|
11
|
+
import click
|
11
12
|
from cornflow.shared.const import (
|
12
13
|
BASE_PERMISSION_ASSIGNATION,
|
13
14
|
)
|
@@ -53,12 +54,14 @@ def register_base_permissions_command(external_app: str = None, verbose: bool =
|
|
53
54
|
save_and_delete_permissions(permissions_to_register, permissions_to_delete)
|
54
55
|
|
55
56
|
if len(permissions_to_register) > 0:
|
56
|
-
current_app.logger.info(
|
57
|
+
current_app.logger.info(
|
58
|
+
f"Permissions registered: {len(permissions_to_register)}"
|
59
|
+
)
|
57
60
|
else:
|
58
61
|
current_app.logger.info("No new permissions to register")
|
59
62
|
|
60
63
|
if len(permissions_to_delete) > 0:
|
61
|
-
current_app.logger.info(f"Permissions deleted: {permissions_to_delete}")
|
64
|
+
current_app.logger.info(f"Permissions deleted: {len(permissions_to_delete)}")
|
62
65
|
else:
|
63
66
|
current_app.logger.info("No permissions to delete")
|
64
67
|
|
@@ -233,7 +236,7 @@ def register_dag_permissions_command(
|
|
233
236
|
from flask import current_app
|
234
237
|
from sqlalchemy.exc import DBAPIError, IntegrityError
|
235
238
|
|
236
|
-
from cornflow.models import
|
239
|
+
from cornflow.models import DeployedWorkflow, PermissionsDAG, UserModel
|
237
240
|
from cornflow.shared import db
|
238
241
|
|
239
242
|
if open_deployment is None:
|
@@ -251,9 +254,10 @@ def register_dag_permissions_command(
|
|
251
254
|
current_app.logger.error(f"Unknown error on database commit: {e}")
|
252
255
|
|
253
256
|
all_users = UserModel.get_all_users().all()
|
254
|
-
all_dags =
|
257
|
+
all_dags = DeployedWorkflow.get_all_objects().all()
|
255
258
|
|
256
259
|
if open_deployment == 1:
|
260
|
+
|
257
261
|
permissions = [
|
258
262
|
PermissionsDAG({"dag_id": dag.id, "user_id": user.id})
|
259
263
|
for user in all_users
|
@@ -295,9 +299,11 @@ def register_dag_permissions_command(
|
|
295
299
|
)
|
296
300
|
|
297
301
|
if verbose:
|
302
|
+
click.echo(f"Workflow permissions registered")
|
298
303
|
if len(permissions) > 1:
|
299
|
-
current_app.logger.info(
|
304
|
+
current_app.logger.info(
|
305
|
+
f"Workflow permissions registered: {len(permissions)}"
|
306
|
+
)
|
300
307
|
else:
|
301
|
-
current_app.logger.info("No new
|
308
|
+
current_app.logger.info("No new Workflow permissions")
|
302
309
|
|
303
|
-
pass
|
cornflow/commands/views.py
CHANGED
@@ -7,6 +7,8 @@ from sqlalchemy.exc import DBAPIError, IntegrityError
|
|
7
7
|
|
8
8
|
from cornflow.endpoints import resources, alarms_resources
|
9
9
|
|
10
|
+
from cornflow.endpoints import alarms_resources, get_resources
|
11
|
+
|
10
12
|
# Imports from internal libraries
|
11
13
|
from cornflow.models import ViewModel
|
12
14
|
from cornflow.shared import db
|
@@ -182,6 +184,7 @@ def get_database_view():
|
|
182
184
|
|
183
185
|
|
184
186
|
def get_resources_to_register(external_app):
|
187
|
+
resources = get_resources()
|
185
188
|
if external_app is None:
|
186
189
|
resources_to_register = resources
|
187
190
|
if current_app.config["ALARMS_ENDPOINTS"]:
|
cornflow/config.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import os
|
2
|
-
from .shared.const import AUTH_DB, PLANNER_ROLE, AUTH_OID
|
2
|
+
from .shared.const import AUTH_DB, PLANNER_ROLE, AUTH_OID, SIGNUP_WITH_AUTH, SIGNUP_WITH_NO_AUTH
|
3
3
|
from apispec import APISpec
|
4
4
|
from apispec.ext.marshmallow import MarshmallowPlugin
|
5
|
+
from cornflow.shared.const import AIRFLOW_BACKEND, DATABRICKS_BACKEND
|
5
6
|
|
6
7
|
|
7
8
|
class DefaultConfig(object):
|
@@ -15,9 +16,7 @@ class DefaultConfig(object):
|
|
15
16
|
SECRET_TOKEN_KEY = os.getenv("SECRET_KEY")
|
16
17
|
SECRET_BI_KEY = os.getenv("SECRET_BI_KEY")
|
17
18
|
SQLALCHEMY_DATABASE_URI = os.getenv("DATABASE_URL", "sqlite:///cornflow.db")
|
18
|
-
|
19
|
-
AIRFLOW_USER = os.getenv("AIRFLOW_USER")
|
20
|
-
AIRFLOW_PWD = os.getenv("AIRFLOW_PWD")
|
19
|
+
|
21
20
|
AUTH_TYPE = int(os.getenv("AUTH_TYPE", AUTH_DB))
|
22
21
|
DEFAULT_ROLE = int(os.getenv("DEFAULT_ROLE", PLANNER_ROLE))
|
23
22
|
CORS_ORIGINS = os.getenv("CORS_ORIGINS", "*")
|
@@ -25,9 +24,24 @@ class DefaultConfig(object):
|
|
25
24
|
DEBUG = True
|
26
25
|
TESTING = True
|
27
26
|
LOG_LEVEL = int(os.getenv("LOG_LEVEL", 20))
|
28
|
-
SIGNUP_ACTIVATED = int(os.getenv("SIGNUP_ACTIVATED",
|
27
|
+
SIGNUP_ACTIVATED = int(os.getenv("SIGNUP_ACTIVATED", SIGNUP_WITH_AUTH))
|
29
28
|
CORNFLOW_SERVICE_USER = os.getenv("CORNFLOW_SERVICE_USER", "service_user")
|
30
29
|
|
30
|
+
# To change the tasks backend used by cornflow to solve the optimization models
|
31
|
+
CORNFLOW_BACKEND = int(os.getenv("CORNFLOW_BACKEND", AIRFLOW_BACKEND))
|
32
|
+
|
33
|
+
# AIRFLOW config
|
34
|
+
AIRFLOW_URL = os.getenv("AIRFLOW_URL")
|
35
|
+
AIRFLOW_USER = os.getenv("AIRFLOW_USER")
|
36
|
+
AIRFLOW_PWD = os.getenv("AIRFLOW_PWD")
|
37
|
+
|
38
|
+
# DATABRICKS config
|
39
|
+
DATABRICKS_URL = os.getenv("DATABRICKS_HOST")
|
40
|
+
DATABRICKS_AUTH_SECRET = os.getenv("DATABRICKS_CLIENT_SECRET")
|
41
|
+
DATABRICKS_TOKEN_ENDPOINT = os.getenv("DATABRICKS_TOKEN_ENDPOINT")
|
42
|
+
DATABRICKS_EP_CLUSTERS = os.getenv("DATABRICKS_EP_CLUSTERS")
|
43
|
+
DATABRICKS_CLIENT_ID = os.getenv("DATABRICKS_CLIENT_ID")
|
44
|
+
DATABRICKS_HEALTH_PATH = os.getenv("DATABRICKS_HEALTH_PATH", "default path")
|
31
45
|
# If service user is allowed to log with username and password
|
32
46
|
SERVICE_USER_ALLOW_PASSWORD_LOGIN = int(
|
33
47
|
os.getenv("SERVICE_USER_ALLOW_PASSWORD_LOGIN", 1)
|
@@ -119,12 +133,17 @@ class Testing(DefaultConfig):
|
|
119
133
|
AIRFLOW_PWD = os.getenv("AIRFLOW_PWD", "admin")
|
120
134
|
OPEN_DEPLOYMENT = 1
|
121
135
|
LOG_LEVEL = int(os.getenv("LOG_LEVEL", 10))
|
136
|
+
SIGNUP_ACTIVATED = SIGNUP_WITH_NO_AUTH
|
137
|
+
|
138
|
+
class TestingDatabricks(Testing):
|
139
|
+
CORNFLOW_BACKEND = DATABRICKS_BACKEND
|
122
140
|
|
123
141
|
|
124
142
|
class TestingOpenAuth(Testing):
|
125
143
|
"""
|
126
144
|
Configuration class for testing some edge cases with Open Auth login
|
127
145
|
"""
|
146
|
+
|
128
147
|
AUTH_TYPE = AUTH_OID
|
129
148
|
OID_PROVIDER = "https://test-provider.example.com"
|
130
149
|
OID_EXPECTED_AUDIENCE = "test-audience-id"
|
@@ -157,5 +176,6 @@ app_config = {
|
|
157
176
|
"testing": Testing,
|
158
177
|
"production": Production,
|
159
178
|
"testing-oauth": TestingOpenAuth,
|
160
|
-
"testing-root": TestingApplicationRoot
|
179
|
+
"testing-root": TestingApplicationRoot,
|
180
|
+
"testing-databricks": TestingDatabricks,
|
161
181
|
}
|
cornflow/endpoints/__init__.py
CHANGED
@@ -4,6 +4,8 @@ All references to endpoints should be imported from here
|
|
4
4
|
The login resource gets created on app startup as it depends on configuration
|
5
5
|
"""
|
6
6
|
|
7
|
+
from flask import current_app
|
8
|
+
from cornflow.shared.const import CONDITIONAL_ENDPOINTS
|
7
9
|
from .action import ActionListEndpoint
|
8
10
|
from .alarms import AlarmsEndpoint, AlarmDetailEndpoint
|
9
11
|
from .apiview import ApiViewListEndpoint
|
@@ -237,3 +239,28 @@ alarms_resources = [
|
|
237
239
|
endpoint="main-alarms",
|
238
240
|
),
|
239
241
|
]
|
242
|
+
|
243
|
+
|
244
|
+
def get_resources():
|
245
|
+
"""
|
246
|
+
Get the resources based on the configuration
|
247
|
+
|
248
|
+
:return: The resources based on the configuration
|
249
|
+
:rtype: list
|
250
|
+
"""
|
251
|
+
base_resources = resources.copy()
|
252
|
+
registered_resources = current_app.view_functions.keys()
|
253
|
+
for resource in registered_resources:
|
254
|
+
if resource in CONDITIONAL_ENDPOINTS.keys():
|
255
|
+
# Check if the resource already exists
|
256
|
+
if resource not in [
|
257
|
+
present_resource["endpoint"] for present_resource in base_resources
|
258
|
+
]:
|
259
|
+
base_resources.append(
|
260
|
+
dict(
|
261
|
+
resource=current_app.view_functions[resource].view_class,
|
262
|
+
urls=CONDITIONAL_ENDPOINTS[resource],
|
263
|
+
endpoint=resource,
|
264
|
+
)
|
265
|
+
)
|
266
|
+
return base_resources
|