1919DEFAULT_POLLING_INTERVAL = 10
2020SUBMISSION_LANGUAGE = "python"
2121USER_AGENT = f"dbt-databricks/{ version } "
22+ LIBRARY_VALID_STATUSES = {"INSTALLED" , "RESTORED" , "SKIPPED" }
2223
2324
2425class PrefixSession :
@@ -47,10 +48,45 @@ def __init__(self, session: Session, host: str, api: str):
4748 self .session = PrefixSession (session , host , api )
4849
4950
51+ class LibraryApi (DatabricksApi ):
52+ def __init__ (self , session : Session , host : str ):
53+ super ().__init__ (session , host , "/api/2.0/libraries" )
54+
55+ def all_libraries_installed (self , cluster_id : str ) -> bool :
56+ status = self .get_cluster_libraries_status (cluster_id )
57+ if "library_statuses" in status :
58+ return all (
59+ library ["status" ] in LIBRARY_VALID_STATUSES
60+ for library in status ["library_statuses" ]
61+ )
62+ else :
63+ return True
64+
65+ def get_cluster_libraries_status (self , cluster_id : str ) -> dict [str , Any ]:
66+ response = self .session .get (
67+ "/cluster-status" ,
68+ json = {"cluster_id" : cluster_id },
69+ )
70+ if response .status_code != 200 :
71+ raise DbtRuntimeError (
72+ f"Error getting status of libraries of a cluster.\n { response .content !r} "
73+ )
74+
75+ json_response = response .json ()
76+ return json_response
77+
78+
5079class ClusterApi (DatabricksApi ):
51- def __init__ (self , session : Session , host : str , max_cluster_start_time : int = 900 ):
80+ def __init__ (
81+ self ,
82+ session : Session ,
83+ host : str ,
84+ libraries : LibraryApi ,
85+ max_cluster_start_time : int = 900 ,
86+ ):
5287 super ().__init__ (session , host , "/api/2.0/clusters" )
5388 self .max_cluster_start_time = max_cluster_start_time
89+ self .libraries = libraries
5490
5591 def status (self , cluster_id : str ) -> str :
5692 # https://docs.databricks.com/dev-tools/api/latest/clusters.html#get
@@ -68,10 +104,19 @@ def wait_for_cluster(self, cluster_id: str) -> None:
68104
69105 while time .time () - start_time < self .max_cluster_start_time :
70106 status_response = self .status (cluster_id )
71- if status_response == "RUNNING" :
72- return
73- else :
107+
108+ if status_response != "RUNNING" :
109+ logger .debug ("Waiting for cluster to start" )
110+ time .sleep (5 )
111+ continue
112+
113+ libraries_status = self .libraries .get_cluster_libraries_status (cluster_id )
114+ if not self .libraries .all_libraries_installed (cluster_id ):
115+ logger .debug (f"Waiting for all libraries to be installed: { libraries_status } " )
74116 time .sleep (5 )
117+ continue
118+
119+ return
75120
76121 raise DbtRuntimeError (
77122 f"Cluster { cluster_id } restart timed out after { self .max_cluster_start_time } seconds"
@@ -96,9 +141,12 @@ def start(self, cluster_id: str) -> None:
96141
97142
98143class CommandContextApi (DatabricksApi ):
99- def __init__ (self , session : Session , host : str , cluster_api : ClusterApi ):
144+ def __init__ (
145+ self , session : Session , host : str , cluster_api : ClusterApi , library_api : LibraryApi
146+ ):
100147 super ().__init__ (session , host , "/api/1.2/contexts" )
101148 self .cluster_api = cluster_api
149+ self .library_api = library_api
102150
103151 def create (self , cluster_id : str ) -> str :
104152 current_status = self .cluster_api .status (cluster_id )
@@ -107,7 +155,9 @@ def create(self, cluster_id: str) -> str:
107155 logger .debug (f"Cluster { cluster_id } is not running. Attempting to restart." )
108156 self .cluster_api .start (cluster_id )
109157 logger .debug (f"Cluster { cluster_id } is now running." )
110- elif current_status != "RUNNING" :
158+ elif current_status != "RUNNING" or not self .library_api .all_libraries_installed (
159+ cluster_id
160+ ):
111161 self .cluster_api .wait_for_cluster (cluster_id )
112162
113163 response = self .session .post (
@@ -532,8 +582,9 @@ def __init__(
532582 timeout : int ,
533583 use_user_folder : bool ,
534584 ):
535- self .clusters = ClusterApi (session , host )
536- self .command_contexts = CommandContextApi (session , host , self .clusters )
585+ self .libraries = LibraryApi (session , host )
586+ self .clusters = ClusterApi (session , host , self .libraries )
587+ self .command_contexts = CommandContextApi (session , host , self .clusters , self .libraries )
537588 self .curr_user = CurrUserApi (session , host )
538589 if use_user_folder :
539590 self .folders : FolderApi = UserFolderApi (session , host , self .curr_user )
0 commit comments