330 lines
9.8 KiB
Python
330 lines
9.8 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2022 Google LLC. All Rights Reserved.
|
|
#
|
|
# Licensed 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.
|
|
"""Methods and constants for global access."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
from apitools.base.py import exceptions as api_exceptions
|
|
from googlecloudsdk.api_lib.container import api_adapter as container_api_adapter
|
|
from googlecloudsdk.api_lib.container.fleet import client as hub_client
|
|
from googlecloudsdk.api_lib.container.fleet import util as hub_util
|
|
from googlecloudsdk.api_lib.run import job
|
|
from googlecloudsdk.api_lib.run import service
|
|
from googlecloudsdk.api_lib.run import worker_pool
|
|
from googlecloudsdk.api_lib.runtime_config import util
|
|
from googlecloudsdk.api_lib.util import apis
|
|
from googlecloudsdk.core import log
|
|
from googlecloudsdk.core import properties
|
|
from googlecloudsdk.core import resources
|
|
|
|
CONTAINER_API_VERSION = 'v1beta1'
|
|
|
|
SERVERLESS_API_NAME = 'run'
|
|
SERVERLESS_API_VERSION = 'v1'
|
|
|
|
_ALL_REGIONS = '-'
|
|
|
|
CLOUDRUN_FEATURE = 'appdevexperience'
|
|
|
|
|
|
def GetServerlessClientInstance(api_version=SERVERLESS_API_VERSION):
|
|
return apis.GetClientInstance(SERVERLESS_API_NAME, api_version)
|
|
|
|
|
|
def ListRegions(client):
|
|
"""Get the list of all available regions from control plane.
|
|
|
|
Args:
|
|
client: (base_api.BaseApiClient), instance of a client to use for the list
|
|
request.
|
|
|
|
Returns:
|
|
A list of str, which are regions.
|
|
"""
|
|
return sorted([l.locationId for l in ListLocations(client)])
|
|
|
|
|
|
def ListLocations(client):
|
|
"""Get the list of all available regions from control plane.
|
|
|
|
Args:
|
|
client: (base_api.BaseApiClient), instance of a client to use for the list
|
|
request.
|
|
|
|
Returns:
|
|
A list of location resources.
|
|
"""
|
|
project_resource_relname = util.ProjectPath(
|
|
properties.VALUES.core.project.Get(required=True)
|
|
)
|
|
return client.projects_locations.List(
|
|
client.MESSAGES_MODULE.RunProjectsLocationsListRequest(
|
|
name=project_resource_relname, pageSize=100
|
|
)
|
|
).locations
|
|
|
|
|
|
def ListServices(client, region=_ALL_REGIONS, field_selector=None):
|
|
"""Get the global services for a OnePlatform project.
|
|
|
|
Args:
|
|
client: (base_api.BaseApiClient), instance of a client to use for the list
|
|
request.
|
|
region: (str) optional name of location to search for services in. If not
|
|
passed, this defaults to the global value for all locations.
|
|
field_selector: (str) optional parameter to pass in request.field_selector.
|
|
|
|
Returns:
|
|
List of googlecloudsdk.api_lib.run import service.Service objects.
|
|
"""
|
|
project = properties.VALUES.core.project.Get(required=True)
|
|
locations = resources.REGISTRY.Parse(
|
|
region,
|
|
params={'projectsId': project},
|
|
collection='run.projects.locations',
|
|
)
|
|
request = client.MESSAGES_MODULE.RunProjectsLocationsServicesListRequest(
|
|
parent=locations.RelativeName(), fieldSelector=field_selector
|
|
)
|
|
response = client.projects_locations_services.List(request)
|
|
|
|
# Log the regions that did not respond.
|
|
if response.unreachable:
|
|
log.warning(
|
|
'The following Cloud Run regions did not respond: {}. '
|
|
'List results may be incomplete.'.format(
|
|
', '.join(sorted(response.unreachable))
|
|
)
|
|
)
|
|
|
|
return [
|
|
service.Service(item, client.MESSAGES_MODULE) for item in response.items
|
|
]
|
|
|
|
|
|
# TODO(b/322180968): Once Worker API is ready, wire up to the Worker API.
|
|
def ListWorkers(client):
|
|
return ListServices(client)
|
|
|
|
|
|
def ListJobs(client, namespace):
|
|
"""Get the global services for a OnePlatform project.
|
|
|
|
Args:
|
|
client: (base_api.BaseApiClient), instance of a client to use for the list
|
|
request.
|
|
namespace: namespace/project to list jobs in
|
|
|
|
Returns:
|
|
List of googlecloudsdk.api_lib.run import job.Job objects.
|
|
"""
|
|
request = client.MESSAGES_MODULE.RunNamespacesJobsListRequest(
|
|
parent=namespace.RelativeName()
|
|
)
|
|
response = client.namespaces_jobs.List(request)
|
|
|
|
# Log the regions that did not respond.
|
|
if response.unreachable:
|
|
log.warning(
|
|
'The following Cloud Run regions did not respond: {}. '
|
|
'List results may be incomplete.'.format(
|
|
', '.join(sorted(response.unreachable))
|
|
)
|
|
)
|
|
|
|
return [job.Job(item, client.MESSAGES_MODULE) for item in response.items]
|
|
|
|
|
|
def ListWorkerPools(client, project):
|
|
"""Get the global list of worker pools for a OnePlatform project.
|
|
|
|
Args:
|
|
client: (base_api.BaseApiClient), instance of a client to use for the list
|
|
request.
|
|
project: project to list worker pools in
|
|
|
|
Returns:
|
|
List of googlecloudsdk.api_lib.run import worker_pool.WorkerPool objects.
|
|
"""
|
|
request = client.MESSAGES_MODULE.RunNamespacesWorkerpoolsListRequest(
|
|
parent=project.RelativeName()
|
|
)
|
|
response = client.namespaces_workerpools.List(request)
|
|
|
|
# Log the regions that did not respond.
|
|
if response.unreachable:
|
|
log.warning(
|
|
'The following Cloud Run regions did not respond: {}. '
|
|
'List results may be incomplete.'.format(
|
|
', '.join(sorted(response.unreachable))
|
|
)
|
|
)
|
|
|
|
return [
|
|
worker_pool.WorkerPool(item, client.MESSAGES_MODULE)
|
|
for item in response.items
|
|
]
|
|
|
|
|
|
def ListClusters(location=None, project=None):
|
|
"""Get all clusters with Cloud Run enabled.
|
|
|
|
Args:
|
|
location: str optional name of location to search for clusters in. Leaving
|
|
this field blank will search in all locations.
|
|
project: str optional name of project to search for clusters in. Leaving
|
|
this field blank will use the project defined by the corresponding
|
|
property.
|
|
|
|
Returns:
|
|
List of
|
|
googlecloudsdk.generated_clients.apis.container.CONTAINER_API_VERSION
|
|
import container_CONTAINER_API_VERSION_messages.Cluster objects
|
|
"""
|
|
container_api = container_api_adapter.NewAPIAdapter(CONTAINER_API_VERSION)
|
|
if not project:
|
|
project = properties.VALUES.core.project.Get(required=True)
|
|
|
|
response = container_api.ListClusters(project, location)
|
|
if response.missingZones:
|
|
log.warning(
|
|
'The following cluster locations did not respond: {}. '
|
|
'List results may be incomplete.'.format(
|
|
', '.join(response.missingZones)
|
|
)
|
|
)
|
|
|
|
def _SortKey(cluster):
|
|
return (cluster.zone, cluster.name)
|
|
|
|
clusters = sorted(response.clusters, key=_SortKey)
|
|
|
|
crfa_cluster_names = ListCloudRunForAnthosClusters(project)
|
|
|
|
return [
|
|
c
|
|
for c in clusters
|
|
if (
|
|
c.name in crfa_cluster_names
|
|
or (
|
|
c.addonsConfig.cloudRunConfig
|
|
and not c.addonsConfig.cloudRunConfig.disabled
|
|
)
|
|
)
|
|
]
|
|
|
|
|
|
def ListVerifiedDomains(client):
|
|
"""Get all verified domains.
|
|
|
|
Args:
|
|
client: (base_api.BaseApiClient), instance of a client to use for the list
|
|
request.
|
|
|
|
Returns:
|
|
List of client.MESSAGES_MODULE.AuthorizedDomain objects
|
|
"""
|
|
project_resource_relname = util.ProjectPath(
|
|
properties.VALUES.core.project.Get(required=True)
|
|
)
|
|
request = client.MESSAGES_MODULE.RunProjectsAuthorizeddomainsListRequest(
|
|
parent=project_resource_relname
|
|
)
|
|
response = client.projects_authorizeddomains.List(request)
|
|
return response.domains
|
|
|
|
|
|
def GetClusterRef(cluster, project=None):
|
|
"""Returns a ref for the specified cluster.
|
|
|
|
Args:
|
|
cluster: container_CONTAINER_API_VERSION_messages.Cluster object
|
|
project: str optional project which overrides the default
|
|
|
|
Returns:
|
|
A Resource object
|
|
"""
|
|
if not project:
|
|
project = properties.VALUES.core.project.Get(required=True)
|
|
return resources.REGISTRY.Parse(
|
|
cluster.name,
|
|
params={'projectId': project, 'zone': cluster.zone},
|
|
collection='container.projects.zones.clusters',
|
|
)
|
|
|
|
|
|
def MultiTenantClustersForProject(project_id, cluster_location):
|
|
"""Returns a list of clusters accounting for multi-tenant projects.
|
|
|
|
This function can also be used for non-multitenant projects and will
|
|
operate on the single passed-in project_id.
|
|
|
|
Args:
|
|
project_id: The id of the project, which may or may not be multi-tenant
|
|
cluster_location: The zone or region of the cluster
|
|
|
|
Returns:
|
|
A list of cluster refs
|
|
"""
|
|
project_ids = []
|
|
project_ids.insert(0, project_id)
|
|
return _ClustersForProjectIds(project_ids, cluster_location)
|
|
|
|
|
|
def _ClustersForProjectIds(project_ids, cluster_location):
|
|
response = []
|
|
for project_id in project_ids:
|
|
clusters = ListClusters(cluster_location, project_id)
|
|
for cluster in clusters:
|
|
response.append(GetClusterRef(cluster, project_id))
|
|
return response
|
|
|
|
|
|
def ListCloudRunForAnthosClusters(project):
|
|
"""Get all clusters with Cloud Run for Anthos enabled.
|
|
|
|
Args:
|
|
project: str optional of project to search for clusters in. Leaving this
|
|
field blank will use the project defined by the corresponding property.
|
|
|
|
Returns:
|
|
List of Cluster string names
|
|
"""
|
|
|
|
crfa_spec = 'projects/%s/locations/global/features/%s' % (
|
|
project,
|
|
CLOUDRUN_FEATURE,
|
|
)
|
|
try:
|
|
f = hub_client.HubClient().GetFeature(crfa_spec)
|
|
except api_exceptions.HttpError:
|
|
return []
|
|
|
|
cluster_state_obj = _ListAnthosClusterStates(f)
|
|
return [name for name, state in cluster_state_obj.items() if state == 'OK']
|
|
|
|
|
|
def _ListAnthosClusterStates(f):
|
|
try:
|
|
cluster_state_obj = {
|
|
hub_util.MembershipShortname(m): s.state.code.name
|
|
for m, s in hub_client.HubClient.ToPyDict(f.membershipStates).items()
|
|
}
|
|
except AttributeError:
|
|
return {}
|
|
return cluster_state_obj
|