CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-google-cloud-talent

Google Cloud Talent API client library for job search and talent management

Pending
Overview
Eval results
Files

tenant-management.mddocs/

Tenant Management

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.

Capabilities

Tenant Creation

Creates new tenant entities that serve as data isolation boundaries for companies, jobs, and all other resources within the Talent API.

def create_tenant(self, parent: str, tenant: Tenant) -> Tenant:
    """
    Creates a new tenant for data isolation.

    Parameters:
    - parent (str): Project resource name where tenant will be created
    - tenant (Tenant): Tenant object with required external_id

    Returns:
    Tenant: Created tenant with generated resource name

    Raises:
    - InvalidArgument: Missing required fields or invalid values
    - AlreadyExists: Tenant with same external_id already exists
    - PermissionDenied: Insufficient permissions to create tenant
    """

Usage Example:

from google.cloud.talent import TenantServiceClient, Tenant

client = TenantServiceClient()

tenant = Tenant(
    external_id="customer-acme-prod"
)

created_tenant = client.create_tenant(
    parent="projects/my-project",
    tenant=tenant
)

print(f"Created tenant: {created_tenant.name}")
print(f"External ID: {created_tenant.external_id}")

Tenant Retrieval

Retrieves individual tenant entities by resource name with complete tenant information and metadata.

def get_tenant(self, name: str) -> Tenant:
    """
    Retrieves a tenant by its resource name.

    Parameters:
    - name (str): Full tenant resource name

    Returns:
    Tenant: Complete tenant object

    Raises:
    - NotFound: Tenant does not exist
    - PermissionDenied: Insufficient permissions to view tenant
    """

Usage Example:

tenant = client.get_tenant(
    name="projects/my-project/tenants/tenant-123"
)

print(f"Tenant external ID: {tenant.external_id}")

Tenant Updates

Updates existing tenant profiles with field-level control using update masks to specify which tenant attributes should be modified.

def update_tenant(self, tenant: Tenant, update_mask: FieldMask = None) -> Tenant:
    """
    Updates an existing tenant.

    Parameters:
    - tenant (Tenant): Tenant object with updated values and resource name
    - update_mask (FieldMask): Specifies which fields to update

    Returns:
    Tenant: Updated tenant object

    Raises:
    - NotFound: Tenant does not exist
    - InvalidArgument: Invalid field values or update mask
    - PermissionDenied: Insufficient permissions to update tenant
    """

Usage Example:

from google.protobuf import field_mask_pb2

# Update tenant external ID
tenant.external_id = "customer-acme-production"

update_mask = field_mask_pb2.FieldMask(paths=["external_id"])

updated_tenant = client.update_tenant(
    tenant=tenant,
    update_mask=update_mask
)

Tenant Deletion

Removes tenant entities from the system. Note that tenants with associated companies or jobs cannot be deleted until all child resources are removed first.

def delete_tenant(self, name: str) -> None:
    """
    Deletes a tenant entity.

    Parameters:
    - name (str): Full tenant resource name

    Raises:
    - NotFound: Tenant does not exist
    - PermissionDenied: Insufficient permissions to delete tenant
    - FailedPrecondition: Tenant has associated companies or jobs that must be deleted first
    """

Usage Example:

from google.api_core import exceptions

try:
    client.delete_tenant(
        name="projects/my-project/tenants/tenant-123"
    )
    print("Tenant deleted successfully")
except exceptions.FailedPrecondition:
    print("Cannot delete tenant with active companies or jobs")

Tenant Listing

Lists tenant entities with pagination support for efficient browsing of large tenant datasets within a project.

def list_tenants(self, parent: str, page_size: int = None, 
                page_token: str = None) -> ListTenantsResponse:
    """
    Lists tenants with pagination.

    Parameters:
    - parent (str): Project resource name
    - page_size (int): Maximum number of tenants to return (max 100)
    - page_token (str): Token for pagination from previous response

    Returns:
    ListTenantsResponse: Tenants list with pagination token and metadata

    Raises:
    - InvalidArgument: Invalid page size
    - PermissionDenied: Insufficient permissions to list tenants
    """

Usage Example:

# List all tenants in a project
response = client.list_tenants(
    parent="projects/my-project",
    page_size=50
)

for tenant in response.tenants:
    print(f"Tenant: {tenant.external_id}")
    print(f"  Resource name: {tenant.name}")

# Handle pagination
while response.next_page_token:
    response = client.list_tenants(
        parent="projects/my-project",
        page_token=response.next_page_token,
        page_size=50
    )
    
    for tenant in response.tenants:
        print(f"Tenant: {tenant.external_id}")

Tenant Data Model

Tenant Entity

class Tenant:
    """
    A tenant resource represents a tenant in the service, which provides
    data isolation and resource management capabilities for multi-tenant
    applications.
    """
    name: str = None  # Resource name (auto-generated)
    external_id: str = None  # Client-defined tenant identifier (required, max 255 chars)

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.

Request and Response Types

Tenant Service Requests

class CreateTenantRequest:
    parent: str = None  # Project resource name
    tenant: Tenant = None  # Tenant to create

class GetTenantRequest:
    name: str = None  # Tenant resource name

class UpdateTenantRequest:
    tenant: Tenant = None  # Tenant with updates
    update_mask: FieldMask = None  # Fields to update

class DeleteTenantRequest:
    name: str = None  # Tenant resource name

class ListTenantsRequest:
    parent: str = None  # Project resource name
    page_size: int = None  # Page size (max 100)
    page_token: str = None  # Pagination token

Tenant Service Responses

class ListTenantsResponse:
    tenants: List[Tenant] = None  # List of tenants
    next_page_token: str = None  # Pagination token for next page
    metadata: ResponseMetadata = None  # Response metadata

Multi-Tenancy Architecture

Tenants provide the foundational data isolation layer in the Google Cloud Talent API:

Project (GCP Project)
└── Tenant (Data isolation boundary)
    ├── Company (Job posting organization)
    │   └── Jobs (Individual job postings)
    ├── Events (User interaction tracking)
    └── Completion (Query suggestions)

Resource Hierarchy Example

# Single project, multiple tenants for different customers
project = "projects/hr-platform-prod"

# Customer A's isolated data
tenant_a = "projects/hr-platform-prod/tenants/customer-a"
company_a1 = "projects/hr-platform-prod/tenants/customer-a/companies/acme-corp"
job_a1 = "projects/hr-platform-prod/tenants/customer-a/jobs/job-001"

# Customer B's isolated data  
tenant_b = "projects/hr-platform-prod/tenants/customer-b"
company_b1 = "projects/hr-platform-prod/tenants/customer-b/companies/beta-inc"
job_b1 = "projects/hr-platform-prod/tenants/customer-b/jobs/job-001"

Integration with Other Services

All other Talent API services require a tenant context:

from google.cloud.talent import (
    TenantServiceClient, CompanyServiceClient, 
    JobServiceClient, EventServiceClient
)

# Create tenant first
tenant_client = TenantServiceClient()
tenant = tenant_client.create_tenant(
    parent="projects/my-project",
    tenant=Tenant(external_id="customer-123")
)

# Use tenant as parent for all other resources
company_client = CompanyServiceClient()
company = company_client.create_company(
    parent=tenant.name,  # Tenant as parent
    company=Company(display_name="Acme Corp", external_id="acme")
)

job_client = JobServiceClient()
job = job_client.create_job(
    parent=tenant.name,  # Tenant as parent
    job=Job(company=company.name, requisition_id="job-1", title="Engineer")
)

# Events also scoped to tenant
event_client = EventServiceClient()
event_client.create_client_event(
    parent=tenant.name,  # Tenant as parent
    client_event=ClientEvent(...)
)

Resource Path Helpers

The client provides helper methods for constructing tenant resource paths:

# Class methods for building resource paths
@classmethod
def tenant_path(cls, project: str, tenant: str) -> str:
    """Constructs a fully-qualified tenant resource name."""

@classmethod
def project_path(cls, project: str) -> str:
    """Constructs a fully-qualified project resource name."""

@classmethod
def parse_tenant_path(cls, path: str) -> Dict[str, str]:
    """Parses a tenant path into its component parts."""

Usage Example:

# Build resource paths
tenant_path = TenantServiceClient.tenant_path(
    project="my-project",
    tenant="tenant-123"
)

project_path = TenantServiceClient.project_path(project="my-project")

# Parse resource paths
path_components = TenantServiceClient.parse_tenant_path(tenant_path)
print(f"Project: {path_components['project']}")
print(f"Tenant: {path_components['tenant']}")

Error Handling

Tenant management operations can raise several types of exceptions:

from google.api_core import exceptions

try:
    tenant = client.create_tenant(parent=parent, tenant=tenant_data)
except exceptions.InvalidArgument as e:
    # Handle validation errors
    print(f"Invalid tenant data: {e}")
except exceptions.AlreadyExists as e:
    # Handle duplicate external_id
    print(f"Tenant already exists: {e}")
except exceptions.PermissionDenied as e:
    # Handle authorization errors
    print(f"Access denied: {e}")

Common error scenarios:

  • InvalidArgument: Missing required external_id, invalid field values, malformed resource names
  • AlreadyExists: Duplicate external_id within the same project
  • NotFound: Tenant or project does not exist
  • PermissionDenied: Insufficient IAM permissions for tenant operations
  • FailedPrecondition: Cannot delete tenant with associated companies or jobs
  • ResourceExhausted: API quota limits exceeded

Best Practices

  1. External ID Strategy: Use meaningful external_id values that map to your application's customer or organization identifiers
  2. Naming Conventions: Establish consistent naming patterns for external_id values (e.g., "customer-{id}-{environment}")
  3. Data Isolation: Ensure your application logic respects tenant boundaries and never mixes data across tenants
  4. Resource Cleanup: When decommissioning a customer, delete all child resources (jobs, companies) before deleting the tenant
  5. Environment Separation: Consider using different external_id patterns for development, staging, and production environments
  6. Monitoring: Implement monitoring to track tenant-level resource usage and API quotas
  7. Access Control: Use IAM policies to control which users and service accounts can manage tenants

Multi-Customer SaaS Example

class TalentAPIService:
    def __init__(self):
        self.tenant_client = TenantServiceClient()
        self.company_client = CompanyServiceClient()
        self.job_client = JobServiceClient()
    
    def onboard_customer(self, customer_id: str, customer_name: str):
        """Onboard a new customer with isolated tenant."""
        tenant = Tenant(external_id=f"customer-{customer_id}-prod")
        
        tenant_response = self.tenant_client.create_tenant(
            parent="projects/hr-saas-platform",
            tenant=tenant
        )
        
        return tenant_response
    
    def create_customer_company(self, customer_id: str, company_data: dict):
        """Create a company within customer's tenant."""
        tenant_name = f"projects/hr-saas-platform/tenants/customer-{customer_id}-prod"
        
        company = Company(
            display_name=company_data["name"],
            external_id=f"company-{company_data['id']}"
        )
        
        return self.company_client.create_company(
            parent=tenant_name,
            company=company
        )

Install with Tessl CLI

npx tessl i tessl/pypi-google-cloud-talent

docs

company-management.md

event-tracking.md

index.md

job-management.md

query-autocompletion.md

search-filtering.md

tenant-management.md

tile.json