Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

38-add-commit-method #54

Merged
merged 16 commits into from
Nov 30, 2024
Merged
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
7 changes: 7 additions & 0 deletions docs/about/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## Version 0.3.2

- Added support for performing commits
- Added support for pulling in job status

---

## Version 0.3.1

- Added support for Service Group objects
Expand Down
223 changes: 105 additions & 118 deletions docs/sdk/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

The SCM (Strata Cloud Manager) client module provides the primary interface for interacting with the Palo Alto Networks
Strata Cloud Manager API. It handles authentication, request management, and provides a clean interface for making API
calls with proper error handling.
calls with proper error handling and Pydantic model validation.

## SCM Client

Expand All @@ -21,7 +21,7 @@ class Scm:
client_id: str,
client_secret: str,
tsg_id: str,
api_base_url: str,
api_base_url: str = "https://api.strata.paloaltonetworks.com",
log_level: str = "ERROR"
)
```
Expand Down Expand Up @@ -51,7 +51,7 @@ def request(self, method: str, endpoint: str, **kwargs)

</div>

Makes a generic HTTP request to the API.
Makes a generic HTTP request to the API and returns a Pydantic model or None.

**Parameters:**

Expand All @@ -69,7 +69,7 @@ def get(self, endpoint: str, params: Optional[Dict[str, Any]] = None, **kwargs)

</div>

Makes a GET request to the specified endpoint.
Makes a GET request to the specified endpoint, automatically handling token refresh.

<div class="termy">

Expand All @@ -81,7 +81,7 @@ def post(self, endpoint: str, **kwargs)

</div>

Makes a POST request to the specified endpoint.
Makes a POST request to the specified endpoint, automatically handling token refresh.

<div class="termy">

Expand All @@ -93,7 +93,7 @@ def put(self, endpoint: str, **kwargs)

</div>

Makes a PUT request to the specified endpoint.
Makes a PUT request to the specified endpoint, automatically handling token refresh.

<div class="termy">

Expand All @@ -105,7 +105,43 @@ def delete(self, endpoint: str, **kwargs)

</div>

Makes a DELETE request to the specified endpoint.
Makes a DELETE request to the specified endpoint, automatically handling token refresh.

### Job Management Methods

<div class="termy">

<!-- termynal -->

```python
def list_jobs(
self,
limit: int = 100,
offset: int = 0,
parent_id: Optional[str] = None
) -> JobListResponse
```

</div>

Lists jobs with pagination support and optional parent ID filtering.

<div class="termy">

<!-- termynal -->

```python
def wait_for_job(
self,
job_id: str,
timeout: int = 300,
poll_interval: int = 10
) -> Optional[JobStatusResponse]
```

</div>

Waits for a job to complete with configurable timeout and polling interval.

## Usage Examples

Expand All @@ -122,8 +158,7 @@ from scm.client import Scm
client = Scm(
client_id="your_client_id",
client_secret="your_client_secret",
tsg_id="your_tsg_id",
api_base_url="https://api.example.com"
tsg_id="your_tsg_id"
)
```

Expand All @@ -141,7 +176,6 @@ client = Scm(
client_id="your_client_id",
client_secret="your_client_secret",
tsg_id="your_tsg_id",
api_base_url="https://api.example.com",
log_level="DEBUG" # Enable detailed logging
)
```
Expand All @@ -166,58 +200,47 @@ response = client.get(

</div>

#### POST Request Example
#### POST Request Example with Pydantic Models

<div class="termy">

<!-- termynal -->

```python
# Create a new address object
new_address = {
"name": "example-address",
"folder": "Texas",
"ip_netmask": "192.168.1.0/24"
}
response = client.post(
endpoint="/config/objects/v1/addresses",
json=new_address
)
```

</div>
from scm.models.operations import CandidatePushRequestModel

#### PUT Request Example

<div class="termy">

<!-- termynal -->
# Create a commit request
commit_request = CandidatePushRequestModel(
folders=["Texas"],
admin=["[email protected]"],
description="Initial commit"
)

```python
# Update an existing address
updated_address = {
"name": "example-address",
"ip_netmask": "192.168.2.0/24"
}
response = client.put(
endpoint="/config/objects/v1/addresses/example-address",
json=updated_address
response = client.post(
endpoint="/config/operations/v1/config-versions/candidate:push",
json=commit_request.model_dump()
)
```

</div>

#### DELETE Request Example
#### Commit Changes Example

<div class="termy">

<!-- termynal -->

```python
# Delete an address object
response = client.delete(
endpoint="/config/objects/v1/addresses/example-address"
# Commit changes with synchronous wait
response = client.commit(
folders=["Texas"],
description="Configuration update",
sync=True,
timeout=300
)

if response.success:
print(f"Commit successful! Job ID: {response.job_id}")
```

</div>
Expand All @@ -233,11 +256,12 @@ response = client.delete(
```python
from scm.client import Scm
from scm.exceptions import (
APIError,
AuthenticationError,
NotFoundError,
BadRequestError,
InvalidObjectError,
ServerError,
APIError
TimeoutError
)


Expand All @@ -251,45 +275,33 @@ def perform_api_operations():
log_level="INFO"
)

# Perform API operations
try:
# List addresses
addresses = client.get("/config/objects/v1/addresses")
print(f"Found {len(addresses)} addresses")

# Create new address
new_address = {
"name": "test-address",
"folder": "Texas",
"ip_netmask": "192.168.1.0/24"
}
created = client.post("/config/objects/v1/addresses", json=new_address)
print(f"Created address: {created['name']}")
# Commit changes
response = client.commit(
folders=["Texas"],
description="Test commit",
sync=True
)
print(f"Commit job ID: {response.job_id}")

except AuthenticationError as e:
print(f"Authentication failed: {e.message}")
print(f"Error code: {e.error_code}")
print(f"HTTP status: {e.http_status_code}")

except NotFoundError as e:
print(f"Resource not found: {e.message}")
if e.details:
print(f"Additional details: {e.details}")

except BadRequestError as e:
print(f"Invalid request: {e.message}")
except InvalidObjectError as e:
print(f"Invalid request data: {e.message}")
if e.details:
print(f"Validation errors: {e.details}")

except TimeoutError as e:
print(f"Operation timed out: {str(e)}")

except ServerError as e:
print(f"Server error occurred: {e.message}")
print(f"Status code: {e.http_status_code}")

except APIError as e:
print(f"API error occurred: {e}")

except Exception as e:
print(f"Unexpected error: {str(e)}")
```

</div>
Expand All @@ -299,20 +311,23 @@ def perform_api_operations():
### Client Configuration

1. **Logging Configuration**

- Use appropriate log levels for different environments
- Set to DEBUG for development and troubleshooting
- Set to ERROR or WARNING for production

2. **Error Handling**

- Always wrap API calls in try-except blocks
- Handle specific exceptions before generic ones
- Log error details for troubleshooting
- Include proper error recovery mechanisms

3. **Session Management**
- Reuse client instances when possible
- Properly close/cleanup sessions when done
- Handle token refresh scenarios
3. **Token Management**

- The client automatically handles token refresh
- No manual token management required
- Tokens are refreshed when expired before requests

### Code Examples

Expand All @@ -332,43 +347,16 @@ client = Scm(


# Reuse for multiple operations
def get_address(object_uuid: str):
return client.get(f"/config/objects/v1/addresses/{object_uuid}")


def create_address(address_data: dict):
return client.post("/config/objects/v1/addresses", json=address_data)
```

</div>

#### Using with Context Managers

<div class="termy">

<!-- termynal -->

```python
from contextlib import contextmanager
def commit_changes(folders: List[str], description: str):
return client.commit(
folders=folders,
description=description,
sync=True
)


@contextmanager
def scm_client_session(**kwargs):
client = Scm(**kwargs)
try:
yield client
finally:
# Cleanup if needed
pass


# Usage
with scm_client_session(
client_id="your_client_id",
client_secret="your_client_secret",
tsg_id="your_tsg_id"
) as client:
addresses = client.get("/config/objects/v1/addresses")
def check_job_status(job_id: str):
return client.get_job_status(job_id)
```

</div>
Expand All @@ -377,20 +365,19 @@ with scm_client_session(

### Authentication Failures

- Invalid credentials
- Expired tokens
- Missing required parameters
- Invalid credentials (`AuthenticationError`)
- Expired tokens (handled automatically)
- Missing required parameters (`InvalidObjectError`)

### Request Failures

- Malformed requests
- Invalid parameters
- Missing required fields
- Resource not found
- Duplicate resources
- Malformed requests (`InvalidObjectError`)
- Invalid parameters (`InvalidObjectError`)
- Resource not found (`NotFoundError`)
- Operation timeouts (`TimeoutError`)

### Server Errors

- Timeouts
- Service unavailable
- Internal server errors
- Service unavailable (`ServerError`)
- Internal server errors (`ServerError`)
- Gateway timeouts (`GatewayTimeoutError`)
Loading