0
# Tenant Management
1
2
Multi-tenant data isolation and management for organizations requiring separate data namespaces, enabling secure multi-customer deployments and data segregation. Tenants provide the foundational isolation layer for all Google Cloud Talent API resources.
3
4
## Capabilities
5
6
### Tenant Creation
7
8
Creates new tenant entities that serve as data isolation boundaries for companies, jobs, and all other resources within the Talent API.
9
10
```python { .api }
11
def create_tenant(self, parent: str, tenant: Tenant) -> Tenant:
12
"""
13
Creates a new tenant for data isolation.
14
15
Parameters:
16
- parent (str): Project resource name where tenant will be created
17
- tenant (Tenant): Tenant object with required external_id
18
19
Returns:
20
Tenant: Created tenant with generated resource name
21
22
Raises:
23
- InvalidArgument: Missing required fields or invalid values
24
- AlreadyExists: Tenant with same external_id already exists
25
- PermissionDenied: Insufficient permissions to create tenant
26
"""
27
```
28
29
**Usage Example:**
30
31
```python
32
from google.cloud.talent import TenantServiceClient, Tenant
33
34
client = TenantServiceClient()
35
36
tenant = Tenant(
37
external_id="customer-acme-prod"
38
)
39
40
created_tenant = client.create_tenant(
41
parent="projects/my-project",
42
tenant=tenant
43
)
44
45
print(f"Created tenant: {created_tenant.name}")
46
print(f"External ID: {created_tenant.external_id}")
47
```
48
49
### Tenant Retrieval
50
51
Retrieves individual tenant entities by resource name with complete tenant information and metadata.
52
53
```python { .api }
54
def get_tenant(self, name: str) -> Tenant:
55
"""
56
Retrieves a tenant by its resource name.
57
58
Parameters:
59
- name (str): Full tenant resource name
60
61
Returns:
62
Tenant: Complete tenant object
63
64
Raises:
65
- NotFound: Tenant does not exist
66
- PermissionDenied: Insufficient permissions to view tenant
67
"""
68
```
69
70
**Usage Example:**
71
72
```python
73
tenant = client.get_tenant(
74
name="projects/my-project/tenants/tenant-123"
75
)
76
77
print(f"Tenant external ID: {tenant.external_id}")
78
```
79
80
### Tenant Updates
81
82
Updates existing tenant profiles with field-level control using update masks to specify which tenant attributes should be modified.
83
84
```python { .api }
85
def update_tenant(self, tenant: Tenant, update_mask: FieldMask = None) -> Tenant:
86
"""
87
Updates an existing tenant.
88
89
Parameters:
90
- tenant (Tenant): Tenant object with updated values and resource name
91
- update_mask (FieldMask): Specifies which fields to update
92
93
Returns:
94
Tenant: Updated tenant object
95
96
Raises:
97
- NotFound: Tenant does not exist
98
- InvalidArgument: Invalid field values or update mask
99
- PermissionDenied: Insufficient permissions to update tenant
100
"""
101
```
102
103
**Usage Example:**
104
105
```python
106
from google.protobuf import field_mask_pb2
107
108
# Update tenant external ID
109
tenant.external_id = "customer-acme-production"
110
111
update_mask = field_mask_pb2.FieldMask(paths=["external_id"])
112
113
updated_tenant = client.update_tenant(
114
tenant=tenant,
115
update_mask=update_mask
116
)
117
```
118
119
### Tenant Deletion
120
121
Removes tenant entities from the system. Note that tenants with associated companies or jobs cannot be deleted until all child resources are removed first.
122
123
```python { .api }
124
def delete_tenant(self, name: str) -> None:
125
"""
126
Deletes a tenant entity.
127
128
Parameters:
129
- name (str): Full tenant resource name
130
131
Raises:
132
- NotFound: Tenant does not exist
133
- PermissionDenied: Insufficient permissions to delete tenant
134
- FailedPrecondition: Tenant has associated companies or jobs that must be deleted first
135
"""
136
```
137
138
**Usage Example:**
139
140
```python
141
from google.api_core import exceptions
142
143
try:
144
client.delete_tenant(
145
name="projects/my-project/tenants/tenant-123"
146
)
147
print("Tenant deleted successfully")
148
except exceptions.FailedPrecondition:
149
print("Cannot delete tenant with active companies or jobs")
150
```
151
152
### Tenant Listing
153
154
Lists tenant entities with pagination support for efficient browsing of large tenant datasets within a project.
155
156
```python { .api }
157
def list_tenants(self, parent: str, page_size: int = None,
158
page_token: str = None) -> ListTenantsResponse:
159
"""
160
Lists tenants with pagination.
161
162
Parameters:
163
- parent (str): Project resource name
164
- page_size (int): Maximum number of tenants to return (max 100)
165
- page_token (str): Token for pagination from previous response
166
167
Returns:
168
ListTenantsResponse: Tenants list with pagination token and metadata
169
170
Raises:
171
- InvalidArgument: Invalid page size
172
- PermissionDenied: Insufficient permissions to list tenants
173
"""
174
```
175
176
**Usage Example:**
177
178
```python
179
# List all tenants in a project
180
response = client.list_tenants(
181
parent="projects/my-project",
182
page_size=50
183
)
184
185
for tenant in response.tenants:
186
print(f"Tenant: {tenant.external_id}")
187
print(f" Resource name: {tenant.name}")
188
189
# Handle pagination
190
while response.next_page_token:
191
response = client.list_tenants(
192
parent="projects/my-project",
193
page_token=response.next_page_token,
194
page_size=50
195
)
196
197
for tenant in response.tenants:
198
print(f"Tenant: {tenant.external_id}")
199
```
200
201
## Tenant Data Model
202
203
### Tenant Entity
204
205
```python { .api }
206
class Tenant:
207
"""
208
A tenant resource represents a tenant in the service, which provides
209
data isolation and resource management capabilities for multi-tenant
210
applications.
211
"""
212
name: str = None # Resource name (auto-generated)
213
external_id: str = None # Client-defined tenant identifier (required, max 255 chars)
214
```
215
216
The Tenant entity is intentionally minimal, serving primarily as an isolation boundary. The external_id should be a meaningful identifier that maps to your application's customer or organization identifiers.
217
218
## Request and Response Types
219
220
### Tenant Service Requests
221
222
```python { .api }
223
class CreateTenantRequest:
224
parent: str = None # Project resource name
225
tenant: Tenant = None # Tenant to create
226
227
class GetTenantRequest:
228
name: str = None # Tenant resource name
229
230
class UpdateTenantRequest:
231
tenant: Tenant = None # Tenant with updates
232
update_mask: FieldMask = None # Fields to update
233
234
class DeleteTenantRequest:
235
name: str = None # Tenant resource name
236
237
class ListTenantsRequest:
238
parent: str = None # Project resource name
239
page_size: int = None # Page size (max 100)
240
page_token: str = None # Pagination token
241
```
242
243
### Tenant Service Responses
244
245
```python { .api }
246
class ListTenantsResponse:
247
tenants: List[Tenant] = None # List of tenants
248
next_page_token: str = None # Pagination token for next page
249
metadata: ResponseMetadata = None # Response metadata
250
```
251
252
## Multi-Tenancy Architecture
253
254
Tenants provide the foundational data isolation layer in the Google Cloud Talent API:
255
256
```
257
Project (GCP Project)
258
└── Tenant (Data isolation boundary)
259
├── Company (Job posting organization)
260
│ └── Jobs (Individual job postings)
261
├── Events (User interaction tracking)
262
└── Completion (Query suggestions)
263
```
264
265
### Resource Hierarchy Example
266
267
```python
268
# Single project, multiple tenants for different customers
269
project = "projects/hr-platform-prod"
270
271
# Customer A's isolated data
272
tenant_a = "projects/hr-platform-prod/tenants/customer-a"
273
company_a1 = "projects/hr-platform-prod/tenants/customer-a/companies/acme-corp"
274
job_a1 = "projects/hr-platform-prod/tenants/customer-a/jobs/job-001"
275
276
# Customer B's isolated data
277
tenant_b = "projects/hr-platform-prod/tenants/customer-b"
278
company_b1 = "projects/hr-platform-prod/tenants/customer-b/companies/beta-inc"
279
job_b1 = "projects/hr-platform-prod/tenants/customer-b/jobs/job-001"
280
```
281
282
## Integration with Other Services
283
284
All other Talent API services require a tenant context:
285
286
```python
287
from google.cloud.talent import (
288
TenantServiceClient, CompanyServiceClient,
289
JobServiceClient, EventServiceClient
290
)
291
292
# Create tenant first
293
tenant_client = TenantServiceClient()
294
tenant = tenant_client.create_tenant(
295
parent="projects/my-project",
296
tenant=Tenant(external_id="customer-123")
297
)
298
299
# Use tenant as parent for all other resources
300
company_client = CompanyServiceClient()
301
company = company_client.create_company(
302
parent=tenant.name, # Tenant as parent
303
company=Company(display_name="Acme Corp", external_id="acme")
304
)
305
306
job_client = JobServiceClient()
307
job = job_client.create_job(
308
parent=tenant.name, # Tenant as parent
309
job=Job(company=company.name, requisition_id="job-1", title="Engineer")
310
)
311
312
# Events also scoped to tenant
313
event_client = EventServiceClient()
314
event_client.create_client_event(
315
parent=tenant.name, # Tenant as parent
316
client_event=ClientEvent(...)
317
)
318
```
319
320
## Resource Path Helpers
321
322
The client provides helper methods for constructing tenant resource paths:
323
324
```python { .api }
325
# Class methods for building resource paths
326
@classmethod
327
def tenant_path(cls, project: str, tenant: str) -> str:
328
"""Constructs a fully-qualified tenant resource name."""
329
330
@classmethod
331
def project_path(cls, project: str) -> str:
332
"""Constructs a fully-qualified project resource name."""
333
334
@classmethod
335
def parse_tenant_path(cls, path: str) -> Dict[str, str]:
336
"""Parses a tenant path into its component parts."""
337
```
338
339
**Usage Example:**
340
341
```python
342
# Build resource paths
343
tenant_path = TenantServiceClient.tenant_path(
344
project="my-project",
345
tenant="tenant-123"
346
)
347
348
project_path = TenantServiceClient.project_path(project="my-project")
349
350
# Parse resource paths
351
path_components = TenantServiceClient.parse_tenant_path(tenant_path)
352
print(f"Project: {path_components['project']}")
353
print(f"Tenant: {path_components['tenant']}")
354
```
355
356
## Error Handling
357
358
Tenant management operations can raise several types of exceptions:
359
360
```python
361
from google.api_core import exceptions
362
363
try:
364
tenant = client.create_tenant(parent=parent, tenant=tenant_data)
365
except exceptions.InvalidArgument as e:
366
# Handle validation errors
367
print(f"Invalid tenant data: {e}")
368
except exceptions.AlreadyExists as e:
369
# Handle duplicate external_id
370
print(f"Tenant already exists: {e}")
371
except exceptions.PermissionDenied as e:
372
# Handle authorization errors
373
print(f"Access denied: {e}")
374
```
375
376
Common error scenarios:
377
- **InvalidArgument**: Missing required external_id, invalid field values, malformed resource names
378
- **AlreadyExists**: Duplicate external_id within the same project
379
- **NotFound**: Tenant or project does not exist
380
- **PermissionDenied**: Insufficient IAM permissions for tenant operations
381
- **FailedPrecondition**: Cannot delete tenant with associated companies or jobs
382
- **ResourceExhausted**: API quota limits exceeded
383
384
## Best Practices
385
386
1. **External ID Strategy**: Use meaningful external_id values that map to your application's customer or organization identifiers
387
2. **Naming Conventions**: Establish consistent naming patterns for external_id values (e.g., "customer-{id}-{environment}")
388
3. **Data Isolation**: Ensure your application logic respects tenant boundaries and never mixes data across tenants
389
4. **Resource Cleanup**: When decommissioning a customer, delete all child resources (jobs, companies) before deleting the tenant
390
5. **Environment Separation**: Consider using different external_id patterns for development, staging, and production environments
391
6. **Monitoring**: Implement monitoring to track tenant-level resource usage and API quotas
392
7. **Access Control**: Use IAM policies to control which users and service accounts can manage tenants
393
394
## Multi-Customer SaaS Example
395
396
```python
397
class TalentAPIService:
398
def __init__(self):
399
self.tenant_client = TenantServiceClient()
400
self.company_client = CompanyServiceClient()
401
self.job_client = JobServiceClient()
402
403
def onboard_customer(self, customer_id: str, customer_name: str):
404
"""Onboard a new customer with isolated tenant."""
405
tenant = Tenant(external_id=f"customer-{customer_id}-prod")
406
407
tenant_response = self.tenant_client.create_tenant(
408
parent="projects/hr-saas-platform",
409
tenant=tenant
410
)
411
412
return tenant_response
413
414
def create_customer_company(self, customer_id: str, company_data: dict):
415
"""Create a company within customer's tenant."""
416
tenant_name = f"projects/hr-saas-platform/tenants/customer-{customer_id}-prod"
417
418
company = Company(
419
display_name=company_data["name"],
420
external_id=f"company-{company_data['id']}"
421
)
422
423
return self.company_client.create_company(
424
parent=tenant_name,
425
company=company
426
)
427
```