4040)
4141
4242from databricks .labs .ucx .__about__ import __version__
43+ from databricks .labs .ucx .account .workspaces import WorkspaceInfo
4344from databricks .labs .ucx .assessment .azure import AzureServicePrincipalInfo
4445from databricks .labs .ucx .assessment .clusters import ClusterInfo , PolicyInfo
4546from databricks .labs .ucx .assessment .init_scripts import GlobalInitScriptInfo
@@ -663,34 +664,94 @@ def install_on_account(self):
663664 # upload the json dump of workspace info in the .ucx folder
664665 ctx .account_workspaces .sync_workspace_info (installed_workspaces )
665666
667+ @staticmethod
668+ def _get_workspace (workspace_id : int , ids_to_workspace : dict [int , Workspace ]) -> Workspace :
669+ try :
670+ workspace = ids_to_workspace [workspace_id ]
671+ return workspace
672+ except KeyError :
673+ msg = "Current workspace is not known, Please run as account-admin: databricks labs ucx sync-workspace-info"
674+ raise KeyError (msg ) from None
675+
676+ def _get_workspace_info (self , current_workspace_id : int ):
677+ account_client = self ._get_safe_account_client ()
678+ workspace = account_client .workspaces .get (current_workspace_id )
679+ current_workspace_client = account_client .get_workspace_client (workspace )
680+ installation = Installation .current (current_workspace_client , self .product_info .product_name ())
681+ workspace_info = WorkspaceInfo (installation , current_workspace_client )
682+ return workspace_info .load_workspace_info ()
683+
666684 def join_collection (
667685 self ,
668686 current_workspace_id : int ,
687+ target_workspace_id : int | None = None ,
669688 ):
670- if not self .is_account_install and self .prompts .confirm (
671- "Do you want to join the current installation to an existing collection?"
672- ):
673-
674- installed_workspaces : list [Workspace ] | None = []
675- accessible_workspaces : list [Workspace ] = []
676- account_client = self ._get_safe_account_client ()
677- ctx = AccountContext (account_client )
678- try :
679- accessible_workspaces = ctx .account_workspaces .get_accessible_workspaces ()
680- except PermissionDenied :
681- logger .warning ("User doesnt have account admin permission, cant join a collection, skipping..." )
682- collection_workspace = self ._get_collection_workspace (accessible_workspaces , account_client )
683- if collection_workspace is not None :
684- installed_workspaces = self ._sync_collection (collection_workspace , current_workspace_id , account_client )
685- if installed_workspaces is not None :
686- ctx .account_workspaces .sync_workspace_info (installed_workspaces )
689+ if self .is_account_install :
690+ # skip joining collection when installer is running for all account workspaces
691+ return None
692+ collection_workspace : Workspace
693+ account_client = self ._get_safe_account_client ()
694+ ctx = AccountContext (account_client )
695+ ids_to_workspace = self ._get_workspace_info (current_workspace_id )
696+ if target_workspace_id is None :
697+ if self .prompts .confirm ("Do you want to join the current installation to an existing collection?" ):
698+ # If joining a collection as part of the installation then collection_workspace_id would be empty
699+ try :
700+ # if user is account admin list and show available workspaces to select from
701+ accessible_workspaces = ctx .account_workspaces .get_accessible_workspaces ()
702+ target_workspace = self ._get_collection_workspace (
703+ accessible_workspaces ,
704+ account_client ,
705+ )
706+ assert target_workspace is not None
707+ target_workspace_id = target_workspace .workspace_id
708+
709+ except PermissionDenied :
710+ # if the user is not account admin, allow user to enter the workspace_id to join as collection.
711+ # if no workspace_id is entered, then exit
712+ logger .warning ("User doesnt have account admin permission, cant list workspaces" )
713+ target_workspace_id = int (
714+ self .prompts .question (
715+ "Please enter, the workspace id to join as a collection (enter 0 to skip it)" ,
716+ valid_number = True ,
717+ default = "0" ,
718+ )
719+ )
720+ else :
721+ return None
722+ if target_workspace_id == 0 or target_workspace_id is None :
723+ # if user didn't enter workspace id
724+ logger .info ("Skipping joining collection..." )
725+ return None
726+ # below code is executed if either joining an existing collection (through the cli)
727+ # or selecting one while installing
728+ collection_workspace = AccountInstaller ._get_workspace (
729+ target_workspace_id ,
730+ ids_to_workspace ,
731+ )
732+ if not ctx .account_workspaces .can_administer (collection_workspace ):
733+ # if user is not workspace admin on the workspace to join as collection then exit
734+ logger .error (
735+ f"User doesnt have admin access on the workspace { target_workspace_id } , " f"cant join collection."
736+ )
737+ return None
738+ if collection_workspace is not None :
739+ self ._sync_collection (
740+ collection_workspace ,
741+ current_workspace_id ,
742+ ids_to_workspace ,
743+ )
744+ return None
687745
688746 def _sync_collection (
689747 self ,
690748 collection_workspace : Workspace ,
691749 current_workspace_id : int ,
692- account_client : AccountClient ,
750+ ids_to_workspace : dict [ int , Workspace ] ,
693751 ) -> list [Workspace ] | None :
752+ # gets the list of existing collection of workspace from the config
753+ # checks if user is workspace admin on all the workspace id, if yes
754+ # then joins the collection and syncs the config with all the affected workspaces
694755 installer = self ._get_installer (collection_workspace )
695756 installed_workspace_ids = installer .config .installed_workspace_ids
696757 if installed_workspace_ids is None :
@@ -701,9 +762,20 @@ def _sync_collection(
701762 )
702763 installed_workspace_ids .append (current_workspace_id )
703764 installed_workspaces = []
704- for account_workspace in account_client .workspaces .list ():
705- if account_workspace .workspace_id in installed_workspace_ids :
706- installed_workspaces .append (account_workspace )
765+ ctx = AccountContext (self ._get_safe_account_client ())
766+ for workspace_id in installed_workspace_ids :
767+ workspace = AccountInstaller ._get_workspace (
768+ workspace_id ,
769+ ids_to_workspace ,
770+ )
771+ installed_workspaces .append (workspace )
772+ if not ctx .account_workspaces .can_administer (workspace ):
773+
774+ logger .error (
775+ f"User doesnt have admin access on the workspace { workspace_id } in the collection, "
776+ f"cant join collection."
777+ )
778+ return None
707779
708780 for installed_workspace in installed_workspaces :
709781 installer = self ._get_installer (installed_workspace )
@@ -715,10 +787,15 @@ def _get_collection_workspace(
715787 accessible_workspaces : list [Workspace ],
716788 account_client : AccountClient ,
717789 ) -> Workspace | None :
790+ # iterate through each workspace and select workspace which has existing ucx installation
791+ # allow user to select from the eligible workspace to join as collection
718792 installed_workspaces = []
719793 for workspace in accessible_workspaces :
720794 workspace_client = account_client .get_workspace_client (workspace )
721- workspace_installation = Installation .existing (workspace_client , self .product_info .product_name ())
795+ workspace_installation = Installation .existing (
796+ workspace_client ,
797+ self .product_info .product_name (),
798+ )
722799 if len (workspace_installation ) > 0 :
723800 installed_workspaces .append (workspace )
724801
@@ -730,12 +807,12 @@ def _get_collection_workspace(
730807 for workspace in installed_workspaces
731808 if workspace .deployment_name is not None
732809 }
733- workspace = self .prompts .choice_from_dict (
810+ target_workspace = self .prompts .choice_from_dict (
734811 "Please select a workspace, the current installation of ucx will be grouped as a "
735812 "collection with the selected workspace" ,
736813 workspaces ,
737814 )
738- return workspace
815+ return target_workspace
739816
740817
741818if __name__ == "__main__" :
@@ -749,5 +826,8 @@ def _get_collection_workspace(
749826 account_installer .install_on_account ()
750827 else :
751828 workspace_installer = WorkspaceInstaller (WorkspaceClient (product = "ucx" , product_version = __version__ ))
829+
752830 workspace_installer .run ()
753- account_installer .join_collection (workspace_installer .workspace_client .get_workspace_id ())
831+ account_installer .join_collection (
832+ workspace_installer .workspace_client .get_workspace_id (),
833+ )
0 commit comments