@@ -1307,18 +1307,29 @@ class StarterWorkspace(object):
13071307
13081308 name : str
13091309 id : str
1310+ database_name : str
1311+ endpoint : Optional [str ]
13101312
13111313 def __init__ (
13121314 self ,
13131315 name : str ,
13141316 id : str ,
1317+ database_name : str ,
1318+ endpoint : Optional [str ] = None ,
13151319 ):
13161320 #: Name of the starter workspace
13171321 self .name = name
13181322
13191323 #: Unique ID of the starter workspace
13201324 self .id = id
13211325
1326+ #: Name of the database associated with the starter workspace
1327+ self .database_name = database_name
1328+
1329+ #: Endpoint to connect to the starter workspace. The endpoint is in the form
1330+ #: of ``hostname:port``
1331+ self .endpoint = endpoint
1332+
13221333 self ._manager : Optional [WorkspaceManager ] = None
13231334
13241335 def __str__ (self ) -> str :
@@ -1351,10 +1362,56 @@ def from_dict(
13511362 out = cls (
13521363 name = obj ['name' ],
13531364 id = obj ['virtualWorkspaceID' ],
1365+ database_name = obj ['databaseName' ],
1366+ endpoint = obj .get ('endpoint' ),
13541367 )
13551368 out ._manager = manager
13561369 return out
13571370
1371+ def connect (self , ** kwargs : Any ) -> connection .Connection :
1372+ """
1373+ Create a connection to the database server for this starter workspace.
1374+
1375+ Parameters
1376+ ----------
1377+ **kwargs : keyword-arguments, optional
1378+ Parameters to the SingleStoreDB `connect` function except host
1379+ and port which are supplied by the starter workspace object
1380+
1381+ Returns
1382+ -------
1383+ :class:`Connection`
1384+
1385+ """
1386+ if not self .endpoint :
1387+ raise ManagementError (
1388+ msg = 'An endpoint has not been set in this '
1389+ 'starter workspace configuration' ,
1390+ )
1391+ # Parse endpoint as host:port
1392+ if ':' in self .endpoint :
1393+ host , port = self .endpoint .split (':' , 1 )
1394+ kwargs ['host' ] = host
1395+ kwargs ['port' ] = int (port )
1396+ else :
1397+ kwargs ['host' ] = self .endpoint
1398+ return connection .connect (** kwargs )
1399+
1400+ def terminate (self ) -> None :
1401+ """
1402+ Terminate the starter workspace.
1403+
1404+ Raises
1405+ ------
1406+ ManagementError
1407+ If no workspace manager is associated with this object.
1408+ """
1409+ if self ._manager is None :
1410+ raise ManagementError (
1411+ msg = 'No workspace manager is associated with this object.' ,
1412+ )
1413+ self ._manager .terminate_starter_workspace (self .id )
1414+
13581415 @property
13591416 def organization (self ) -> Organization :
13601417 if self ._manager is None :
@@ -1375,7 +1432,7 @@ def stage(self) -> Stage:
13751432 stages = stage
13761433
13771434 @property
1378- def starter_workspaces (self ) -> NamedList [StarterWorkspace ]:
1435+ def starter_workspaces (self ) -> NamedList [' StarterWorkspace' ]:
13791436 """Return a list of available starter workspaces."""
13801437 if self ._manager is None :
13811438 raise ManagementError (
@@ -1386,6 +1443,67 @@ def starter_workspaces(self) -> NamedList[StarterWorkspace]:
13861443 [StarterWorkspace .from_dict (item , self ._manager ) for item in res .json ()],
13871444 )
13881445
1446+ def create_user (
1447+ self ,
1448+ user_name : str ,
1449+ password : Optional [str ] = None ,
1450+ ) -> Dict [str , str ]:
1451+ """
1452+ Create a new user for this starter workspace.
1453+
1454+ Parameters
1455+ ----------
1456+ user_name : str
1457+ The starter workspace user name to connect the new user to the database
1458+ password : str, optional
1459+ Password for the new user. If not provided, a password will be
1460+ auto-generated by the system.
1461+
1462+ Returns
1463+ -------
1464+ Dict[str, str]
1465+ Dictionary containing 'userID' and 'password' of the created user
1466+
1467+ Raises
1468+ ------
1469+ ManagementError
1470+ If no workspace manager is associated with this object.
1471+ """
1472+ if self ._manager is None :
1473+ raise ManagementError (
1474+ msg = 'No workspace manager is associated with this object.' ,
1475+ )
1476+
1477+ return self ._manager .create_starter_workspace_user (self .id , user_name , password )
1478+
1479+ @classmethod
1480+ def create_starter_workspace (
1481+ cls ,
1482+ manager : 'WorkspaceManager' ,
1483+ name : str ,
1484+ database_name : str ,
1485+ workspace_group : dict [str , str ],
1486+ ) -> 'StarterWorkspace' :
1487+ """
1488+ Create a new starter (shared tier) workspace.
1489+
1490+ Parameters
1491+ ----------
1492+ manager : WorkspaceManager
1493+ The WorkspaceManager instance to use for the API call
1494+ name : str
1495+ Name of the starter workspace
1496+ database_name : str
1497+ Name of the database for the starter workspace
1498+ workspace_group : dict[str, str]
1499+ Workspace group input (dict with keys: 'name', 'cell_id')
1500+
1501+ Returns
1502+ -------
1503+ :class:`StarterWorkspace`
1504+ """
1505+ return manager .create_starter_workspace (name , database_name , workspace_group )
1506+
13891507
13901508class Billing (object ):
13911509 """Billing information."""
@@ -1717,6 +1835,131 @@ def get_starter_workspace(self, id: str) -> StarterWorkspace:
17171835 res = self ._get (f'sharedtier/virtualWorkspaces/{ id } ' )
17181836 return StarterWorkspace .from_dict (res .json (), manager = self )
17191837
1838+ def create_starter_workspace (
1839+ self ,
1840+ name : str ,
1841+ database_name : str ,
1842+ workspace_group : dict [str , str ],
1843+ ) -> 'StarterWorkspace' :
1844+ """
1845+ Create a new starter (shared tier) workspace.
1846+
1847+ Parameters
1848+ ----------
1849+ name : str
1850+ Name of the starter workspace
1851+ database_name : str
1852+ Name of the database for the starter workspace
1853+ workspace_group : dict[str, str]
1854+ Workspace group input (dict with keys: 'name', 'cell_id')
1855+
1856+ Returns
1857+ -------
1858+ :class:`StarterWorkspace`
1859+ """
1860+ if not workspace_group or not isinstance (workspace_group , dict ):
1861+ raise ValueError (
1862+ 'workspace_group must be a dict with keys: '
1863+ "'name', 'cell_id'" ,
1864+ )
1865+ if set (workspace_group .keys ()) != {'name' , 'cell_id' }:
1866+ raise ValueError ("workspace_group must contain only 'name' and 'cell_id'" )
1867+
1868+ payload = {
1869+ 'name' : name ,
1870+ 'databaseName' : database_name ,
1871+ 'workspaceGroup' : {
1872+ 'name' : workspace_group ['name' ],
1873+ 'cellID' : workspace_group ['cell_id' ],
1874+ },
1875+ }
1876+
1877+ res = self ._post ('sharedtier/virtualWorkspaces' , json = payload )
1878+ virtual_workspace_id = res .json ().get ('virtualWorkspaceID' )
1879+ if not virtual_workspace_id :
1880+ raise ManagementError (msg = 'No virtualWorkspaceID returned from API' )
1881+
1882+ res = self ._get (f'sharedtier/virtualWorkspaces/{ virtual_workspace_id } ' )
1883+ return StarterWorkspace .from_dict (res .json (), self )
1884+
1885+ def terminate_starter_workspace (
1886+ self ,
1887+ id : str ,
1888+ ) -> None :
1889+ """
1890+ Terminate a starter (shared tier) workspace.
1891+
1892+ Parameters
1893+ ----------
1894+ id : str
1895+ ID of the starter workspace
1896+ wait_on_terminated : bool, optional
1897+ Wait for the starter workspace to go into 'Terminated' mode before returning
1898+ wait_interval : int, optional
1899+ Number of seconds between each server check
1900+ wait_timeout : int, optional
1901+ Total number of seconds to check server before giving up
1902+
1903+ Raises
1904+ ------
1905+ ManagementError
1906+ If timeout is reached
1907+
1908+ """
1909+ self ._delete (f'sharedtier/virtualWorkspaces/{ id } ' )
1910+
1911+ def create_starter_workspace_user (
1912+ self ,
1913+ starter_workspace_id : str ,
1914+ username : str ,
1915+ password : Optional [str ] = None ,
1916+ ) -> Dict [str , str ]:
1917+ """
1918+ Create a new user for a starter workspace.
1919+
1920+ Parameters
1921+ ----------
1922+ starter_workspace_id : str
1923+ ID of the starter workspace
1924+ user_name : str
1925+ The starter workspace user name to connect the new user to the database
1926+ password : str, optional
1927+ Password for the new user. If not provided, a password will be
1928+ auto-generated by the system.
1929+
1930+ Returns
1931+ -------
1932+ Dict[str, str]
1933+ Dictionary containing 'userID' and 'password' of the created user
1934+
1935+ """
1936+ payload = {
1937+ 'userName' : username ,
1938+ }
1939+ if password is not None :
1940+ payload ['password' ] = password
1941+
1942+ res = self ._post (
1943+ f'sharedtier/virtualWorkspaces/{ starter_workspace_id } /users' ,
1944+ json = payload ,
1945+ )
1946+
1947+ response_data = res .json ()
1948+ user_id = response_data .get ('userID' )
1949+ if not user_id :
1950+ raise ManagementError (msg = 'No userID returned from API' )
1951+
1952+ # Return the password provided by user or generated by API
1953+ returned_password = password if password is not None \
1954+ else response_data .get ('password' )
1955+ if not returned_password :
1956+ raise ManagementError (msg = 'No password available from API response' )
1957+
1958+ return {
1959+ 'userID' : user_id ,
1960+ 'password' : returned_password ,
1961+ }
1962+
17201963
17211964def manage_workspaces (
17221965 access_token : Optional [str ] = None ,
0 commit comments