diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d0a17ff2..85c6d399b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ - `git`: [v0.4.0](services/git/CHANGELOG.md#v040) - **Version**: Minimal version is now python 3.9 - `iaas`: + - [v0.8.0](services/iaas/CHANGELOG.md#v080) + - **Feature:** Add new method to get project details `GetProjectDetails` - [v0.7.0](services/iaas/CHANGELOG.md#v070) - **Docs:** Improved descriptions of properties in structs with their possible values - **Feature:** Add `Agent` field to `CreateImagePayload`, `UpdateImagePayload` and `Image` model diff --git a/services/iaas/CHANGELOG.md b/services/iaas/CHANGELOG.md index 1717245ef..6c0999d96 100644 --- a/services/iaas/CHANGELOG.md +++ b/services/iaas/CHANGELOG.md @@ -1,3 +1,6 @@ +## v0.8.0 +- **Feature:** Add new method to get project details `GetProjectDetails` + ## v0.7.0 - **Docs:** Improved descriptions of properties in structs with their possible values - **Feature:** Add `Agent` field to `CreateImagePayload`, `UpdateImagePayload` and `Image` model diff --git a/services/iaas/pyproject.toml b/services/iaas/pyproject.toml index fbe86b830..1fafb3dc6 100644 --- a/services/iaas/pyproject.toml +++ b/services/iaas/pyproject.toml @@ -3,7 +3,7 @@ name = "stackit-iaas" [tool.poetry] name = "stackit-iaas" -version = "v0.7.0" +version = "v0.8.0" authors = [ "STACKIT Developer Tools ", ] diff --git a/services/iaas/src/stackit/iaas/__init__.py b/services/iaas/src/stackit/iaas/__init__.py index af58a7ed8..e9f002e2f 100644 --- a/services/iaas/src/stackit/iaas/__init__.py +++ b/services/iaas/src/stackit/iaas/__init__.py @@ -35,6 +35,7 @@ "AllowedAddressesInner", "Area", "AreaConfig", + "AreaId", "AreaPrefixConfigIPv4", "AvailabilityZoneListResponse", "Backup", @@ -95,6 +96,7 @@ "PartialUpdateNetworkAreaPayload", "PartialUpdateNetworkPayload", "PortRange", + "Project", "ProjectListResponse", "Protocol", "PublicIp", @@ -125,6 +127,7 @@ "SetImageSharePayload", "Snapshot", "SnapshotListResponse", + "StaticAreaID", "UpdateAreaAddressFamily", "UpdateAreaIPv4", "UpdateAttachedVolumePayload", @@ -179,6 +182,7 @@ ) from stackit.iaas.models.area import Area as Area from stackit.iaas.models.area_config import AreaConfig as AreaConfig +from stackit.iaas.models.area_id import AreaId as AreaId from stackit.iaas.models.area_prefix_config_ipv4 import ( AreaPrefixConfigIPv4 as AreaPrefixConfigIPv4, ) @@ -313,6 +317,7 @@ PartialUpdateNetworkPayload as PartialUpdateNetworkPayload, ) from stackit.iaas.models.port_range import PortRange as PortRange +from stackit.iaas.models.project import Project as Project from stackit.iaas.models.project_list_response import ( ProjectListResponse as ProjectListResponse, ) @@ -377,6 +382,7 @@ from stackit.iaas.models.snapshot_list_response import ( SnapshotListResponse as SnapshotListResponse, ) +from stackit.iaas.models.static_area_id import StaticAreaID as StaticAreaID from stackit.iaas.models.update_area_address_family import ( UpdateAreaAddressFamily as UpdateAreaAddressFamily, ) diff --git a/services/iaas/src/stackit/iaas/api/default_api.py b/services/iaas/src/stackit/iaas/api/default_api.py index e7d62e5c8..be3bf0f55 100644 --- a/services/iaas/src/stackit/iaas/api/default_api.py +++ b/services/iaas/src/stackit/iaas/api/default_api.py @@ -80,6 +80,7 @@ from stackit.iaas.models.partial_update_network_payload import ( PartialUpdateNetworkPayload, ) +from stackit.iaas.models.project import Project from stackit.iaas.models.project_list_response import ProjectListResponse from stackit.iaas.models.public_ip import PublicIp from stackit.iaas.models.public_ip_list_response import PublicIpListResponse @@ -15397,6 +15398,256 @@ def _get_organization_request_serialize( _request_auth=_request_auth, ) + @validate_call + def get_project_details( + self, + project_id: Annotated[ + str, + Field(min_length=36, strict=True, max_length=36, description="The identifier (ID) of a STACKIT Project."), + ], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> Project: + """Get project details. + + Get details about a STACKIT project. + + :param project_id: The identifier (ID) of a STACKIT Project. (required) + :type project_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_project_details_serialize( + project_id=project_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "Project", + "400": "Error", + "401": "Error", + "403": "Error", + "404": "Error", + "500": "Error", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + @validate_call + def get_project_details_with_http_info( + self, + project_id: Annotated[ + str, + Field(min_length=36, strict=True, max_length=36, description="The identifier (ID) of a STACKIT Project."), + ], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[Project]: + """Get project details. + + Get details about a STACKIT project. + + :param project_id: The identifier (ID) of a STACKIT Project. (required) + :type project_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_project_details_serialize( + project_id=project_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "Project", + "400": "Error", + "401": "Error", + "403": "Error", + "404": "Error", + "500": "Error", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + @validate_call + def get_project_details_without_preload_content( + self, + project_id: Annotated[ + str, + Field(min_length=36, strict=True, max_length=36, description="The identifier (ID) of a STACKIT Project."), + ], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Get project details. + + Get details about a STACKIT project. + + :param project_id: The identifier (ID) of a STACKIT Project. (required) + :type project_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._get_project_details_serialize( + project_id=project_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "Project", + "400": "Error", + "401": "Error", + "403": "Error", + "404": "Error", + "500": "Error", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + return response_data.response + + def _get_project_details_serialize( + self, + project_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = {} + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if project_id is not None: + _path_params["projectId"] = project_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + # set the HTTP header `Accept` + if "Accept" not in _header_params: + _header_params["Accept"] = self.api_client.select_header_accept(["application/json"]) + + # authentication setting + _auth_settings: List[str] = [] + + return self.api_client.param_serialize( + method="GET", + resource_path="/v1/projects/{projectId}", + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth, + ) + @validate_call def get_project_nic( self, diff --git a/services/iaas/src/stackit/iaas/models/__init__.py b/services/iaas/src/stackit/iaas/models/__init__.py index c0aa4e43e..1e7590a3d 100644 --- a/services/iaas/src/stackit/iaas/models/__init__.py +++ b/services/iaas/src/stackit/iaas/models/__init__.py @@ -21,6 +21,7 @@ from stackit.iaas.models.allowed_addresses_inner import AllowedAddressesInner from stackit.iaas.models.area import Area from stackit.iaas.models.area_config import AreaConfig +from stackit.iaas.models.area_id import AreaId from stackit.iaas.models.area_prefix_config_ipv4 import AreaPrefixConfigIPv4 from stackit.iaas.models.availability_zone_list_response import ( AvailabilityZoneListResponse, @@ -99,6 +100,7 @@ PartialUpdateNetworkPayload, ) from stackit.iaas.models.port_range import PortRange +from stackit.iaas.models.project import Project from stackit.iaas.models.project_list_response import ProjectListResponse from stackit.iaas.models.protocol import Protocol from stackit.iaas.models.public_ip import PublicIp @@ -133,6 +135,7 @@ from stackit.iaas.models.set_image_share_payload import SetImageSharePayload from stackit.iaas.models.snapshot import Snapshot from stackit.iaas.models.snapshot_list_response import SnapshotListResponse +from stackit.iaas.models.static_area_id import StaticAreaID from stackit.iaas.models.update_area_address_family import UpdateAreaAddressFamily from stackit.iaas.models.update_area_ipv4 import UpdateAreaIPv4 from stackit.iaas.models.update_attached_volume_payload import ( diff --git a/services/iaas/src/stackit/iaas/models/area_id.py b/services/iaas/src/stackit/iaas/models/area_id.py new file mode 100644 index 000000000..ba44e8a59 --- /dev/null +++ b/services/iaas/src/stackit/iaas/models/area_id.py @@ -0,0 +1,155 @@ +# coding: utf-8 + +""" + IaaS-API + + This API allows you to create and modify IaaS resources. + + The version of the OpenAPI document: 1 + Contact: stackit-iaas@mail.schwarz + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations + +import json +import pprint +from typing import Any, Dict, Optional, Set, Union + +from pydantic import ( + BaseModel, + ConfigDict, + Field, + ValidationError, + field_validator, +) +from typing_extensions import Annotated, Self + +from stackit.iaas.models.static_area_id import StaticAreaID + + +AREAID_ONE_OF_SCHEMAS = ["StaticAreaID", "str"] + + +class AreaId(BaseModel): + """ + The identifier (ID) of an area. + """ + + # data type: str + oneof_schema_1_validator: Optional[Annotated[str, Field(min_length=36, strict=True, max_length=36)]] = Field( + default=None, description="Universally Unique Identifier (UUID)." + ) + # data type: StaticAreaID + oneof_schema_2_validator: Optional[StaticAreaID] = None + actual_instance: Optional[Union[StaticAreaID, str]] = None + one_of_schemas: Set[str] = {"StaticAreaID", "str"} + + model_config = ConfigDict( + validate_assignment=True, + protected_namespaces=(), + ) + + def __init__(self, *args, **kwargs) -> None: + if args: + if len(args) > 1: + raise ValueError("If a position argument is used, only 1 is allowed to set `actual_instance`") + if kwargs: + raise ValueError("If a position argument is used, keyword arguments cannot be used.") + super().__init__(actual_instance=args[0]) + else: + super().__init__(**kwargs) + + @field_validator("actual_instance") + def actual_instance_must_validate_oneof(cls, v): + instance = AreaId.model_construct() + error_messages = [] + match = 0 + # validate data type: str + try: + instance.oneof_schema_1_validator = v + match += 1 + except (ValidationError, ValueError) as e: + error_messages.append(str(e)) + # validate data type: StaticAreaID + if not isinstance(v, StaticAreaID): + error_messages.append(f"Error! Input type `{type(v)}` is not `StaticAreaID`") + else: + match += 1 + if match == 0: + # no match + raise ValueError( + "No match found when setting `actual_instance` in AreaId with oneOf schemas: StaticAreaID, str. Details: " + + ", ".join(error_messages) + ) + else: + return v + + @classmethod + def from_dict(cls, obj: Union[str, Dict[str, Any]]) -> Self: + return cls.from_json(json.dumps(obj)) + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Returns the object represented by the json string""" + instance = cls.model_construct() + error_messages = [] + match = 0 + + # deserialize data into str + try: + # validation + instance.oneof_schema_1_validator = json.loads(json_str) + # assign value to actual_instance + instance.actual_instance = instance.oneof_schema_1_validator + match += 1 + except (ValidationError, ValueError) as e: + error_messages.append(str(e)) + # deserialize data into StaticAreaID + try: + instance.actual_instance = StaticAreaID.from_json(json_str) + match += 1 + except (ValidationError, ValueError) as e: + error_messages.append(str(e)) + + if match > 1: + # more than 1 match + raise ValueError( + "Multiple matches found when deserializing the JSON string into AreaId with oneOf schemas: StaticAreaID, str. Details: " + + ", ".join(error_messages) + ) + elif match == 0: + # no match + raise ValueError( + "No match found when deserializing the JSON string into AreaId with oneOf schemas: StaticAreaID, str. Details: " + + ", ".join(error_messages) + ) + else: + return instance + + def to_json(self) -> str: + """Returns the JSON representation of the actual instance""" + if self.actual_instance is None: + return "null" + + if hasattr(self.actual_instance, "to_json") and callable(self.actual_instance.to_json): + return self.actual_instance.to_json() + else: + return json.dumps(self.actual_instance) + + def to_dict(self) -> Optional[Union[Dict[str, Any], StaticAreaID, str]]: + """Returns the dict representation of the actual instance""" + if self.actual_instance is None: + return None + + if hasattr(self.actual_instance, "to_dict") and callable(self.actual_instance.to_dict): + return self.actual_instance.to_dict() + else: + # primitive type + return self.actual_instance + + def to_str(self) -> str: + """Returns the string representation of the actual instance""" + return pprint.pformat(self.model_dump()) diff --git a/services/iaas/src/stackit/iaas/models/project.py b/services/iaas/src/stackit/iaas/models/project.py new file mode 100644 index 000000000..f598de506 --- /dev/null +++ b/services/iaas/src/stackit/iaas/models/project.py @@ -0,0 +1,160 @@ +# coding: utf-8 + +""" + IaaS-API + + This API allows you to create and modify IaaS resources. + + The version of the OpenAPI document: 1 + Contact: stackit-iaas@mail.schwarz + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations + +import json +import pprint +import re # noqa: F401 +from datetime import datetime +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import ( + BaseModel, + ConfigDict, + Field, + StrictBool, + StrictStr, + field_validator, +) +from typing_extensions import Annotated, Self + +from stackit.iaas.models.area_id import AreaId + + +class Project(BaseModel): + """ + Object that represents a STACKIT project. + """ # noqa: E501 + + area_id: AreaId = Field(alias="areaId") + created_at: Optional[datetime] = Field( + default=None, description="Date-time when resource was created.", alias="createdAt" + ) + internet_access: Optional[StrictBool] = Field(default=None, alias="internetAccess") + openstack_project_id: Optional[Annotated[str, Field(min_length=32, strict=True, max_length=32)]] = Field( + default=None, + description="The identifier (ID) of the OpenStack project in the main region eu01.", + alias="openstackProjectId", + ) + project_id: Annotated[str, Field(min_length=36, strict=True, max_length=36)] = Field( + description="Universally Unique Identifier (UUID).", alias="projectId" + ) + state: StrictStr = Field( + description="The state of a resource object. Possible values: `CREATING`, `CREATED`, `DELETING`, `DELETED`, `FAILED`, `UPDATED`, `UPDATING`." + ) + updated_at: Optional[datetime] = Field( + default=None, description="Date-time when resource was last updated.", alias="updatedAt" + ) + __properties: ClassVar[List[str]] = [ + "areaId", + "createdAt", + "internetAccess", + "openstackProjectId", + "projectId", + "state", + "updatedAt", + ] + + @field_validator("openstack_project_id") + def openstack_project_id_validate_regular_expression(cls, value): + """Validates the regular expression""" + if value is None: + return value + + if not re.match(r"^[0-9a-f]{32}$", value): + raise ValueError(r"must validate the regular expression /^[0-9a-f]{32}$/") + return value + + @field_validator("project_id") + def project_id_validate_regular_expression(cls, value): + """Validates the regular expression""" + if not re.match(r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", value): + raise ValueError( + r"must validate the regular expression /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/" + ) + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of Project from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + * OpenAPI `readOnly` fields are excluded. + * OpenAPI `readOnly` fields are excluded. + * OpenAPI `readOnly` fields are excluded. + """ + excluded_fields: Set[str] = set( + [ + "created_at", + "openstack_project_id", + "updated_at", + ] + ) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of area_id + if self.area_id: + _dict["areaId"] = self.area_id.to_dict() + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of Project from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "areaId": AreaId.from_dict(obj["areaId"]) if obj.get("areaId") is not None else None, + "createdAt": obj.get("createdAt"), + "internetAccess": obj.get("internetAccess"), + "openstackProjectId": obj.get("openstackProjectId"), + "projectId": obj.get("projectId"), + "state": obj.get("state"), + "updatedAt": obj.get("updatedAt"), + } + ) + return _obj diff --git a/services/iaas/src/stackit/iaas/models/static_area_id.py b/services/iaas/src/stackit/iaas/models/static_area_id.py new file mode 100644 index 000000000..979f9ded6 --- /dev/null +++ b/services/iaas/src/stackit/iaas/models/static_area_id.py @@ -0,0 +1,37 @@ +# coding: utf-8 + +""" + IaaS-API + + This API allows you to create and modify IaaS resources. + + The version of the OpenAPI document: 1 + Contact: stackit-iaas@mail.schwarz + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations + +import json +from enum import Enum + +from typing_extensions import Self + + +class StaticAreaID(str, Enum): + """ + The identifier (ID) of a static area. + """ + + """ + allowed enum values + """ + PUBLIC = "PUBLIC" + SCHWARZ = "SCHWARZ" + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Create an instance of StaticAreaID from a JSON string""" + return cls(json.loads(json_str))