feat: Add new gcloud commands, API clients, and third-party libraries across various services.

This commit is contained in:
2026-01-01 20:26:35 +01:00
parent 5e23cbece0
commit a19e592eb7
25221 changed files with 8324611 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""Utility for Looker instance backups."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.looker import backups
from googlecloudsdk.core import properties
from googlecloudsdk.core import resources
def ModifyInstanceBackupNameAlpha(unused_instance_ref, args, patch_request):
"""Create a backup of a Looker instance."""
if args.IsSpecified('backup'):
backup_name = args.backup
if len(backup_name.split('/')) <= 1:
parent = resources.REGISTRY.Parse(
args.instance,
params={
'projectsId': properties.VALUES.core.project.GetOrFail,
'locationsId': args.region,
},
api_version='v1alpha2',
collection='looker.projects.locations.instances',
).RelativeName()
patch_request.restoreInstanceRequest.backup = (
parent + '/backups/' + backup_name
)
return patch_request
return patch_request
def ModifyInstanceBackupName(unused_instance_ref, args, patch_request):
"""Create a backup of a Looker instance."""
if args.IsSpecified('backup'):
backup_name = args.backup
if len(backup_name.split('/')) <= 1:
parent = resources.REGISTRY.Parse(
args.instance,
params={
'projectsId': properties.VALUES.core.project.GetOrFail,
'locationsId': args.region,
},
api_version=backups.API_VERSION_DEFAULT,
collection='looker.projects.locations.instances',
).RelativeName()
patch_request.restoreInstanceRequest.backup = (
parent + '/backups/' + backup_name
)
return patch_request
return patch_request

View File

@@ -0,0 +1,173 @@
# -*- 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.
"""Common flags for some of the Looker commands.
Flags are specified with functions that take in a single argument, the parser,
and add the newly constructed flag to that parser.
Example:
def AddFlagName(parser):
parser.add_argument(
'--flag-name',
... // Other flag details.
)
"""
from googlecloudsdk.calliope.concepts import concepts
from googlecloudsdk.command_lib.util import completers
from googlecloudsdk.command_lib.util.concepts import concept_parsers
from googlecloudsdk.command_lib.util.concepts import presentation_specs
class InstanceCompleter(completers.ListCommandCompleter):
def __init__(self, **kwargs):
super(InstanceCompleter, self).__init__(
collection='looker.projects.locations.instances',
list_command='looker instances list',
**kwargs
)
def AddInstance(parser):
parser.add_argument(
'--instance',
required=True,
completer=InstanceCompleter,
help=""" \
ID of the instance or fully qualified identifier for the instance.
To set the instance attribute:
- provide the argument --instance on the command line.
""",
)
def AddInstanceConcept(parser, instance_concept_str):
concept_parsers.ConceptParser(
[GetInstancePresentationSpec(instance_concept_str)]
).AddToParser(parser)
def AddKmsKeyGroup(parser):
"""Register flags for KMS Key."""
key_group = parser.add_group(
required=True,
help=(
'Key resource - The Cloud KMS (Key Management Service) cryptokey'
' that will be used to protect the Looker instance and backups. The'
" 'Looker Service Agent' service account must hold role 'Cloud"
" KMS CryptoKey Encrypter'. The arguments in this group"
' can be used to specify the attributes of this resource.'
),
)
key_group.add_argument(
'--kms-key',
metavar='KMS_KEY',
required=True,
help='Fully qualified identifier (name) for the key.',
)
def AddTargetGcsUriGroup(parser):
"""Register flags for Target GCS URI."""
target_group = parser.add_group(
mutex=True,
required=True,
help=(
'Export Destination - The path and storage where the export will be'
' stored.'
),
)
target_group.add_argument(
'--target-gcs-uri',
metavar='TARGET_GCS_URI',
help=(
'The path to the folder in Google Cloud Storage where the export will'
' be stored. The URI is in the form `gs://bucketName/folderName`. The'
' Looker Service Agent should have the role Storage Object Creator.'
),
)
def AddExportInstanceArgs(parser):
"""Register flags Export Instance command."""
AddInstanceConcept(
parser,
(
'Arguments and flags that specify the Looker instance you want to'
' export.'
),
)
AddTargetGcsUriGroup(parser)
AddKmsKeyGroup(parser)
def AddImportInstanceArgs(parser):
"""Register flags Import Instance command."""
AddInstanceConcept(
parser,
(
'Arguments and flags that specify the Looker instance you want to'
' import.'
),
)
source_group = parser.add_group(
mutex=True,
required=True,
help=(
'Import Destination - The path and storage where the import will be'
' retrieved from.'
),
)
source_group.add_argument(
'--source-gcs-uri',
metavar='SOURCE_GCS_URI',
help=(
'The path to the folder in Google Cloud Storage where the import'
' will be retrieved from. The URI is in the form'
' `gs://bucketName/folderName`.'
),
)
def GetRegionAttributeConfig():
return concepts.ResourceParameterAttributeConfig(
'region', 'The region of the {resource}.'
)
def GetInstanceAttributeConfig():
return concepts.ResourceParameterAttributeConfig(
'instance', 'The instance of the {resource}.'
)
def GetInstanceResourceSpec():
return concepts.ResourceSpec(
'looker.projects.locations.instances',
'instance',
projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG,
locationsId=GetRegionAttributeConfig(),
instancesId=GetInstanceAttributeConfig(),
)
def GetInstancePresentationSpec(group_help):
return presentation_specs.ResourcePresentationSpec(
'instance', GetInstanceResourceSpec(), group_help, required=True
)

View File

@@ -0,0 +1,301 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""Utility for updating Looker instances.
This utily is primarily used for modifying request hooks for update requests for
Looker instances. See go/gcloud-creating-commands#request-hooks for more
details.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.core.console import console_io
def _WarnForAdminSettingsUpdate():
"""Adds prompt that warns about allowed email domains update."""
message = 'Change to instance allowed email domain requested. '
message += (
'Updating the allowed email domains from cli means the value provided'
' will be considered as the entire list and not an amendment to the'
' existing list of allowed email domains.'
)
console_io.PromptContinue(
message=message,
prompt_string='Do you want to proceed with update?',
cancel_on_no=True,
)
def _WarnForPscAllowedVpcsUpdate():
"""Adds prompt that warns about allowed vpcs update."""
message = (
'Change to instance PSC allowed Virtual Private Cloud networks'
' requested. '
)
message += (
'Updating the allowed VPC networks from cli means the value provided'
' will be considered as the entire list and not an amendment to the'
' existing list of allowed vpcs.'
)
console_io.PromptContinue(
message=message,
prompt_string='Do you want to proceed with update?',
cancel_on_no=True,
)
def _WarnForPscAllowedVpcsRemovalUpdate():
"""Adds prompt that warns about allowed vpcs removal."""
message = 'Removal of instance PSC allowed vpcs requested. '
console_io.PromptContinue(
message=message,
prompt_string='Do you want to proceed with removal of PSC allowed vpcs?',
cancel_on_no=True,
)
def _WarnForPscServiceAttachmentsUpdate():
"""Adds prompt that warns about service attachments update."""
message = 'Change to instance PSC service attachments requested. '
message += (
'Updating the PSC service attachments from cli means the value provided'
' will be considered as the entire list and not an amendment to the'
' existing list of PSC service attachments'
)
console_io.PromptContinue(
message=message,
prompt_string='Do you want to proceed with update?',
cancel_on_no=True,
)
def _WarnForPscServiceAttachmentsRemovalUpdate():
"""Adds prompt that warns about service attachments removal."""
message = 'Removal of instance PSC service attachments requested. '
console_io.PromptContinue(
message=message,
prompt_string=(
'Do you want to proceed with removal of service attachments?'
),
cancel_on_no=True,
)
def AddFieldToUpdateMask(field, patch_request):
"""Adds fields to the update mask of the patch request.
Args:
field: the field of the update mask to patch request for Looker instances.
patch_request: the request of the actual update command to be modified
Returns:
A patch request object to be sent to the server. The object is an instance
of UpdateInstanceRequest: http://shortn/_yn9MhWaGJx
"""
update_mask = patch_request.updateMask
if update_mask:
if update_mask.count(field) == 0:
patch_request.updateMask = '%s,%s' % (update_mask, field)
else:
patch_request.updateMask = field
return patch_request
def ModifyAllowedEmailDomains(unused_instance_ref, args, patch_request):
"""Python hook to modify allowed email domains in looker instance update request."""
if args.IsSpecified('allowed_email_domains'):
# Changing allowed email domains means this list will be overwritten in the
# DB and not amended and users should be warned before proceeding.
_WarnForAdminSettingsUpdate()
patch_request.instance.adminSettings.allowedEmailDomains = (
args.allowed_email_domains
)
patch_request = AddFieldToUpdateMask(
'admin_settings.allowed_email_domains', patch_request
)
return patch_request
def UpdateMaintenanceWindow(unused_instance_ref, args, patch_request):
"""Hook to update maintenance window to the update mask of the request."""
if args.IsSpecified('maintenance_window_day') or args.IsSpecified(
'maintenance_window_time'
):
patch_request = AddFieldToUpdateMask('maintenance_window', patch_request)
return patch_request
def UpdateEnablePublicIpAlpha(unused_instance_ref, args, patch_request):
"""Hook to update public IP to the update mask of the request for alpha."""
if args.IsSpecified('enable_public_ip'):
patch_request = AddFieldToUpdateMask('enable_public_ip', patch_request)
return patch_request
def UpdatePublicIPEnabled(unused_instance_ref, args, patch_request):
"""Hook to update public IP to the update mask of the request fo GA."""
if args.IsSpecified('public_ip_enabled'):
patch_request = AddFieldToUpdateMask('public_ip_enabled', patch_request)
return patch_request
def UpdateOauthClient(unused_instance_ref, args, patch_request):
"""Hook to update Oauth configs to the update mask of the request."""
if args.IsSpecified('oauth_client_id') and args.IsSpecified(
'oauth_client_secret'
):
patch_request = AddFieldToUpdateMask(
'oauth_config.client_id', patch_request
)
patch_request = AddFieldToUpdateMask(
'oauth_config.client_secret', patch_request
)
return patch_request
def UpdateDenyMaintenancePeriod(unused_instance_ref, args, patch_request):
"""Hook to update deny maintenance period to the update mask of the request."""
if (
args.IsSpecified('deny_maintenance_period_start_date')
or args.IsSpecified('deny_maintenance_period_end_date')
or args.IsSpecified('deny_maintenance_period_time')
):
patch_request = AddFieldToUpdateMask(
'deny_maintenance_period', patch_request
)
return patch_request
def UpdateUserMetadata(unused_instance_ref, args, patch_request):
"""Hook to update deny user metadata to the update mask of the request."""
if (
args.IsSpecified('add_viewer_users')
or args.IsSpecified('add_standard_users')
or args.IsSpecified('add_developer_users')
):
patch_request = AddFieldToUpdateMask('user_metadata', patch_request)
return patch_request
def UpdateCustomDomain(unused_instance_ref, args, patch_request):
"""Hook to update custom domain to the update mask of the request."""
if args.IsSpecified('custom_domain'):
patch_request = AddFieldToUpdateMask('custom_domain', patch_request)
return patch_request
def UpdatePscAllowedVpcs(unused_instance_ref, args, patch_request):
"""Hook to update psc confing allowed vpcs to the update mask of the request."""
if args.IsSpecified('psc_allowed_vpcs'):
# Changing allowed email domains means this list will be overwritten in the
# DB and not amended and users should be warned before proceeding.
_WarnForPscAllowedVpcsUpdate()
patch_request.instance.pscConfig.allowedVpcs = args.psc_allowed_vpcs
patch_request = AddFieldToUpdateMask(
'psc_config.allowed_vpcs', patch_request
)
elif args.IsSpecified('clear_psc_allowed_vpcs'):
_WarnForPscAllowedVpcsRemovalUpdate()
patch_request = AddFieldToUpdateMask(
'psc_config.allowed_vpcs', patch_request
)
return patch_request
def UpdatePscServiceAttachments(unused_instance_ref, args, patch_request):
"""Hook to update psc confing service attachments to the update mask of the request."""
if args.IsSpecified('psc_service_attachment'):
_WarnForPscServiceAttachmentsUpdate()
patch_request = AddFieldToUpdateMask(
'psc_config.service_attachments', patch_request
)
elif args.IsSpecified('clear_psc_service_attachments'):
_WarnForPscServiceAttachmentsRemovalUpdate()
patch_request = AddFieldToUpdateMask(
'psc_config.service_attachments', patch_request
)
return patch_request
def UpdateGeminiAiConfig(unused_instance_ref, args, patch_request):
"""Hook to update gemini enabled to the update mask of the request."""
if args.IsSpecified('gemini_enabled'):
patch_request = AddFieldToUpdateMask('gemini_enabled', patch_request)
if args.IsSpecified('gemini_preview_tester_enabled'):
patch_request = AddFieldToUpdateMask(
'gemini_ai_config.trusted_tester', patch_request
)
if args.IsSpecified('gemini_prompt_log_enabled'):
patch_request = AddFieldToUpdateMask(
'gemini_ai_config.prompt_logging', patch_request
)
return patch_request
def UpdatePeriodicExportConfig(unused_instance_ref, args, patch_request):
"""Hook to handle periodic export config updates."""
if (
args.IsSpecified('clear_periodic_export_config')
or args.IsSpecified('periodic_export_kms_key')
or args.IsSpecified('periodic_export_gcs_uri')
or args.IsSpecified('periodic_export_start_time')
):
patch_request = AddFieldToUpdateMask(
'periodic_export_config', patch_request
)
if args.IsSpecified('clear_periodic_export_config'):
patch_request.instance.periodicExportConfig = None
return patch_request
def UpdateControlledEgressConfig(unused_instance_ref, args, patch_request):
"""Hook to handle controlled egress config updates."""
if args.IsSpecified('egress_enabled'):
patch_request = AddFieldToUpdateMask(
'controlled_egress_enabled', patch_request
)
if args.IsSpecified('marketplace_enabled'):
if args.marketplace_enabled:
_WarnForMarketplaceEnabledUpdate()
patch_request = AddFieldToUpdateMask(
'controlled_egress_config.marketplace_enabled', patch_request
)
if args.IsSpecified('egress_fqdns'):
patch_request = AddFieldToUpdateMask(
'controlled_egress_config.egress_fqdns', patch_request
)
return patch_request
def _WarnForMarketplaceEnabledUpdate():
"""Adds prompt that warns about marketplace enabled update."""
message = 'Change to instance marketplace enabled requested. '
message += (
'Enabling connection to the Looker Marketplace will also allow egress to'
' github.com.'
)
console_io.PromptContinue(
message=message,
prompt_string='Do you want to proceed with update?',
cancel_on_no=True,
)

View File

@@ -0,0 +1,144 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""Utility for creating Looker instances."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.core.util import times
def GetMessagesModuleForVersion(version):
return apis.GetMessagesModule('looker', version)
def ParseToDateTypeV1Alpha(date):
"""Convert the input to Date Type for v1alpha* Create method."""
messages = GetMessagesModuleForVersion('v1alpha2')
return ParseDate(date, messages)
def ParseToDateTypeV1(date):
"""Convert the input to Date Type for v1 Create method."""
messages = GetMessagesModuleForVersion('v1')
return ParseDate(date, messages)
def ParseDate(date, messages, fmt='%Y-%m-%d'):
"""Convert to Date Type."""
datetime_obj = times.ParseDateTime(date, fmt=fmt)
return messages.Date(
year=datetime_obj.year, month=datetime_obj.month, day=datetime_obj.day
)
def ParseTimeOfDayDenyPeriodV1Alpha(time_of_day):
"""Convert input to TimeOfDay type for Deny Main Period v1alpha*."""
messages = GetMessagesModuleForVersion('v1alpha2')
arg = '--deny-maintenance-period-time'
error_message = (
"'--deny-maintenance-period-time' must be used in a valid 24-hr UTC Time"
' format.'
)
CheckTimeOfDayField(time_of_day, error_message, arg)
return ParseTimeOfDay(time_of_day, messages)
def ParseTimeOfDayDenyPeriodV1(time_of_day):
"""Convert input to TimeOfDay type for Deny Main Period v1."""
messages = GetMessagesModuleForVersion('v1')
arg = '--deny-maintenance-period-time'
error_message = (
"'--deny-maintenance-period-time' must be used in a valid 24-hr UTC Time"
' format.'
)
CheckTimeOfDayField(time_of_day, error_message, arg)
return ParseTimeOfDay(time_of_day, messages)
def ParseTimeOfDayMainWindowV1Alpha(time_of_day):
"""Convert input to TimeOfDay type for Main Window v1alpha*."""
messages = GetMessagesModuleForVersion('v1alpha2')
arg = '--maintenance-window-time'
error_message = (
"'--maintenance-window-time' must be used in a valid 24-hr UTC Time"
' format.'
)
CheckTimeOfDayField(time_of_day, error_message, arg)
return ParseTimeOfDay(time_of_day, messages)
def ParseTimeOfDayMainWindowV1(time_of_day):
"""Convert input to TimeOfDay type for Main Window v1."""
messages = GetMessagesModuleForVersion('v1')
arg = '--maintenance-window-time'
error_message = (
"'--maintenance-window-time' must be used in a valid 24-hr UTC Time"
' format.'
)
CheckTimeOfDayField(time_of_day, error_message, arg)
return ParseTimeOfDay(time_of_day, messages)
def ParseTimeOfDayPeriodicExportStartTimeV1Alpha(time_of_day):
"""Convert input to TimeOfDay type for Periodic Export Start Time v1alpha2."""
messages = GetMessagesModuleForVersion('v1alpha2')
arg = '--periodic-export-start-time'
error_message = (
"'--periodic-export-start-time' must be used in a valid 24-hr UTC Time"
' format.'
)
CheckTimeOfDayField(time_of_day, error_message, arg)
return ParseTimeOfDay(time_of_day, messages)
def ParseTimeOfDayPeriodicExportStartTimeV1(time_of_day):
"""Convert input to TimeOfDay type for Periodic Export Start Time v1."""
messages = GetMessagesModuleForVersion('v1')
arg = '--periodic-export-start-time'
error_message = (
"'--periodic-export-start-time' must be used in a valid 24-hr UTC Time"
' format.'
)
CheckTimeOfDayField(time_of_day, error_message, arg)
return ParseTimeOfDay(time_of_day, messages)
def CheckTimeOfDayField(time_of_day, error_message, arg):
"""Check if input is a valid TimeOfDay format."""
hour_and_min = time_of_day.split(':')
if (
len(hour_and_min) != 2
or not hour_and_min[0].isdigit()
or not hour_and_min[1].isdigit()
):
raise exceptions.InvalidArgumentException(arg, error_message)
hour = int(hour_and_min[0])
minute = int(hour_and_min[1])
if hour < 0 or minute < 0 or hour > 23 or minute > 59:
# NOMUTANTS -- Even with this 1 line removed, the affected tests still pass.
raise exceptions.InvalidArgumentException(arg, error_message)
def ParseTimeOfDay(time_of_day, messages):
hour_and_min = time_of_day.split(':')
hour = int(hour_and_min[0])
minute = int(hour_and_min[1])
return messages.TimeOfDay(hours=hour, minutes=minute)

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""Utilities for `gcloud looker operations` commands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.core import log
def LogCanceledOperation(response, args):
operation = args.CONCEPTS.operation.Parse()
log.status.Print(
'Cancellation in progress for [{}].'.format(operation.Name()))
return response

View File

@@ -0,0 +1,60 @@
project:
name: project
collection: looker.projects
attributes:
- &project
parameter_name: projectsId
attribute_name: project
help: |
The project name.
property: core/project
region:
name: region
collection: looker.projects.locations
attributes:
- *project
- &region
parameter_name: locationsId
attribute_name: region
help: |
The name of the Looker region of the {resource}. Overrides the default
looker/region property value for this command invocation.
property: looker/region
disable_auto_completers: false
instance:
name: instance
collection: looker.projects.locations.instances
request_id_field: instanceId
attributes:
- *region
- &instance
parameter_name: instancesId
attribute_name: instance
help: The name of the Looker instance.
disable_auto_completers: false
backup:
name: backup
collection: looker.projects.locations.instances.backups
request_id_field: backupId
attributes:
- *project
- *region
- *instance
- &backup
parameter_name: backupsId
attribute_name: backup
help: The name of the backup of a Looker instance.
disable_auto_completers: false
operation:
name: operation
collection: looker.projects.locations.operations
attributes:
- *region
- parameter_name: operationsId
attribute_name: operation
help: The name of the Looker operation.
disable_auto_completers: false