Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions clients/client-python/gravitino/api/authorization/owner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from abc import ABC, abstractmethod
from enum import Enum


class Owner(ABC):
"""The interface of an owner. The owner represents the user or group who owns a metadata object."""

class Type(Enum):
"""The type of the owner."""

USER = "USER"
GROUP = "GROUP"

@abstractmethod
def name(self) -> str:
"""The name of the owner.

Returns:
str: The name of the owner.
"""

@abstractmethod
def type(self) -> "Owner.Type":
"""The type of the owner.

Returns:
Owner.Type: The type of the owner.
"""
37 changes: 37 additions & 0 deletions clients/client-python/gravitino/client/gravitino_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@

from typing import Dict, List, Optional

from gravitino.api.authorization.owner import Owner
from gravitino.api.catalog import Catalog
from gravitino.api.catalog_change import CatalogChange
from gravitino.api.job.job_handle import JobHandle
from gravitino.api.job.job_template import JobTemplate
from gravitino.api.job.job_template_change import JobTemplateChange
from gravitino.api.job.supports_jobs import SupportsJobs
from gravitino.api.metadata_object import MetadataObject
from gravitino.api.tag.tag_operations import TagOperations
from gravitino.auth.auth_data_provider import AuthDataProvider
from gravitino.client.gravitino_client_base import GravitinoClientBase
Expand Down Expand Up @@ -330,3 +332,38 @@ def delete_tag(self, tag_name) -> bool:
NoSuchMetalakeException: If the metalake does not exist.
"""
return self.get_metalake().delete_tag(tag_name)

# Owner operations
def get_owner(self, metadata_object: MetadataObject) -> Optional[Owner]:
"""Get the owner of a metadata object.

Args:
metadata_object: The metadata object to get the owner for.

Returns:
Optional[Owner]: The owner of the metadata object, or None if no owner is set.

Raises:
NoSuchMetadataObjectException: If the metadata object does not exist.
NotFoundException: If a related resource is not found.
MetalakeNotInUseException: If the metalake is not in use.
"""
return self.get_metalake().get_owner(metadata_object)

def set_owner(
self, metadata_object: MetadataObject, owner_name: str, owner_type: Owner.Type
) -> None:
"""Set the owner of a metadata object.

Args:
metadata_object: The metadata object to set the owner for.
owner_name: The name of the owner.
owner_type: The type of the owner (USER or GROUP).

Raises:
NoSuchMetadataObjectException: If the metadata object does not exist.
NotFoundException: If a related resource is not found.
MetalakeNotInUseException: If the metalake is not in use.
UnsupportedOperationException: If the operation is not supported.
"""
self.get_metalake().set_owner(metadata_object, owner_name, owner_type)
63 changes: 62 additions & 1 deletion clients/client-python/gravitino/client/gravitino_metalake.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@
# under the License.

import logging
from typing import Dict, List
from typing import Dict, List, Optional

from gravitino.api.authorization.owner import Owner
from gravitino.api.catalog import Catalog
from gravitino.api.catalog_change import CatalogChange
from gravitino.api.job.job_handle import JobHandle
from gravitino.api.job.job_template import JobTemplate
from gravitino.api.job.job_template_change import JobTemplateChange
from gravitino.api.job.supports_jobs import SupportsJobs
from gravitino.api.metadata_object import MetadataObject
from gravitino.api.tag.tag import Tag
from gravitino.api.tag.tag_operations import TagOperations
from gravitino.client.dto_converters import DTOConverters
Expand All @@ -40,6 +42,7 @@
from gravitino.dto.requests.job_template_updates_request import (
JobTemplateUpdatesRequest,
)
from gravitino.dto.requests.owner_set_request import OwnerSetRequest
from gravitino.dto.requests.tag_create_request import TagCreateRequest
from gravitino.dto.requests.tag_updates_request import TagUpdatesRequest
from gravitino.dto.responses.catalog_list_response import CatalogListResponse
Expand All @@ -50,13 +53,16 @@
from gravitino.dto.responses.job_response import JobResponse
from gravitino.dto.responses.job_template_list_response import JobTemplateListResponse
from gravitino.dto.responses.job_template_response import JobTemplateResponse
from gravitino.dto.responses.owner_response import OwnerResponse
from gravitino.dto.responses.set_response import SetResponse
from gravitino.dto.responses.tag_response import (
TagListResponse,
TagNamesListResponse,
TagResponse,
)
from gravitino.exceptions.handlers.catalog_error_handler import CATALOG_ERROR_HANDLER
from gravitino.exceptions.handlers.job_error_handler import JOB_ERROR_HANDLER
from gravitino.exceptions.handlers.owner_error_handler import OWNER_ERROR_HANDLER
from gravitino.exceptions.handlers.tag_error_handler import TAG_ERROR_HANDLER
from gravitino.rest.rest_utils import encode_string
from gravitino.utils.http_client import HTTPClient
Expand All @@ -82,6 +88,7 @@ class GravitinoMetalake(
API_METALAKES_CATALOGS_PATH = "api/metalakes/{}/catalogs/{}"
API_METALAKES_JOB_TEMPLATES_PATH = "api/metalakes/{}/jobs/templates"
API_METALAKES_JOB_RUNS_PATH = "api/metalakes/{}/jobs/runs"
API_METALAKES_OWNERS_PATH = "api/metalakes/{}/owners/{}"
API_METALAKES_TAG_PATH = "api/metalakes/{}/tags/{}"
API_METALAKES_TAGS_PATH = "api/metalakes/{}/tags"

Expand Down Expand Up @@ -704,3 +711,57 @@ def delete_tag(self, tag_name) -> bool:
drop_response.validate()

return drop_response.dropped()

#########
# Owner operations
#########
def get_owner(self, metadata_object: MetadataObject) -> Optional[Owner]:
"""Get the owner of a metadata object.

Args:
metadata_object: The metadata object to get the owner for.

Returns:
Optional[Owner]: The owner of the metadata object, or None if no owner is set.

Raises:
NoSuchMetadataObjectException: If the metadata object does not exist.
NotFoundException: If a related resource is not found.
MetalakeNotInUseException: If the metalake is not in use.
"""
url = self.API_METALAKES_OWNERS_PATH.format(
encode_string(self.name()),
f"{metadata_object.type().value}/{encode_string(metadata_object.full_name())}",
)
response = self.rest_client.get(url, error_handler=OWNER_ERROR_HANDLER)
resp = OwnerResponse.from_json(response.body, infer_missing=True)
resp.validate()
return resp.owner()

def set_owner(
self, metadata_object: MetadataObject, owner_name: str, owner_type: Owner.Type
) -> None:
"""Set the owner of a metadata object.

Args:
metadata_object: The metadata object to set the owner for.
owner_name: The name of the owner.
owner_type: The type of the owner (USER or GROUP).

Raises:
NoSuchMetadataObjectException: If the metadata object does not exist.
NotFoundException: If a related resource is not found.
MetalakeNotInUseException: If the metalake is not in use.
UnsupportedOperationException: If the operation is not supported.
"""
url = self.API_METALAKES_OWNERS_PATH.format(
encode_string(self.name()),
f"{metadata_object.type().value}/{encode_string(metadata_object.full_name())}",
)
req = OwnerSetRequest(owner_name, owner_type)
req.validate()
response = self.rest_client.put(
url, json=req, error_handler=OWNER_ERROR_HANDLER
)
set_resp = SetResponse.from_json(response.body, infer_missing=True)
set_resp.validate()
18 changes: 18 additions & 0 deletions clients/client-python/gravitino/dto/authorization/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from gravitino.dto.authorization.owner_dto import OwnerDTO
37 changes: 37 additions & 0 deletions clients/client-python/gravitino/dto/authorization/owner_dto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from dataclasses import dataclass, field

from dataclasses_json import config, dataclass_json

from gravitino.api.authorization.owner import Owner


@dataclass_json
@dataclass
class OwnerDTO(Owner):
"""Represents an Owner Data Transfer Object (DTO)."""

_name: str = field(metadata=config(field_name="name"))
_type: Owner.Type = field(metadata=config(field_name="type"))

def name(self) -> str:
return self._name

def type(self) -> Owner.Type:
return self._type
43 changes: 43 additions & 0 deletions clients/client-python/gravitino/dto/requests/owner_set_request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from dataclasses import dataclass, field

from dataclasses_json import config, dataclass_json

from gravitino.api.authorization.owner import Owner
from gravitino.exceptions.base import IllegalArgumentException
from gravitino.rest.rest_message import RESTRequest


@dataclass_json
@dataclass
class OwnerSetRequest(RESTRequest):
"""Represents a request to set an owner for a metadata object."""

_name: str = field(metadata=config(field_name="name"))
_type: Owner.Type = field(metadata=config(field_name="type"))

def __init__(self, name: str, owner_type: Owner.Type):
self._name = name
self._type = owner_type

def validate(self) -> None:
if not self._name:
raise IllegalArgumentException('"name" field is required')
if self._type is None:
raise IllegalArgumentException('"type" field is required')
45 changes: 45 additions & 0 deletions clients/client-python/gravitino/dto/responses/owner_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from dataclasses import dataclass, field
from typing import Optional

from dataclasses_json import config

from gravitino.dto.authorization.owner_dto import OwnerDTO
from gravitino.dto.responses.base_response import BaseResponse
from gravitino.exceptions.base import IllegalArgumentException


@dataclass
class OwnerResponse(BaseResponse):
"""Represents a response for the get owner operation."""

_owner: Optional[OwnerDTO] = field(
default=None, metadata=config(field_name="owner")
)

def owner(self) -> Optional[OwnerDTO]:
return self._owner

def validate(self) -> None:
super().validate()
if self._owner is not None:
if not self._owner.name():
raise IllegalArgumentException("owner name must not be empty")
if self._owner.type() is None:
raise IllegalArgumentException("owner type must not be None")
32 changes: 32 additions & 0 deletions clients/client-python/gravitino/dto/responses/set_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

from dataclasses import dataclass, field

from dataclasses_json import config

from gravitino.dto.responses.base_response import BaseResponse


@dataclass
class SetResponse(BaseResponse):
"""Represents a response for a set operation."""

_set: bool = field(metadata=config(field_name="set"))

def set(self) -> bool:
return self._set
Loading