Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add search spec 'projection' #31

Merged
merged 1 commit into from
Mar 19, 2024
Merged
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
100 changes: 83 additions & 17 deletions src/cloudforet/search/conf/search_conf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# aliases are convert 'key' to 'value' name
# tags are store 'key' at tags with result['value']
RESOURCE_TYPES = {
"identity.ServiceAccount": {
"request": {
Expand All @@ -7,17 +9,38 @@
"data.subscription_id",
"data.tenant_id",
"data.project_id",
]
],
"projection": {
"name": 1,
"data": 1,
"service_account_id": 1,
"domain_id": 1,
"workspace_id": 1,
"project_id": 1,
"account": {
"$switch": {
"branches": [
{
"case": {"$ifNull": ["$data.account_id", None]},
"then": "$data.account_id",
},
{
"case": {"$ifNull": ["$data.subscription_id", None]},
"then": "$data.subscription_id",
},
{
"case": {"$ifNull": ["$data.project_id", None]},
"then": "$data.project_id",
},
],
"default": "$service_account_id",
}
},
},
},
"response": {
"resource_id": "service_account_id",
"name": "{account} ({name})",
"aliases": [
{"data.account_id": "account"},
{"data.subscription_id": "account"},
{"data.project_id": "account"},
{"service_account_id": "account"},
],
"name": "{name} ({account})",
},
},
"identity.Project": {
Expand All @@ -29,30 +52,73 @@
"response": {"resource_id": "workspace_id", "name": "{name}"},
},
"inventory.CloudServiceType": {
"request": {"search": ["name", "group", "provider"]},
"request": {
"search": ["name", "group", "provider"],
"projection": {
"group": 1,
"name": 1,
"provider": 1,
"cloud_service_type_id": 1,
"workspace_id": 1,
"domain_id": 1,
"icon": "$tags.spaceone:icon",
},
},
"response": {
"resource_id": "cloud_service_type_id",
"name": "{group} > {name}",
"aliases": [
{"tags.spaceone:icon": "icon"},
],
"tags": {
"provider": "{provider}",
"icon": "{icon}",
"group": "{group}",
"name": "{name}",
"provider": "provider",
"icon": "icon",
"group": "group",
"name": "name",
},
},
},
"inventory.CloudService": {
"request": {
"search": ["name", "ip_addresses", "account"],
"filter": [{"state": "ACTIVE"}],
"projection": {
"cloud_service_id": 1,
"cloud_service_type": 1,
"cloud_service_group": 1,
"name": 1,
"provider": 1,
"ip_addresses": {
"$reduce": {
"input": "$ip_addresses",
"initialValue": "",
"in": {"$concat": ["$$value", "$$this", ","]},
}
},
"project_id": 1,
"workspace_id": 1,
"domain_id": 1,
"ref_resource_id": "$reference.resource_id",
"cloud_service_type_key": {
"$concat": [
"$provider",
":",
"$cloud_service_type",
":",
"$cloud_service_group",
]
},
},
},
"response": {
"resource_id": "cloud_service_id",
"name": "{name}",
"name": "{name}({ip_addresses})({ref_resource_id})",
"description": "{cloud_service_group} > {cloud_service_type}",
"tags": {
"cloud_service_type_key": "cloud_service_type_key",
"ip_addresses": "ip_addresses",
"provider": "provider",
"group": "cloud_service_group",
"name": "cloud_service_type",
"resource_id": "resource_id",
},
},
},
"dashboard.PublicDashboard": {
Expand Down
22 changes: 22 additions & 0 deletions src/cloudforet/search/lib/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
def save_to_dict_value(
data: dict,
dotted_key: str,
value: any,
default_value: any = None,
overwrite: bool = False,
) -> dict:
if "." in dotted_key:
key, rest_dotted_key = dotted_key.split(".", 1)
print("key, rest_dotted_key", key, rest_dotted_key)
if key not in data:
data[key] = {}

if len(rest_dotted_key) > 0:
print("nested")
save_to_dict_value(data[key], rest_dotted_key, value, default_value)
else:
if dotted_key not in data or overwrite is True:
data[dotted_key] = value
print("not dotted", data, dotted_key, value)

return data
3 changes: 2 additions & 1 deletion src/cloudforet/search/manager/resource_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def search_resource(
self,
domain_id: str,
find_filter: dict,
projection: dict,
resource_type: str,
limit: int,
page: int,
Expand All @@ -30,7 +31,7 @@ def search_resource(

results = list(
self.client[db_name][collection_name].find(
filter=find_filter, limit=limit, skip=skip_count
filter=find_filter, projection=projection, limit=limit, skip=skip_count
)
)

Expand Down
11 changes: 6 additions & 5 deletions src/cloudforet/search/service/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from spaceone.core.service.utils import *
from spaceone.core.utils import *

from cloudforet.search.lib.utils import *
from cloudforet.search.manager.resource_manager import ResourceManager
from cloudforet.search.manager.identity_manager import IdentityManager
from cloudforet.search.model.resource.response import *
Expand Down Expand Up @@ -146,8 +147,9 @@ def search(self, params: ResourceSearchRequest) -> Union[ResourcesResponse, dict
)

# search resources
projection = self.search_conf[resource_type]["request"].get("projection", {})
results = self.resource_manager.search_resource(
domain_id, find_filter, resource_type, limit, page
domain_id, find_filter, projection, resource_type, limit, page
)

next_token = self._encode_next_token_base64(
Expand Down Expand Up @@ -280,8 +282,6 @@ def _make_response(
# Make description at response
if description_format:
result["description"] = description_format.format(**result)
if aliases:
result = self._convert_result_by_alias(result, aliases)
if tags:
result = self._add_additional_info_to_tags(result, tags)
else:
Expand Down Expand Up @@ -400,14 +400,15 @@ def _convert_result_by_alias(result: dict, aliases: list) -> dict:
for target_field, alias_name in alias.items():
if value := get_dict_value(result, target_field):
if not result.get(alias_name):
result[alias_name] = value
result[alias_name] = value.format(**result)
# result = save_to_dict_value(result, alias_name, value)
return result

@staticmethod
def _add_additional_info_to_tags(result: dict, tags: dict) -> dict:
response_tags = {}
for key, value in tags.items():
if target_value := get_dict_value(result, key):
if target_value := get_dict_value(result, value):
response_tags[key] = target_value
result["tags"] = response_tags
return result