diff --git a/scaleway-async/scaleway_async/webhosting/v1/__init__.py b/scaleway-async/scaleway_async/webhosting/v1/__init__.py index 325d01061..8e47713e0 100644 --- a/scaleway-async/scaleway_async/webhosting/v1/__init__.py +++ b/scaleway-async/scaleway_async/webhosting/v1/__init__.py @@ -1,5 +1,8 @@ # This file was automatically generated. DO NOT EDIT. # If you have any remark or suggestion do not hesitate to open an issue. +from .types import BackupItemType +from .types import BackupStatus +from .content import BACKUP_TRANSIENT_STATUSES from .types import DnsRecordStatus from .types import DnsRecordType from .types import DnsRecordsStatus @@ -13,6 +16,7 @@ from .types import DomainZoneOwner from .types import HostingStatus from .content import HOSTING_TRANSIENT_STATUSES +from .types import ListBackupsRequestOrderBy from .types import ListDatabaseUsersRequestOrderBy from .types import ListDatabasesRequestOrderBy from .types import ListFtpAccountsRequestOrderBy @@ -29,6 +33,7 @@ from .types import HostingDomainCustomDomain from .types import OfferOption from .types import PlatformControlPanel +from .types import BackupItem from .types import HostingDomain from .types import CreateDatabaseRequestUser from .types import CreateHostingRequestDomainConfiguration @@ -39,6 +44,8 @@ from .types import HostingUser from .types import Offer from .types import Platform +from .types import BackupItemGroup +from .types import Backup from .types import ControlPanel from .types import DatabaseUser from .types import Database @@ -47,6 +54,11 @@ from .types import MailAccount from .types import Website from .types import DomainAvailability +from .types import BackupApiGetBackupRequest +from .types import BackupApiListBackupItemsRequest +from .types import BackupApiListBackupsRequest +from .types import BackupApiRestoreBackupItemsRequest +from .types import BackupApiRestoreBackupRequest from .types import CheckUserOwnsDomainResponse from .types import ControlPanelApiListControlPanelsRequest from .types import DatabaseApiAssignDatabaseUserRequest @@ -72,14 +84,18 @@ from .types import FtpAccountApiListFtpAccountsRequest from .types import FtpAccountApiRemoveFtpAccountRequest from .types import Hosting +from .types import HostingApiAddCustomDomainRequest from .types import HostingApiCreateHostingRequest from .types import HostingApiCreateSessionRequest from .types import HostingApiDeleteHostingRequest from .types import HostingApiGetHostingRequest from .types import HostingApiGetResourceSummaryRequest from .types import HostingApiListHostingsRequest +from .types import HostingApiRemoveCustomDomainRequest from .types import HostingApiResetHostingPasswordRequest from .types import HostingApiUpdateHostingRequest +from .types import ListBackupItemsResponse +from .types import ListBackupsResponse from .types import ListControlPanelsResponse from .types import ListDatabaseUsersResponse from .types import ListDatabasesResponse @@ -95,9 +111,12 @@ from .types import OfferApiListOffersRequest from .types import ResetHostingPasswordResponse from .types import ResourceSummary +from .types import RestoreBackupItemsResponse +from .types import RestoreBackupResponse from .types import SearchDomainsResponse from .types import Session from .types import WebsiteApiListWebsitesRequest +from .api import WebhostingV1BackupAPI from .api import WebhostingV1ControlPanelAPI from .api import WebhostingV1DatabaseAPI from .api import WebhostingV1DnsAPI @@ -108,6 +127,9 @@ from .api import WebhostingV1WebsiteAPI __all__ = [ + "BackupItemType", + "BackupStatus", + "BACKUP_TRANSIENT_STATUSES", "DnsRecordStatus", "DnsRecordType", "DnsRecordsStatus", @@ -121,6 +143,7 @@ "DomainZoneOwner", "HostingStatus", "HOSTING_TRANSIENT_STATUSES", + "ListBackupsRequestOrderBy", "ListDatabaseUsersRequestOrderBy", "ListDatabasesRequestOrderBy", "ListFtpAccountsRequestOrderBy", @@ -137,6 +160,7 @@ "HostingDomainCustomDomain", "OfferOption", "PlatformControlPanel", + "BackupItem", "HostingDomain", "CreateDatabaseRequestUser", "CreateHostingRequestDomainConfiguration", @@ -147,6 +171,8 @@ "HostingUser", "Offer", "Platform", + "BackupItemGroup", + "Backup", "ControlPanel", "DatabaseUser", "Database", @@ -155,6 +181,11 @@ "MailAccount", "Website", "DomainAvailability", + "BackupApiGetBackupRequest", + "BackupApiListBackupItemsRequest", + "BackupApiListBackupsRequest", + "BackupApiRestoreBackupItemsRequest", + "BackupApiRestoreBackupRequest", "CheckUserOwnsDomainResponse", "ControlPanelApiListControlPanelsRequest", "DatabaseApiAssignDatabaseUserRequest", @@ -180,14 +211,18 @@ "FtpAccountApiListFtpAccountsRequest", "FtpAccountApiRemoveFtpAccountRequest", "Hosting", + "HostingApiAddCustomDomainRequest", "HostingApiCreateHostingRequest", "HostingApiCreateSessionRequest", "HostingApiDeleteHostingRequest", "HostingApiGetHostingRequest", "HostingApiGetResourceSummaryRequest", "HostingApiListHostingsRequest", + "HostingApiRemoveCustomDomainRequest", "HostingApiResetHostingPasswordRequest", "HostingApiUpdateHostingRequest", + "ListBackupItemsResponse", + "ListBackupsResponse", "ListControlPanelsResponse", "ListDatabaseUsersResponse", "ListDatabasesResponse", @@ -203,9 +238,12 @@ "OfferApiListOffersRequest", "ResetHostingPasswordResponse", "ResourceSummary", + "RestoreBackupItemsResponse", + "RestoreBackupResponse", "SearchDomainsResponse", "Session", "WebsiteApiListWebsitesRequest", + "WebhostingV1BackupAPI", "WebhostingV1ControlPanelAPI", "WebhostingV1DatabaseAPI", "WebhostingV1DnsAPI", diff --git a/scaleway-async/scaleway_async/webhosting/v1/api.py b/scaleway-async/scaleway_async/webhosting/v1/api.py index 212b454c9..e949b8c29 100644 --- a/scaleway-async/scaleway_async/webhosting/v1/api.py +++ b/scaleway-async/scaleway_async/webhosting/v1/api.py @@ -15,6 +15,7 @@ ) from .types import ( HostingStatus, + ListBackupsRequestOrderBy, ListDatabaseUsersRequestOrderBy, ListDatabasesRequestOrderBy, ListFtpAccountsRequestOrderBy, @@ -23,6 +24,8 @@ ListOffersRequestOrderBy, ListWebsitesRequestOrderBy, AutoConfigDomainDns, + Backup, + BackupApiRestoreBackupItemsRequest, CheckUserOwnsDomainResponse, ControlPanel, CreateDatabaseRequestUser, @@ -42,9 +45,12 @@ FtpAccountApiChangeFtpAccountPasswordRequest, FtpAccountApiCreateFtpAccountRequest, Hosting, + HostingApiAddCustomDomainRequest, HostingApiCreateHostingRequest, HostingApiUpdateHostingRequest, HostingSummary, + ListBackupItemsResponse, + ListBackupsResponse, ListControlPanelsResponse, ListDatabaseUsersResponse, ListDatabasesResponse, @@ -61,24 +67,31 @@ OfferOptionRequest, ResetHostingPasswordResponse, ResourceSummary, + RestoreBackupItemsResponse, + RestoreBackupResponse, SearchDomainsResponse, Session, SyncDomainDnsRecordsRequestRecord, Website, ) from .content import ( + BACKUP_TRANSIENT_STATUSES, DOMAIN_TRANSIENT_STATUSES, HOSTING_TRANSIENT_STATUSES, ) from .marshalling import ( + unmarshal_Backup, unmarshal_DatabaseUser, unmarshal_Database, unmarshal_FtpAccount, + unmarshal_HostingSummary, unmarshal_MailAccount, unmarshal_CheckUserOwnsDomainResponse, unmarshal_DnsRecords, unmarshal_Domain, unmarshal_Hosting, + unmarshal_ListBackupItemsResponse, + unmarshal_ListBackupsResponse, unmarshal_ListControlPanelsResponse, unmarshal_ListDatabaseUsersResponse, unmarshal_ListDatabasesResponse, @@ -89,8 +102,11 @@ unmarshal_ListWebsitesResponse, unmarshal_ResetHostingPasswordResponse, unmarshal_ResourceSummary, + unmarshal_RestoreBackupItemsResponse, + unmarshal_RestoreBackupResponse, unmarshal_SearchDomainsResponse, unmarshal_Session, + marshal_BackupApiRestoreBackupItemsRequest, marshal_DatabaseApiAssignDatabaseUserRequest, marshal_DatabaseApiChangeDatabaseUserPasswordRequest, marshal_DatabaseApiCreateDatabaseRequest, @@ -100,6 +116,7 @@ marshal_DnsApiSyncDomainDnsRecordsRequest, marshal_FtpAccountApiChangeFtpAccountPasswordRequest, marshal_FtpAccountApiCreateFtpAccountRequest, + marshal_HostingApiAddCustomDomainRequest, marshal_HostingApiCreateHostingRequest, marshal_HostingApiUpdateHostingRequest, marshal_MailAccountApiChangeMailAccountPasswordRequest, @@ -111,6 +128,292 @@ ) +class WebhostingV1BackupAPI(API): + """ + This API allows you to list and restore backups for your cPanel and WordPress Web Hosting service. + """ + + async def list_backups( + self, + *, + hosting_id: str, + region: Optional[ScwRegion] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + order_by: Optional[ListBackupsRequestOrderBy] = None, + ) -> ListBackupsResponse: + """ + List all available backups for a hosting account. + :param hosting_id: UUID of the hosting account. + :param region: Region to target. If none is passed will use default region from the config. + :param page: Page number to retrieve. + :param page_size: Number of backups to return per page. + :param order_by: Order in which to return the list of backups. + :return: :class:`ListBackupsResponse ` + + Usage: + :: + + result = await api.list_backups( + hosting_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "GET", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/backups", + params={ + "order_by": order_by, + "page": page, + "page_size": page_size or self.client.default_page_size, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListBackupsResponse(res.json()) + + async def list_backups_all( + self, + *, + hosting_id: str, + region: Optional[ScwRegion] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + order_by: Optional[ListBackupsRequestOrderBy] = None, + ) -> List[Backup]: + """ + List all available backups for a hosting account. + :param hosting_id: UUID of the hosting account. + :param region: Region to target. If none is passed will use default region from the config. + :param page: Page number to retrieve. + :param page_size: Number of backups to return per page. + :param order_by: Order in which to return the list of backups. + :return: :class:`List[Backup] ` + + Usage: + :: + + result = await api.list_backups_all( + hosting_id="example", + ) + """ + + return await fetch_all_pages_async( + type=ListBackupsResponse, + key="backups", + fetcher=self.list_backups, + args={ + "hosting_id": hosting_id, + "region": region, + "page": page, + "page_size": page_size, + "order_by": order_by, + }, + ) + + async def get_backup( + self, + *, + hosting_id: str, + backup_id: str, + region: Optional[ScwRegion] = None, + ) -> Backup: + """ + Get info about a backup specified by the backup ID. + :param hosting_id: UUID of the hosting account. + :param backup_id: ID of the backup to retrieve. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`Backup ` + + Usage: + :: + + result = await api.get_backup( + hosting_id="example", + backup_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + param_backup_id = validate_path_param("backup_id", backup_id) + + res = self._request( + "GET", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/backups/{param_backup_id}", + ) + + self._throw_on_error(res) + return unmarshal_Backup(res.json()) + + async def wait_for_backup( + self, + *, + hosting_id: str, + backup_id: str, + region: Optional[ScwRegion] = None, + options: Optional[WaitForOptions[Backup, Union[bool, Awaitable[bool]]]] = None, + ) -> Backup: + """ + Get info about a backup specified by the backup ID. + :param hosting_id: UUID of the hosting account. + :param backup_id: ID of the backup to retrieve. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`Backup ` + + Usage: + :: + + result = await api.get_backup( + hosting_id="example", + backup_id="example", + ) + """ + + if not options: + options = WaitForOptions() + + if not options.stop: + options.stop = lambda res: res.status not in BACKUP_TRANSIENT_STATUSES + + return await wait_for_resource_async( + fetcher=self.get_backup, + options=options, + args={ + "hosting_id": hosting_id, + "backup_id": backup_id, + "region": region, + }, + ) + + async def restore_backup( + self, + *, + hosting_id: str, + backup_id: str, + region: Optional[ScwRegion] = None, + ) -> RestoreBackupResponse: + """ + Restore an entire backup to your hosting environment. + :param hosting_id: UUID of the hosting account. + :param backup_id: ID of the backup to fully restore. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`RestoreBackupResponse ` + + Usage: + :: + + result = await api.restore_backup( + hosting_id="example", + backup_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + param_backup_id = validate_path_param("backup_id", backup_id) + + res = self._request( + "POST", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/backups/{param_backup_id}/restore", + body={}, + ) + + self._throw_on_error(res) + return unmarshal_RestoreBackupResponse(res.json()) + + async def list_backup_items( + self, + *, + hosting_id: str, + backup_id: str, + region: Optional[ScwRegion] = None, + ) -> ListBackupItemsResponse: + """ + List items within a specific backup, grouped by type. + :param hosting_id: UUID of the hosting account. + :param backup_id: ID of the backup to list items from. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`ListBackupItemsResponse ` + + Usage: + :: + + result = await api.list_backup_items( + hosting_id="example", + backup_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "GET", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/backup-items", + params={ + "backup_id": backup_id, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListBackupItemsResponse(res.json()) + + async def restore_backup_items( + self, + *, + hosting_id: str, + region: Optional[ScwRegion] = None, + item_ids: Optional[List[str]] = None, + ) -> RestoreBackupItemsResponse: + """ + Restore specific items from a backup (e.g., a database or mailbox). + :param hosting_id: UUID of the hosting account. + :param region: Region to target. If none is passed will use default region from the config. + :param item_ids: List of backup item IDs to restore individually. + :return: :class:`RestoreBackupItemsResponse ` + + Usage: + :: + + result = await api.restore_backup_items( + hosting_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "POST", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/restore-backup-items", + body=marshal_BackupApiRestoreBackupItemsRequest( + BackupApiRestoreBackupItemsRequest( + hosting_id=hosting_id, + region=region, + item_ids=item_ids, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_RestoreBackupItemsResponse(res.json()) + + class WebhostingV1ControlPanelAPI(API): """ This API allows you to manage your Web Hosting services. @@ -1555,6 +1858,84 @@ async def get_resource_summary( self._throw_on_error(res) return unmarshal_ResourceSummary(res.json()) + async def add_custom_domain( + self, + *, + hosting_id: str, + domain_name: str, + region: Optional[ScwRegion] = None, + ) -> HostingSummary: + """ + Attach a custom domain to a webhosting. + :param hosting_id: Hosting ID to which the custom domain is attached to. + :param domain_name: The custom domain name to attach to the hosting. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`HostingSummary ` + + Usage: + :: + + result = await api.add_custom_domain( + hosting_id="example", + domain_name="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "POST", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/add-custom-domain", + body=marshal_HostingApiAddCustomDomainRequest( + HostingApiAddCustomDomainRequest( + hosting_id=hosting_id, + domain_name=domain_name, + region=region, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_HostingSummary(res.json()) + + async def remove_custom_domain( + self, + *, + hosting_id: str, + region: Optional[ScwRegion] = None, + ) -> HostingSummary: + """ + Detach a custom domain from a webhosting. + :param hosting_id: Hosting ID to which the custom domain is detached from. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`HostingSummary ` + + Usage: + :: + + result = await api.remove_custom_domain( + hosting_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "POST", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/remove-custom-domain", + body={}, + ) + + self._throw_on_error(res) + return unmarshal_HostingSummary(res.json()) + class WebhostingV1FtpAccountAPI(API): """ diff --git a/scaleway-async/scaleway_async/webhosting/v1/content.py b/scaleway-async/scaleway_async/webhosting/v1/content.py index 895da5659..e77f5228b 100644 --- a/scaleway-async/scaleway_async/webhosting/v1/content.py +++ b/scaleway-async/scaleway_async/webhosting/v1/content.py @@ -3,11 +3,18 @@ from typing import List from .types import ( + BackupStatus, DomainAvailabilityStatus, DomainStatus, HostingStatus, ) +BACKUP_TRANSIENT_STATUSES: List[BackupStatus] = [ + BackupStatus.RESTORING, +] +""" +Lists transient statutes of the enum :class:`BackupStatus `. +""" DOMAIN_AVAILABILITY_TRANSIENT_STATUSES: List[DomainAvailabilityStatus] = [ DomainAvailabilityStatus.VALIDATING, ] diff --git a/scaleway-async/scaleway_async/webhosting/v1/marshalling.py b/scaleway-async/scaleway_async/webhosting/v1/marshalling.py index 3825815ee..fc5100f5e 100644 --- a/scaleway-async/scaleway_async/webhosting/v1/marshalling.py +++ b/scaleway-async/scaleway_async/webhosting/v1/marshalling.py @@ -16,31 +16,36 @@ DomainAction, DomainAvailabilityAction, DomainDnsAction, + Backup, DatabaseUser, Database, FtpAccount, + AutoConfigDomainDns, + HostingDomainCustomDomain, + HostingDomain, + HostingSummary, MailAccount, CheckUserOwnsDomainResponse, - AutoConfigDomainDns, DnsRecord, Nameserver, DnsRecords, Domain, PlatformControlPanelUrls, - HostingDomainCustomDomain, OfferOption, PlatformControlPanel, - HostingDomain, HostingUser, Offer, Platform, Hosting, + BackupItem, + BackupItemGroup, + ListBackupItemsResponse, + ListBackupsResponse, ControlPanel, ListControlPanelsResponse, ListDatabaseUsersResponse, ListDatabasesResponse, ListFtpAccountsResponse, - HostingSummary, ListHostingsResponse, ListMailAccountsResponse, ListOffersResponse, @@ -48,9 +53,12 @@ ListWebsitesResponse, ResetHostingPasswordResponse, ResourceSummary, + RestoreBackupItemsResponse, + RestoreBackupResponse, DomainAvailability, SearchDomainsResponse, Session, + BackupApiRestoreBackupItemsRequest, DatabaseApiAssignDatabaseUserRequest, DatabaseApiChangeDatabaseUserPasswordRequest, CreateDatabaseRequestUser, @@ -62,6 +70,7 @@ DnsApiSyncDomainDnsRecordsRequest, FtpAccountApiChangeFtpAccountPasswordRequest, FtpAccountApiCreateFtpAccountRequest, + HostingApiAddCustomDomainRequest, CreateHostingRequestDomainConfiguration, OfferOptionRequest, HostingApiCreateHostingRequest, @@ -75,6 +84,39 @@ ) +def unmarshal_Backup(data: Any) -> Backup: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'Backup' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("size", None) + if field is not None: + args["size"] = field + + field = data.get("status", None) + if field is not None: + args["status"] = field + + field = data.get("total_items", None) + if field is not None: + args["total_items"] = field + + 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 + + return Backup(**args) + + def unmarshal_DatabaseUser(data: Any) -> DatabaseUser: if not isinstance(data, dict): raise TypeError( @@ -132,10 +174,41 @@ def unmarshal_FtpAccount(data: Any) -> FtpAccount: return FtpAccount(**args) -def unmarshal_MailAccount(data: Any) -> MailAccount: +def unmarshal_AutoConfigDomainDns(data: Any) -> AutoConfigDomainDns: if not isinstance(data, dict): raise TypeError( - "Unmarshalling the type 'MailAccount' failed as data isn't a dictionary." + "Unmarshalling the type 'AutoConfigDomainDns' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("nameservers", None) + if field is not None: + args["nameservers"] = field + + field = data.get("web_records", None) + if field is not None: + args["web_records"] = field + + field = data.get("mail_records", None) + if field is not None: + args["mail_records"] = field + + field = data.get("all_records", None) + if field is not None: + args["all_records"] = field + + field = data.get("none", None) + if field is not None: + args["none"] = field + + return AutoConfigDomainDns(**args) + + +def unmarshal_HostingDomainCustomDomain(data: Any) -> HostingDomainCustomDomain: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'HostingDomainCustomDomain' failed as data isn't a dictionary." ) args: Dict[str, Any] = {} @@ -144,57 +217,147 @@ def unmarshal_MailAccount(data: Any) -> MailAccount: if field is not None: args["domain"] = field - field = data.get("username", None) + field = data.get("domain_status", None) if field is not None: - args["username"] = field + args["domain_status"] = field - return MailAccount(**args) + field = data.get("dns_status", None) + if field is not None: + args["dns_status"] = field + + field = data.get("auto_config_domain_dns", None) + if field is not None: + args["auto_config_domain_dns"] = unmarshal_AutoConfigDomainDns(field) + else: + args["auto_config_domain_dns"] = None + return HostingDomainCustomDomain(**args) -def unmarshal_CheckUserOwnsDomainResponse(data: Any) -> CheckUserOwnsDomainResponse: + +def unmarshal_HostingDomain(data: Any) -> HostingDomain: if not isinstance(data, dict): raise TypeError( - "Unmarshalling the type 'CheckUserOwnsDomainResponse' failed as data isn't a dictionary." + "Unmarshalling the type 'HostingDomain' failed as data isn't a dictionary." ) args: Dict[str, Any] = {} - field = data.get("owns_domain", None) + field = data.get("subdomain", None) if field is not None: - args["owns_domain"] = field + args["subdomain"] = field - return CheckUserOwnsDomainResponse(**args) + field = data.get("custom_domain", None) + if field is not None: + args["custom_domain"] = unmarshal_HostingDomainCustomDomain(field) + else: + args["custom_domain"] = None + return HostingDomain(**args) -def unmarshal_AutoConfigDomainDns(data: Any) -> AutoConfigDomainDns: + +def unmarshal_HostingSummary(data: Any) -> HostingSummary: if not isinstance(data, dict): raise TypeError( - "Unmarshalling the type 'AutoConfigDomainDns' failed as data isn't a dictionary." + "Unmarshalling the type 'HostingSummary' failed as data isn't a dictionary." ) args: Dict[str, Any] = {} - field = data.get("nameservers", None) + field = data.get("id", None) if field is not None: - args["nameservers"] = field + args["id"] = field - field = data.get("web_records", None) + field = data.get("project_id", None) if field is not None: - args["web_records"] = field + args["project_id"] = field - field = data.get("mail_records", None) + field = data.get("status", None) if field is not None: - args["mail_records"] = field + args["status"] = field - field = data.get("all_records", None) + field = data.get("protected", None) if field is not None: - args["all_records"] = field + args["protected"] = field - field = data.get("none", None) + field = data.get("offer_name", None) if field is not None: - args["none"] = field + args["offer_name"] = field - return AutoConfigDomainDns(**args) + field = data.get("region", None) + if field is not None: + args["region"] = field + + 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("updated_at", None) + if field is not None: + args["updated_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["updated_at"] = None + + field = data.get("domain", None) + if field is not None: + args["domain"] = field + else: + args["domain"] = None + + field = data.get("dns_status", None) + if field is not None: + args["dns_status"] = field + else: + args["dns_status"] = None + + field = data.get("domain_status", None) + if field is not None: + args["domain_status"] = field + else: + args["domain_status"] = None + + field = data.get("domain_info", None) + if field is not None: + args["domain_info"] = unmarshal_HostingDomain(field) + else: + args["domain_info"] = None + + return HostingSummary(**args) + + +def unmarshal_MailAccount(data: Any) -> MailAccount: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'MailAccount' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("domain", None) + if field is not None: + args["domain"] = field + + field = data.get("username", None) + if field is not None: + args["username"] = field + + return MailAccount(**args) + + +def unmarshal_CheckUserOwnsDomainResponse(data: Any) -> CheckUserOwnsDomainResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'CheckUserOwnsDomainResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("owns_domain", None) + if field is not None: + args["owns_domain"] = field + + return CheckUserOwnsDomainResponse(**args) def unmarshal_DnsRecord(data: Any) -> DnsRecord: @@ -368,35 +531,6 @@ def unmarshal_PlatformControlPanelUrls(data: Any) -> PlatformControlPanelUrls: return PlatformControlPanelUrls(**args) -def unmarshal_HostingDomainCustomDomain(data: Any) -> HostingDomainCustomDomain: - if not isinstance(data, dict): - raise TypeError( - "Unmarshalling the type 'HostingDomainCustomDomain' failed as data isn't a dictionary." - ) - - args: Dict[str, Any] = {} - - field = data.get("domain", None) - if field is not None: - args["domain"] = field - - field = data.get("domain_status", None) - if field is not None: - args["domain_status"] = field - - field = data.get("dns_status", None) - if field is not None: - args["dns_status"] = field - - field = data.get("auto_config_domain_dns", None) - if field is not None: - args["auto_config_domain_dns"] = unmarshal_AutoConfigDomainDns(field) - else: - args["auto_config_domain_dns"] = None - - return HostingDomainCustomDomain(**args) - - def unmarshal_OfferOption(data: Any) -> OfferOption: if not isinstance(data, dict): raise TypeError( @@ -463,27 +597,6 @@ def unmarshal_PlatformControlPanel(data: Any) -> PlatformControlPanel: return PlatformControlPanel(**args) -def unmarshal_HostingDomain(data: Any) -> HostingDomain: - if not isinstance(data, dict): - raise TypeError( - "Unmarshalling the type 'HostingDomain' failed as data isn't a dictionary." - ) - - args: Dict[str, Any] = {} - - field = data.get("subdomain", None) - if field is not None: - args["subdomain"] = field - - field = data.get("custom_domain", None) - if field is not None: - args["custom_domain"] = unmarshal_HostingDomainCustomDomain(field) - else: - args["custom_domain"] = None - - return HostingDomain(**args) - - def unmarshal_HostingUser(data: Any) -> HostingUser: if not isinstance(data, dict): raise TypeError( @@ -696,6 +809,106 @@ def unmarshal_Hosting(data: Any) -> Hosting: return Hosting(**args) +def unmarshal_BackupItem(data: Any) -> BackupItem: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'BackupItem' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("name", None) + if field is not None: + args["name"] = field + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("size", None) + if field is not None: + args["size"] = field + + field = data.get("status", None) + if field is not None: + args["status"] = field + + 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 + + return BackupItem(**args) + + +def unmarshal_BackupItemGroup(data: Any) -> BackupItemGroup: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'BackupItemGroup' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("items", None) + if field is not None: + args["items"] = ( + [unmarshal_BackupItem(v) for v in field] if field is not None else None + ) + + return BackupItemGroup(**args) + + +def unmarshal_ListBackupItemsResponse(data: Any) -> ListBackupItemsResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListBackupItemsResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + field = data.get("groups", None) + if field is not None: + args["groups"] = ( + [unmarshal_BackupItemGroup(v) for v in field] if field is not None else None + ) + + return ListBackupItemsResponse(**args) + + +def unmarshal_ListBackupsResponse(data: Any) -> ListBackupsResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListBackupsResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + field = data.get("backups", None) + if field is not None: + args["backups"] = ( + [unmarshal_Backup(v) for v in field] if field is not None else None + ) + + return ListBackupsResponse(**args) + + def unmarshal_ControlPanel(data: Any) -> ControlPanel: if not isinstance(data, dict): raise TypeError( @@ -809,77 +1022,6 @@ def unmarshal_ListFtpAccountsResponse(data: Any) -> ListFtpAccountsResponse: return ListFtpAccountsResponse(**args) -def unmarshal_HostingSummary(data: Any) -> HostingSummary: - if not isinstance(data, dict): - raise TypeError( - "Unmarshalling the type 'HostingSummary' failed as data isn't a dictionary." - ) - - args: Dict[str, Any] = {} - - field = data.get("id", None) - if field is not None: - args["id"] = field - - field = data.get("project_id", None) - if field is not None: - args["project_id"] = field - - field = data.get("status", None) - if field is not None: - args["status"] = field - - field = data.get("protected", None) - if field is not None: - args["protected"] = field - - field = data.get("offer_name", None) - if field is not None: - args["offer_name"] = field - - field = data.get("region", None) - if field is not None: - args["region"] = field - - 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("updated_at", None) - if field is not None: - args["updated_at"] = parser.isoparse(field) if isinstance(field, str) else field - else: - args["updated_at"] = None - - field = data.get("domain", None) - if field is not None: - args["domain"] = field - else: - args["domain"] = None - - field = data.get("dns_status", None) - if field is not None: - args["dns_status"] = field - else: - args["dns_status"] = None - - field = data.get("domain_status", None) - if field is not None: - args["domain_status"] = field - else: - args["domain_status"] = None - - field = data.get("domain_info", None) - if field is not None: - args["domain_info"] = unmarshal_HostingDomain(field) - else: - args["domain_info"] = None - - return HostingSummary(**args) - - def unmarshal_ListHostingsResponse(data: Any) -> ListHostingsResponse: if not isinstance(data, dict): raise TypeError( @@ -1035,6 +1177,28 @@ def unmarshal_ResourceSummary(data: Any) -> ResourceSummary: return ResourceSummary(**args) +def unmarshal_RestoreBackupItemsResponse(data: Any) -> RestoreBackupItemsResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'RestoreBackupItemsResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + return RestoreBackupItemsResponse(**args) + + +def unmarshal_RestoreBackupResponse(data: Any) -> RestoreBackupResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'RestoreBackupResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + return RestoreBackupResponse(**args) + + def unmarshal_DomainAvailability(data: Any) -> DomainAvailability: if not isinstance(data, dict): raise TypeError( @@ -1108,6 +1272,18 @@ def unmarshal_Session(data: Any) -> Session: return Session(**args) +def marshal_BackupApiRestoreBackupItemsRequest( + request: BackupApiRestoreBackupItemsRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.item_ids is not None: + output["item_ids"] = request.item_ids + + return output + + def marshal_DatabaseApiAssignDatabaseUserRequest( request: DatabaseApiAssignDatabaseUserRequest, defaults: ProfileDefaults, @@ -1315,6 +1491,18 @@ def marshal_FtpAccountApiCreateFtpAccountRequest( return output +def marshal_HostingApiAddCustomDomainRequest( + request: HostingApiAddCustomDomainRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.domain_name is not None: + output["domain_name"] = request.domain_name + + return output + + def marshal_CreateHostingRequestDomainConfiguration( request: CreateHostingRequestDomainConfiguration, defaults: ProfileDefaults, diff --git a/scaleway-async/scaleway_async/webhosting/v1/types.py b/scaleway-async/scaleway_async/webhosting/v1/types.py index 13e8ef91e..5d8a68805 100644 --- a/scaleway-async/scaleway_async/webhosting/v1/types.py +++ b/scaleway-async/scaleway_async/webhosting/v1/types.py @@ -20,6 +20,34 @@ ) +class BackupItemType(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_BACKUP_ITEM_TYPE = "unknown_backup_item_type" + FULL = "full" + WEB = "web" + MAIL = "mail" + DB = "db" + DB_USER = "db_user" + FTP_USER = "ftp_user" + DNS_ZONE = "dns_zone" + CRON_JOB = "cron_job" + SSL_CERTIFICATE = "ssl_certificate" + + def __str__(self) -> str: + return str(self.value) + + +class BackupStatus(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_BACKUP_STATUS = "unknown_backup_status" + ACTIVE = "active" + LOCKED = "locked" + DISABLED = "disabled" + DAMAGED = "damaged" + RESTORING = "restoring" + + def __str__(self) -> str: + return str(self.value) + + class DnsRecordStatus(str, Enum, metaclass=StrEnumMeta): UNKNOWN_STATUS = "unknown_status" VALID = "valid" @@ -131,6 +159,14 @@ def __str__(self) -> str: return str(self.value) +class ListBackupsRequestOrderBy(str, Enum, metaclass=StrEnumMeta): + CREATED_AT_DESC = "created_at_desc" + CREATED_AT_ASC = "created_at_asc" + + def __str__(self) -> str: + return str(self.value) + + class ListDatabaseUsersRequestOrderBy(str, Enum, metaclass=StrEnumMeta): USERNAME_ASC = "username_asc" USERNAME_DESC = "username_desc" @@ -352,6 +388,39 @@ class PlatformControlPanel: """ +@dataclass +class BackupItem: + id: str + """ + ID of the item. + """ + + name: str + """ + Name of the item (e.g., `database name`, `email address`). + """ + + type_: BackupItemType + """ + Type of the item (e.g., email, database, FTP). + """ + + size: int + """ + Size of the item in bytes. + """ + + status: BackupStatus + """ + Status of the item. Available values are `active`, `damaged`, and `restoring`. + """ + + created_at: Optional[datetime] + """ + Date and time at which this item was backed up. + """ + + @dataclass class HostingDomain: subdomain: str @@ -563,6 +632,47 @@ class Platform: """ +@dataclass +class BackupItemGroup: + type_: BackupItemType + """ + Type of items (e.g., email, database, FTP). + """ + + items: List[BackupItem] + """ + List of individual backup items of this type. + """ + + +@dataclass +class Backup: + id: str + """ + ID of the backup. + """ + + size: int + """ + Total size of the backup in bytes. + """ + + status: BackupStatus + """ + Status of the backup. Available values are `active`, `locked`, and `restoring`. + """ + + total_items: int + """ + Total number of restorable items in the backup. + """ + + created_at: Optional[datetime] + """ + Creation date of the backup. + """ + + @dataclass class ControlPanel: name: str @@ -752,6 +862,106 @@ class DomainAvailability: """ +@dataclass +class BackupApiGetBackupRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + backup_id: str + """ + ID of the backup to retrieve. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + +@dataclass +class BackupApiListBackupItemsRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + backup_id: str + """ + ID of the backup to list items from. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + +@dataclass +class BackupApiListBackupsRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + page: Optional[int] + """ + Page number to retrieve. + """ + + page_size: Optional[int] + """ + Number of backups to return per page. + """ + + order_by: Optional[ListBackupsRequestOrderBy] + """ + Order in which to return the list of backups. + """ + + +@dataclass +class BackupApiRestoreBackupItemsRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + item_ids: Optional[List[str]] + """ + List of backup item IDs to restore individually. + """ + + +@dataclass +class BackupApiRestoreBackupRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + backup_id: str + """ + ID of the backup to fully restore. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + @dataclass class CheckUserOwnsDomainResponse: owns_domain: bool @@ -1381,6 +1591,24 @@ class Hosting: """ +@dataclass +class HostingApiAddCustomDomainRequest: + hosting_id: str + """ + Hosting ID to which the custom domain is attached to. + """ + + domain_name: str + """ + The custom domain name to attach to the hosting. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + @dataclass class HostingApiCreateHostingRequest: offer_id: str @@ -1554,6 +1782,19 @@ class HostingApiListHostingsRequest: """ +@dataclass +class HostingApiRemoveCustomDomainRequest: + hosting_id: str + """ + Hosting ID to which the custom domain is detached from. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + @dataclass class HostingApiResetHostingPasswordRequest: hosting_id: str @@ -1605,6 +1846,32 @@ class HostingApiUpdateHostingRequest: """ +@dataclass +class ListBackupItemsResponse: + total_count: int + """ + Total number of backup item groups. + """ + + groups: List[BackupItemGroup] + """ + List of backup item groups categorized by type. + """ + + +@dataclass +class ListBackupsResponse: + total_count: int + """ + Total number of available backups. + """ + + backups: List[Backup] + """ + List of available backups. + """ + + @dataclass class ListControlPanelsResponse: total_count: int @@ -1890,6 +2157,16 @@ class ResourceSummary: """ +@dataclass +class RestoreBackupItemsResponse: + pass + + +@dataclass +class RestoreBackupResponse: + pass + + @dataclass class SearchDomainsResponse: domains_available: List[DomainAvailability] diff --git a/scaleway/scaleway/webhosting/v1/__init__.py b/scaleway/scaleway/webhosting/v1/__init__.py index 325d01061..8e47713e0 100644 --- a/scaleway/scaleway/webhosting/v1/__init__.py +++ b/scaleway/scaleway/webhosting/v1/__init__.py @@ -1,5 +1,8 @@ # This file was automatically generated. DO NOT EDIT. # If you have any remark or suggestion do not hesitate to open an issue. +from .types import BackupItemType +from .types import BackupStatus +from .content import BACKUP_TRANSIENT_STATUSES from .types import DnsRecordStatus from .types import DnsRecordType from .types import DnsRecordsStatus @@ -13,6 +16,7 @@ from .types import DomainZoneOwner from .types import HostingStatus from .content import HOSTING_TRANSIENT_STATUSES +from .types import ListBackupsRequestOrderBy from .types import ListDatabaseUsersRequestOrderBy from .types import ListDatabasesRequestOrderBy from .types import ListFtpAccountsRequestOrderBy @@ -29,6 +33,7 @@ from .types import HostingDomainCustomDomain from .types import OfferOption from .types import PlatformControlPanel +from .types import BackupItem from .types import HostingDomain from .types import CreateDatabaseRequestUser from .types import CreateHostingRequestDomainConfiguration @@ -39,6 +44,8 @@ from .types import HostingUser from .types import Offer from .types import Platform +from .types import BackupItemGroup +from .types import Backup from .types import ControlPanel from .types import DatabaseUser from .types import Database @@ -47,6 +54,11 @@ from .types import MailAccount from .types import Website from .types import DomainAvailability +from .types import BackupApiGetBackupRequest +from .types import BackupApiListBackupItemsRequest +from .types import BackupApiListBackupsRequest +from .types import BackupApiRestoreBackupItemsRequest +from .types import BackupApiRestoreBackupRequest from .types import CheckUserOwnsDomainResponse from .types import ControlPanelApiListControlPanelsRequest from .types import DatabaseApiAssignDatabaseUserRequest @@ -72,14 +84,18 @@ from .types import FtpAccountApiListFtpAccountsRequest from .types import FtpAccountApiRemoveFtpAccountRequest from .types import Hosting +from .types import HostingApiAddCustomDomainRequest from .types import HostingApiCreateHostingRequest from .types import HostingApiCreateSessionRequest from .types import HostingApiDeleteHostingRequest from .types import HostingApiGetHostingRequest from .types import HostingApiGetResourceSummaryRequest from .types import HostingApiListHostingsRequest +from .types import HostingApiRemoveCustomDomainRequest from .types import HostingApiResetHostingPasswordRequest from .types import HostingApiUpdateHostingRequest +from .types import ListBackupItemsResponse +from .types import ListBackupsResponse from .types import ListControlPanelsResponse from .types import ListDatabaseUsersResponse from .types import ListDatabasesResponse @@ -95,9 +111,12 @@ from .types import OfferApiListOffersRequest from .types import ResetHostingPasswordResponse from .types import ResourceSummary +from .types import RestoreBackupItemsResponse +from .types import RestoreBackupResponse from .types import SearchDomainsResponse from .types import Session from .types import WebsiteApiListWebsitesRequest +from .api import WebhostingV1BackupAPI from .api import WebhostingV1ControlPanelAPI from .api import WebhostingV1DatabaseAPI from .api import WebhostingV1DnsAPI @@ -108,6 +127,9 @@ from .api import WebhostingV1WebsiteAPI __all__ = [ + "BackupItemType", + "BackupStatus", + "BACKUP_TRANSIENT_STATUSES", "DnsRecordStatus", "DnsRecordType", "DnsRecordsStatus", @@ -121,6 +143,7 @@ "DomainZoneOwner", "HostingStatus", "HOSTING_TRANSIENT_STATUSES", + "ListBackupsRequestOrderBy", "ListDatabaseUsersRequestOrderBy", "ListDatabasesRequestOrderBy", "ListFtpAccountsRequestOrderBy", @@ -137,6 +160,7 @@ "HostingDomainCustomDomain", "OfferOption", "PlatformControlPanel", + "BackupItem", "HostingDomain", "CreateDatabaseRequestUser", "CreateHostingRequestDomainConfiguration", @@ -147,6 +171,8 @@ "HostingUser", "Offer", "Platform", + "BackupItemGroup", + "Backup", "ControlPanel", "DatabaseUser", "Database", @@ -155,6 +181,11 @@ "MailAccount", "Website", "DomainAvailability", + "BackupApiGetBackupRequest", + "BackupApiListBackupItemsRequest", + "BackupApiListBackupsRequest", + "BackupApiRestoreBackupItemsRequest", + "BackupApiRestoreBackupRequest", "CheckUserOwnsDomainResponse", "ControlPanelApiListControlPanelsRequest", "DatabaseApiAssignDatabaseUserRequest", @@ -180,14 +211,18 @@ "FtpAccountApiListFtpAccountsRequest", "FtpAccountApiRemoveFtpAccountRequest", "Hosting", + "HostingApiAddCustomDomainRequest", "HostingApiCreateHostingRequest", "HostingApiCreateSessionRequest", "HostingApiDeleteHostingRequest", "HostingApiGetHostingRequest", "HostingApiGetResourceSummaryRequest", "HostingApiListHostingsRequest", + "HostingApiRemoveCustomDomainRequest", "HostingApiResetHostingPasswordRequest", "HostingApiUpdateHostingRequest", + "ListBackupItemsResponse", + "ListBackupsResponse", "ListControlPanelsResponse", "ListDatabaseUsersResponse", "ListDatabasesResponse", @@ -203,9 +238,12 @@ "OfferApiListOffersRequest", "ResetHostingPasswordResponse", "ResourceSummary", + "RestoreBackupItemsResponse", + "RestoreBackupResponse", "SearchDomainsResponse", "Session", "WebsiteApiListWebsitesRequest", + "WebhostingV1BackupAPI", "WebhostingV1ControlPanelAPI", "WebhostingV1DatabaseAPI", "WebhostingV1DnsAPI", diff --git a/scaleway/scaleway/webhosting/v1/api.py b/scaleway/scaleway/webhosting/v1/api.py index 8a6214acf..9d785c5ab 100644 --- a/scaleway/scaleway/webhosting/v1/api.py +++ b/scaleway/scaleway/webhosting/v1/api.py @@ -15,6 +15,7 @@ ) from .types import ( HostingStatus, + ListBackupsRequestOrderBy, ListDatabaseUsersRequestOrderBy, ListDatabasesRequestOrderBy, ListFtpAccountsRequestOrderBy, @@ -23,6 +24,8 @@ ListOffersRequestOrderBy, ListWebsitesRequestOrderBy, AutoConfigDomainDns, + Backup, + BackupApiRestoreBackupItemsRequest, CheckUserOwnsDomainResponse, ControlPanel, CreateDatabaseRequestUser, @@ -42,9 +45,12 @@ FtpAccountApiChangeFtpAccountPasswordRequest, FtpAccountApiCreateFtpAccountRequest, Hosting, + HostingApiAddCustomDomainRequest, HostingApiCreateHostingRequest, HostingApiUpdateHostingRequest, HostingSummary, + ListBackupItemsResponse, + ListBackupsResponse, ListControlPanelsResponse, ListDatabaseUsersResponse, ListDatabasesResponse, @@ -61,24 +67,31 @@ OfferOptionRequest, ResetHostingPasswordResponse, ResourceSummary, + RestoreBackupItemsResponse, + RestoreBackupResponse, SearchDomainsResponse, Session, SyncDomainDnsRecordsRequestRecord, Website, ) from .content import ( + BACKUP_TRANSIENT_STATUSES, DOMAIN_TRANSIENT_STATUSES, HOSTING_TRANSIENT_STATUSES, ) from .marshalling import ( + unmarshal_Backup, unmarshal_DatabaseUser, unmarshal_Database, unmarshal_FtpAccount, + unmarshal_HostingSummary, unmarshal_MailAccount, unmarshal_CheckUserOwnsDomainResponse, unmarshal_DnsRecords, unmarshal_Domain, unmarshal_Hosting, + unmarshal_ListBackupItemsResponse, + unmarshal_ListBackupsResponse, unmarshal_ListControlPanelsResponse, unmarshal_ListDatabaseUsersResponse, unmarshal_ListDatabasesResponse, @@ -89,8 +102,11 @@ unmarshal_ListWebsitesResponse, unmarshal_ResetHostingPasswordResponse, unmarshal_ResourceSummary, + unmarshal_RestoreBackupItemsResponse, + unmarshal_RestoreBackupResponse, unmarshal_SearchDomainsResponse, unmarshal_Session, + marshal_BackupApiRestoreBackupItemsRequest, marshal_DatabaseApiAssignDatabaseUserRequest, marshal_DatabaseApiChangeDatabaseUserPasswordRequest, marshal_DatabaseApiCreateDatabaseRequest, @@ -100,6 +116,7 @@ marshal_DnsApiSyncDomainDnsRecordsRequest, marshal_FtpAccountApiChangeFtpAccountPasswordRequest, marshal_FtpAccountApiCreateFtpAccountRequest, + marshal_HostingApiAddCustomDomainRequest, marshal_HostingApiCreateHostingRequest, marshal_HostingApiUpdateHostingRequest, marshal_MailAccountApiChangeMailAccountPasswordRequest, @@ -111,6 +128,292 @@ ) +class WebhostingV1BackupAPI(API): + """ + This API allows you to list and restore backups for your cPanel and WordPress Web Hosting service. + """ + + def list_backups( + self, + *, + hosting_id: str, + region: Optional[ScwRegion] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + order_by: Optional[ListBackupsRequestOrderBy] = None, + ) -> ListBackupsResponse: + """ + List all available backups for a hosting account. + :param hosting_id: UUID of the hosting account. + :param region: Region to target. If none is passed will use default region from the config. + :param page: Page number to retrieve. + :param page_size: Number of backups to return per page. + :param order_by: Order in which to return the list of backups. + :return: :class:`ListBackupsResponse ` + + Usage: + :: + + result = api.list_backups( + hosting_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "GET", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/backups", + params={ + "order_by": order_by, + "page": page, + "page_size": page_size or self.client.default_page_size, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListBackupsResponse(res.json()) + + def list_backups_all( + self, + *, + hosting_id: str, + region: Optional[ScwRegion] = None, + page: Optional[int] = None, + page_size: Optional[int] = None, + order_by: Optional[ListBackupsRequestOrderBy] = None, + ) -> List[Backup]: + """ + List all available backups for a hosting account. + :param hosting_id: UUID of the hosting account. + :param region: Region to target. If none is passed will use default region from the config. + :param page: Page number to retrieve. + :param page_size: Number of backups to return per page. + :param order_by: Order in which to return the list of backups. + :return: :class:`List[Backup] ` + + Usage: + :: + + result = api.list_backups_all( + hosting_id="example", + ) + """ + + return fetch_all_pages( + type=ListBackupsResponse, + key="backups", + fetcher=self.list_backups, + args={ + "hosting_id": hosting_id, + "region": region, + "page": page, + "page_size": page_size, + "order_by": order_by, + }, + ) + + def get_backup( + self, + *, + hosting_id: str, + backup_id: str, + region: Optional[ScwRegion] = None, + ) -> Backup: + """ + Get info about a backup specified by the backup ID. + :param hosting_id: UUID of the hosting account. + :param backup_id: ID of the backup to retrieve. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`Backup ` + + Usage: + :: + + result = api.get_backup( + hosting_id="example", + backup_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + param_backup_id = validate_path_param("backup_id", backup_id) + + res = self._request( + "GET", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/backups/{param_backup_id}", + ) + + self._throw_on_error(res) + return unmarshal_Backup(res.json()) + + def wait_for_backup( + self, + *, + hosting_id: str, + backup_id: str, + region: Optional[ScwRegion] = None, + options: Optional[WaitForOptions[Backup, bool]] = None, + ) -> Backup: + """ + Get info about a backup specified by the backup ID. + :param hosting_id: UUID of the hosting account. + :param backup_id: ID of the backup to retrieve. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`Backup ` + + Usage: + :: + + result = api.get_backup( + hosting_id="example", + backup_id="example", + ) + """ + + if not options: + options = WaitForOptions() + + if not options.stop: + options.stop = lambda res: res.status not in BACKUP_TRANSIENT_STATUSES + + return wait_for_resource( + fetcher=self.get_backup, + options=options, + args={ + "hosting_id": hosting_id, + "backup_id": backup_id, + "region": region, + }, + ) + + def restore_backup( + self, + *, + hosting_id: str, + backup_id: str, + region: Optional[ScwRegion] = None, + ) -> RestoreBackupResponse: + """ + Restore an entire backup to your hosting environment. + :param hosting_id: UUID of the hosting account. + :param backup_id: ID of the backup to fully restore. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`RestoreBackupResponse ` + + Usage: + :: + + result = api.restore_backup( + hosting_id="example", + backup_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + param_backup_id = validate_path_param("backup_id", backup_id) + + res = self._request( + "POST", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/backups/{param_backup_id}/restore", + body={}, + ) + + self._throw_on_error(res) + return unmarshal_RestoreBackupResponse(res.json()) + + def list_backup_items( + self, + *, + hosting_id: str, + backup_id: str, + region: Optional[ScwRegion] = None, + ) -> ListBackupItemsResponse: + """ + List items within a specific backup, grouped by type. + :param hosting_id: UUID of the hosting account. + :param backup_id: ID of the backup to list items from. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`ListBackupItemsResponse ` + + Usage: + :: + + result = api.list_backup_items( + hosting_id="example", + backup_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "GET", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/backup-items", + params={ + "backup_id": backup_id, + }, + ) + + self._throw_on_error(res) + return unmarshal_ListBackupItemsResponse(res.json()) + + def restore_backup_items( + self, + *, + hosting_id: str, + region: Optional[ScwRegion] = None, + item_ids: Optional[List[str]] = None, + ) -> RestoreBackupItemsResponse: + """ + Restore specific items from a backup (e.g., a database or mailbox). + :param hosting_id: UUID of the hosting account. + :param region: Region to target. If none is passed will use default region from the config. + :param item_ids: List of backup item IDs to restore individually. + :return: :class:`RestoreBackupItemsResponse ` + + Usage: + :: + + result = api.restore_backup_items( + hosting_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "POST", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/restore-backup-items", + body=marshal_BackupApiRestoreBackupItemsRequest( + BackupApiRestoreBackupItemsRequest( + hosting_id=hosting_id, + region=region, + item_ids=item_ids, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_RestoreBackupItemsResponse(res.json()) + + class WebhostingV1ControlPanelAPI(API): """ This API allows you to manage your Web Hosting services. @@ -1555,6 +1858,84 @@ def get_resource_summary( self._throw_on_error(res) return unmarshal_ResourceSummary(res.json()) + def add_custom_domain( + self, + *, + hosting_id: str, + domain_name: str, + region: Optional[ScwRegion] = None, + ) -> HostingSummary: + """ + Attach a custom domain to a webhosting. + :param hosting_id: Hosting ID to which the custom domain is attached to. + :param domain_name: The custom domain name to attach to the hosting. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`HostingSummary ` + + Usage: + :: + + result = api.add_custom_domain( + hosting_id="example", + domain_name="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "POST", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/add-custom-domain", + body=marshal_HostingApiAddCustomDomainRequest( + HostingApiAddCustomDomainRequest( + hosting_id=hosting_id, + domain_name=domain_name, + region=region, + ), + self.client, + ), + ) + + self._throw_on_error(res) + return unmarshal_HostingSummary(res.json()) + + def remove_custom_domain( + self, + *, + hosting_id: str, + region: Optional[ScwRegion] = None, + ) -> HostingSummary: + """ + Detach a custom domain from a webhosting. + :param hosting_id: Hosting ID to which the custom domain is detached from. + :param region: Region to target. If none is passed will use default region from the config. + :return: :class:`HostingSummary ` + + Usage: + :: + + result = api.remove_custom_domain( + hosting_id="example", + ) + """ + + param_region = validate_path_param( + "region", region or self.client.default_region + ) + param_hosting_id = validate_path_param("hosting_id", hosting_id) + + res = self._request( + "POST", + f"/webhosting/v1/regions/{param_region}/hostings/{param_hosting_id}/remove-custom-domain", + body={}, + ) + + self._throw_on_error(res) + return unmarshal_HostingSummary(res.json()) + class WebhostingV1FtpAccountAPI(API): """ diff --git a/scaleway/scaleway/webhosting/v1/content.py b/scaleway/scaleway/webhosting/v1/content.py index 895da5659..e77f5228b 100644 --- a/scaleway/scaleway/webhosting/v1/content.py +++ b/scaleway/scaleway/webhosting/v1/content.py @@ -3,11 +3,18 @@ from typing import List from .types import ( + BackupStatus, DomainAvailabilityStatus, DomainStatus, HostingStatus, ) +BACKUP_TRANSIENT_STATUSES: List[BackupStatus] = [ + BackupStatus.RESTORING, +] +""" +Lists transient statutes of the enum :class:`BackupStatus `. +""" DOMAIN_AVAILABILITY_TRANSIENT_STATUSES: List[DomainAvailabilityStatus] = [ DomainAvailabilityStatus.VALIDATING, ] diff --git a/scaleway/scaleway/webhosting/v1/marshalling.py b/scaleway/scaleway/webhosting/v1/marshalling.py index 3825815ee..fc5100f5e 100644 --- a/scaleway/scaleway/webhosting/v1/marshalling.py +++ b/scaleway/scaleway/webhosting/v1/marshalling.py @@ -16,31 +16,36 @@ DomainAction, DomainAvailabilityAction, DomainDnsAction, + Backup, DatabaseUser, Database, FtpAccount, + AutoConfigDomainDns, + HostingDomainCustomDomain, + HostingDomain, + HostingSummary, MailAccount, CheckUserOwnsDomainResponse, - AutoConfigDomainDns, DnsRecord, Nameserver, DnsRecords, Domain, PlatformControlPanelUrls, - HostingDomainCustomDomain, OfferOption, PlatformControlPanel, - HostingDomain, HostingUser, Offer, Platform, Hosting, + BackupItem, + BackupItemGroup, + ListBackupItemsResponse, + ListBackupsResponse, ControlPanel, ListControlPanelsResponse, ListDatabaseUsersResponse, ListDatabasesResponse, ListFtpAccountsResponse, - HostingSummary, ListHostingsResponse, ListMailAccountsResponse, ListOffersResponse, @@ -48,9 +53,12 @@ ListWebsitesResponse, ResetHostingPasswordResponse, ResourceSummary, + RestoreBackupItemsResponse, + RestoreBackupResponse, DomainAvailability, SearchDomainsResponse, Session, + BackupApiRestoreBackupItemsRequest, DatabaseApiAssignDatabaseUserRequest, DatabaseApiChangeDatabaseUserPasswordRequest, CreateDatabaseRequestUser, @@ -62,6 +70,7 @@ DnsApiSyncDomainDnsRecordsRequest, FtpAccountApiChangeFtpAccountPasswordRequest, FtpAccountApiCreateFtpAccountRequest, + HostingApiAddCustomDomainRequest, CreateHostingRequestDomainConfiguration, OfferOptionRequest, HostingApiCreateHostingRequest, @@ -75,6 +84,39 @@ ) +def unmarshal_Backup(data: Any) -> Backup: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'Backup' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("size", None) + if field is not None: + args["size"] = field + + field = data.get("status", None) + if field is not None: + args["status"] = field + + field = data.get("total_items", None) + if field is not None: + args["total_items"] = field + + 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 + + return Backup(**args) + + def unmarshal_DatabaseUser(data: Any) -> DatabaseUser: if not isinstance(data, dict): raise TypeError( @@ -132,10 +174,41 @@ def unmarshal_FtpAccount(data: Any) -> FtpAccount: return FtpAccount(**args) -def unmarshal_MailAccount(data: Any) -> MailAccount: +def unmarshal_AutoConfigDomainDns(data: Any) -> AutoConfigDomainDns: if not isinstance(data, dict): raise TypeError( - "Unmarshalling the type 'MailAccount' failed as data isn't a dictionary." + "Unmarshalling the type 'AutoConfigDomainDns' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("nameservers", None) + if field is not None: + args["nameservers"] = field + + field = data.get("web_records", None) + if field is not None: + args["web_records"] = field + + field = data.get("mail_records", None) + if field is not None: + args["mail_records"] = field + + field = data.get("all_records", None) + if field is not None: + args["all_records"] = field + + field = data.get("none", None) + if field is not None: + args["none"] = field + + return AutoConfigDomainDns(**args) + + +def unmarshal_HostingDomainCustomDomain(data: Any) -> HostingDomainCustomDomain: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'HostingDomainCustomDomain' failed as data isn't a dictionary." ) args: Dict[str, Any] = {} @@ -144,57 +217,147 @@ def unmarshal_MailAccount(data: Any) -> MailAccount: if field is not None: args["domain"] = field - field = data.get("username", None) + field = data.get("domain_status", None) if field is not None: - args["username"] = field + args["domain_status"] = field - return MailAccount(**args) + field = data.get("dns_status", None) + if field is not None: + args["dns_status"] = field + + field = data.get("auto_config_domain_dns", None) + if field is not None: + args["auto_config_domain_dns"] = unmarshal_AutoConfigDomainDns(field) + else: + args["auto_config_domain_dns"] = None + return HostingDomainCustomDomain(**args) -def unmarshal_CheckUserOwnsDomainResponse(data: Any) -> CheckUserOwnsDomainResponse: + +def unmarshal_HostingDomain(data: Any) -> HostingDomain: if not isinstance(data, dict): raise TypeError( - "Unmarshalling the type 'CheckUserOwnsDomainResponse' failed as data isn't a dictionary." + "Unmarshalling the type 'HostingDomain' failed as data isn't a dictionary." ) args: Dict[str, Any] = {} - field = data.get("owns_domain", None) + field = data.get("subdomain", None) if field is not None: - args["owns_domain"] = field + args["subdomain"] = field - return CheckUserOwnsDomainResponse(**args) + field = data.get("custom_domain", None) + if field is not None: + args["custom_domain"] = unmarshal_HostingDomainCustomDomain(field) + else: + args["custom_domain"] = None + return HostingDomain(**args) -def unmarshal_AutoConfigDomainDns(data: Any) -> AutoConfigDomainDns: + +def unmarshal_HostingSummary(data: Any) -> HostingSummary: if not isinstance(data, dict): raise TypeError( - "Unmarshalling the type 'AutoConfigDomainDns' failed as data isn't a dictionary." + "Unmarshalling the type 'HostingSummary' failed as data isn't a dictionary." ) args: Dict[str, Any] = {} - field = data.get("nameservers", None) + field = data.get("id", None) if field is not None: - args["nameservers"] = field + args["id"] = field - field = data.get("web_records", None) + field = data.get("project_id", None) if field is not None: - args["web_records"] = field + args["project_id"] = field - field = data.get("mail_records", None) + field = data.get("status", None) if field is not None: - args["mail_records"] = field + args["status"] = field - field = data.get("all_records", None) + field = data.get("protected", None) if field is not None: - args["all_records"] = field + args["protected"] = field - field = data.get("none", None) + field = data.get("offer_name", None) if field is not None: - args["none"] = field + args["offer_name"] = field - return AutoConfigDomainDns(**args) + field = data.get("region", None) + if field is not None: + args["region"] = field + + 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("updated_at", None) + if field is not None: + args["updated_at"] = parser.isoparse(field) if isinstance(field, str) else field + else: + args["updated_at"] = None + + field = data.get("domain", None) + if field is not None: + args["domain"] = field + else: + args["domain"] = None + + field = data.get("dns_status", None) + if field is not None: + args["dns_status"] = field + else: + args["dns_status"] = None + + field = data.get("domain_status", None) + if field is not None: + args["domain_status"] = field + else: + args["domain_status"] = None + + field = data.get("domain_info", None) + if field is not None: + args["domain_info"] = unmarshal_HostingDomain(field) + else: + args["domain_info"] = None + + return HostingSummary(**args) + + +def unmarshal_MailAccount(data: Any) -> MailAccount: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'MailAccount' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("domain", None) + if field is not None: + args["domain"] = field + + field = data.get("username", None) + if field is not None: + args["username"] = field + + return MailAccount(**args) + + +def unmarshal_CheckUserOwnsDomainResponse(data: Any) -> CheckUserOwnsDomainResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'CheckUserOwnsDomainResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("owns_domain", None) + if field is not None: + args["owns_domain"] = field + + return CheckUserOwnsDomainResponse(**args) def unmarshal_DnsRecord(data: Any) -> DnsRecord: @@ -368,35 +531,6 @@ def unmarshal_PlatformControlPanelUrls(data: Any) -> PlatformControlPanelUrls: return PlatformControlPanelUrls(**args) -def unmarshal_HostingDomainCustomDomain(data: Any) -> HostingDomainCustomDomain: - if not isinstance(data, dict): - raise TypeError( - "Unmarshalling the type 'HostingDomainCustomDomain' failed as data isn't a dictionary." - ) - - args: Dict[str, Any] = {} - - field = data.get("domain", None) - if field is not None: - args["domain"] = field - - field = data.get("domain_status", None) - if field is not None: - args["domain_status"] = field - - field = data.get("dns_status", None) - if field is not None: - args["dns_status"] = field - - field = data.get("auto_config_domain_dns", None) - if field is not None: - args["auto_config_domain_dns"] = unmarshal_AutoConfigDomainDns(field) - else: - args["auto_config_domain_dns"] = None - - return HostingDomainCustomDomain(**args) - - def unmarshal_OfferOption(data: Any) -> OfferOption: if not isinstance(data, dict): raise TypeError( @@ -463,27 +597,6 @@ def unmarshal_PlatformControlPanel(data: Any) -> PlatformControlPanel: return PlatformControlPanel(**args) -def unmarshal_HostingDomain(data: Any) -> HostingDomain: - if not isinstance(data, dict): - raise TypeError( - "Unmarshalling the type 'HostingDomain' failed as data isn't a dictionary." - ) - - args: Dict[str, Any] = {} - - field = data.get("subdomain", None) - if field is not None: - args["subdomain"] = field - - field = data.get("custom_domain", None) - if field is not None: - args["custom_domain"] = unmarshal_HostingDomainCustomDomain(field) - else: - args["custom_domain"] = None - - return HostingDomain(**args) - - def unmarshal_HostingUser(data: Any) -> HostingUser: if not isinstance(data, dict): raise TypeError( @@ -696,6 +809,106 @@ def unmarshal_Hosting(data: Any) -> Hosting: return Hosting(**args) +def unmarshal_BackupItem(data: Any) -> BackupItem: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'BackupItem' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("id", None) + if field is not None: + args["id"] = field + + field = data.get("name", None) + if field is not None: + args["name"] = field + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("size", None) + if field is not None: + args["size"] = field + + field = data.get("status", None) + if field is not None: + args["status"] = field + + 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 + + return BackupItem(**args) + + +def unmarshal_BackupItemGroup(data: Any) -> BackupItemGroup: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'BackupItemGroup' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("type", None) + if field is not None: + args["type_"] = field + + field = data.get("items", None) + if field is not None: + args["items"] = ( + [unmarshal_BackupItem(v) for v in field] if field is not None else None + ) + + return BackupItemGroup(**args) + + +def unmarshal_ListBackupItemsResponse(data: Any) -> ListBackupItemsResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListBackupItemsResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + field = data.get("groups", None) + if field is not None: + args["groups"] = ( + [unmarshal_BackupItemGroup(v) for v in field] if field is not None else None + ) + + return ListBackupItemsResponse(**args) + + +def unmarshal_ListBackupsResponse(data: Any) -> ListBackupsResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'ListBackupsResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + field = data.get("total_count", None) + if field is not None: + args["total_count"] = field + + field = data.get("backups", None) + if field is not None: + args["backups"] = ( + [unmarshal_Backup(v) for v in field] if field is not None else None + ) + + return ListBackupsResponse(**args) + + def unmarshal_ControlPanel(data: Any) -> ControlPanel: if not isinstance(data, dict): raise TypeError( @@ -809,77 +1022,6 @@ def unmarshal_ListFtpAccountsResponse(data: Any) -> ListFtpAccountsResponse: return ListFtpAccountsResponse(**args) -def unmarshal_HostingSummary(data: Any) -> HostingSummary: - if not isinstance(data, dict): - raise TypeError( - "Unmarshalling the type 'HostingSummary' failed as data isn't a dictionary." - ) - - args: Dict[str, Any] = {} - - field = data.get("id", None) - if field is not None: - args["id"] = field - - field = data.get("project_id", None) - if field is not None: - args["project_id"] = field - - field = data.get("status", None) - if field is not None: - args["status"] = field - - field = data.get("protected", None) - if field is not None: - args["protected"] = field - - field = data.get("offer_name", None) - if field is not None: - args["offer_name"] = field - - field = data.get("region", None) - if field is not None: - args["region"] = field - - 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("updated_at", None) - if field is not None: - args["updated_at"] = parser.isoparse(field) if isinstance(field, str) else field - else: - args["updated_at"] = None - - field = data.get("domain", None) - if field is not None: - args["domain"] = field - else: - args["domain"] = None - - field = data.get("dns_status", None) - if field is not None: - args["dns_status"] = field - else: - args["dns_status"] = None - - field = data.get("domain_status", None) - if field is not None: - args["domain_status"] = field - else: - args["domain_status"] = None - - field = data.get("domain_info", None) - if field is not None: - args["domain_info"] = unmarshal_HostingDomain(field) - else: - args["domain_info"] = None - - return HostingSummary(**args) - - def unmarshal_ListHostingsResponse(data: Any) -> ListHostingsResponse: if not isinstance(data, dict): raise TypeError( @@ -1035,6 +1177,28 @@ def unmarshal_ResourceSummary(data: Any) -> ResourceSummary: return ResourceSummary(**args) +def unmarshal_RestoreBackupItemsResponse(data: Any) -> RestoreBackupItemsResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'RestoreBackupItemsResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + return RestoreBackupItemsResponse(**args) + + +def unmarshal_RestoreBackupResponse(data: Any) -> RestoreBackupResponse: + if not isinstance(data, dict): + raise TypeError( + "Unmarshalling the type 'RestoreBackupResponse' failed as data isn't a dictionary." + ) + + args: Dict[str, Any] = {} + + return RestoreBackupResponse(**args) + + def unmarshal_DomainAvailability(data: Any) -> DomainAvailability: if not isinstance(data, dict): raise TypeError( @@ -1108,6 +1272,18 @@ def unmarshal_Session(data: Any) -> Session: return Session(**args) +def marshal_BackupApiRestoreBackupItemsRequest( + request: BackupApiRestoreBackupItemsRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.item_ids is not None: + output["item_ids"] = request.item_ids + + return output + + def marshal_DatabaseApiAssignDatabaseUserRequest( request: DatabaseApiAssignDatabaseUserRequest, defaults: ProfileDefaults, @@ -1315,6 +1491,18 @@ def marshal_FtpAccountApiCreateFtpAccountRequest( return output +def marshal_HostingApiAddCustomDomainRequest( + request: HostingApiAddCustomDomainRequest, + defaults: ProfileDefaults, +) -> Dict[str, Any]: + output: Dict[str, Any] = {} + + if request.domain_name is not None: + output["domain_name"] = request.domain_name + + return output + + def marshal_CreateHostingRequestDomainConfiguration( request: CreateHostingRequestDomainConfiguration, defaults: ProfileDefaults, diff --git a/scaleway/scaleway/webhosting/v1/types.py b/scaleway/scaleway/webhosting/v1/types.py index 13e8ef91e..5d8a68805 100644 --- a/scaleway/scaleway/webhosting/v1/types.py +++ b/scaleway/scaleway/webhosting/v1/types.py @@ -20,6 +20,34 @@ ) +class BackupItemType(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_BACKUP_ITEM_TYPE = "unknown_backup_item_type" + FULL = "full" + WEB = "web" + MAIL = "mail" + DB = "db" + DB_USER = "db_user" + FTP_USER = "ftp_user" + DNS_ZONE = "dns_zone" + CRON_JOB = "cron_job" + SSL_CERTIFICATE = "ssl_certificate" + + def __str__(self) -> str: + return str(self.value) + + +class BackupStatus(str, Enum, metaclass=StrEnumMeta): + UNKNOWN_BACKUP_STATUS = "unknown_backup_status" + ACTIVE = "active" + LOCKED = "locked" + DISABLED = "disabled" + DAMAGED = "damaged" + RESTORING = "restoring" + + def __str__(self) -> str: + return str(self.value) + + class DnsRecordStatus(str, Enum, metaclass=StrEnumMeta): UNKNOWN_STATUS = "unknown_status" VALID = "valid" @@ -131,6 +159,14 @@ def __str__(self) -> str: return str(self.value) +class ListBackupsRequestOrderBy(str, Enum, metaclass=StrEnumMeta): + CREATED_AT_DESC = "created_at_desc" + CREATED_AT_ASC = "created_at_asc" + + def __str__(self) -> str: + return str(self.value) + + class ListDatabaseUsersRequestOrderBy(str, Enum, metaclass=StrEnumMeta): USERNAME_ASC = "username_asc" USERNAME_DESC = "username_desc" @@ -352,6 +388,39 @@ class PlatformControlPanel: """ +@dataclass +class BackupItem: + id: str + """ + ID of the item. + """ + + name: str + """ + Name of the item (e.g., `database name`, `email address`). + """ + + type_: BackupItemType + """ + Type of the item (e.g., email, database, FTP). + """ + + size: int + """ + Size of the item in bytes. + """ + + status: BackupStatus + """ + Status of the item. Available values are `active`, `damaged`, and `restoring`. + """ + + created_at: Optional[datetime] + """ + Date and time at which this item was backed up. + """ + + @dataclass class HostingDomain: subdomain: str @@ -563,6 +632,47 @@ class Platform: """ +@dataclass +class BackupItemGroup: + type_: BackupItemType + """ + Type of items (e.g., email, database, FTP). + """ + + items: List[BackupItem] + """ + List of individual backup items of this type. + """ + + +@dataclass +class Backup: + id: str + """ + ID of the backup. + """ + + size: int + """ + Total size of the backup in bytes. + """ + + status: BackupStatus + """ + Status of the backup. Available values are `active`, `locked`, and `restoring`. + """ + + total_items: int + """ + Total number of restorable items in the backup. + """ + + created_at: Optional[datetime] + """ + Creation date of the backup. + """ + + @dataclass class ControlPanel: name: str @@ -752,6 +862,106 @@ class DomainAvailability: """ +@dataclass +class BackupApiGetBackupRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + backup_id: str + """ + ID of the backup to retrieve. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + +@dataclass +class BackupApiListBackupItemsRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + backup_id: str + """ + ID of the backup to list items from. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + +@dataclass +class BackupApiListBackupsRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + page: Optional[int] + """ + Page number to retrieve. + """ + + page_size: Optional[int] + """ + Number of backups to return per page. + """ + + order_by: Optional[ListBackupsRequestOrderBy] + """ + Order in which to return the list of backups. + """ + + +@dataclass +class BackupApiRestoreBackupItemsRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + item_ids: Optional[List[str]] + """ + List of backup item IDs to restore individually. + """ + + +@dataclass +class BackupApiRestoreBackupRequest: + hosting_id: str + """ + UUID of the hosting account. + """ + + backup_id: str + """ + ID of the backup to fully restore. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + @dataclass class CheckUserOwnsDomainResponse: owns_domain: bool @@ -1381,6 +1591,24 @@ class Hosting: """ +@dataclass +class HostingApiAddCustomDomainRequest: + hosting_id: str + """ + Hosting ID to which the custom domain is attached to. + """ + + domain_name: str + """ + The custom domain name to attach to the hosting. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + @dataclass class HostingApiCreateHostingRequest: offer_id: str @@ -1554,6 +1782,19 @@ class HostingApiListHostingsRequest: """ +@dataclass +class HostingApiRemoveCustomDomainRequest: + hosting_id: str + """ + Hosting ID to which the custom domain is detached from. + """ + + region: Optional[ScwRegion] + """ + Region to target. If none is passed will use default region from the config. + """ + + @dataclass class HostingApiResetHostingPasswordRequest: hosting_id: str @@ -1605,6 +1846,32 @@ class HostingApiUpdateHostingRequest: """ +@dataclass +class ListBackupItemsResponse: + total_count: int + """ + Total number of backup item groups. + """ + + groups: List[BackupItemGroup] + """ + List of backup item groups categorized by type. + """ + + +@dataclass +class ListBackupsResponse: + total_count: int + """ + Total number of available backups. + """ + + backups: List[Backup] + """ + List of available backups. + """ + + @dataclass class ListControlPanelsResponse: total_count: int @@ -1890,6 +2157,16 @@ class ResourceSummary: """ +@dataclass +class RestoreBackupItemsResponse: + pass + + +@dataclass +class RestoreBackupResponse: + pass + + @dataclass class SearchDomainsResponse: domains_available: List[DomainAvailability]