Как вывести список папок и проектов внутри папок в GCP
В моей организации GCP, имеющей следующую иерархию
Org--> folder--> folder--> folder--> projects--> Resources
. У меня есть учетная запись службы глобального просмотра, у которой есть необходимое разрешение для перечисления проектов и папок. Я использую клиентскую библиотеку GCP JAVA, но вижу список папок, которые мне нужно использовать
https://cloudresourcemanager.googleapis.com/v2/folders
который находится в v2 Cloud Resource Manager API, но для перечисления проектов мне нужно
https://cloudresourcemanager.googleapis.com/v1/projects
который находится в v1 Cloud Resource Manager API. Есть ли способ использовать клиентскую библиотеку GCP JAVA, чтобы объединить папки и проекты?
3 ответа
Насколько я могу судить, не существует единого метода, который позволил бы перечислить как папки, так и проекты.
Если вы считаете, что эта функция должна быть доступна, вы можете создать запрос функции .
В качестве альтернативы есть сценарий bash, который использует команды gcloud для получения аналогичного результата:
#!/usr/bin/env bash
: "${ORGANIZATION:?Need to export ORGANIZATION and it must be non-empty}"
# gcloud format
FORMAT="csv[no-heading](name,displayName.encode(base64))"
# Enumerates Folders recursively
folders()
{
LINES=("$@")
for LINE in ${LINES[@]}
do
# Parses lines of the form folder,name
VALUES=(${LINE//,/ })
FOLDER=${VALUES[0]}
# Decodes the encoded name
NAME=$(echo ${VALUES[1]} | base64 --decode)
echo "Folder: ${FOLDER} (${NAME})"
folders $(gcloud resource-manager folders list \
--folder=${FOLDER} \
--format="${FORMAT}")
done
}
# Start at the Org
echo "Org: ${ORGANIZATION}"
LINES=$(gcloud resource-manager folders list \
--organization=${ORGANIZATION} \
--format="${FORMAT}")
# Descend
folders ${LINES[0]}
Вы просите самый ужасный API в Google Cloud. Это плохой и ужасный API, и ваша проблема является результатом этого ... В любом случае, мне потребовалось несколько часов, чтобы попробовать, и я могу предложить вам использовать Discovery API (такой простой в python и очень мало документированных и трудных для использования в Ява). Действительно, вы не можете использовать автоматически сгенерированную клиентскую библиотеку, вам нужно использовать прямой вызов API или Discovery API.
Во-первых, добавьте эту зависимость в определение Maven
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-discovery</artifactId>
<version>v1-rev20190129-1.31.0</version>
</dependency>
Затем использование Discovery API.
// Build the discovery API object
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
Discovery discovery = (new Discovery.Builder(httpTransport,jsonFactory,null)).build();
// Prepare your credential for the calls
GoogleCredentials credential = GoogleCredentials.getApplicationDefault();
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(new HttpCredentialsAdapter(credential));
// Discover the API V1 of resource manager
RestDescription apiV1 = discovery.apis().getRest("cloudresourcemanager", "v1").execute();
// Discover the API V2 of resource manager
RestDescription apiV2 = discovery.apis().getRest("cloudresourcemanager", "v2").execute();
//Get a Method in the v1, here list project
RestMethod methodListProject = apiV1.getResources().get("projects").getMethods().get("list");
//Get a Method in the v2, here list folders
RestMethod methodListFolder = apiV2.getResources().get("folders").getMethods().get("list");
/////////////////////// V1 call /////////////////////
//Create the URL to call, with no query parameter here
GenericUrl urlProjectList = new GenericUrl(UriTemplate.expand(apiV1.getBaseUrl() + methodListProject.getPath(), null, true));
System.out.println(urlProjectList);
//Prepare the request
HttpRequest requestProjectList = requestFactory.buildRequest(methodListProject.getHttpMethod(), urlProjectList, null);
//Execute and print the result
System.out.println(requestProjectList.execute().parseAsString());
/////////////////////// V2 call /////////////////////
//Prepare the parameter for the call
JsonSchema param = new JsonSchema();
param.set(
"parent", String.format("organizations/%s", "<OrganisationID>"));
//Create the URL to call, with the query parameter
GenericUrl urlFolderList = new GenericUrl(UriTemplate.expand(apiV1.getBaseUrl() + methodListFolder.getPath(), param, true));
System.out.println(urlFolderList);
//Prepare the request
HttpRequest requestFolderList = requestFactory.buildRequest(methodListFolder.getHttpMethod(), urlFolderList, null);
//Execute and print the result
System.out.println(requestFolderList.execute().parseAsString());
Оба работают в одном коде в одно и то же время. Не очень читабельно. Я рекомендую вам обернуть это в классы, которые соответствуют вашим требованиям для лучшей читаемости / повторного использования.
Вам нужно много использовать описание API, чтобы знать и понимать, какие существуют методы и их параметры.
Решение и описание Python опубликованы в GCP Resource Manager — все перечислено Джоан Грау .
Код работает довольно хорошо без изменений:
from googleapiclient.discovery import build
import google.auth
credentials, _ = google.auth.default()
# V1 is needed to call all methods except for the ones related to folders
rm_v1_client = build('cloudresourcemanager', 'v1', credentials=credentials, cache_discovery=False)
# V2 is needed to call folder-related methods
rm_v2_client = build('cloudresourcemanager', 'v2', credentials=credentials, cache_discovery=False)
ORGANIZATION_ID = '[MY-ORG-ID]'
def listAllProjects():
# Start by listing all the projects under the organization
filter='parent.type="organization" AND parent.id="{}"'.format(ORGANIZATION_ID)
projects_under_org = rm_v1_client.projects().list(filter=filter).execute()
# Get all the project IDs
all_projects = [p['projectId'] for p in projects_under_org['projects']]
# Now retrieve all the folders under the organization
parent="organizations/"+ORGANIZATION_ID
folders_under_org = rm_v2_client.folders().list(parent=parent).execute()
# Make sure that there are actually folders under the org
if not folders_under_org:
return all_projects
# Now sabe the Folder IDs
folder_ids = [f['name'].split('/')[1] for f in folders_under_org['folders']]
# Start iterating over the folders
while folder_ids:
# Get the last folder of the list
current_id = folder_ids.pop()
# Get subfolders and add them to the list of folders
subfolders = rm_v2_client.folders().list(parent="folders/"+current_id).execute()
if subfolders:
folder_ids.extend([f['name'].split('/')[1] for f in subfolders['folders']])
# Now, get the projects under that folder
filter='parent.type="folder" AND parent.id="{}"'.format(current_id)
projects_under_folder = rm_v1_client.projects().list(filter=filter).execute()
# Add projects if there are any
if projects_under_folder:
all_projects.extend([p['projectId'] for p in projects_under_folder['projects']])
# Finally, return all the projects
return all_projects
if __name__=='__main__':
print(listAllProjects())
Единственное отличие от блога заключается в том, что я создал специальную роль на уровне организации и применил ее к учетной записи службы. Роль включает в себя эти разрешения диспетчера ресурсов.
- resourcesmanager.folders.get
- resourcesmanager.folders.list
- resourcesmanager.projects.get
- resourcesmanager.projects.list
Приведенный выше код извлекает проекты из подпапок, но не обрабатывает разбиение на страницы, если проектов или папок больше, чем размер страницы по умолчанию. Это может быть проблемой для крупных организаций.
Я внес некоторые изменения для управления нумерацией страниц. Обратите внимание, что я установил pageSize=2, чтобы проверить его работу, но удалил его, чтобы вернуться к значению по умолчанию в рабочей среде.
Эта версия функции также возвращает список идентификаторов всех обнаруженных папок.
from googleapiclient import discovery
from googleapiclient.discovery import build
def listAllProjects(credentials, ORGANIZATION_ID):
# V1 is needed to call all methods except for the ones related to folders
all_projects = []
folder_ids = []
rm_v1_client = build('cloudresourcemanager', 'v1', credentials=credentials, cache_discovery=False)
# V2 is needed to call folder-related methods
rm_v2_client = build('cloudresourcemanager', 'v2', credentials=credentials, cache_discovery=False)
# Start by listing all the projects under the organization
filter='parent.type="organization" AND parent.id="{}"'.format(ORGANIZATION_ID)
request = rm_v1_client.projects().list(pageSize=2, filter=filter)
while request is not None:
response = request.execute()
if response:
projects_in_org_page = response['projects']
# Get all the project IDs
all_projects.extend(projects_in_org_page)
request = rm_v1_client.projects().list_next(previous_request=request, previous_response=response)
# Now retrieve all the folders under the organization
parent="organizations/"+ORGANIZATION_ID
#folders_under_org = rm_v2_client.folders().list(parent=parent).execute()
request = rm_v2_client.folders().list(pageSize=2, parent=parent)
while request is not None:
response = request.execute()
if response:
# Now save the Folder IDs
folder_ids_in_page = [f['name'].split('/')[1] for f in response['folders']]
# Get all the project IDs
folder_ids.extend(folder_ids_in_page)
request = rm_v2_client.folders().list_next(previous_request=request, previous_response=response)
# Make sure that there are actually folders under the org
if not folder_ids:
return all_projects, folder_ids
found_folder_ids = folder_ids.copy() # because folder_ids will be popped till it empties
# Start iterating over the folders
while folder_ids:
# Get the last folder of the list
current_id = folder_ids.pop()
# Get subfolders and add them to the list of folders
subfolders = rm_v2_client.folders().list(pageSize=2, parent="folders/"+current_id).execute()
if subfolders:
folder_ids.extend([f['name'].split('/')[1] for f in subfolders['folders']])
found_folder_ids.extend(folder_ids_in_page)
request = rm_v2_client.folders().list(pageSize=2, parent="folders/"+current_id)
while request is not None:
response = request.execute()
if response:
# Now save the Folder IDs
folder_ids_in_page = [f['name'].split('/')[1] for f in response['folders']]
# Get all the project IDs
folder_ids.extend(folder_ids_in_page)
found_folder_ids.extend(folder_ids_in_page)
request = rm_v2_client.folders().list_next(previous_request=request, previous_response=response)
# Now, get the projects under that folder
filter='parent.type="folder" AND parent.id="{}"'.format(current_id)
projects_under_folder = rm_v1_client.projects().list(filter=filter).execute()
request = rm_v1_client.projects().list(filter=filter)
while request is not None:
response = request.execute()
if response:
projects_under_folder_page = response['projects']
# Get all the project IDs
all_projects.extend(projects_under_folder_page)
request = rm_v1_client.projects().list_next(previous_request=request, previous_response=response)
# Finally, return all the projects
return all_projects, found_folder_ids