diff --git a/scm/config/objects/__init__.py b/scm/config/objects/__init__.py index 9997531c..1bad5cd5 100644 --- a/scm/config/objects/__init__.py +++ b/scm/config/objects/__init__.py @@ -8,3 +8,9 @@ from .service import Service from .service_group import ServiceGroup from .tag import Tag + +""" +# these are SDK implementations created by not currently implemented in the API +# these will all return a 403 status code until implemented +from .auto_tag_actions import AutoTagAction +""" diff --git a/scm/config/objects/auto_tag_actions.py b/scm/config/objects/auto_tag_actions.py index 2b3baa26..3b6fda93 100644 --- a/scm/config/objects/auto_tag_actions.py +++ b/scm/config/objects/auto_tag_actions.py @@ -1,306 +1,346 @@ # scm/config/objects/auto_tag_actions.py -# Standard library imports -import logging -from typing import List, Dict, Any, Optional - -# Local SDK imports -from scm.config import BaseObject -from scm.exceptions import ( - InvalidObjectError, - MissingQueryParameterError, -) -from scm.models.objects.auto_tag_actions import ( - AutoTagActionCreateModel, - AutoTagActionUpdateModel, - AutoTagActionResponseModel, -) - - -class AutoTagAction(BaseObject): - """ - Manages Auto-Tag Action objects in Palo Alto Networks' Strata Cloud Manager. - """ - - ENDPOINT = "/auto-tag-actions" - DEFAULT_LIMIT = 10000 - - def __init__(self, api_client): - super().__init__(api_client) - self.logger = logging.getLogger(__name__) - - def create( - self, - data: Dict[str, Any], - ) -> AutoTagActionResponseModel: - """ - Creates a new Auto-Tag Action object. - - Returns: - AutoTagActionResponseModel - """ - auto_tag_action = AutoTagActionCreateModel(**data) - payload = auto_tag_action.model_dump(exclude_unset=True) - response: Dict[str, Any] = self.api_client.post( - self.ENDPOINT, - json=payload, - ) - return AutoTagActionResponseModel(**response) - - def update( - self, - auto_tag_action: AutoTagActionUpdateModel, - ) -> AutoTagActionResponseModel: - """ - Updates an existing auto-tag action object. - - Args: - auto_tag_action: AutoTagActionUpdateModel instance containing the update data - - Returns: - AutoTagActionResponseModel - """ - payload = auto_tag_action.model_dump(exclude_unset=True) - # Note: The API requires name to identify the object; no endpoint for id-based updates. - # We send the request to the same endpoint without an object_id in the URL. - if "id" in payload: - payload.pop("id", None) - - response: Dict[str, Any] = self.api_client.put( - self.ENDPOINT, - json=payload, - ) - - return AutoTagActionResponseModel(**response) - - @staticmethod - def _apply_filters( - auto_tag_actions: List[AutoTagActionResponseModel], - filters: Dict[str, Any], - ) -> List[AutoTagActionResponseModel]: - """ - Apply client-side filtering to the list of auto-tag actions. - - Args: - auto_tag_actions: List of AutoTagActionResponseModel objects - filters: Dictionary of filter criteria - - Returns: - List[AutoTagActionResponseModel]: Filtered list of auto-tag actions - """ - # No filters defined in this specification. - return auto_tag_actions - - @staticmethod - def _build_container_params( - folder: Optional[str], - snippet: Optional[str], - device: Optional[str], - ) -> dict: - """ - Builds a dictionary of container parameters based on the provided arguments. - """ - return { - k: v - for k, v in {"folder": folder, "snippet": snippet, "device": device}.items() - if v is not None - } - - def list( - self, - folder: Optional[str] = None, - snippet: Optional[str] = None, - device: Optional[str] = None, - **filters, - ) -> List[AutoTagActionResponseModel]: - """ - Lists auto-tag action objects with optional filtering. - - Args: - folder (str, optional): The folder in which the resource is defined. - snippet (str, optional): The snippet in which the resource is defined. - device (str, optional): The device in which the resource is defined. - **filters: Additional filters (no filters defined for auto-tag actions). - - Returns: - List[AutoTagActionResponseModel]: A list of auto-tag action objects. - """ - if folder == "": - raise MissingQueryParameterError( - message="Field 'folder' cannot be empty", - error_code="E003", - http_status_code=400, - details={ - "field": "folder", - "error": '"folder" is not allowed to be empty', - }, - ) - - params = {"limit": self.DEFAULT_LIMIT} - - container_parameters = self._build_container_params(folder, snippet, device) - if len(container_parameters) != 1: - raise InvalidObjectError( - message="Exactly one of 'folder', 'snippet', or 'device' must be provided.", - error_code="E003", - http_status_code=400, - details={"error": "Invalid container parameters"}, - ) - - params.update(container_parameters) - - response = self.api_client.get( - self.ENDPOINT, - params=params, - ) - - if not isinstance(response, dict): - raise InvalidObjectError( - message="Invalid response format: expected dictionary", - error_code="E003", - http_status_code=500, - details={"error": "Response is not a dictionary"}, - ) - - if "data" not in response: - raise InvalidObjectError( - message="Invalid response format: missing 'data' field", - error_code="E003", - http_status_code=500, - details={ - "field": "data", - "error": '"data" field missing in the response', - }, - ) - - if not isinstance(response["data"], list): - raise InvalidObjectError( - message="Invalid response format: 'data' field must be a list", - error_code="E003", - http_status_code=500, - details={ - "field": "data", - "error": '"data" field must be a list', - }, - ) - - auto_tag_actions = [ - AutoTagActionResponseModel(**item) for item in response["data"] - ] - return self._apply_filters(auto_tag_actions, filters) - - def fetch( - self, - name: str, - folder: Optional[str] = None, - snippet: Optional[str] = None, - device: Optional[str] = None, - ) -> AutoTagActionResponseModel: - """ - Fetches a single auto-tag action by name. - - Args: - name (str): The name of the auto-tag action to fetch. - folder (str, optional): The folder in which the resource is defined. - snippet (str, optional): The snippet in which the resource is defined. - device (str, optional): The device in which the resource is defined. - - Returns: - AutoTagActionResponseModel: The fetched auto-tag action object as a Pydantic model. - """ - if not name: - raise MissingQueryParameterError( - message="Field 'name' cannot be empty", - error_code="E003", - http_status_code=400, - details={"field": "name", "error": '"name" is not allowed to be empty'}, - ) - - if folder == "": - raise MissingQueryParameterError( - message="Field 'folder' cannot be empty", - error_code="E003", - http_status_code=400, - details={ - "field": "folder", - "error": '"folder" is not allowed to be empty', - }, - ) - - params = {} - container_parameters = self._build_container_params(folder, snippet, device) - if len(container_parameters) != 1: - raise InvalidObjectError( - message="Exactly one of 'folder', 'snippet', or 'device' must be provided.", - error_code="E003", - http_status_code=400, - details={ - "error": "Exactly one of 'folder', 'snippet', or 'device' must be provided." - }, - ) - - params.update(container_parameters) - params["name"] = name - - response = self.api_client.get( - self.ENDPOINT, - params=params, - ) - - if not isinstance(response, dict): - raise InvalidObjectError( - message="Invalid response format: expected dictionary", - error_code="E003", - http_status_code=500, - details={"error": "Response is not a dictionary"}, - ) - - if "id" in response: - return AutoTagActionResponseModel(**response) - else: - raise InvalidObjectError( - message="Invalid response format: missing 'id' field", - error_code="E003", - http_status_code=500, - details={"error": "Response missing 'id' field"}, - ) - - def delete( - self, - name: str, - folder: Optional[str] = None, - snippet: Optional[str] = None, - device: Optional[str] = None, - ) -> None: - """ - Deletes an auto-tag action object by name. - - Args: - name (str): The name of the auto-tag action to delete. - folder (str, optional): The folder in which the resource is defined. - snippet (str, optional): The snippet in which the resource is defined. - device (str, optional): The device in which the resource is defined. - """ - if not name: - raise MissingQueryParameterError( - message="Field 'name' cannot be empty", - error_code="E003", - http_status_code=400, - details={"field": "name", "error": '"name" is not allowed to be empty'}, - ) - - container_parameters = self._build_container_params(folder, snippet, device) - if len(container_parameters) != 1: - raise InvalidObjectError( - message="Exactly one of 'folder', 'snippet', or 'device' must be provided.", - error_code="E003", - http_status_code=400, - details={"error": "Invalid container parameters"}, - ) - - params = {} - params.update(container_parameters) - params["name"] = name - - # Note: The API requires a 'name' query param to identify the action to delete. - self.api_client.delete(self.ENDPOINT, params=params) +# +# # Standard library imports +# import logging +# from typing import List, Dict, Any, Optional +# +# # Local SDK imports +# from scm.config import BaseObject +# from scm.exceptions import ( +# InvalidObjectError, +# MissingQueryParameterError, +# ) +# from scm.models.objects.auto_tag_actions import ( +# AutoTagActionCreateModel, +# AutoTagActionUpdateModel, +# AutoTagActionResponseModel, +# ) +# +# +# class AutoTagAction(BaseObject): +# """ +# Manages Auto-Tag Action objects in Palo Alto Networks' Strata Cloud Manager. +# """ +# +# ENDPOINT = "/config/objects/v1/auto-tag-actions" +# DEFAULT_LIMIT = 10000 +# +# def __init__( +# self, +# api_client, +# ): +# super().__init__(api_client) +# self.logger = logging.getLogger(__name__) +# +# def create( +# self, +# data: Dict[str, Any], +# ) -> AutoTagActionResponseModel: +# """ +# Creates a new Auto-Tag Action object. +# +# Returns: +# AutoTagActionResponseModel +# """ +# # Use the dictionary "data" to pass into Pydantic and return a modeled object +# auto_tag_action = AutoTagActionCreateModel(**data) +# +# # Convert back to a Python dictionary, removing any unset fields +# payload = auto_tag_action.model_dump(exclude_unset=True) +# +# # Send the updated object to the remote API as JSON, expecting a dictionary object to be returned +# response: Dict[str, Any] = self.api_client.post( +# self.ENDPOINT, +# json=payload, +# ) +# +# # Return the SCM API response as a new Pydantic object +# return AutoTagActionResponseModel(**response) +# +# def update( +# self, +# auto_tag_action: AutoTagActionUpdateModel, +# ) -> AutoTagActionResponseModel: +# """ +# Updates an existing auto-tag action object. +# +# Args: +# auto_tag_action: AutoTagActionUpdateModel instance containing the update data +# +# Returns: +# AutoTagActionResponseModel +# """ +# # Convert to dict for API request, excluding unset fields +# payload = auto_tag_action.model_dump(exclude_unset=True) +# +# # Note: The API requires name to identify the object; no endpoint for id-based updates +# if "id" in payload: +# payload.pop("id", None) +# +# # Send the updated object to the remote API as JSON +# response: Dict[str, Any] = self.api_client.put( +# self.ENDPOINT, +# json=payload, +# ) +# +# # Return the SCM API response as a new Pydantic object +# return AutoTagActionResponseModel(**response) +# +# @staticmethod +# def _apply_filters( +# auto_tag_actions: List[AutoTagActionResponseModel], +# filters: Dict[str, Any], +# ) -> List[AutoTagActionResponseModel]: +# """ +# Apply client-side filtering to the list of auto-tag actions. +# +# Args: +# auto_tag_actions: List of AutoTagActionResponseModel objects +# filters: Dictionary of filter criteria +# +# Returns: +# List[AutoTagActionResponseModel]: Filtered list of auto-tag actions +# """ +# # No filters defined in this specification +# return auto_tag_actions +# +# @staticmethod +# def _build_container_params( +# folder: Optional[str], +# snippet: Optional[str], +# device: Optional[str], +# ) -> dict: +# """Builds container parameters dictionary.""" +# return { +# k: v +# for k, v in {"folder": folder, "snippet": snippet, "device": device}.items() +# if v is not None +# } +# +# def list( +# self, +# folder: Optional[str] = None, +# snippet: Optional[str] = None, +# device: Optional[str] = None, +# **filters, +# ) -> List[AutoTagActionResponseModel]: +# """ +# Lists auto-tag action objects with optional filtering. +# +# Args: +# folder: Optional folder name +# snippet: Optional snippet name +# device: Optional device name +# **filters: Additional filters (no filters defined for auto-tag actions) +# +# Returns: +# List[AutoTagActionResponseModel]: A list of auto-tag action objects +# """ +# if folder == "": +# raise MissingQueryParameterError( +# message="Field 'folder' cannot be empty", +# error_code="E003", +# http_status_code=400, +# details={ +# "field": "folder", +# "error": '"folder" is not allowed to be empty', +# }, +# ) +# +# params = {"limit": self.DEFAULT_LIMIT} +# +# container_parameters = self._build_container_params( +# folder, +# snippet, +# device, +# ) +# +# if len(container_parameters) != 1: +# raise InvalidObjectError( +# message="Exactly one of 'folder', 'snippet', or 'device' must be provided.", +# error_code="E003", +# http_status_code=400, +# details={"error": "Invalid container parameters"}, +# ) +# +# params.update(container_parameters) +# +# response = self.api_client.get( +# self.ENDPOINT, +# params=params, +# ) +# +# if not isinstance(response, dict): +# raise InvalidObjectError( +# message="Invalid response format: expected dictionary", +# error_code="E003", +# http_status_code=500, +# details={"error": "Response is not a dictionary"}, +# ) +# +# if "data" not in response: +# raise InvalidObjectError( +# message="Invalid response format: missing 'data' field", +# error_code="E003", +# http_status_code=500, +# details={ +# "field": "data", +# "error": '"data" field missing in the response', +# }, +# ) +# +# if not isinstance(response["data"], list): +# raise InvalidObjectError( +# message="Invalid response format: 'data' field must be a list", +# error_code="E003", +# http_status_code=500, +# details={ +# "field": "data", +# "error": '"data" field must be a list', +# }, +# ) +# +# auto_tag_actions = [ +# AutoTagActionResponseModel(**item) for item in response["data"] +# ] +# +# return self._apply_filters( +# auto_tag_actions, +# filters, +# ) +# +# def fetch( +# self, +# name: str, +# folder: Optional[str] = None, +# snippet: Optional[str] = None, +# device: Optional[str] = None, +# ) -> AutoTagActionResponseModel: +# """ +# Fetches a single auto-tag action by name. +# +# Args: +# name: The name of the auto-tag action to fetch +# folder: Optional folder name +# snippet: Optional snippet name +# device: Optional device name +# +# Returns: +# AutoTagActionResponseModel: The fetched auto-tag action object +# """ +# if not name: +# raise MissingQueryParameterError( +# message="Field 'name' cannot be empty", +# error_code="E003", +# http_status_code=400, +# details={ +# "field": "name", +# "error": '"name" is not allowed to be empty', +# }, +# ) +# +# if folder == "": +# raise MissingQueryParameterError( +# message="Field 'folder' cannot be empty", +# error_code="E003", +# http_status_code=400, +# details={ +# "field": "folder", +# "error": '"folder" is not allowed to be empty', +# }, +# ) +# +# params = {} +# +# container_parameters = self._build_container_params( +# folder, +# snippet, +# device, +# ) +# +# if len(container_parameters) != 1: +# raise InvalidObjectError( +# message="Exactly one of 'folder', 'snippet', or 'device' must be provided.", +# error_code="E003", +# http_status_code=400, +# details={ +# "error": "Exactly one of 'folder', 'snippet', or 'device' must be provided." +# }, +# ) +# +# params.update(container_parameters) +# params["name"] = name +# +# response = self.api_client.get( +# self.ENDPOINT, +# params=params, +# ) +# +# if not isinstance(response, dict): +# raise InvalidObjectError( +# message="Invalid response format: expected dictionary", +# error_code="E003", +# http_status_code=500, +# details={"error": "Response is not a dictionary"}, +# ) +# +# if "id" in response: +# return AutoTagActionResponseModel(**response) +# else: +# raise InvalidObjectError( +# message="Invalid response format: missing 'id' field", +# error_code="E003", +# http_status_code=500, +# details={"error": "Response missing 'id' field"}, +# ) +# +# def delete( +# self, +# name: str, +# folder: Optional[str] = None, +# snippet: Optional[str] = None, +# device: Optional[str] = None, +# ) -> None: +# """ +# Deletes an auto-tag action object by name. +# +# Args: +# name: The name of the auto-tag action to delete +# folder: Optional folder name +# snippet: Optional snippet name +# device: Optional device name +# """ +# if not name: +# raise MissingQueryParameterError( +# message="Field 'name' cannot be empty", +# error_code="E003", +# http_status_code=400, +# details={ +# "field": "name", +# "error": '"name" is not allowed to be empty', +# }, +# ) +# +# container_parameters = self._build_container_params( +# folder, +# snippet, +# device, +# ) +# +# if len(container_parameters) != 1: +# raise InvalidObjectError( +# message="Exactly one of 'folder', 'snippet', or 'device' must be provided.", +# error_code="E003", +# http_status_code=400, +# details={"error": "Invalid container parameters"}, +# ) +# +# params = {} +# params.update(container_parameters) +# params["name"] = name +# +# self.api_client.delete( +# self.ENDPOINT, +# params=params, +# ) diff --git a/scm/models/objects/__init__.py b/scm/models/objects/__init__.py index 817cae91..0a5f2cbf 100644 --- a/scm/models/objects/__init__.py +++ b/scm/models/objects/__init__.py @@ -40,3 +40,13 @@ TagResponseModel, TagUpdateModel, ) + +""" +# these are pydantic implementations created by not currently implemented in the API +# these will all return a 403 status code until implemented +from .auto_tag_actions import ( + AutoTagActionCreateModel, + AutoTagActionResponseModel, + AutoTagActionUpdateModel, +) +""" diff --git a/scm/models/objects/auto_tag_actions.py b/scm/models/objects/auto_tag_actions.py index 020f0446..d00a4951 100644 --- a/scm/models/objects/auto_tag_actions.py +++ b/scm/models/objects/auto_tag_actions.py @@ -1,160 +1,247 @@ # scm/models/objects/auto_tag_actions.py -# Standard library imports -from typing import Optional, List -from uuid import UUID - -# External libraries -from pydantic import ( - BaseModel, - Field, - model_validator, - ConfigDict, - constr, -) - -TagString = constr(max_length=127) - - -class TaggingModel(BaseModel): - """ - Base model for Address objects containing fields common to all CRUD operations. - - Attributes: - target (str): Source or Destination Address, User, X-Forwarded-For Address. - action (str): Add or Remove tag option. - timeout (Optional[int]): Timeout value. - tags (Optional[TagString]): Tags for address object. - """ - - # Required fields - target: str = Field( - ..., - description="Source or Destination Address, User, X-Forwarded-For Address", - ) - action: str = Field( - ..., - description="Add or Remove tag option", - pattern=r"^(add-tag|remove-tag)$", - ) - timeout: Optional[int] = Field( - None, - description="Timeout value", - ) - tags: Optional[List[TagString]] = Field( - None, - description="Tags for address object", - ) - - -class ActionTypeModel(BaseModel): - tagging: TaggingModel = Field( - ..., - description="Tagging configuration", - ) - - -class ActionModel(BaseModel): - name: str = Field( - ..., - description="Name of the action", - max_length=63, - pattern=r"^[0-9a-zA-Z._-]+$", - ) - type: ActionTypeModel = Field( - ..., - description="Type configuration for the action", - ) - - -class AutoTagActionBaseModel(BaseModel): - model_config = ConfigDict( - populate_by_name=True, - validate_assignment=True, - arbitrary_types_allowed=True, - ) - - name: str = Field( - ..., - description="Alphanumeric string [ 0-9a-zA-Z._-]", - max_length=63, - pattern=r"^[0-9a-zA-Z._-]+$", - ) - description: Optional[str] = Field( - None, - description="Description", - max_length=1023, - ) - filter: str = Field( - ..., - description="Tag based filter defining group membership", - max_length=2047, - ) - send_to_panorama: Optional[bool] = Field( - None, - description="Send to Panorama", - ) - quarantine: Optional[bool] = Field( - None, - description="Quarantine option", - ) - actions: Optional[List[ActionModel]] = Field( - None, - description="List of actions", - ) - folder: Optional[str] = Field( - None, - pattern=r"^[a-zA-Z\d\-_. ]+$", - max_length=64, - description="The folder in which the resource is defined", - ) - snippet: Optional[str] = Field( - None, - pattern=r"^[a-zA-Z\d\-_. ]+$", - max_length=64, - description="The snippet in which the resource is defined", - ) - device: Optional[str] = Field( - None, - pattern=r"^[a-zA-Z\d\-_. ]+$", - max_length=64, - description="The device in which the resource is defined", - ) - - -class AutoTagActionCreateModel(AutoTagActionBaseModel): - @model_validator(mode="after") - def validate_container_type(self) -> "AutoTagActionCreateModel": - container_fields = [ - "folder", - "snippet", - "device", - ] - provided = [ - field for field in container_fields if getattr(self, field) is not None - ] - if len(provided) != 1: - raise ValueError( - "Exactly one of 'folder', 'snippet', or 'device' must be provided." - ) - return self - - -class AutoTagActionUpdateModel(AutoTagActionBaseModel): - id: Optional[UUID] = Field( - ..., - description="The UUID of the resource", - examples=["123e4567-e89b-12d3-a456-426655440000"], - ) - - -class AutoTagActionResponseModel(AutoTagActionBaseModel): - id: UUID = Field( - ..., - description="The UUID of the resource", - examples=["123e4567-e89b-12d3-a456-426655440000"], - ) - log_type: str = Field( - ..., - description="Log type of the resource", - ) +# # Standard library imports +# from typing import Optional, List +# from uuid import UUID +# +# # External libraries +# from pydantic import ( +# BaseModel, +# Field, +# field_validator, +# model_validator, +# ConfigDict, +# constr, +# ) +# +# TagString = constr(max_length=127) +# +# +# class TaggingModel(BaseModel): +# """ +# Base model for tagging configuration. +# +# Attributes: +# target (str): Source or Destination Address, User, X-Forwarded-For Address. +# action (str): Add or Remove tag option. +# timeout (Optional[int]): Timeout value in seconds. +# tags (Optional[List[TagString]]): List of tags to apply. +# """ +# +# target: str = Field( +# ..., +# description="Source or Destination Address, User, X-Forwarded-For Address", +# ) +# action: str = Field( +# ..., +# description="Add or Remove tag option", +# pattern=r"^(add-tag|remove-tag)$", +# ) +# timeout: Optional[int] = Field( +# None, +# description="Timeout value in seconds", +# ) +# tags: Optional[List[TagString]] = Field( +# None, +# description="List of tags to apply", +# ) +# +# @field_validator("tags", mode="before") +# def ensure_list_of_strings(cls, v): # noqa +# if isinstance(v, str): +# return [v] +# elif isinstance(v, list): +# return v +# else: +# raise ValueError("Tags must be a string or a list of strings") +# +# @field_validator("tags") +# def ensure_unique_items(cls, v): # noqa +# if v and len(v) != len(set(v)): +# raise ValueError("List items must be unique") +# return v +# +# +# class ActionTypeModel(BaseModel): +# """ +# Model for action type configuration. +# +# Attributes: +# tagging (TaggingModel): Tagging configuration settings. +# """ +# +# tagging: TaggingModel = Field( +# ..., +# description="Tagging configuration", +# ) +# +# +# class ActionModel(BaseModel): +# """ +# Model for individual actions. +# +# Attributes: +# name (str): Name of the action. +# type (ActionTypeModel): Type configuration for the action. +# """ +# +# name: str = Field( +# ..., +# description="Name of the action", +# max_length=63, +# pattern=r"^[0-9a-zA-Z._-]+$", +# ) +# type: ActionTypeModel = Field( +# ..., +# description="Type configuration for the action", +# ) +# +# +# class AutoTagActionBaseModel(BaseModel): +# """ +# Base model for Auto Tag Action objects containing fields common to all CRUD operations. +# +# Attributes: +# name (str): Name of the auto tag action. +# log_type (str): Log type of the resource. +# description (Optional[str]): Description of the auto tag action. +# filter (str): Tag based filter defining group membership. +# send_to_panorama (Optional[bool]): Whether to send to Panorama. +# quarantine (Optional[bool]): Quarantine option setting. +# actions (Optional[List[ActionModel]]): List of actions to perform. +# folder (Optional[str]): The folder in which the resource is defined. +# snippet (Optional[str]): The snippet in which the resource is defined. +# device (Optional[str]): The device in which the resource is defined. +# """ +# +# # Pydantic model configuration +# model_config = ConfigDict( +# populate_by_name=True, +# validate_assignment=True, +# arbitrary_types_allowed=True, +# ) +# +# # Required fields +# name: str = Field( +# ..., +# description="Alphanumeric string [ 0-9a-zA-Z._-]", +# max_length=63, +# pattern=r"^[0-9a-zA-Z._-]+$", +# ) +# filter: str = Field( +# ..., +# description="Tag based filter defining group membership", +# max_length=2047, +# ) +# log_type: str = Field( +# ..., +# description="Log type of the resource", +# ) +# +# # Optional fields +# description: Optional[str] = Field( +# None, +# description="Description of the auto tag action", +# max_length=1023, +# ) +# send_to_panorama: Optional[bool] = Field( +# None, +# description="Send to Panorama", +# ) +# quarantine: Optional[bool] = Field( +# None, +# description="Quarantine option", +# ) +# actions: Optional[List[ActionModel]] = Field( +# None, +# description="List of actions", +# ) +# +# # Container Types +# folder: Optional[str] = Field( +# None, +# pattern=r"^[a-zA-Z\d\-_. ]+$", +# max_length=64, +# description="The folder in which the resource is defined", +# examples=["Prisma Access"], +# ) +# snippet: Optional[str] = Field( +# None, +# pattern=r"^[a-zA-Z\d\-_. ]+$", +# max_length=64, +# description="The snippet in which the resource is defined", +# examples=["My Snippet"], +# ) +# device: Optional[str] = Field( +# None, +# pattern=r"^[a-zA-Z\d\-_. ]+$", +# max_length=64, +# description="The device in which the resource is defined", +# examples=["My Device"], +# ) +# +# +# class AutoTagActionCreateModel(AutoTagActionBaseModel): +# """ +# Represents the creation of a new Auto Tag Action object. +# +# This class defines the structure and validation rules for an AutoTagActionCreateModel object, +# it inherits all fields from the AutoTagActionBaseModel class, and provides a custom validator +# to ensure that the creation request contains exactly one of the following container types: +# - folder +# - snippet +# - device +# +# Error: +# ValueError: Raised when container type validation fails. +# """ +# +# @model_validator(mode="after") +# def validate_container_type(self) -> "AutoTagActionCreateModel": +# """Validates that exactly one container type is provided.""" +# container_fields = [ +# "folder", +# "snippet", +# "device", +# ] +# provided = [ +# field for field in container_fields if getattr(self, field) is not None +# ] +# if len(provided) != 1: +# raise ValueError( +# "Exactly one of 'folder', 'snippet', or 'device' must be provided." +# ) +# return self +# +# +# class AutoTagActionUpdateModel(AutoTagActionBaseModel): +# """ +# Represents the update of an existing Auto Tag Action object. +# +# This class defines the structure and validation rules for an AutoTagActionUpdateModel object. +# """ +# +# id: Optional[UUID] = Field( +# ..., +# description="The UUID of the resource", +# examples=["123e4567-e89b-12d3-a456-426655440000"], +# ) +# +# +# class AutoTagActionResponseModel(AutoTagActionBaseModel): +# """ +# Represents the response model for Auto Tag Action objects. +# +# This class defines the structure for an AutoTagActionResponseModel object, +# it inherits all fields from the AutoTagActionBaseModel class and adds its own +# attributes for id. +# +# Attributes: +# id (UUID): The UUID of the resource. +# """ +# +# id: UUID = Field( +# ..., +# description="The UUID of the resource", +# examples=["123e4567-e89b-12d3-a456-426655440000"], +# )