diff --git a/scaleway-async/scaleway_async/audit_trail/v1alpha1/__init__.py b/scaleway-async/scaleway_async/audit_trail/v1alpha1/__init__.py index 04afd89e..d80c01fa 100644 --- a/scaleway-async/scaleway_async/audit_trail/v1alpha1/__init__.py +++ b/scaleway-async/scaleway_async/audit_trail/v1alpha1/__init__.py @@ -38,8 +38,11 @@ from .types import Event from .types import SystemEvent from .types import ProductService +from .types import ExportJobS3 from .types import ListCombinedEventsResponseCombinedEvent from .types import Product +from .types import CreateExportJobRequest +from .types import ExportJob from .types import ListAuthenticationEventsRequest from .types import ListAuthenticationEventsResponse from .types import ListCombinedEventsRequest @@ -89,8 +92,11 @@ "Event", "SystemEvent", "ProductService", + "ExportJobS3", "ListCombinedEventsResponseCombinedEvent", "Product", + "CreateExportJobRequest", + "ExportJob", "ListAuthenticationEventsRequest", "ListAuthenticationEventsResponse", "ListCombinedEventsRequest", diff --git a/scaleway-async/scaleway_async/audit_trail/v1alpha1/api.py b/scaleway-async/scaleway_async/audit_trail/v1alpha1/api.py index a05cc66b..eb22c82a 100644 --- a/scaleway-async/scaleway_async/audit_trail/v1alpha1/api.py +++ b/scaleway-async/scaleway_async/audit_trail/v1alpha1/api.py @@ -16,16 +16,21 @@ ListCombinedEventsRequestOrderBy, ListEventsRequestOrderBy, ResourceType, + CreateExportJobRequest, + ExportJob, + ExportJobS3, ListAuthenticationEventsResponse, ListCombinedEventsResponse, ListEventsResponse, ListProductsResponse, ) from .marshalling import ( + unmarshal_ExportJob, unmarshal_ListAuthenticationEventsResponse, unmarshal_ListCombinedEventsResponse, unmarshal_ListEventsResponse, unmarshal_ListProductsResponse, + marshal_CreateExportJobRequest, ) @@ -248,3 +253,53 @@ async def list_products( self._throw_on_error(res) return unmarshal_ListProductsResponse(res.json()) + + async def create_export_job( + self, + *, + name: str, + region: Optional[ScwRegion] = None, + organization_id: Optional[str] = None, + s3: Optional[ExportJobS3] = None, + tags: Optional[dict[str, str]] = None, + ) -> ExportJob: + """ + Create an export job. + Create an export job for a specified organization. This allows you to export audit trail events to a destination, such as an S3 bucket. The request requires the organization ID, a name for the export, and a destination configuration. + :param name: Name of the export. + :param region: Region to target. If none is passed will use default region from the config. + :param organization_id: ID of the Organization to target. + :param s3: The configuration specifying the bucket where the audit trail events will be exported. + One-Of ('destination'): at most one of 's3' could be set. + :param tags: Tags of the export. + :return: :class:`ExportJob ` + + Usage: + :: + + result = await api.create_export_job( + name="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + + res = self._request( + "POST", + f"/audit-trail/v1alpha1/regions/{param_region}/export-jobs", + body=marshal_CreateExportJobRequest( + CreateExportJobRequest( + name=name, + region=region, + organization_id=organization_id, + tags=tags, + s3=s3, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_ExportJob(res.json()) diff --git a/scaleway-async/scaleway_async/audit_trail/v1alpha1/marshalling.py b/scaleway-async/scaleway_async/audit_trail/v1alpha1/marshalling.py index 8c6d6fcb..dbfa196a 100644 --- a/scaleway-async/scaleway_async/audit_trail/v1alpha1/marshalling.py +++ b/scaleway-async/scaleway_async/audit_trail/v1alpha1/marshalling.py @@ -4,12 +4,19 @@ from typing import Any from dateutil import parser +from scaleway_core.profile import ProfileDefaults +from scaleway_core.utils import ( + OneOfPossibility, + resolve_one_of, +) from .types import ( AuthenticationEventFailureReason, AuthenticationEventMFAType, AuthenticationEventMethod, AuthenticationEventOrigin, AuthenticationEventResult, + ExportJobS3, + ExportJob, AccountOrganizationInfo, AccountProjectInfo, AccountUserInfo, @@ -44,12 +51,103 @@ ProductService, Product, ListProductsResponse, + CreateExportJobRequest, ) from ...std.types import ( CountryCode as StdCountryCode, ) +def unmarshal_ExportJobS3(data: Any) -> ExportJobS3: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ExportJobS3' failed as data isn't a dictionary." + ) + + args: dict[str, Any] = {} + + field = data.get("bucket", None) + if field is not None: + args["bucket"] = field + else: + args["bucket"] = None + + field = data.get("region", None) + if field is not None: + args["region"] = field + else: + args["region"] = None + + field = data.get("prefix", None) + if field is not None: + args["prefix"] = field + else: + args["prefix"] = None + + field = data.get("project_id", None) + if field is not None: + args["project_id"] = field + else: + args["project_id"] = None + + return ExportJobS3(**args) + + +def unmarshal_ExportJob(data: Any) -> ExportJob: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ExportJob' failed as data isn't a dictionary." + ) + + args: dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + else: + args["id"] = None + + field = data.get("organization_id", None) + if field is not None: + args["organization_id"] = field + else: + args["organization_id"] = None + + field = data.get("name", None) + if field is not None: + args["name"] = field + else: + args["name"] = None + + field = data.get("tags", None) + if field is not None: + args["tags"] = field + else: + args["tags"] = {} + + field = data.get("s3", None) + if field is not None: + args["s3"] = unmarshal_ExportJobS3(field) + else: + args["s3"] = None + + field = data.get("created_at", None) + if field is not None: + args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["created_at"] = None + + field = data.get("last_run_at", None) + if field is not None: + args["last_run_at"] = ( + parser.isoparse(field) if isinstance(field, str) else field + ) + else: + args["last_run_at"] = None + + return ExportJob(**args) + + def unmarshal_AccountOrganizationInfo(data: Any) -> AccountOrganizationInfo: if not isinstance(data, dict): raise TypeError( @@ -1144,3 +1242,55 @@ def unmarshal_ListProductsResponse(data: Any) -> ListProductsResponse: args["total_count"] = 0 return ListProductsResponse(**args) + + +def marshal_ExportJobS3( + request: ExportJobS3, + defaults: ProfileDefaults, +) -> dict[str, Any]: + output: dict[str, Any] = {} + + if request.bucket is not None: + output["bucket"] = request.bucket + + if request.region is not None: + output["region"] = request.region + else: + output["region"] = defaults.default_region + + if request.prefix is not None: + output["prefix"] = request.prefix + + if request.project_id is not None: + output["project_id"] = request.project_id + + return output + + +def marshal_CreateExportJobRequest( + request: CreateExportJobRequest, + defaults: ProfileDefaults, +) -> dict[str, Any]: + output: dict[str, Any] = {} + output.update( + resolve_one_of( + [ + OneOfPossibility( + param="s3", value=request.s3, marshal_func=marshal_ExportJobS3 + ), + ] + ), + ) + + if request.name is not None: + output["name"] = request.name + + if request.organization_id is not None: + output["organization_id"] = request.organization_id + else: + output["organization_id"] = defaults.default_organization_id + + if request.tags is not None: + output["tags"] = {key: value for key, value in request.tags.items()} + + return output diff --git a/scaleway-async/scaleway_async/audit_trail/v1alpha1/types.py b/scaleway-async/scaleway_async/audit_trail/v1alpha1/types.py index df31b468..829e5772 100644 --- a/scaleway-async/scaleway_async/audit_trail/v1alpha1/types.py +++ b/scaleway-async/scaleway_async/audit_trail/v1alpha1/types.py @@ -495,6 +495,18 @@ class ProductService: methods: list[str] +@dataclass +class ExportJobS3: + bucket: str + region: ScwRegion + """ + Region to target. If none is passed will use default region from the config. + """ + + prefix: Optional[str] = None + project_id: Optional[str] = None + + @dataclass class ListCombinedEventsResponseCombinedEvent: api: Optional[Event] = None @@ -522,6 +534,66 @@ class Product: """ +@dataclass +class CreateExportJobRequest: + name: str + """ + Name of the export. + """ + + region: Optional[ScwRegion] = None + """ + Region to target. If none is passed will use default region from the config. + """ + + organization_id: Optional[str] = None + """ + ID of the Organization to target. + """ + + tags: Optional[dict[str, str]] = field(default_factory=dict) + """ + Tags of the export. + """ + + s3: Optional[ExportJobS3] = None + + +@dataclass +class ExportJob: + id: str + """ + ID of the export job. + """ + + organization_id: str + """ + ID of the targeted Organization. + """ + + name: str + """ + Name of the export. + """ + + tags: dict[str, str] + """ + Tags of the export. + """ + + created_at: Optional[datetime] = None + """ + Export job creation date. + """ + + last_run_at: Optional[datetime] = None + """ + Last export date. + """ + + s3: Optional[ExportJobS3] = None + + @dataclass class ListAuthenticationEventsRequest: region: Optional[ScwRegion] = None diff --git a/scaleway/scaleway/audit_trail/v1alpha1/__init__.py b/scaleway/scaleway/audit_trail/v1alpha1/__init__.py index 04afd89e..d80c01fa 100644 --- a/scaleway/scaleway/audit_trail/v1alpha1/__init__.py +++ b/scaleway/scaleway/audit_trail/v1alpha1/__init__.py @@ -38,8 +38,11 @@ from .types import Event from .types import SystemEvent from .types import ProductService +from .types import ExportJobS3 from .types import ListCombinedEventsResponseCombinedEvent from .types import Product +from .types import CreateExportJobRequest +from .types import ExportJob from .types import ListAuthenticationEventsRequest from .types import ListAuthenticationEventsResponse from .types import ListCombinedEventsRequest @@ -89,8 +92,11 @@ "Event", "SystemEvent", "ProductService", + "ExportJobS3", "ListCombinedEventsResponseCombinedEvent", "Product", + "CreateExportJobRequest", + "ExportJob", "ListAuthenticationEventsRequest", "ListAuthenticationEventsResponse", "ListCombinedEventsRequest", diff --git a/scaleway/scaleway/audit_trail/v1alpha1/api.py b/scaleway/scaleway/audit_trail/v1alpha1/api.py index e4198824..d4c5e54e 100644 --- a/scaleway/scaleway/audit_trail/v1alpha1/api.py +++ b/scaleway/scaleway/audit_trail/v1alpha1/api.py @@ -16,16 +16,21 @@ ListCombinedEventsRequestOrderBy, ListEventsRequestOrderBy, ResourceType, + CreateExportJobRequest, + ExportJob, + ExportJobS3, ListAuthenticationEventsResponse, ListCombinedEventsResponse, ListEventsResponse, ListProductsResponse, ) from .marshalling import ( + unmarshal_ExportJob, unmarshal_ListAuthenticationEventsResponse, unmarshal_ListCombinedEventsResponse, unmarshal_ListEventsResponse, unmarshal_ListProductsResponse, + marshal_CreateExportJobRequest, ) @@ -248,3 +253,53 @@ def list_products( self._throw_on_error(res) return unmarshal_ListProductsResponse(res.json()) + + def create_export_job( + self, + *, + name: str, + region: Optional[ScwRegion] = None, + organization_id: Optional[str] = None, + s3: Optional[ExportJobS3] = None, + tags: Optional[dict[str, str]] = None, + ) -> ExportJob: + """ + Create an export job. + Create an export job for a specified organization. This allows you to export audit trail events to a destination, such as an S3 bucket. The request requires the organization ID, a name for the export, and a destination configuration. + :param name: Name of the export. + :param region: Region to target. If none is passed will use default region from the config. + :param organization_id: ID of the Organization to target. + :param s3: The configuration specifying the bucket where the audit trail events will be exported. + One-Of ('destination'): at most one of 's3' could be set. + :param tags: Tags of the export. + :return: :class:`ExportJob ` + + Usage: + :: + + result = api.create_export_job( + name="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + + res = self._request( + "POST", + f"/audit-trail/v1alpha1/regions/{param_region}/export-jobs", + body=marshal_CreateExportJobRequest( + CreateExportJobRequest( + name=name, + region=region, + organization_id=organization_id, + tags=tags, + s3=s3, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_ExportJob(res.json()) diff --git a/scaleway/scaleway/audit_trail/v1alpha1/marshalling.py b/scaleway/scaleway/audit_trail/v1alpha1/marshalling.py index 8c6d6fcb..dbfa196a 100644 --- a/scaleway/scaleway/audit_trail/v1alpha1/marshalling.py +++ b/scaleway/scaleway/audit_trail/v1alpha1/marshalling.py @@ -4,12 +4,19 @@ from typing import Any from dateutil import parser +from scaleway_core.profile import ProfileDefaults +from scaleway_core.utils import ( + OneOfPossibility, + resolve_one_of, +) from .types import ( AuthenticationEventFailureReason, AuthenticationEventMFAType, AuthenticationEventMethod, AuthenticationEventOrigin, AuthenticationEventResult, + ExportJobS3, + ExportJob, AccountOrganizationInfo, AccountProjectInfo, AccountUserInfo, @@ -44,12 +51,103 @@ ProductService, Product, ListProductsResponse, + CreateExportJobRequest, ) from ...std.types import ( CountryCode as StdCountryCode, ) +def unmarshal_ExportJobS3(data: Any) -> ExportJobS3: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ExportJobS3' failed as data isn't a dictionary." + ) + + args: dict[str, Any] = {} + + field = data.get("bucket", None) + if field is not None: + args["bucket"] = field + else: + args["bucket"] = None + + field = data.get("region", None) + if field is not None: + args["region"] = field + else: + args["region"] = None + + field = data.get("prefix", None) + if field is not None: + args["prefix"] = field + else: + args["prefix"] = None + + field = data.get("project_id", None) + if field is not None: + args["project_id"] = field + else: + args["project_id"] = None + + return ExportJobS3(**args) + + +def unmarshal_ExportJob(data: Any) -> ExportJob: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ExportJob' failed as data isn't a dictionary." + ) + + args: dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + else: + args["id"] = None + + field = data.get("organization_id", None) + if field is not None: + args["organization_id"] = field + else: + args["organization_id"] = None + + field = data.get("name", None) + if field is not None: + args["name"] = field + else: + args["name"] = None + + field = data.get("tags", None) + if field is not None: + args["tags"] = field + else: + args["tags"] = {} + + field = data.get("s3", None) + if field is not None: + args["s3"] = unmarshal_ExportJobS3(field) + else: + args["s3"] = None + + field = data.get("created_at", None) + if field is not None: + args["created_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["created_at"] = None + + field = data.get("last_run_at", None) + if field is not None: + args["last_run_at"] = ( + parser.isoparse(field) if isinstance(field, str) else field + ) + else: + args["last_run_at"] = None + + return ExportJob(**args) + + def unmarshal_AccountOrganizationInfo(data: Any) -> AccountOrganizationInfo: if not isinstance(data, dict): raise TypeError( @@ -1144,3 +1242,55 @@ def unmarshal_ListProductsResponse(data: Any) -> ListProductsResponse: args["total_count"] = 0 return ListProductsResponse(**args) + + +def marshal_ExportJobS3( + request: ExportJobS3, + defaults: ProfileDefaults, +) -> dict[str, Any]: + output: dict[str, Any] = {} + + if request.bucket is not None: + output["bucket"] = request.bucket + + if request.region is not None: + output["region"] = request.region + else: + output["region"] = defaults.default_region + + if request.prefix is not None: + output["prefix"] = request.prefix + + if request.project_id is not None: + output["project_id"] = request.project_id + + return output + + +def marshal_CreateExportJobRequest( + request: CreateExportJobRequest, + defaults: ProfileDefaults, +) -> dict[str, Any]: + output: dict[str, Any] = {} + output.update( + resolve_one_of( + [ + OneOfPossibility( + param="s3", value=request.s3, marshal_func=marshal_ExportJobS3 + ), + ] + ), + ) + + if request.name is not None: + output["name"] = request.name + + if request.organization_id is not None: + output["organization_id"] = request.organization_id + else: + output["organization_id"] = defaults.default_organization_id + + if request.tags is not None: + output["tags"] = {key: value for key, value in request.tags.items()} + + return output diff --git a/scaleway/scaleway/audit_trail/v1alpha1/types.py b/scaleway/scaleway/audit_trail/v1alpha1/types.py index df31b468..829e5772 100644 --- a/scaleway/scaleway/audit_trail/v1alpha1/types.py +++ b/scaleway/scaleway/audit_trail/v1alpha1/types.py @@ -495,6 +495,18 @@ class ProductService: methods: list[str] +@dataclass +class ExportJobS3: + bucket: str + region: ScwRegion + """ + Region to target. If none is passed will use default region from the config. + """ + + prefix: Optional[str] = None + project_id: Optional[str] = None + + @dataclass class ListCombinedEventsResponseCombinedEvent: api: Optional[Event] = None @@ -522,6 +534,66 @@ class Product: """ +@dataclass +class CreateExportJobRequest: + name: str + """ + Name of the export. + """ + + region: Optional[ScwRegion] = None + """ + Region to target. If none is passed will use default region from the config. + """ + + organization_id: Optional[str] = None + """ + ID of the Organization to target. + """ + + tags: Optional[dict[str, str]] = field(default_factory=dict) + """ + Tags of the export. + """ + + s3: Optional[ExportJobS3] = None + + +@dataclass +class ExportJob: + id: str + """ + ID of the export job. + """ + + organization_id: str + """ + ID of the targeted Organization. + """ + + name: str + """ + Name of the export. + """ + + tags: dict[str, str] + """ + Tags of the export. + """ + + created_at: Optional[datetime] = None + """ + Export job creation date. + """ + + last_run_at: Optional[datetime] = None + """ + Last export date. + """ + + s3: Optional[ExportJobS3] = None + + @dataclass class ListAuthenticationEventsRequest: region: Optional[ScwRegion] = None