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
22 changes: 22 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"version": "0.2.0",
"configurations": [
{
"name":"Module Debug",
"type":"debugpy",
"request":"launch",
"module":"spaceone.core.command",
"python":"${workspaceFolder}/.venv/bin/python",
"env": {
"PYTHONPATH":"./src:"
},
"args":[
"run",
"plugin-server",
"-p 50051",
"plugin"
]
}
]
}

17 changes: 17 additions & 0 deletions api_pagination.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
api_pagination:
cloudresourcemanager_v1:
page_size: 100
methods:
list_projects:
page_size: 50
cloudresourcemanager_v3:
page_size: 50
methods:
list_projects:
page_size: 50
list_folders:
page_size: 50
search_folders:
page_size: 50
default:
page_size: 200
3 changes: 2 additions & 1 deletion pkg/pip_requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
google-api-python-client
google-api-python-client
PyYAML
18 changes: 18 additions & 0 deletions src/plugin/config/global_conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from pathlib import Path

import yaml


def load_pagination_config():
# 프로젝트 루트의 api_pagination.yaml 파일을 찾기
config_path = Path(__file__).parent.parent.parent.parent / "api_pagination.yaml"

if config_path.exists():
with open(config_path, "r") as f:
config = yaml.safe_load(f)
return config
else:
return {"api_pagination": {"default": {"page_size": 200}}}


PAGINATION_CONFIG = load_pagination_config()
99 changes: 84 additions & 15 deletions src/plugin/connector/base_connector.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import logging

import google.oauth2.service_account
import googleapiclient
import googleapiclient.discovery
import logging

from spaceone.core.connector import BaseConnector

from plugin.config.global_conf import PAGINATION_CONFIG

_LOGGER = logging.getLogger(__name__)


Expand All @@ -13,19 +15,6 @@ class GoogleCloudConnector(BaseConnector):
version = None

def __init__(self, *args, **kwargs):
"""
kwargs
- schema
- options
- secret_data

secret_data(dict)
- type: ..
- project_id: ...
- token_uri: ...
- ...
"""

super().__init__(*args, **kwargs)
secret_data = kwargs.get("secret_data")
self.project_id = secret_data.get("project_id")
Expand All @@ -47,3 +36,83 @@ def generate_query(self, **query):
}
)
return query

def get_page_size(self, method_name=None):
try:
config = PAGINATION_CONFIG.get("api_pagination", {})
connector_name = f"{self.google_client_service}_{self.version}"
default_page_size = config.get("default", {}).get("page_size", 200)

_LOGGER.debug(
f"[PAGINATION] get_page_size - connector_name: {connector_name}, method_name: {method_name}"
)

if connector_name in config:
connector_config = config[connector_name]
connector_page_size = connector_config.get(
"page_size", default_page_size
)

if method_name and "methods" in connector_config:
method_config = connector_config["methods"].get(method_name)
if method_config:
page_size = method_config.get("page_size", connector_page_size)
_LOGGER.debug(
f"[PAGINATION] Using method-specific page_size: {page_size}"
)
return page_size

_LOGGER.debug(
f"[PAGINATION] Using connector page_size: {connector_page_size}"
)
return connector_page_size

_LOGGER.debug(f"[PAGINATION] Using default page_size: {default_page_size}")
return default_page_size
except Exception as e:
_LOGGER.error(f"[PAGINATION] Error in get_page_size: {e}")
return 200

def list_with_pagination(self, method, method_name=None, **kwargs):
page_size = self.get_page_size(method_name)
all_results = []
page_token = None
page_count = 0

_LOGGER.debug(f"[PAGINATION] {method_name}: page_size={page_size}")

while True:
page_count += 1
params = kwargs.copy()
params["pageSize"] = page_size

if page_token:
params["pageToken"] = page_token

try:
result = method(**params).execute()
items = result.get(
"projects", result.get("folders", result.get("organizations", []))
)

_LOGGER.debug(
f"[PAGINATION] {method_name}: page {page_count} -> {len(items)} items"
)

all_results.extend(items)
page_token = result.get("nextPageToken")

if not page_token:
_LOGGER.debug(
f"[PAGINATION] {method_name}: No more pages (no nextPageToken)"
)
break

except Exception as e:
_LOGGER.error(f"[PAGINATION] Error in {method_name}: {e}")
break

_LOGGER.debug(
f"[PAGINATION] === END list_with_pagination === total: {len(all_results)} items"
)
return all_results
7 changes: 4 additions & 3 deletions src/plugin/connector/resource_manager_v1_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def __init__(self, **kwargs):
super().__init__(**kwargs)
self.secret_data = kwargs.get("secret_data", {})

def list_projects(self):
result = self.client.projects().list().execute()
return result.get("projects", [])
def list_projects(self, filter=None):
return self.list_with_pagination(
self.client.projects().list, method_name="list_projects", filter=filter
)
21 changes: 14 additions & 7 deletions src/plugin/connector/resource_manager_v3_connector.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
import itertools
import logging

from plugin.connector.base_connector import GoogleCloudConnector

Expand All @@ -17,21 +17,28 @@ def __init__(self, **kwargs):
self.secret_data = kwargs.get("secret_data", {})

def list_projects(self, parent):
result = self.client.projects().list(parent=parent).execute()
return result.get("projects", [])
projects = self.list_with_pagination(
self.client.projects().list,
method_name="list_projects",
parent=parent,
showDeleted=True,
)
return projects

def get_organization(self, organization_id):
return self.client.organizations().get(name=organization_id).execute()

def list_folders(self, parent):
results = self.client.folders().list(parent=parent).execute()
return results.get("folders", [])
return self.list_with_pagination(
self.client.folders().list, method_name="list_folders", parent=parent
)

def list_role_bindings(self, resource):
result = self.client.projects().getIamPolicy(resource=resource).execute()
bindings = result.get("bindings", [])
return list(itertools.chain(*[binding["members"] for binding in bindings]))

def search_folders(self):
results = self.client.folders().search().execute()
return results.get("folders", [])
return self.list_with_pagination(
self.client.folders().search, method_name="search_folders"
)
Loading
Loading