Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
390 changes: 390 additions & 0 deletions MISSING_FEATURES_SNIPPETS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,390 @@
# OSBAPI 2.17 Missing Features - Implementation Snippets

## 1. Service Binding Rotation Support

### ServicePlan.binding_rotatable field
```python
# In openbrokerapi/catalog.py ServicePlan class
class ServicePlan:
def __init__(
self,
id: str,
name: str,
description: str,
metadata: Optional[ServicePlanMetadata] = None,
free: Optional[bool] = None,
bindable: Optional[bool] = None,
binding_rotatable: Optional[bool] = None, # NEW: Supports binding rotation
schemas: Optional[Schemas] = None,
**kwargs,
):
# ... existing fields ...
self.binding_rotatable = binding_rotatable
```

### BindDetails.predecessor_binding_id field
```python
# In openbrokerapi/service_broker.py BindDetails class
class BindDetails:
def __init__(
self,
service_id: str,
plan_id: str,
app_guid: Optional[str] = None,
bind_resource: Optional[dict] = None,
context: Optional[dict] = None,
parameters: Optional[dict] = None,
predecessor_binding_id: Optional[str] = None, # NEW: For binding rotation
**kwargs,
):
# ... existing initialization ...
self.predecessor_binding_id = predecessor_binding_id
```

### BindingMetadata class
```python
# New class in openbrokerapi/service_broker.py
class BindingMetadata:
def __init__(
self,
expires_at: Optional[str] = None,
renew_before: Optional[str] = None,
**kwargs
):
self.expires_at = expires_at
self.renew_before = renew_before
self.__dict__.update(kwargs)
```

## 2. Maintenance Info Object

### MaintenanceInfo class
```python
# New class in openbrokerapi/catalog.py
class MaintenanceInfo:
def __init__(
self,
version: str,
description: Optional[str] = None,
**kwargs
):
self.version = version
self.description = description
self.__dict__.update(kwargs)
```

### ServicePlan.maintenance_info field
```python
# In openbrokerapi/catalog.py ServicePlan class
class ServicePlan:
def __init__(
self,
# ... existing fields ...
maintenance_info: Optional[MaintenanceInfo] = None, # NEW
**kwargs,
):
# ... existing initialization ...
self.maintenance_info = maintenance_info
```

### ProvisionDetails.maintenance_info field
```python
# In openbrokerapi/service_broker.py ProvisionDetails class
class ProvisionDetails:
def __init__(
self,
service_id: str,
plan_id: str,
organization_guid: Optional[str] = None,
space_guid: Optional[str] = None,
parameters: Optional[dict] = None,
context: Optional[dict] = None,
maintenance_info: Optional[MaintenanceInfo] = None, # NEW
**kwargs,
):
# ... existing initialization ...
self.maintenance_info = maintenance_info
```

### UpdateDetails.maintenance_info field
```python
# In openbrokerapi/service_broker.py UpdateDetails class
class UpdateDetails:
def __init__(
self,
service_id: str,
plan_id: Optional[str] = None,
parameters: Optional[dict] = None,
previous_values: Optional[dict] = None,
context: Optional[dict] = None,
maintenance_info: Optional[MaintenanceInfo] = None, # NEW
**kwargs,
):
# ... existing initialization ...
self.maintenance_info = maintenance_info
```

### PreviousValues.maintenance_info field
```python
# In openbrokerapi/service_broker.py PreviousValues class
class PreviousValues:
def __init__(
self,
plan_id: Optional[str] = None,
service_id: Optional[str] = None,
organization_id: Optional[str] = None,
space_id: Optional[str] = None,
maintenance_info: Optional[MaintenanceInfo] = None, # NEW
**kwargs,
):
# ... existing initialization ...
self.maintenance_info = maintenance_info
```

## 3. Service Instance Metadata

### ServiceInstanceMetadata class
```python
# New class in openbrokerapi/service_broker.py or response.py
class ServiceInstanceMetadata:
def __init__(
self,
labels: Optional[dict] = None,
attributes: Optional[dict] = None,
**kwargs
):
self.labels = labels
self.attributes = attributes
self.__dict__.update(kwargs)
```

### ProvisioningResponse.metadata field
```python
# In openbrokerapi/response.py ProvisioningResponse class
class ProvisioningResponse(AsyncResponse):
def __init__(
self,
dashboard_url: str,
operation: str,
metadata: Optional[ServiceInstanceMetadata] = None, # NEW
):
self.dashboard_url = dashboard_url
self.operation = operation
self.metadata = metadata
```

### GetInstanceResponse.metadata field
```python
# In openbrokerapi/response.py GetInstanceResponse class
class GetInstanceResponse:
def __init__(
self,
service_id: str,
plan_id: str,
dashboard_url: Optional[str] = None,
parameters: Optional[dict] = None,
maintenance_info: Optional[MaintenanceInfo] = None, # NEW
metadata: Optional[ServiceInstanceMetadata] = None, # NEW
):
# ... existing initialization ...
self.maintenance_info = maintenance_info
self.metadata = metadata
```

## 4. Network Endpoints

### Endpoint class
```python
# New class in openbrokerapi/service_broker.py
class Endpoint:
def __init__(
self,
host: str,
ports: List[str],
protocol: Optional[str] = "tcp",
**kwargs
):
self.host = host
self.ports = ports
self.protocol = protocol
self.__dict__.update(kwargs)
```

### BindResponse.endpoints field
```python
# In openbrokerapi/response.py BindResponse class
class BindResponse:
def __init__(
self,
credentials: Optional[dict] = None,
syslog_drain_url: Optional[str] = None,
route_service_url: Optional[str] = None,
volume_mounts: Optional[List[VolumeMount]] = None,
operation: Optional[str] = None,
metadata: Optional[BindingMetadata] = None, # NEW
endpoints: Optional[List[Endpoint]] = None, # NEW
):
# ... existing initialization ...
self.metadata = metadata
self.endpoints = endpoints
```

### GetBindingResponse.endpoints field
```python
# In openbrokerapi/response.py GetBindingResponse class
class GetBindingResponse:
def __init__(
self,
credentials: Optional[dict] = None,
syslog_drain_url: Optional[str] = None,
route_service_url: Optional[str] = None,
volume_mounts: Optional[List[VolumeMount]] = None,
parameters: Optional[dict] = None,
metadata: Optional[BindingMetadata] = None, # NEW
endpoints: Optional[List[Endpoint]] = None, # NEW
):
# ... existing initialization ...
self.metadata = metadata
self.endpoints = endpoints
```

## 5. Service Context Updates

### Service.allow_context_updates field
```python
# In openbrokerapi/service_broker.py Service class
class Service:
def __init__(
self,
id: str,
name: str,
description: str,
bindable: bool,
plans: List[ServicePlan],
tags: Optional[List[str]] = None,
requires: Optional[List[str]] = None,
metadata: Optional[ServiceMetadata] = None,
dashboard_client: Optional[ServiceDashboardClient] = None,
plan_updateable: bool = False,
instances_retrievable: bool = False,
bindings_retrievable: bool = False,
allow_context_updates: Optional[bool] = None, # NEW
**kwargs,
):
# ... existing initialization ...
self.allow_context_updates = allow_context_updates
```

## 6. Error Codes

### MaintenanceInfoConflict error
```python
# In openbrokerapi/errors.py
class ErrMaintenanceInfoConflict(ServiceException):
def __init__(self):
super().__init__("MaintenanceInfoConflict")
```

## 7. Polling Duration

### ServicePlan.maximum_polling_duration field
```python
# In openbrokerapi/catalog.py ServicePlan class
class ServicePlan:
def __init__(
self,
# ... existing fields ...
maximum_polling_duration: Optional[int] = None, # NEW: Duration in seconds
**kwargs,
):
# ... existing initialization ...
self.maximum_polling_duration = maximum_polling_duration
```

## 8. Retry-After Headers

### LastOperationResponse with retry timing
```python
# In openbrokerapi/response.py LastOperationResponse class
class LastOperationResponse:
def __init__(
self,
state: OperationState,
description: str,
retry_after: Optional[int] = None, # NEW: Retry-After header value
instance_usable: Optional[bool] = None,
update_repeatable: Optional[bool] = None,
):
self.state = state.value
self.description = description
self.retry_after = retry_after
self.instance_usable = instance_usable
self.update_repeatable = update_repeatable
```

## Usage Examples

### Service Binding Rotation Example
```python
# Creating a service plan that supports binding rotation
plan = ServicePlan(
id="rotatable-plan",
name="Rotatable Plan",
description="A plan that supports credential rotation",
binding_rotatable=True, # Enable rotation
maintenance_info=MaintenanceInfo(
version="1.0.0",
description="Initial version"
)
)

# Creating a successor binding during rotation
bind_details = BindDetails(
service_id="service-123",
plan_id="rotatable-plan",
predecessor_binding_id="old-binding-456" # Rotating from this binding
)
```

### Service with Maintenance Info Example
```python
# Service with maintenance support
service = Service(
id="maintenance-service",
name="Maintenance Service",
description="Service supporting maintenance operations",
bindable=True,
allow_context_updates=True, # Allow context updates
plans=[
ServicePlan(
id="plan-1",
name="Standard",
description="Standard plan with maintenance",
maintenance_info=MaintenanceInfo(
version="2.1.0",
description="Latest stable version"
),
maximum_polling_duration=300 # 5 minutes max polling
)
]
)
```

### Binding with Expiration Metadata Example
```python
# Binding response with expiration information
binding_response = BindResponse(
credentials={"username": "user", "password": "pass"},
metadata=BindingMetadata(
expires_at="2024-12-31T23:59:59.0Z",
renew_before="2024-12-30T23:59:59.0Z"
),
endpoints=[
Endpoint(
host="database.example.com",
ports=["5432"],
protocol="tcp"
)
]
)
```
Loading