bfabric-web-apps 0.2.2__tar.gz → 0.2.4__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.
Files changed (21) hide show
  1. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/PKG-INFO +1 -1
  2. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/__init__.py +2 -1
  3. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/layouts/layouts.py +74 -53
  4. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/objects/BfabricInterface.py +9 -3
  5. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/callbacks.py +27 -10
  6. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/charging.py +4 -2
  7. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/components.py +4 -3
  8. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/config.py +4 -0
  9. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/run_main_pipeline.py +120 -87
  10. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/pyproject.toml +1 -1
  11. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/LICENSE +0 -0
  12. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/objects/Logger.py +0 -0
  13. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/app_init.py +0 -0
  14. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/create_app_in_bfabric.py +0 -0
  15. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/dataset_utils.py +0 -0
  16. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/get_logger.py +0 -0
  17. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/get_power_user_wrapper.py +0 -0
  18. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/redis_connection.py +0 -0
  19. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/redis_queue.py +0 -0
  20. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/redis_worker_init.py +0 -0
  21. {bfabric_web_apps-0.2.2 → bfabric_web_apps-0.2.4}/bfabric_web_apps/utils/resource_utilities.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bfabric-web-apps
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: A package containing handy boilerplate utilities for developing bfabric web-applications
5
5
  Author: Marc Zuber, Griffin White, GWC GmbH
6
6
  Requires-Python: >=3.10,<4.0
@@ -29,8 +29,9 @@ from .utils.callbacks import (
29
29
  )
30
30
 
31
31
  from .utils.config import settings as config
32
+ from .utils.components import no_auth, expired, no_entity, dev, auth, charge_switch
32
33
 
33
- from. utils.run_main_pipeline import run_main_job, read_file_as_bytes
34
+ from .utils.run_main_pipeline import run_main_job, read_file_as_bytes
34
35
 
35
36
  from .utils.resource_utilities import (
36
37
  create_workunit,
@@ -2,7 +2,7 @@ from dash import html, dcc
2
2
  import dash_bootstrap_components as dbc
3
3
  import bfabric_web_apps
4
4
 
5
- def get_static_layout(base_title=None, main_content=None, documentation_content=None, layout_config={}):
5
+ def get_static_layout(base_title=None, main_content=None, documentation_content=None, layout_config={}, include_header=True):
6
6
  """
7
7
  Returns a layout with static tabs for Main, Documentation, and Report a Bug.
8
8
  The main content is customizable, while the other tabs are generic.
@@ -29,6 +29,78 @@ def get_static_layout(base_title=None, main_content=None, documentation_content=
29
29
  if layout_config.get("bug", False):
30
30
  tab_list.append(dbc.Tab(dcc.Loading(get_report_bug_tab()), label="Report a Bug", tab_id="report-bug"))
31
31
 
32
+ if not include_header:
33
+ header_row = dbc.Row()
34
+
35
+ else:
36
+ header_row = dbc.Row(
37
+ dbc.Col(
38
+ html.Div(
39
+ children=[
40
+ # Page Title (Aligned Left)
41
+ html.P(
42
+ id="page-title",
43
+ children=[str(" ")],
44
+ style={"font-size": "40px", "margin-left": "20px", "margin-top": "10px"}
45
+ ),
46
+ html.Div(
47
+ children=[
48
+ html.A(
49
+ dbc.Button(
50
+ "B-Fabric Entity",
51
+ id="bfabric-entity-button",
52
+ color="secondary", # Greyish color
53
+ style={
54
+ "font-size": "18px",
55
+ "padding": "10px 20px",
56
+ "border-radius": "8px",
57
+ "margin-right": "10px"
58
+ }
59
+ ),
60
+ id="bfabric-entity-link",
61
+ href="#", # will be set in the Callback
62
+ target="_blank"
63
+ ),
64
+ html.A(
65
+ dbc.Button(
66
+ "View Logs",
67
+ id="dynamic-link-button",
68
+ color="secondary", # Greyish color
69
+ style={
70
+ "font-size": "18px",
71
+ "padding": "10px 20px",
72
+ "border-radius": "8px"
73
+ }
74
+ ),
75
+ id="dynamic-link",
76
+ href="#", # Will be dynamically set in the callback
77
+ target="_blank"
78
+ )
79
+ ],
80
+ style={
81
+ "position": "absolute",
82
+ "right": "20px",
83
+ "top": "10px", # Aligns with title
84
+ "display": "flex",
85
+ "align-items": "center"
86
+ }
87
+ ),
88
+ ],
89
+ style={
90
+ "position": "relative", # Ensures absolute positioning works
91
+ "margin-top": "0px",
92
+ "min-height": "80px",
93
+ "height": "6vh",
94
+ "border-bottom": "2px solid #d4d7d9",
95
+ "display": "flex",
96
+ "align-items": "center",
97
+ "justify-content": "space-between", # Title left, button right
98
+ "padding-right": "20px" # Space between button & right edge
99
+ }
100
+ ),
101
+ ),
102
+ )
103
+
32
104
  return html.Div(
33
105
  children=[
34
106
  dcc.Location(id='url', refresh=False),
@@ -68,59 +140,8 @@ def get_static_layout(base_title=None, main_content=None, documentation_content=
68
140
  ),
69
141
  ),
70
142
  ),
71
-
72
143
  # Page Title Section + View Logs Button (Aligned Right)
73
- dbc.Row(
74
- dbc.Col(
75
- html.Div(
76
- children=[
77
- # Page Title (Aligned Left)
78
- html.P(
79
- id="page-title",
80
- children=[str(" ")],
81
- style={"font-size": "40px", "margin-left": "20px", "margin-top": "10px"}
82
- ),
83
-
84
- # View Logs Button (Aligned Right)
85
- html.Div(
86
- children=[
87
- html.A(
88
- dbc.Button(
89
- "View Logs",
90
- id="dynamic-link-button",
91
- color="secondary", # Greyish color
92
- style={
93
- "font-size": "18px",
94
- "padding": "10px 20px",
95
- "border-radius": "8px"
96
- }
97
- ),
98
- id="dynamic-link",
99
- href="#", # Will be dynamically set in the callback
100
- target="_blank"
101
- )
102
- ],
103
- style={
104
- "position": "absolute",
105
- "right": "20px",
106
- "top": "10px", # Aligns with title
107
- }
108
- ),
109
- ],
110
- style={
111
- "position": "relative", # Ensures absolute positioning works
112
- "margin-top": "0px",
113
- "min-height": "80px",
114
- "height": "6vh",
115
- "border-bottom": "2px solid #d4d7d9",
116
- "display": "flex",
117
- "align-items": "center",
118
- "justify-content": "space-between", # Title left, button right
119
- "padding-right": "20px" # Space between button & right edge
120
- }
121
- ),
122
- ),
123
- ),
144
+ header_row,
124
145
 
125
146
  # Bug Report Alerts (Restored)
126
147
  dbc.Row(
@@ -9,8 +9,10 @@ from bfabric_web_apps.utils.get_logger import get_logger
9
9
  import os
10
10
  import bfabric_web_apps
11
11
 
12
- VALIDATION_URL = "https://fgcz-bfabric.uzh.ch/bfabric/rest/token/validate?token="
13
- HOST = "fgcz-bfabric.uzh.ch"
12
+ from bfabric_web_apps.utils.config import settings
13
+
14
+ HOST = settings.PRODUCTION_BFABRIC_DOMAIN
15
+ VALIDATION_URL = f"https://{HOST}/bfabric/rest/token/validate?token="
14
16
 
15
17
  class BfabricInterface( Bfabric ):
16
18
  _instance = None # Singleton instance
@@ -89,7 +91,11 @@ class BfabricInterface( Bfabric ):
89
91
  return "EXPIRED"
90
92
 
91
93
  envioronment_name = str(userinfo['environment']).strip().lower()
92
- environment_dict = {"production":"https://fgcz-bfabric.uzh.ch/bfabric","prod":"https://fgcz-bfabric.uzh.ch/bfabric","test":"https://fgcz-bfabric-test.uzh.ch/bfabric"}
94
+ environment_dict = {
95
+ "production":f"https://{settings.PRODUCTION_BFABRIC_DOMAIN}/bfabric",
96
+ "prod":f"https://{settings.PRODUCTION_BFABRIC_DOMAIN}/bfabric",
97
+ "test":f"https://{settings.TEST_BFABRIC_DOMAIN}/bfabric"
98
+ }
93
99
 
94
100
  token_data = dict(
95
101
  environment = userinfo['environment'],
@@ -7,7 +7,7 @@ from bfabric_web_apps.utils.get_logger import get_logger
7
7
  from rq import Queue
8
8
  from .redis_connection import redis_conn
9
9
  from rq.registry import StartedJobRegistry, FailedJobRegistry, FinishedJobRegistry
10
-
10
+ from bfabric_web_apps.utils.config import settings
11
11
 
12
12
  def process_url_and_token(url_params):
13
13
  """
@@ -25,22 +25,27 @@ def process_url_and_token(url_params):
25
25
  - page_title (str): Title for the page header.
26
26
  - session_details (list): HTML-formatted session details.
27
27
  - job_link (str): Dynamically generated link to the job page.
28
+ - entity_link (str): Link to the B-Fabric entity page.
28
29
  """
29
30
  base_title = " "
30
31
 
31
32
  if not url_params:
32
- return None, None, None, None, base_title, None, None
33
+ return None, None, None, None, base_title, None, None, None
33
34
 
34
35
  token = "".join(url_params.split('token=')[1:])
36
+
37
+ # TODO: Implement environment spec once implemented in bfabric production
38
+ # environment = url_params.split('environment=')[1].split('&')[0].strip().lower()
39
+
35
40
  tdata_raw = bfabric_interface.token_to_data(token)
36
41
 
37
42
  if tdata_raw:
38
43
  if tdata_raw == "EXPIRED":
39
- return None, None, None, None, base_title, None, None
44
+ return None, None, None, None, base_title, None, None, None
40
45
  else:
41
46
  tdata = json.loads(tdata_raw)
42
47
  else:
43
- return None, None, None, None, base_title, None, None
48
+ return None, None, None, None, base_title, None, None, None
44
49
 
45
50
  if tdata:
46
51
  entity_data_json = bfabric_interface.entity_data(tdata)
@@ -55,14 +60,26 @@ def process_url_and_token(url_params):
55
60
  environment = tdata.get("environment", "").strip().lower() # 'test' or 'prod'
56
61
  tdata["environment"] = environment.lower()
57
62
 
63
+
64
+ # Build B-Fabric entity link
65
+ entity_link = None
66
+ base_url = tdata.get("webbase_data") # e.g. https://fgcz-bfabric-test.uzh.ch/bfabric
67
+ eclass = (tdata.get("entityClass_data").lower()) # Get the entity class name (e.g., "Plate")
68
+ eid = tdata.get("entity_id_data") # Get the entity ID (e.g., 5044)
69
+
70
+ if base_url and eclass and eid:
71
+ entity_link = f"{base_url}/{str(eclass)}/show.html?id={eid}&tab=details"
72
+
73
+
74
+ # Build job link if job ID is available
58
75
  job_id = tdata.get("jobId", None) # Extract job ID
59
76
 
60
77
  job_link = None
61
78
  if job_id:
62
79
  if "test" in environment:
63
- job_link = f"https://fgcz-bfabric-test.uzh.ch/bfabric/job/show.html?id={job_id}&tab=details"
80
+ job_link = f"https://{settings.TEST_BFABRIC_DOMAIN}/bfabric/job/show.html?id={job_id}&tab=details"
64
81
  else:
65
- job_link = f"https://fgcz-bfabric.uzh.ch/bfabric/job/show.html?id={job_id}&tab=details"
82
+ job_link = f"https://{settings.PRODUCTION_BFABRIC_DOMAIN}/bfabric/job/show.html?id={job_id}&tab=details"
66
83
 
67
84
  session_details = [
68
85
  html.P([
@@ -88,9 +105,9 @@ def process_url_and_token(url_params):
88
105
  ])
89
106
  ]
90
107
 
91
- return token, tdata, entity_data, app_data, page_title, session_details, job_link
108
+ return token, tdata, entity_data, app_data, page_title, session_details, job_link, entity_link
92
109
  else:
93
- return None, None, None, None, base_title, None, None
110
+ return None, None, None, None, base_title, None, None, None
94
111
 
95
112
 
96
113
  def submit_bug_report(n_clicks, bug_description, token, entity_data):
@@ -184,8 +201,8 @@ def populate_workunit_details(token_data):
184
201
  """
185
202
 
186
203
  environment_urls = {
187
- "test": "https://fgcz-bfabric-test.uzh.ch/bfabric/workunit/show.html?id=",
188
- "production": "https://fgcz-bfabric.uzh.ch/bfabric/workunit/show.html?id="
204
+ "test": f"https://{settings.TEST_BFABRIC_DOMAIN}/bfabric/workunit/show.html?id=",
205
+ "production": f"https://{settings.PRODUCTION_BFABRIC_DOMAIN}/bfabric/workunit/show.html?id="
189
206
  }
190
207
 
191
208
  if token_data:
@@ -2,7 +2,7 @@
2
2
  from bfabric_web_apps.utils.get_logger import get_logger
3
3
  from bfabric_web_apps.utils.get_power_user_wrapper import get_power_user_wrapper
4
4
 
5
- def create_charge(token_data, container_id, service_id):
5
+ def create_charge(token_data, container_id, service_id, n_charges=1):
6
6
  """
7
7
  Create a charge in B-Fabric.
8
8
 
@@ -10,6 +10,7 @@ def create_charge(token_data, container_id, service_id):
10
10
  token_data (dict): Authentication token data.
11
11
  container_id (int): Container ID (Order ID).
12
12
  service_id (int): Service ID.
13
+ n_charges (int): Number of total charges. Default is 1.
13
14
 
14
15
  Returns:
15
16
  list[dict]: List of charge data.
@@ -25,7 +26,8 @@ def create_charge(token_data, container_id, service_id):
25
26
  charge_data = {
26
27
  "serviceid": service_id,
27
28
  "containerid": container_id,
28
- "chargerid": usr_id
29
+ "chargerid": usr_id,
30
+ "total": str(n_charges),
29
31
  }
30
32
 
31
33
  # Create and log the charge
@@ -1,16 +1,17 @@
1
1
  from dash import html
2
2
  import dash_daq as daq
3
+ from bfabric_web_apps.utils.config import settings
3
4
 
4
5
  DEVELOPER_EMAIL = "gwhite@fgcz.ethz.ch"
5
6
 
6
7
  expired = [
7
8
  html.P("Your session has expired. Please log into bfabric to continue:"),
8
- html.A('Login to Bfabric', href='https://fgcz-bfabric.uzh.ch/bfabric/')
9
+ html.A('Login to Bfabric', href=f'https://{settings.PRODUCTION_BFABRIC_DOMAIN}/bfabric/')
9
10
  ]
10
11
 
11
12
  no_entity = [
12
13
  html.P("There was an error fetching the data for your entity. Please try accessing the applicaiton again from bfabric:"),
13
- html.A('Login to Bfabric', href='https://fgcz-bfabric.uzh.ch/bfabric/')
14
+ html.A('Login to Bfabric', href=f'https://{settings.PRODUCTION_BFABRIC_DOMAIN}/bfabric/')
14
15
  ]
15
16
 
16
17
  dev = [html.P("This page is under development. Please check back later."),html.Br(),html.A("email the developer for more details",href="mailto:"+DEVELOPER_EMAIL)]
@@ -19,7 +20,7 @@ auth = [html.Div(id="auth-div")]
19
20
 
20
21
  no_auth = [
21
22
  html.P("You are not currently logged into an active session. Please log into bfabric to continue:"),
22
- html.A('Login to Bfabric', href='https://fgcz-bfabric.uzh.ch/bfabric/')
23
+ html.A('Login to Bfabric', href=f'https://{settings.PRODUCTION_BFABRIC_DOMAIN}/bfabric/')
23
24
  ]
24
25
 
25
26
  charge_switch = [
@@ -34,6 +34,10 @@ class Settings(BaseSettings):
34
34
  # Which dataset template id to use for dataset creation
35
35
  DATASET_TEMPLATE_ID: int = 0
36
36
 
37
+ # B-Fabric url paths
38
+ PRODUCTION_BFABRIC_DOMAIN: str = "fgcz-bfabric.uzh.ch"
39
+ TEST_BFABRIC_DOMAIN: str = "fgcz-bfabric-test.uzh.ch"
40
+
37
41
  class Config:
38
42
 
39
43
  env_file = ".env"
@@ -6,6 +6,9 @@ import subprocess
6
6
  from pathlib import Path
7
7
  import time
8
8
  from collections import defaultdict
9
+ import signal
10
+ import sys
11
+ import atexit
9
12
 
10
13
  from .get_logger import get_logger
11
14
  from .get_power_user_wrapper import get_power_user_wrapper
@@ -74,7 +77,7 @@ def run_main_job(
74
77
  """
75
78
 
76
79
  # STEP 0: Parse token, logger, etc.
77
- token, token_data, entity_data, app_data, page_title, session_details, job_link = process_url_and_token(token)
80
+ token, token_data, entity_data, app_data, page_title, session_details, job_link, bfabric_entity_link = process_url_and_token(token)
78
81
 
79
82
  if token is None:
80
83
  raise ValueError("Error: 'token' is None")
@@ -85,111 +88,130 @@ def run_main_job(
85
88
  if app_data is None:
86
89
  raise ValueError("Error: 'app_data' is None")
87
90
 
88
-
89
91
  L = get_logger(token_data)
90
92
  print("Token Data:", token_data)
91
93
  print("Entity Data:", entity_data)
92
94
  print("App Data:", app_data)
93
-
94
-
95
- # Step 1: Save files to the server
96
- try:
97
- summary = save_files_from_bytes(files_as_byte_strings, L)
98
- L.log_operation("Success | ORIGIN: run_main_job function", f"File copy summary: {summary}", params=None, flush_logs=True)
99
- print("Summary:", summary)
100
-
101
- except Exception as e:
102
- # If something unexpected blows up the entire process
103
- L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to copy files: {e}", params=None, flush_logs=True)
104
- print("Error copying files:", e)
105
-
106
-
107
- # STEP 2: Execute bash commands
108
- try:
109
- bash_log = execute_and_log_bash_commands(bash_commands)
110
- L.log_operation("Success | ORIGIN: run_main_job function", f"Bash commands executed success | origin: run_main_job functionfully:\n{bash_log}",
111
- params=None, flush_logs=True)
112
- except Exception as e:
113
- L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to execute bash commands: {e}",
114
- params=None, flush_logs=True)
115
- print("Error executing bash commands:", e)
116
95
 
96
+ job_id = token_data.get("jobId", None)
97
+ set_job_status(token_data, job_id, "running")
98
+ job_status = "running"
117
99
 
118
- # STEP 3: Create Workunits
119
100
  try:
120
- workunit_map, workunit_container_map = create_workunits_step(token_data, app_data, resource_paths, L)
121
- except Exception as e:
122
- L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to create workunits in B-Fabric: {e}",
123
- params=None, flush_logs=True)
124
- print("Error creating workunits:", e)
125
- workunit_map = []
126
-
101
+ # Step 1: Save files to the server
102
+ try:
103
+ summary = save_files_from_bytes(files_as_byte_strings, L)
104
+ L.log_operation("Success | ORIGIN: run_main_job function", f"File copy summary: {summary}", params=None, flush_logs=True)
105
+ print("Summary:", summary)
106
+
107
+ except Exception as e:
108
+ # If something unexpected blows up the entire process
109
+ job_status = "failed"
110
+ L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to copy files: {e}", params=None, flush_logs=True)
111
+ print("Error copying files:", e)
127
112
 
128
- # STEP 4: Create Dataset
129
- if dataset_dict:
130
- for container_id, dataset_data in dataset_dict.items():
113
+
114
+ # STEP 2: Execute bash commands
115
+ try:
116
+ bash_log = execute_and_log_bash_commands(bash_commands)
117
+ L.log_operation("Success | ORIGIN: run_main_job function", f"Bash commands executed success | origin: run_main_job functionfully:\n{bash_log}",
118
+ params=None, flush_logs=True)
119
+ except Exception as e:
120
+ job_status = "failed"
121
+ L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to execute bash commands: {e}",
122
+ params=None, flush_logs=True)
123
+ print("Error executing bash commands:", e)
131
124
 
132
- dataset_name = f'Dataset - {str(app_data.get("name", "Unknown App"))} - Container {container_id}'
133
- linked_workunit_id = workunit_container_map.get(str(container_id), None)
134
125
 
135
- try:
136
- dataset = dictionary_to_dataset(dataset_data, dataset_name, container_id, DATASET_TEMPLATE_ID, linked_workunit_id)
137
- dataset = create_dataset(token_data, dataset)
138
- L.log_operation("Success | ORIGIN: run_main_job function", f'Dataset {dataset.get("id", "Null")} created successfully for container {container_id}', params=None, flush_logs=True)
139
- print(f"Dataset created successfully for container {container_id}")
140
- except Exception as e:
141
- L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to create dataset for container {container_id}: {e}", params=None, flush_logs=True)
142
- print(f"Error creating dataset for container {container_id}:", e)
143
- else:
144
- L.log_operation("Info | ORIGIN: run_main_job function", "No dataset creation requested.", params=None, flush_logs=True)
145
- print("No dataset creation requested.")
126
+ # STEP 3: Create Workunits
127
+ try:
128
+ workunit_map, workunit_container_map = create_workunits_step(token_data, app_data, resource_paths, L)
129
+ except Exception as e:
130
+ job_status = "failed"
131
+ L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to create workunits in B-Fabric: {e}",
132
+ params=None, flush_logs=True)
133
+ print("Error creating workunits:", e)
134
+ workunit_map = {}
135
+
136
+
137
+ # STEP 4: Create Dataset
138
+ if dataset_dict:
139
+ for container_id, dataset_data in dataset_dict.items():
140
+
141
+ dataset_name = f'Dataset - {str(app_data.get("name", "Unknown App"))} - Container {container_id}'
142
+ linked_workunit_id = workunit_container_map.get(str(container_id), None)
143
+
144
+ try:
145
+ dataset = dictionary_to_dataset(dataset_data, dataset_name, container_id, DATASET_TEMPLATE_ID, linked_workunit_id)
146
+ dataset = create_dataset(token_data, dataset)
147
+ L.log_operation("Success | ORIGIN: run_main_job function", f'Dataset {dataset.get("id", "Null")} created successfully for container {container_id}', params=None, flush_logs=True)
148
+ print(f"Dataset created successfully for container {container_id}")
149
+ except Exception as e:
150
+ job_status = "failed"
151
+ L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to create dataset for container {container_id}: {e}", params=None, flush_logs=True)
152
+ print(f"Error creating dataset for container {container_id}:", e)
153
+ else:
154
+ L.log_operation("Info | ORIGIN: run_main_job function", "No dataset creation requested.", params=None, flush_logs=True)
155
+ print("No dataset creation requested.")
146
156
 
147
157
 
148
- # STEP 5: Register Resources (Refactored)
149
- try:
150
- attach_resources_to_workunits(token_data, L, workunit_map)
151
- except Exception as e:
152
- L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to register resources: {e}", params=None, flush_logs=True)
153
- print("Error registering resources:", e)
158
+ # STEP 5: Register Resources (Refactored)
159
+ try:
160
+ attach_resources_to_workunits(token_data, L, workunit_map)
161
+ except Exception as e:
162
+ job_status = "failed"
163
+ L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to register resources: {e}", params=None, flush_logs=True)
164
+ print("Error registering resources:", e)
154
165
 
155
- # STEP 6: Attach gstore files (logs, reports, etc.) to B-Fabric entity as a Link
156
- try:
157
- attach_gstore_files_to_entities_as_link(token_data, L, attachment_paths)
158
- print("Attachment Paths:", attachment_paths)
159
- except Exception as e:
160
- L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to attach extra files: {e}", params=None, flush_logs=True)
161
- print("Error attaching extra files:", e)
166
+ # STEP 6: Attach gstore files (logs, reports, etc.) to B-Fabric entity as a Link
167
+ try:
168
+ attach_gstore_files_to_entities_as_link(token_data, L, attachment_paths)
169
+ print("Attachment Paths:", attachment_paths)
170
+ except Exception as e:
171
+ job_status = "failed"
172
+ L.log_operation("Error | ORIGIN: run_main_job function", f"Failed to attach extra files: {e}", params=None, flush_logs=True)
173
+ print("Error attaching extra files:", e)
162
174
 
163
175
 
164
- # STEP 7: Charge the container for the service
165
- if charge:
176
+ # STEP 7: Charge the container for the service
177
+ if charge:
178
+
179
+ if service_id == 0:
180
+ print("Service ID not provided. Skipping charge creation.")
181
+ L.log_operation("Info | ORIGIN: run_main_job function", "Service ID not provided. Skipping charge creation.", params=None, flush_logs=True)
182
+ else:
183
+ container_ids = charge
184
+ print("Container IDs to charge:", container_ids)
185
+ if not container_ids:
186
+ L.log_operation("Error | ORIGIN: run_main_job function", "No container IDs found for charging.", params=None, flush_logs=True)
187
+ print("Error: No container IDs found for charging.")
188
+ set_job_status(token_data, job_id, "failed")
189
+ return
190
+ for container_id in container_ids:
191
+ charges = create_charge(token_data, container_id, service_id)
192
+ charge_id = charges[0].get("id")
193
+ L.log_operation("Success | ORIGIN: run_main_job function", f"Charge created for container {container_id} with service ID {service_id} and charge id {charge_id}", params=None, flush_logs=False)
194
+ print(f"Charge created with id {charge_id} for container {container_id} with service ID {service_id}")
195
+ L.flush_logs()
196
+ else:
197
+ L.log_operation("Info | ORIGIN: run_main_job function", "Charge creation skipped.", params=None, flush_logs=True)
198
+ print("Charge creation skipped.")
166
199
 
167
- if service_id == 0:
168
- print("Service ID not provided. Skipping charge creation.")
169
- L.log_operation("Info | ORIGIN: run_main_job function", "Service ID not provided. Skipping charge creation.", params=None, flush_logs=True)
200
+ # Final log message
201
+ if job_status == "running":
202
+ set_job_status(token_data, job_id, "done")
203
+ L.log_operation("Success | ORIGIN: run_main_job function", "All steps completed successfully.", params=None, flush_logs=True)
204
+ print("All steps completed successfully.")
170
205
  else:
171
- container_ids = charge
172
- print("Container IDs to charge:", container_ids)
173
- if not container_ids:
174
- L.log_operation("Error | ORIGIN: run_main_job function", "No container IDs found for charging.", params=None, flush_logs=True)
175
- print("Error: No container IDs found for charging.")
176
- return
177
- for container_id in container_ids:
178
- charges = create_charge(token_data, container_id, service_id)
179
- charge_id = charges[0].get("id")
180
- L.log_operation("Success | ORIGIN: run_main_job function", f"Charge created for container {container_id} with service ID {service_id} and charge id {charge_id}", params=None, flush_logs=False)
181
- print(f"Charge created with id {charge_id} for container {container_id} with service ID {service_id}")
182
- L.flush_logs()
183
- else:
184
- L.log_operation("Info | ORIGIN: run_main_job function", "Charge creation skipped.", params=None, flush_logs=True)
185
- print("Charge creation skipped.")
186
-
187
- # Final log message
188
- L.log_operation("Success | ORIGIN: run_main_job function", "All steps completed successfully.", params=None, flush_logs=True)
189
- print("All steps completed successfully.")
206
+ set_job_status(token_data, job_id, "failed")
207
+ L.log_operation("Failed | ORIGIN: run_main_job function", "The Pipline did not run successfully", params=None, flush_logs=True)
208
+
209
+ # It’s the “catch absolutely everything” version of except Exception
210
+ except BaseException as e:
211
+ set_job_status(token_data, job_id, "failed")
212
+ L.log_operation("Error | ORIGIN: run_main_job function", f"Unhandled termination: {e}", params=None, flush_logs=True)
190
213
 
191
214
  #---------------------------------------------------------------------------------------------------------------------
192
- #---------------------------------------------------------------------------------------------------------------------
193
215
 
194
216
 
195
217
  # -----------------------------------------------------------------------------
@@ -547,3 +569,14 @@ def read_file_as_bytes(file_path, max_size_mb=400):
547
569
  file_as_bytes = f.read()
548
570
 
549
571
  return file_as_bytes
572
+
573
+ def set_job_status(token_data, job_id, set_status_to):
574
+ """
575
+ Updates the job status in B-Fabric.
576
+
577
+ :param token_data: Authentication token data
578
+ :param job_id: ID of the job to update
579
+ :param set_status_to: String, e.g. "running", "done", or "failed"
580
+ """
581
+ wrapper = get_power_user_wrapper(token_data)
582
+ wrapper.save("job", {"id": job_id, "status": set_status_to})
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "bfabric-web-apps"
3
- version = "0.2.2"
3
+ version = "0.2.4"
4
4
  description = "A package containing handy boilerplate utilities for developing bfabric web-applications"
5
5
  authors = ["Marc Zuber, Griffin White, GWC GmbH"]
6
6