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,38 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""The super-group for the logging CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA
)
class Logging(base.Group):
"""Manage Cloud Logging."""
category = base.MANAGEMENT_TOOLS_CATEGORY
def Filter(self, context, args):
# TODO(b/190536377): Determine if command group works with project number
base.RequireProjectID(args)
del context, args
base.EnableUserProjectQuotaWithFallback()

View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""The buckets command group for the Cloud Logging CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA
)
class Buckets(base.Group):
"""Manage Cloud Logging buckets.
Commands for managing Cloud Logging buckets. A bucket is a container of logs
that can be managed as a unit, for example by setting the retention period.
"""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,201 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging buckets create' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Create(base.CreateCommand):
"""Create a bucket.
After creating a bucket, use a log sink to route logs into the bucket.
## EXAMPLES
To create a bucket 'my-bucket' in location 'global', run:
$ {command} my-bucket --location=global --description="my custom bucket"
To create a bucket with extended retention, run:
$ {command} my-bucket --location=global --retention-days=365
To create a bucket in cloud region 'us-central1', run:
$ {command} my-bucket --location=us-central1
To create a bucket with custom index of 'jsonPayload.foo', run:
$ {command} my-bucket
--index=fieldPath=jsonPayload.foo,type=INDEX_TYPE_STRING
To create a bucket with custom CMEK, run:
$ {command} my-bucket --location=us-central1
--cmek-kms-key-name=CMEK_KMS_KEY_NAME
To asynchronously create a bucket enrolled into Log Analytics, run:
$ {command} my-bucket --location=global --async --enable-analytics
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('BUCKET_ID', help='ID of the bucket to create.')
parser.add_argument(
'--description', help='A textual description for the bucket.')
parser.add_argument(
'--restricted-fields',
help='Comma-separated list of field paths that require permission '
'checks in this bucket. The following fields and their children are '
'eligible: textPayload, jsonPayload, protoPayload, httpRequest, labels,'
' sourceLocation.',
type=arg_parsers.ArgList(),
metavar='RESTRICTED_FIELD',
)
parser.add_argument(
'--retention-days',
type=int,
help=arg_parsers.UniverseHelpText(
default=(
'The period logs will be retained, after which logs will'
' automatically be deleted. The default is 30 days.'
),
universe_help='This is not available.\n',
),
)
parser.add_argument(
'--index',
action='append',
type=arg_parsers.ArgDict(
spec={
'fieldPath': str,
'type': util.IndexTypeToEnum
},
required_keys=['fieldPath', 'type']),
metavar='KEY=VALUE, ...',
help=(
'Specify an index to be added to the log bucket. This flag can be '
'repeated. The ``fieldPath\'\' and ``type\'\' attributes are '
'required. For example: '
' --index=fieldPath=jsonPayload.foo,type=INDEX_TYPE_STRING. '
'The following keys are accepted:\n\n'
'*fieldPath*::: The LogEntry field path to index. '
'For example: jsonPayload.request.status. '
'Paths are limited to 800 characters and can include only '
'letters, digits, underscores, hyphens, and periods.\n\n'
'*type*::: The type of data in this index. '
'For example: INDEX_TYPE_STRING '
'Supported types are INDEX_TYPE_STRING and '
'INDEX_TYPE_INTEGER. \n\n '))
parser.add_argument(
'--cmek-kms-key-name',
help='A valid `kms_key_name` will enable CMEK for the bucket.')
parser.add_argument(
'--enable-analytics',
action='store_true',
default=None,
help=arg_parsers.UniverseHelpText(
default=(
'Whether to opt the bucket into Log Analytics. Once opted in,'
' the bucket cannot be opted out of Log Analytics.'
),
universe_help='This is not available.\n',
),
)
base.ASYNC_FLAG.AddToParser(parser)
util.AddBucketLocationArg(
parser, True,
'Location in which to create the bucket. Once the bucket is created, '
'the location cannot be changed.')
util.GetTagsArg().AddToParser(parser)
def _Run(self, args):
bucket_data = {}
if args.IsSpecified('retention_days'):
bucket_data['retentionDays'] = args.retention_days
if args.IsSpecified('description'):
bucket_data['description'] = args.description
if args.IsSpecified('restricted_fields'):
bucket_data['restrictedFields'] = args.restricted_fields
if args.IsSpecified('index'):
bucket_data['indexConfigs'] = args.index
if args.IsSpecified('enable_analytics'):
bucket_data['analyticsEnabled'] = args.enable_analytics
if args.IsSpecified('tags'):
tags = util.GetTagsFromArgs(args, util.GetMessages().LogBucket.TagsValue)
bucket_data['tags'] = tags
if args.IsSpecified('cmek_kms_key_name'):
console_io.PromptContinue(
'CMEK cannot be disabled on a bucket once enabled.',
cancel_on_no=True)
cmek_settings = util.GetMessages().CmekSettings(
kmsKeyName=args.cmek_kms_key_name)
bucket_data['cmekSettings'] = cmek_settings
if args.async_:
result = util.GetClient().projects_locations_buckets.CreateAsync(
util.GetMessages().LoggingProjectsLocationsBucketsCreateAsyncRequest(
bucketId=args.BUCKET_ID,
parent=util.CreateResourceName(
util.GetProjectResource(args.project).RelativeName(),
'locations',
args.location,
),
logBucket=util.GetMessages().LogBucket(**bucket_data),
)
)
log.CreatedResource(result.name, 'bucket', is_async=True)
return result
else:
return util.GetClient().projects_locations_buckets.Create(
util.GetMessages().LoggingProjectsLocationsBucketsCreateRequest(
bucketId=args.BUCKET_ID,
parent=util.CreateResourceName(
util.GetProjectResource(args.project).RelativeName(),
'locations',
args.location,
),
logBucket=util.GetMessages().LogBucket(**bucket_data),
)
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The created bucket.
"""
return self._Run(args)

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging buckets delete' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.UniverseCompatible
class Delete(base.DeleteCommand):
"""Delete a bucket.
## EXAMPLES
To delete bucket 'my-bucket' in location 'global', run:
$ {command} my-bucket --location=global
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'BUCKET_ID', help='ID of the bucket to delete.')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket.')
util.AddParentArgs(parser, 'bucket to delete')
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
"""
console_io.PromptContinue(
'Really delete bucket [%s]? (You can undelete it within 7 days if you '
'change your mind later)' % args.BUCKET_ID,
cancel_on_no=True)
util.GetClient().projects_locations_buckets.Delete(
util.GetMessages().LoggingProjectsLocationsBucketsDeleteRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location),
'buckets', args.BUCKET_ID)))
log.DeletedResource(args.BUCKET_ID)

View File

@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging buckets describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
Display information about a bucket.
""",
'EXAMPLES': """
To describe a bucket in a project, run:
$ {command} my-bucket --location=global
""",
}
@base.UniverseCompatible
class Describe(base.DescribeCommand):
"""Display information about a bucket."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('BUCKET_ID', help='The id of the bucket to describe.')
util.AddParentArgs(parser, 'bucket to describe')
util.AddBucketLocationArg(parser, True, 'Location of the bucket.')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The specified bucket.
"""
return util.GetClient().projects_locations_buckets.Get(
util.GetMessages().LoggingProjectsLocationsBucketsGetRequest(
name=util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets',
args.BUCKET_ID)))
Describe.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging buckets list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
List the buckets for a project.
""",
'EXAMPLES': """
To list the buckets in a project, run:
$ {command}
""",
}
@base.UniverseCompatible
class List(base.ListCommand):
"""List the defined buckets."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
util.AddParentArgs(parser, 'buckets to list')
util.AddBucketLocationArg(
parser, False,
'Location from which to list buckets. By default, buckets in all '
'locations will be listed')
parser.display_info.AddFormat(
'table(name.segment(-3):label=LOCATION, '
'name.segment(-1):label=BUCKET_ID, retentionDays, '
'cmekSettings.yesno(yes="TRUE", no=""):label=CMEK, '
'restrictedFields, indexConfigs, lifecycle_state, locked, '
'create_time, update_time)'
)
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Yields:
The list of buckets.
"""
result = util.GetClient().projects_locations_buckets.List(
util.GetMessages().LoggingProjectsLocationsBucketsListRequest(
parent=util.GetBucketLocationFromArgs(args)))
for bucket in result.buckets:
yield bucket
List.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,83 @@
# -*- 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.
"""'logging buckets move' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core.console import console_io
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.Hidden
class Move(base.Command):
"""Move a bucket.
In order to be movable, a bucket must satisfy the following restrictions:
- Be a ```_Default``` or ```_Required``` bucket
- Have a location of global
- Have a non-project parent when it is a ```_Default``` bucket
## EXAMPLES
To move the ```_Required``` bucket from `global` to another location, run:
$ {command} _Required --location=global --new-location=us-central1
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('BUCKET_ID', help='ID of the bucket to move.')
parser.add_argument(
'--new-location',
required=True,
help='New location to move the bucket to.')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket.')
util.AddParentArgs(parser, 'bucket to move')
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
A long running operation containing related information.
"""
parent_name = util.GetParentFromArgs(args)
source_bucket = util.CreateResourceName(
util.CreateResourceName(parent_name, 'locations', args.location),
'buckets', args.BUCKET_ID)
new_bucket = util.CreateResourceName(
util.CreateResourceName(parent_name, 'locations', args.new_location),
'buckets', args.BUCKET_ID)
console_io.PromptContinue(
'Really move bucket [%s] to [%s]? ' % (source_bucket, new_bucket),
cancel_on_no=True)
return util.GetClient().projects_locations_buckets.Move(
util.GetMessages().MoveBucketRequest(
name=source_bucket, newName=new_bucket))

View File

@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging buckets undelete' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class Undelete(base.RestoreCommand):
"""Undelete a bucket.
## EXAMPLES
To undelete bucket 'my-bucket' in location 'global', run:
$ {command} my-bucket --location=global
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'BUCKET_ID', help='ID of the bucket to undelete.')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket.')
util.AddParentArgs(parser, 'bucket to undelete')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
"""
util.GetClient().projects_locations_buckets.Undelete(
util.GetMessages().LoggingProjectsLocationsBucketsUndeleteRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location),
'buckets', args.BUCKET_ID)))

View File

@@ -0,0 +1,332 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging buckets update' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as calliope_exceptions
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
DETAILED_HELP = {
'DESCRIPTION': """
Update the properties of a bucket.
""",
'EXAMPLES': """
To update a bucket in your project, run:
$ {command} my-bucket --location=global --description=my-new-description
To update a bucket in your project and remove all indexes, run:
$ {command} my-bucket --location=global --clear-indexes
To update a bucket in your project and remove an index, run:
$ {command} my-bucket --location=global --remove-indexes=jsonPayload.foo2
To update a bucket in your project and add an index, run:
$ {command} my-bucket --location=global --add-index=fieldPath=jsonPayload.foo2,type=INDEX_TYPE_STRING
To update a bucket in your project and update an existing index, run:
$ {command} my-bucket --location=global --update-index=fieldPath=jsonPayload.foo,type=INDEX_TYPE_INTEGER
To update a bucket in your project and update existing cmek, run:
$ {command} my-bucket --location=global --cmek-kms-key-name=CMEK_KEY_NAME
To asynchronously enroll a bucket in your project into Log Analytics, run:
$ {command} my-bucket --location=global --async --enable-analytics
""",
}
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Update(base.UpdateCommand):
"""Update a bucket.
Changes one or more properties associated with a bucket.
"""
def __init__(self, *args, **kwargs):
super(Update, self).__init__(*args, **kwargs)
self._current_bucket = None
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('BUCKET_ID', help='The id of the bucket to update.')
parser.add_argument(
'--retention-days',
type=int,
help=arg_parsers.UniverseHelpText(
default='A new retention period for the bucket.',
universe_help='This is not available.\n',
),
)
parser.add_argument(
'--description', help='A new description for the bucket.')
util.AddParentArgs(parser, 'bucket to update')
util.AddBucketLocationArg(parser, True, 'Location of the bucket.')
parser.add_argument(
'--locked',
action='store_true',
help=('Lock the bucket and prevent it from being modified or deleted '
'(unless it is empty).'))
parser.add_argument(
'--restricted-fields',
help='A new set of restricted fields for the bucket.',
type=arg_parsers.ArgList(),
metavar='RESTRICTED_FIELD')
parser.add_argument(
'--clear-indexes',
action='store_true',
help=('Remove all logging indexes from the bucket.'))
parser.add_argument(
'--remove-indexes',
type=arg_parsers.ArgList(),
metavar='FIELD PATH',
help=('Specify the field path of the logging index(es) to delete.'))
parser.add_argument(
'--add-index',
action='append',
type=arg_parsers.ArgDict(
spec={
'fieldPath': str,
'type': util.IndexTypeToEnum
},
required_keys=['fieldPath', 'type']),
metavar='KEY=VALUE, ...',
help=('Add an index to be added to the log bucket. This flag can be '
'repeated. The ``fieldPath\'\' and ``type\'\' attributes are '
'required. For example: '
' --index=fieldPath=jsonPayload.foo,type=INDEX_TYPE_STRING. '
'The following keys are accepted:\n\n'
'*fieldPath*::: The LogEntry field path to index. '
'For example: jsonPayload.request.status. '
'Paths are limited to 800 characters and can include only '
'letters, digits, underscores, hyphens, and periods.\n\n'
'*type*::: The type of data in this index. '
'For example: INDEX_TYPE_STRING '
'Supported types are strings and integers. \n\n '))
parser.add_argument(
'--update-index',
action='append',
type=arg_parsers.ArgDict(
spec={
'fieldPath': str,
'type': util.IndexTypeToEnum
},
required_keys=['fieldPath', 'type']),
metavar='KEY=VALUE, ...',
help=(
'Update an index to be added to the log bucket. '
'This will update the type of the index, and also update its '
'createTime to the new update time. '
'This flag can be repeated. The ``fieldPath\'\' and ``type\'\' '
'attributes are required. For example: '
' --index=fieldPath=jsonPayload.foo,type=INDEX_TYPE_STRING. '
'The following keys are accepted:\n\n'
'*fieldPath*::: The LogEntry field path to index. '
'For example: jsonPayload.request.status. '
'Paths are limited to 800 characters and can include only '
'letters, digits, underscores, hyphens, and periods.\n\n'
'*type*::: The type of data in this index. '
'For example: INDEX_TYPE_STRING '
'Supported types are strings and integers. '))
parser.add_argument(
'--enable-analytics',
action='store_true',
default=None,
help=arg_parsers.UniverseHelpText(
default=(
'Whether to opt the bucket into Log Analytics. Once opted in,'
' the bucket cannot be opted out of Log Analytics.'
),
universe_help='This is not available.\n',
),
)
parser.add_argument(
'--cmek-kms-key-name',
help='A valid `kms_key_name` will enable CMEK for the bucket.')
base.ASYNC_FLAG.AddToParser(parser)
def GetCurrentBucket(self, args):
"""Returns a bucket specified by the arguments.
Loads the current bucket at most once. If called multiple times, the
previously-loaded bucket will be returned.
Args:
args: The argument set. This is not checked across GetCurrentBucket calls,
and must be consistent.
"""
if not self._current_bucket:
self._current_bucket = util.GetClient().projects_locations_buckets.Get(
util.GetMessages().LoggingProjectsLocationsBucketsGetRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location
),
'buckets',
args.BUCKET_ID,
)
)
)
return self._current_bucket
def _Run(self, args):
bucket_data = {}
update_mask = []
parameter_names = ['--retention-days', '--description', '--locked']
if args.IsSpecified('retention_days'):
bucket_data['retentionDays'] = args.retention_days
update_mask.append('retention_days')
if args.IsSpecified('description'):
bucket_data['description'] = args.description
update_mask.append('description')
if args.IsSpecified('locked'):
bucket_data['locked'] = args.locked
update_mask.append('locked')
if args.locked:
console_io.PromptContinue(
'WARNING: Locking a bucket cannot be undone.',
default=False,
cancel_on_no=True)
if args.IsSpecified('restricted_fields'):
bucket_data['restrictedFields'] = args.restricted_fields
update_mask.append('restricted_fields')
if args.IsSpecified('enable_analytics'):
bucket_data['analyticsEnabled'] = args.enable_analytics
update_mask.append('analytics_enabled')
if (args.IsSpecified('clear_indexes') or
args.IsSpecified('remove_indexes') or args.IsSpecified('add_index') or
args.IsSpecified('update_index')):
bucket = self.GetCurrentBucket(args)
bucket_data['indexConfigs'] = []
update_mask.append('index_configs')
indexes_to_remove = (
args.remove_indexes if args.IsSpecified('remove_indexes') else [])
indexes_to_update = (
args.update_index if args.IsSpecified('update_index') else [])
for index in bucket.indexConfigs:
if index.fieldPath in indexes_to_remove:
indexes_to_remove.remove(index.fieldPath)
else:
for i in range(len(indexes_to_update)):
if index.fieldPath == indexes_to_update[i]['fieldPath']:
for key, value in indexes_to_update[i].items():
if key == 'type':
index.type = value
indexes_to_update.pop(i)
break
bucket_data['indexConfigs'].append(index)
if indexes_to_remove:
raise calliope_exceptions.InvalidArgumentException(
'--remove-indexes',
'Indexes {0} do not exist'.format(','.join(indexes_to_remove)))
if indexes_to_update:
raise calliope_exceptions.InvalidArgumentException(
'--update-index', 'Indexes {0} do not exist'.format(','.join(
[index['fieldPath'] for index in indexes_to_update])))
if args.IsSpecified('clear_indexes'):
bucket_data['indexConfigs'] = []
if args.IsSpecified('add_index'):
bucket_data['indexConfigs'] += args.add_index
if args.IsSpecified('cmek_kms_key_name'):
bucket = self.GetCurrentBucket(args)
if not bucket.cmekSettings:
# This is the first time CMEK settings are being applied. Warn the user
# that this is irreversible.
console_io.PromptContinue(
'CMEK cannot be disabled on a bucket once enabled.',
cancel_on_no=True)
cmek_settings = util.GetMessages().CmekSettings(
kmsKeyName=args.cmek_kms_key_name)
bucket_data['cmekSettings'] = cmek_settings
update_mask.append('cmek_settings')
if not update_mask:
raise calliope_exceptions.MinimumArgumentException(
parameter_names, 'Please specify at least one property to update')
if args.async_:
result = util.GetClient().projects_locations_buckets.UpdateAsync(
util.GetMessages().LoggingProjectsLocationsBucketsUpdateAsyncRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args),
'locations',
args.location,
),
'buckets',
args.BUCKET_ID,
),
logBucket=util.GetMessages().LogBucket(**bucket_data),
updateMask=','.join(update_mask),
)
)
log.UpdatedResource(result.name, 'bucket', is_async=True)
return result
else:
return util.GetClient().projects_locations_buckets.Patch(
util.GetMessages().LoggingProjectsLocationsBucketsPatchRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args),
'locations',
args.location,
),
'buckets',
args.BUCKET_ID,
),
logBucket=util.GetMessages().LogBucket(**bucket_data),
updateMask=','.join(update_mask),
)
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated bucket.
"""
return self._Run(args)
Update.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""Cloud Logging cmek-settings group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.DefaultUniverseOnly
@base.Hidden
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA
)
class CmekSettings(base.Group):
"""Manages the customer-managed encryption key (CMEK) settings for the Cloud Logging Logs Router."""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging cmek-settings describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
class Describe(base.DescribeCommand):
# pylint: disable=line-too-long
"""Display the CMEK settings for the Cloud Logging Logs Router.
If *kmsKeyName* is present in the output, then CMEK is enabled for your
project, folder, organization or billing-account. You can also find the Logs
Router service account using this command.
## EXAMPLE
To describe the Logs Router CMEK settings for a project, run:
$ {command} --project=[PROJECT_ID]
To describe the Logs Router CMEK settings for an organization, run:
$ {command} --organization=[ORGANIZATION_ID]
kmsKeyName:
'projects/my-project/locations/my-location/keyRings/my-keyring/cryptoKeys/key'
name: 'organizations/[ORGANIZATION_ID]/cmekSettings'
serviceAccountId:
'[SERVICE_ACCOUNT_ID]@gcp-sa-logging.iam.gserviceaccount.com'
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
util.AddParentArgs(parser, 'CMEK settings to describe')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The CMEK settings for the specified project, folder, organizations
or billing-account.
"""
parent_name = util.GetParentFromArgs(args)
return util.GetClient().v2.GetCmekSettings(
util.GetMessages().LoggingGetCmekSettingsRequest(name=parent_name))

View File

@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging cmek-settings update' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.kms import resource_args as kms_resource_args
from googlecloudsdk.command_lib.resource_manager import completers
class Update(base.Command):
# pylint: disable=line-too-long
"""Update the CMEK settings for the Cloud Logging Logs Router.
Use this command to update the *--kms-key-name* associated with the
Cloud Logging Logs Router.
The Cloud KMS key must already exist and Cloud Logging must have
permission to access it.
Customer-managed encryption keys (CMEK) for the Logs Router can currently
only be configured at the organization-level and will apply to all projects
in the organization.
## EXAMPLES
To enable CMEK for the Logs Router for an organization, run:
$ {command} --organization=[ORGANIZATION_ID]
--kms-key-name='projects/my-project/locations/my-location/keyRings/my-keyring/cryptoKeys/key'
To disable CMEK for the Logs Router for an organization, run:
$ {command} --organization=[ORGANIZATION_ID] --clear-kms-key
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'--organization',
required=True,
metavar='ORGANIZATION_ID',
completer=completers.OrganizationCompleter,
help='Organization to update Logs Router CMEK settings for.')
group = parser.add_mutually_exclusive_group(required=True)
kms_resource_args.AddKmsKeyResourceArg(
group,
resource='logs being processed by the Cloud Logging Logs Router',
permission_info=('The Cloud KMS CryptoKey Encrypter/Decryper role must '
'be assigned to the Cloud Logging Logs Router service '
'account'),
name='--kms-key-name')
group.add_argument(
'--clear-kms-key',
action='store_true',
help=('Disable CMEK for the Logs Router by clearing out Cloud KMS '
'cryptokey in the organization\'s CMEK settings.'))
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated CMEK settings.
"""
cmek_settings = {}
if args.IsSpecified('kms_key_name'):
cmek_settings['kmsKeyName'] = (
args.CONCEPTS.kms_key_name.Parse().RelativeName())
if args.IsSpecified('clear_kms_key'):
cmek_settings['kmsKeyName'] = ''
parent_name = util.GetParentFromArgs(args)
return util.GetClient().organizations.UpdateCmekSettings(
util.GetMessages().LoggingOrganizationsUpdateCmekSettingsRequest(
name=parent_name,
cmekSettings=util.GetMessages().CmekSettings(**cmek_settings),
updateMask='kms_key_name'))

View File

@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""'logging copy' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core.console import console_io
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Copy(base.Command):
"""Copy log entries."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'bucket_id',
help='Id of the log bucket to copy logs from. Example: my-bucket',
)
parser.add_argument(
'destination',
help=(
'Destination to copy logs to. Example: Cloud Storage bucket:'
' storage.googleapis.com/my-cloud-storage-bucket'
),
)
parser.add_argument(
'--location', required=True, help='Location of the log bucket.'
)
parser.add_argument(
'--log-filter',
required=False,
help=(
'A filter specifying which log entries to copy. '
'The filter must be no more than 20k characters. '
'An empty filter matches all log entries.'
),
)
util.AddParentArgs(parser, 'log entries to copy')
def _Run(self, args):
if not args.log_filter:
console_io.PromptContinue(
'An empty filter matches all log entries.', cancel_on_no=True)
parent_name = util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location),
'buckets', args.bucket_id)
request = util.GetMessages().CopyLogEntriesRequest(
destination=args.destination, filter=args.log_filter, name=parent_name)
return util.GetClient().entries.Copy(request)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
A copy_log_entries operation.
"""
return self._Run(args)
Copy.detailed_help = {
'DESCRIPTION':
"""\
{command} starts the process to copy log entries from a log bucket to a destination.
""",
'EXAMPLES':
"""\
To start a copy log entries operation, run:
$ {command} BUCKET_ID DESTINATION --location=LOCATION
To copy log entries in a specific time window, run:
$ {command} BUCKET_ID DESTINATION --location=LOCATION --log-filter='timestamp<="2021-05-31T23:59:59Z" AND timestamp>="2021-05-31T00:00:00Z"'
""",
}

View File

@@ -0,0 +1,36 @@
# -*- 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.
"""The links command group for the Cloud Logging CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Links(base.Group):
"""Manage linked datasets.
Commands for managing linked datasets. A linked BigQuery dataset contains log
data for the linked dataset's parent log bucket.
"""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,112 @@
# -*- 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.
"""'logging links create' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core import resources
DETAILED_HELP = {
'DESCRIPTION': """
Create a linked dataset for a log bucket.
""",
'EXAMPLES': """
To create a linked dataset in a project, run:
$ {command} my-link --bucket=my-bucket --location=global
""",
}
class Create(base.CreateCommand):
"""Create a linked dataset on an analytics log bucket."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('LINK_ID', help='ID of the linked dataset to create.')
parser.add_argument(
'--description', help='A textual description for the linked dataset.'
)
util.AddParentArgs(parser, 'linked dataset to create')
util.AddBucketLocationArg(
parser,
True,
'Location of the bucket that will hold the linked datasert.',
)
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of the bucket that will hold the linked dataset',
)
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Linked dataset creation operation.
"""
link_data = {}
if args.IsSpecified('description'):
link_data['description'] = args.description
client = util.GetClient()
create_op = client.projects_locations_buckets_links.Create(
util.GetMessages().LoggingProjectsLocationsBucketsLinksCreateRequest(
linkId=args.LINK_ID,
parent=util.CreateResourceName(
util.CreateResourceName(
util.GetProjectResource(args.project).RelativeName(),
'locations',
args.location,
),
'buckets',
args.bucket,
),
link=util.GetMessages().Link(**link_data),
)
)
if args.async_:
log.CreatedResource(create_op.name, 'link', is_async=True)
return create_op
else:
create_op_ref = resources.REGISTRY.ParseRelativeName(
create_op.name,
collection='logging.projects.locations.operations',
)
return waiter.WaitFor(
waiter.CloudOperationPollerNoResources(
client.projects_locations_operations
),
create_op_ref,
'Waiting for operation [{}] to complete'.format(create_op.name),
)
Create.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,99 @@
# -*- 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.
"""'logging links delete' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core import resources
DETAILED_HELP = {
'DESCRIPTION': """
Delete a bucket's linked dataset.
""",
'EXAMPLES': """
To delete a bucket's linked dataset, run:
$ {command} my-link --bucket=my-bucket --location=global
""",
}
class Delete(base.DeleteCommand):
"""Delete a linked dataset."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('LINK_ID', help='ID of the linked dataset to delete.')
util.AddBucketLocationArg(parser, True, 'Location of the bucket.')
util.AddParentArgs(parser, 'linked dataset to delete')
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of bucket',
)
base.ASYNC_FLAG.AddToParser(parser)
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Linked dataset delete operation.
"""
client = util.GetClient()
delete_op = client.projects_locations_buckets_links.Delete(
util.GetMessages().LoggingProjectsLocationsBucketsLinksDeleteRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetBucketLocationFromArgs(args),
'buckets',
args.bucket,
),
'links',
args.LINK_ID,
)
)
)
if args.async_:
log.DeletedResource(delete_op.name, 'link', is_async=True)
return delete_op
else:
delete_op_ref = resources.REGISTRY.ParseRelativeName(
delete_op.name,
collection='logging.projects.locations.operations',
)
return waiter.WaitFor(
waiter.CloudOperationPollerNoResources(
client.projects_locations_operations
),
delete_op_ref,
'Waiting for operation [{}] to complete'.format(delete_op.name),
)
Delete.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,76 @@
# -*- 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.
"""'logging buckets describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
Display information about a linked dataset.
""",
'EXAMPLES': """
To describe a linked dataset in a project, run:
$ {command} my-link --bucket=my-bucket --location=global
""",
}
class Describe(base.DescribeCommand):
"""Display information about a linked dataset."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('LINK_ID', help='Id of the linked dataset to describe.')
util.AddParentArgs(parser, 'linked dataset to describe')
util.AddBucketLocationArg(parser, True, 'Location of the bucket.')
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of bucket',
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The specified linked dataset
"""
return util.GetClient().projects_locations_buckets_links.Get(
util.GetMessages().LoggingProjectsLocationsBucketsLinksGetRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets', args.bucket
),
'links',
args.LINK_ID,
)
)
)
Describe.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,78 @@
# -*- 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.
"""'logging links list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
List the linked datasets created for a bucket.
""",
'EXAMPLES': """
To list the linked datasets created for a bucket, run:
$ {command}
""",
}
class List(base.ListCommand):
"""List created linked datasets on the specified bucket."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
util.AddParentArgs(parser, 'linked datasets to list')
util.AddBucketLocationArg(parser, True, 'Location of the specified bucket')
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of bucket',
)
parser.display_info.AddFormat(
'table(name.segment(-1):label=LINK_ID, create_time)'
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Yields:
The list of linked datasets.
"""
result = util.GetClient().projects_locations_buckets_links.List(
util.GetMessages().LoggingProjectsLocationsBucketsLinksListRequest(
parent=util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets', args.bucket
)
)
)
for link in result.links:
yield link
List.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""The buckets command group for the Cloud Logging CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA
)
class Locations(base.Group):
"""Query Cloud Logging locations.
Commands for querying Cloud Logging locations. Cloud Logging log buckets may
be created in these locations.
"""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging buckets describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION':
"""
Displays information about a location.
""",
'EXAMPLES':
"""
To describe a location in a project, run:
$ {command} my-location
""",
}
@base.UniverseCompatible
class Describe(base.DescribeCommand):
"""Display information about a location."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('LOCATION_ID', help='Id of the location to describe.')
util.AddParentArgs(parser, 'location to describe')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The specified location
"""
return util.GetClient().projects_locations.Get(
util.GetMessages().LoggingProjectsLocationsGetRequest(
name=util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.LOCATION_ID)))
Describe.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging views list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
Lists the available locations for Cloud Logging.
""",
'EXAMPLES': """
To list the available locations, run:
$ {command}
""",
}
@base.UniverseCompatible
class List(base.ListCommand):
"""List the availables location."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
util.AddParentArgs(parser, 'locations to list')
parser.display_info.AddFormat('table(locationId)')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Yields:
The list of locations.
"""
result = util.GetClient().projects_locations.List(
util.GetMessages().LoggingProjectsLocationsListRequest(
name=util.GetParentFromArgs(args)))
for location in result.locations:
yield location
List.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Cloud Logging logs group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class Logs(base.Group):
"""Manages your project's logs."""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""'logging logs delete' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.DefaultUniverseOnly
class Delete(base.DeleteCommand):
"""Delete all entries from a log in the global ```_Default``` log bucket.
## EXAMPLES
To delete all entries from log 'my-log' in the global ```_Default``` log
bucket:
$ {command} my-log
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('log_name', help='Log name.')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
"""
console_io.PromptContinue(
'Really delete all log entries from [%s]?' % args.log_name,
cancel_on_no=True)
util.GetClient().projects_logs.Delete(
util.GetMessages().LoggingProjectsLogsDeleteRequest(
logName=util.CreateLogResourceName(
util.GetCurrentProjectParent(), args.log_name)))
log.DeletedResource(args.log_name)
Delete.detailed_help = {
'DESCRIPTION': ("""
{index}
With no entries, the log will not appear in the list of your
project's logs. However, you can write new entries to the log.
"""),
}

View File

@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""'logging logs list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core import properties
from googlecloudsdk.core import resources
@base.UniverseCompatible
class List(base.ListCommand):
"""List your project's logs.
Only logs that contain log entries are listed.
## EXAMPLES
To list all logs in current project:
$ {command}
To list all logs for a view:
$ {command} --bucket=[BUCKET_ID] --location=[LOCATION] --view=[VIEW_ID]
"""
@staticmethod
def Args(parser):
base.PAGE_SIZE_FLAG.RemoveFromParser(parser)
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat('table(.:label=NAME)')
view_group = parser.add_argument_group(
help='These arguments are used in conjunction with the parent to '
'construct a view resource.')
view_group.add_argument(
'--location',
required=True,
metavar='LOCATION',
help='Location of the log bucket.')
view_group.add_argument(
'--bucket',
required=True,
help='Id of the log bucket.')
view_group.add_argument(
'--view',
required=True,
help='Id of the view.')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The list of logs.
"""
project = properties.VALUES.core.project.Get(required=True)
project_ref = resources.REGISTRY.Parse(
project, collection='cloudresourcemanager.projects')
parent = project_ref.RelativeName()
if args.IsSpecified('view'):
# We are replacing the parent with the resourceName path for a view
# instead of populating the resourceNames field.
# This is due to the parent being a legacy required field.
parent = util.CreateResourceName(
util.CreateResourceName(
util.CreateResourceName(parent, 'locations', args.location),
'buckets', args.bucket), 'views', args.view)
request = util.GetMessages().LoggingProjectsLogsListRequest(parent=parent)
result = list_pager.YieldFromList(
util.GetClient().projects_logs,
request,
field='logNames',
limit=args.limit,
batch_size=None,
batch_size_attribute='pageSize')
return result

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Cloud Logging metrics group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.DefaultUniverseOnly
class Metrics(base.Group):
"""Manages logs-based metrics."""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""'logging metrics create' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
DETAILED_HELP = {
'DESCRIPTION':
"""\
Create a logs-based metric to count the number of log entries that
match a filter expression. Logs-based metrics can also be used to
extract values from logs and create a distribution of the values.
""",
'EXAMPLES':
"""\
To create a metric that counts the number of log entries with a
severity level higher than WARNING, run:
$ {command} high_severity_count --description="Number of high severity log entries" --log-filter="severity > WARNING"
Detailed information about filters can be found at:
[](https://cloud.google.com/logging/docs/view/logging-query-language)
To create a metric that uses advanced features like distribution or
user-defined labels, run:
$ {command} my_metric --config-from-file=$PATH_TO_FILE
The config file can be in YAML or JSON format. Detailed information
about how to configure metrics can be found at: [](https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics#LogMetric).
To create a bucket log-based metric, run:
$ {command} my_bucket_metric --description="DESCRIPTION" --log-filter="LOG_FILTER" --bucket-name="BUCKET_NAME"
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class Create(base.CreateCommand):
"""Create a logs-based metric."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('metric_name', help='The name of the new metric.')
config_group = parser.add_argument_group(help='Data about the new metric.',
mutex=True,
required=True
)
legacy_mode_group = config_group.add_argument_group(
help=('A group of arguments to specify simple counter logs-based '
'metrics. '))
legacy_mode_group.add_argument(
'--description', required=True,
help='The metric\'s description.')
legacy_mode_group.add_argument(
'--log-filter', required=True,
help='The metric\'s filter expression.')
legacy_mode_group.add_argument(
'--bucket-name',
help='The Log Bucket name which owns the log-based metric.')
config_group.add_argument('--config-from-file',
help=('A path to a YAML or JSON file specifying '
'the logs-based metric to create.'),
type=arg_parsers.FileContents())
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The created metric.
"""
messages = util.GetMessages()
new_metric = util.CreateLogMetric(
metric_name=args.metric_name,
description=args.description,
log_filter=args.log_filter,
bucket_name=args.bucket_name,
data=args.config_from_file)
request = messages.LoggingProjectsMetricsCreateRequest(
parent=util.GetCurrentProjectParent(), logMetric=new_metric)
result = util.GetClient().projects_metrics.Create(request)
log.CreatedResource(args.metric_name)
return result
Create.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""'logging metrics delete' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
class Delete(base.DeleteCommand):
"""Delete a logs-based metric."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'metric_name', help='The name of the metric to delete.')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
"""
console_io.PromptContinue(
'Really delete metric [%s]?' % args.metric_name, cancel_on_no=True)
util.GetClient().projects_metrics.Delete(
util.GetMessages().LoggingProjectsMetricsDeleteRequest(
metricName=util.CreateResourceName(
util.GetCurrentProjectParent(), 'metrics', args.metric_name)))
log.DeletedResource(args.metric_name)
Delete.detailed_help = {
'DESCRIPTION': """\
Delete a logs-based metric called high_severity_count.
""",
'EXAMPLES': """\
To delete a metric called high_severity_count, run:
$ {command} high_severity_count
""",
}

View File

@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""'logging metrics describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
class Describe(base.DescribeCommand):
"""Display the definition of a logs-based metric."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'metric_name', help='The name of the metric.')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The specified metric with its description and configured filter.
"""
return util.GetClient().projects_metrics.Get(
util.GetMessages().LoggingProjectsMetricsGetRequest(
metricName=util.CreateResourceName(
util.GetCurrentProjectParent(), 'metrics', args.metric_name)))
Describe.detailed_help = {
'DESCRIPTION': """\
Show the definition of a logs-based metric.
""",
'EXAMPLES': """\
To show the definition of a metric called high_severity_count, run:
$ {command} high_severity_count
""",
}

View File

@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""'logging metrics list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.GA)
class ListGA(base.ListCommand):
"""Display all logs-based metrics."""
detailed_help = {
'DESCRIPTION': """\
List all logs-based metrics.
""",
'EXAMPLES': """\
To list the top 10 logs-based metrics, run:
$ {command} --limit=10
""",
}
@staticmethod
def Args(parser):
base.PAGE_SIZE_FLAG.RemoveFromParser(parser)
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat('table(name, description, filter)')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The list of metrics.
"""
request = util.GetMessages().LoggingProjectsMetricsListRequest(
parent=util.GetCurrentProjectParent())
return list_pager.YieldFromList(
util.GetClient().projects_metrics, request, field='metrics',
limit=args.limit, batch_size=None, batch_size_attribute='pageSize')
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA)
class ListBeta(ListGA):
"""Display all logs-based metrics."""
detailed_help = {
'DESCRIPTION': """\
Lists all logs-based metrics.
""",
'EXAMPLES': """\
To list up to 10 logs-based metrics, run:
$ {command} --limit=10
To view as a simple table with just the name, description, and filter
fields, run:
$ {command} --format="table(name, description, filter)"
""",
}
@staticmethod
def Args(parser):
base.PAGE_SIZE_FLAG.RemoveFromParser(parser)
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat('yaml')

View File

@@ -0,0 +1,134 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""'logging metrics update' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
DETAILED_HELP = {
'DESCRIPTION':
"""\
Update the description or the filter expression of an existing
logs-based metric.
""",
'EXAMPLES':
"""\
To update the description of a metric called high_severity_count, run:
$ {command} high_severity_count --description="Count of high-severity log entries."
To update the filter expression of the metric, run:
$ {command} high_severity_count --log-filter="severity >= WARNING"
Detailed information about filters can be found at:
[](https://cloud.google.com/logging/docs/view/logging-query-language)
For advanced features such as user-defined labels and distribution
metrics, update using a config file:
$ {command} high_severity_count --config-from-file=$PATH_TO_FILE
The config file should be in YAML format. Detailed information about
how to configure metrics can be found at: [](https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.metrics#LogMetric).
Any top-level fields in the LogMetric definition that aren't specified
in the config file will not be updated in the metric.
To update the bucket associated with a bucket log-based metric, run:
$ {command} my-bucket-metric --bucket-name="NEW_BUCKET_NAME"
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class Update(base.UpdateCommand):
"""Update the definition of a logs-based metric."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'metric_name', help='The name of the log-based metric to update.')
config_group = parser.add_argument_group(
help='Data about the metric to update.', mutex=True, required=True)
legacy_mode_group = config_group.add_argument_group(
help=('Arguments to specify information about simple counter logs-'
'based metrics.'))
legacy_mode_group.add_argument(
'--description',
required=False,
help=('A new description for the metric. '
'If omitted, the description is not changed.'))
legacy_mode_group.add_argument(
'--log-filter',
required=False,
help=('A new filter string for the metric. '
'If omitted, the filter is not changed.'))
config_group.add_argument(
'--config-from-file',
help=('A path to a YAML file specifying the '
'updates to be made to the logs-based '
'metric.'),
type=arg_parsers.FileContents())
legacy_mode_group.add_argument(
'--bucket-name',
help='The Log Bucket name which owns the log-based metric.')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated metric.
"""
# Calling the API's Update method on a non-existing metric creates it.
# Make sure the metric exists so we don't accidentally create it.
metric = util.GetClient().projects_metrics.Get(
util.GetMessages().LoggingProjectsMetricsGetRequest(
metricName=util.CreateResourceName(util.GetCurrentProjectParent(),
'metrics', args.metric_name)))
updated_metric = util.UpdateLogMetric(
metric,
description=args.description,
log_filter=args.log_filter,
bucket_name=args.bucket_name,
data=args.config_from_file)
result = util.GetClient().projects_metrics.Update(
util.GetMessages().LoggingProjectsMetricsUpdateRequest(
metricName=util.CreateResourceName(util.GetCurrentProjectParent(),
'metrics', args.metric_name),
logMetric=updated_metric))
log.UpdatedResource(args.metric_name)
return result
Update.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""Cloud Logging operations group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Operations(base.Group):
"""Manage long running operations."""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""'logging operations cancel' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core.console import console_io
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA
)
class Cancel(base.Command):
"""Cancel a long running operation.
Cancel a long running operation with given OPERATION_ID in given LOCATION.
This operation can be a copy_log_entries operation which is scheduled before.
## EXAMPLES
To cancel an operation, run:
$ {command} OPERATION_ID --location=LOCATION
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('operation_id', help='The Id of the operation.')
parser.add_argument(
'--location', required=True, help='Location of the operation.')
util.AddParentArgs(parser, 'operation to cancel')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
A long running operation.
"""
operation_name = util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location),
'operations', args.operation_id)
operation_reference = util.GetOperationReference(args.operation_id, args)
console_io.PromptContinue('Really cancel operation [%s]?' % operation_name,
cancel_on_no=True)
request = util.GetMessages(
).LoggingProjectsLocationsOperationsCancelRequest(name=operation_name)
util.GetClient().projects_locations_operations.Cancel(request)
print('Cancelled [%s]' % operation_reference)
print('Note:it may take up to 10 minutes for the '
"operation's status to be updated.")

View File

@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""'logging operations describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.resource import resource_projector
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA
)
class Describe(base.Command):
"""Display the information about a long running operation.
Display the information about a long running operation which was scheduled
before. For example, a copy_log_entries operation scheduled by command:
"gcloud alpha logging copy BUCKET_ID DESTINATION --location=LOCATION"
OPERATION_ID and LOCATION are required to locate such operation.
## EXAMPLES
To describe an operation, run:
$ {command} OPERATION_ID --location=LOCATION
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('operation_id', help='The Id of the operation.')
parser.add_argument(
'--location', required=True, help='Location of the operation.')
util.AddParentArgs(parser, 'operation to describe')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
A long running operation.
"""
parent_name = util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location),
'operations', args.operation_id)
request = util.GetMessages().LoggingProjectsLocationsOperationsGetRequest(
name=parent_name)
result = util.GetClient().projects_locations_operations.Get(request)
serialize_op = resource_projector.MakeSerializable(result)
self._cancellation_requested = serialize_op.get('metadata', {}).get(
'cancellationRequested', '')
return result
def Epilog(self, resources_were_displayed):
if self._cancellation_requested:
log.status.Print(
'Note: Cancellation happens asynchronously. It may take up to 10 '
"minutes for the operation's status to change to cancelled.")

View File

@@ -0,0 +1,156 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""'logging operations list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.resource import resource_projector
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA
)
class List(base.ListCommand):
"""List long running operations."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'--location', required=True, help='Location of the operations.')
parser.add_argument(
'--operation-filter',
required=True,
help=arg_parsers.UniverseHelpText(
default=(
'Filter expression that specifies the operations to return.'
),
universe_help='Not all operation types are supported.\n',
),
)
parser.add_argument(
'--page-token',
type=str,
help=(
'The next_page_token value returned from a previous List request,'
' if any.'
),
)
base.URI_FLAG.RemoveFromParser(parser)
base.FILTER_FLAG.RemoveFromParser(parser)
util.AddParentArgs(parser, 'operations to list')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Yields:
A list of operations.
"""
operation_name = util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location)
request = util.GetMessages().LoggingProjectsLocationsOperationsListRequest(
name=operation_name,
filter=args.operation_filter,
pageSize=args.page_size,
pageToken=args.page_token,
)
result = util.GetClient().projects_locations_operations.List(request)
self._cancellation_requested = False
for operation in result.operations:
yield operation
if not self._cancellation_requested:
serialize_op = resource_projector.MakeSerializable(operation)
self._cancellation_requested = serialize_op.get('metadata', {}).get(
'cancellationRequested', '')
if result.nextPageToken:
yield result.nextPageToken
def Epilog(self, resources_were_displayed):
if self._cancellation_requested:
log.status.Print(
'Note: Cancellation happens asynchronously. It may take up to 10 '
"minutes for the operation's status to change to cancelled.")
List.detailed_help = {
'DESCRIPTION': """
Return a list of long running operations in the given LOCATION. The
operations were scheduled by other gcloud commands.
For example, a CopyLogEntries operation may be scheduled by the command:
`gcloud logging copy BUCKET_ID DESTINATION --location=LOCATION`.
The `--operation-filter` flag is required and must specify the
`request_type`. Supported request types include but are not limited to:
`CopyLogEntries`, `CreateBucket` and `UpdateBucket`.
Additional supported filter expressions include: `operation_start_time`,
`operation_finish_time` and `operation_state`. These can be combined
with the case-sensitive keyword `AND` between them.
For `operation_start_time` and `operation_end_time`, the operators >=,
>, <=, and < are supported.
Timestamps must be in either RFC3339 or ISO8601 formats. If the
timestamp contains a time value, then it must be quoted. For examples:
"YYYY-MM-DDTHH:MM:SSZ", "YYYY-MM-DDTHH:MM:SS.mmmZ", "YY-MM-DD",
"YYYY-MM-DDTHH:MM:SS-0000", "YYYY-MM-DDTHH:MM+0000", "YYYY-MM-DD",
YYYY-MM-DD, YY-MM-DD, etc.
The `operation_state` filter expression can be used to filter for
operations that are in a specific state. The value can be one of the
following: `SCHEDULED`, `WAITING_FOR_PRECONDITIONS`, `RUNNING`,
`SUCCESS`, `FAILURE`, `CANCELLED`, `PENDING`.
For `operation_state`, the operators = and != are supported.
Other filter options are not supported.
""",
'EXAMPLES': """\
To list CopyLogEntries operations, run:
$ {command} --location=LOCATION --operation-filter='request_type=CopyLogEntries'
To list CopyLogEntries operations that started after a specified time, run:
$ {command} --location=LOCATION --operation-filter='request_type=CopyLogEntries AND operation_start_time>="2023-11-20T00:00:00Z"'
To list CopyLogEntries operations that finished before a specified time, run:
$ {command} --location=LOCATION --operation-filter='request_type=CopyLogEntries AND operation_finish_time<="2023-11-20T00:00:00Z"'
To list CopyLogEntries operations that completed successfully, run:
$ {command} --location=LOCATION --operation-filter='request_type=CopyLogEntries AND operation_state=SUCCESS'
To list CopyLogEntries operations that have not failed, run:
$ {command} --location=LOCATION --operation-filter='request_type=CopyLogEntries AND operation_state!=FAILURE'
""",
}

View File

@@ -0,0 +1,168 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""'logging read' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import common
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.logs import read as read_logs_lib
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Read(base.Command):
"""Read log entries."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
read_logs_lib.LogFilterPositionalArgs(parser)
read_logs_lib.LoggingReadArgs(parser)
target_group = parser.add_mutually_exclusive_group()
target_group.add_argument(
'--resource-names',
type=arg_parsers.ArgList(),
metavar='RESOURCE',
help='Resource name(s) to read logs from. A resource can either be an '
'top-level resource (e.g., "projects/my-project") or a full log view '
'resource path (e.g., '
'"projects/my-project/locations/my-location/buckets/my-bucket/'
'views/my-view"). Multiple resources can be specified, separated by a '
'comma.')
view_group = target_group.add_argument_group(
help='These arguments are used in conjunction with the parent to '
'construct a view resource.')
view_group.add_argument(
'--location',
required=True,
metavar='LOCATION',
help='Location of the log bucket. If this argument is provided then '
'`--bucket` and `--view` must also be specified.')
view_group.add_argument(
'--bucket',
required=True,
help='Id of the log bucket. If this argument is provided then '
'`--location` and `--view` must also be specified.')
view_group.add_argument(
'--view',
required=True,
help='Id of the view. If this argument is provided then '
'`--location` and `--bucket` must also be specified.')
util.AddParentArgs(parser, 'log entries to read')
def _Run(self, args):
filter_clauses = read_logs_lib.MakeTimestampFilters(args)
filter_clauses += [args.log_filter] if args.log_filter else []
if args.IsSpecified('location'):
# Explicit parent/location/bucket/view specification.
parent = util.CreateResourceName(
util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location),
'buckets', args.bucket), 'views', args.view)
elif args.IsSpecified('resource_names'):
# Explicit resource names listing.
parent = None
else:
# Neither is explicitly located, default scope to parent-from-args.
parent = util.GetParentFromArgs(args)
return common.FetchLogs(
read_logs_lib.JoinFilters(filter_clauses, operator='AND') or None,
order_by=args.order,
limit=args.limit,
parent=parent,
resource_names=args.resource_names)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The list of log entries.
"""
return self._Run(args)
Read.detailed_help = {
'DESCRIPTION':
"""\
{command} reads log entries. Log entries matching *log-filter* are
returned in order of decreasing timestamps, most-recent entries first.
If the log entries come from multiple logs, then entries from different
logs might be intermingled in the results.
""",
'EXAMPLES':
"""\
To read log entries from Google Compute Engine instances, run:
$ {command} "resource.type=gce_instance"
To read log entries with severity ERROR or higher, run:
$ {command} "severity>=ERROR"
To read log entries written in a specific time window, run:
$ {command} 'timestamp<="2015-05-31T23:59:59Z" AND timestamp>="2015-05-31T00:00:00Z"'
To read up to 10 log entries in your project's syslog log from Compute
Engine instances containing payloads that include the word `SyncAddress`
and format the output in `JSON` format, run:
$ {command} "resource.type=gce_instance AND logName=projects/[PROJECT_ID]/logs/syslog AND textPayload:SyncAddress" --limit=10 --format=json
To read a log entry from a folder, run:
$ {command} "resource.type=global" --folder=[FOLDER_ID] --limit=1
To read a log entry from a global log bucket, run:
$ {command} --bucket=<bucket-id> --location=[LOCATION] --limit=1
To read a log entry from the global ```_Required``` log bucket using the bucket's ```_Default``` log view:
$ {command} "" --bucket=_Required --location=global --view=_Default --limit=1
To read a log entry from a log bucket using the bucket's ```_AllLogs``` log view:
$ {command} "" --bucket=[BUCKET_ID] --location=[LOCATION] --view=_AllLogs --limit=1
To read a log entry from a log bucket using a custom log view that you have created for the bucket:
$ {command} "" --bucket=[BUCKET_ID] --location=[LOCATION] --view=[VIEW_ID] --limit=1
To read log entries from multiple resources, specify them as a
comma-delimeted sequence with --resource-names. Each resource name can
be specified either as a top-level resource (e.g.,
projects/[PROJECT_ID], folders/[FOLDER_ID], etc.) or as a Log View
resource (e.g.,
projects/[PROJECT_ID]/locations/[LOCATION]/buckets/[BUCKET_NAME]/views/[VIEW_ID]).
$ {command} "" --resource-names=[RESOURCE-1],[RESOURCE-2]
""",
}

View File

@@ -0,0 +1,109 @@
# -*- 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.
"""'logging redact' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core.console import console_io
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.Hidden
class Redact(base.Command):
"""Redact log entries."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'bucket_id',
help='Log bucket from which to redact log entries.',
)
parser.add_argument(
'--location', required=True, help='Location of the bucket.'
)
parser.add_argument(
'--log-filter',
required=False,
help=(
'A filter specifying which log entries to Redact. '
'The filter must be no more than 20k characters. '
'An empty filter matches all log entries.'
),
)
parser.add_argument(
'--reason',
required=True,
help=(
'The reason for the redaction. This field will be recorded in'
' redacted log entries and should omit sensitive information.'
' Required to be less than 1024 characters.'
),
)
util.AddParentArgs(parser, 'log entries to redact')
def _Run(self, args):
if not args.log_filter:
console_io.PromptContinue(
'An empty filter matches all log entries.', cancel_on_no=True
)
bucket_name = util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args), 'locations', args.location
),
'buckets',
args.bucket_id,
)
request = util.GetMessages().RedactLogEntriesRequest(
filter=args.log_filter, name=bucket_name, reason=args.reason
)
return util.GetClient().entries.Redact(request)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: An argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
A redact_log_entries operation.
"""
return self._Run(args)
Redact.detailed_help = {
'DESCRIPTION': """\
{command} starts the process to redact log entries from a log bucket.
""",
'EXAMPLES': """\
To start a redact log entries operation, run:
$ {command} "BUCKET_ID --location=LOCATION --reason='redacting logs'"
To redact log entries in a specific time window, run:
$ {command} "BUCKET_ID --location=LOCATION --reason='redacting logs within a window' --log-filter='timestamp<="2021-05-31T23:59:59Z" AND timestamp>="2021-05-31T00:00:00Z"'"
""",
}

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Cloud Logging resource-descriptors group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class ResourceDescriptors(base.Group):
"""Get information about resource descriptors."""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""'logging resource-descriptors list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class List(base.ListCommand):
"""List all available resource descriptors.
## EXAMPLES
To list all resource descriptors:
$ {command}
"""
@staticmethod
def Args(parser):
base.PAGE_SIZE_FLAG.RemoveFromParser(parser)
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat(
'table(type, description, labels[].key.list())')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The list of log entries.
"""
return list_pager.YieldFromList(
util.GetClient().monitoredResourceDescriptors,
util.GetMessages().LoggingMonitoredResourceDescriptorsListRequest(),
field='resourceDescriptors', limit=args.limit,
batch_size=args.limit, batch_size_attribute='pageSize')
List.detailed_help = {
'DESCRIPTION': ("""
List all available resource descriptors that are used by Cloud
Logging. Each log entry must be associated with a valid resource
descriptor.
"""),
}

View File

@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""The scopes command group for the Cloud Logging CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Scopes(base.Group):
"""Manages Cloud Logging log scopes.
Commands for managing Cloud Logging log scopes. A scope is used to describe a
group of resources to read log entries from.
"""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,109 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""'logging scopes create' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Create(base.CreateCommand):
"""Create a log scope.
After creating a log scope, you can use it to view logs in 1 or more
resources.
## EXAMPLES
To create a log scope in a project, run:
$ {command} my-scope --resource-names=projects/my-project
To create a log scope in a project with a description, run:
$ {command} my-scope --resource-names=projects/my-project --description="my
custom log scope"
To create a log scope that contains more than 1 resource, such as projects and
views, run:
$ {command} my-scope
--resource-names=projects/my-project,projects/my-project2,
projects/my-project/locations/global/buckets/my-bucket/views/my-view1,
projects/my-project/locations/global/buckets/my-bucket/views/my-view2,
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('LOG_SCOPE_ID', help='ID of the log scope to create.')
parser.add_argument(
'--description', help='A textual description for the log scope.'
)
parser.add_argument(
'--resource-names',
help=(
' Comma-separated list of resource names in this log scope. It'
' could be one or more parent resources or one or more views. '
' A log scope can include a maximum of 50 projects and a maximum of'
' 100 resources in total. For example, projects/[PROJECT_ID],'
' projects/[PROJECT_ID]/locations/[LOCATION_ID]/buckets/[BUCKET_ID]/views/[VIEW_ID]`'
),
metavar='RESOURCE_NAMES',
required=True,
type=arg_parsers.ArgList(),
)
util.AddParentArgs(
parser, 'log scope to create', exclude_billing_account=True
)
def _Run(self, args):
scope_data = {}
if args.IsSpecified('description'):
scope_data['description'] = args.description
if args.IsSpecified('resource_names'):
scope_data['resourceNames'] = args.resource_names
return util.GetClient().projects_locations_logScopes.Create(
util.GetMessages().LoggingProjectsLocationsLogScopesCreateRequest(
logScope=util.GetMessages().LogScope(**scope_data),
logScopeId=args.LOG_SCOPE_ID,
parent=util.CreateResourceName(
util.GetProjectResource(args.project).RelativeName(),
'locations',
'global',
),
)
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The created log scope.
"""
return self._Run(args)

View File

@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""'logging scopes delete' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.UniverseCompatible
class Delete(base.DeleteCommand):
"""Delete a log scope.
## EXAMPLES
To delete a log scope, run:
$ {command} my-scope
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('LOG_SCOPE_ID', help='ID of the log scope to delete.')
util.AddParentArgs(
parser, 'log scope to delete', exclude_billing_account=True
)
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
"""
console_io.PromptContinue(
'Really delete log scope [%s]? (You can not recover it after deletion)'
% args.LOG_SCOPE_ID,
cancel_on_no=True,
)
util.GetClient().projects_locations_logScopes.Delete(
util.GetMessages().LoggingProjectsLocationsLogScopesDeleteRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args, exclude_billing_account=True),
'locations',
'global',
),
'logScopes',
args.LOG_SCOPE_ID,
)
)
)
log.DeletedResource(args.LOG_SCOPE_ID)

View File

@@ -0,0 +1,76 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""'logging scopes describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
Display information about a log scope.
""",
'EXAMPLES': """
To describe a log scope in a project, run:
$ {command} my-scope --project=my-project
""",
}
@base.UniverseCompatible
class Describe(base.DescribeCommand):
"""Display information about a log scope."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'LOG_SCOPE_ID', help='The ID of the log scope to describe.'
)
util.AddParentArgs(
parser, 'log scope to describe', exclude_billing_account=True
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The specified log scope.
"""
return util.GetClient().projects_locations_logScopes.Get(
util.GetMessages().LoggingProjectsLocationsLogScopesGetRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetParentFromArgs(args, exclude_billing_account=True),
'locations',
'global',
),
'logScopes',
args.LOG_SCOPE_ID,
)
)
)
Describe.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""'logging scopes list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
List the log scopes for a project.
""",
'EXAMPLES': """
To list the log scopes in a project, run:
$ {command} --project=my-project
""",
}
@base.UniverseCompatible
class List(base.ListCommand):
"""List the defined log scopes."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
util.AddParentArgs(
parser, 'log scopes to list', exclude_billing_account=True
)
parser.display_info.AddFormat(
'table(name.segment(-3):label=LOCATION, '
'name.segment(-1):label=LOG_SCOPE_ID, '
'resource_name, description, create_time, update_time)'
)
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Yields:
The list of log scopes.
"""
result = util.GetClient().projects_locations_logScopes.List(
util.GetMessages().LoggingProjectsLocationsLogScopesListRequest(
parent=util.CreateResourceName(
util.GetProjectResource(args.project).RelativeName(),
'locations',
'global',
),
)
)
for scope in result.logScopes:
yield scope
List.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""'logging scopes update' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as calliope_exceptions
DETAILED_HELP = {
'DESCRIPTION': """
Update the properties of a log scope.
""",
'EXAMPLES': """
To update the description of a log scope in a project, run:
$ {command} my-scope --description=my-new-description --project=my-project
To update the resource name of a log scope in a project. Ensure that you
provide all the resource names including the existing ones. For example,
if the log scope has the resource name my-project, and you want to update
the log scope to have the resource name another-project, run the following:
$ {command} my-scope --resource-names=projects/my-project,projects/another-project --project=my-project
""",
}
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Update(base.UpdateCommand):
"""Update a log scope.
Changes one or more properties associated with a log scope.
"""
def __init__(self, *args, **kwargs):
super(Update, self).__init__(*args, **kwargs)
self._current_scope = None
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'LOG_SCOPE_ID', help='The ID of the log scope to update.'
)
parser.add_argument(
'--description', help='A new description for the log scope.'
)
parser.add_argument(
'--resource-names',
help='A new set of resource names for the log scope.',
type=arg_parsers.ArgList(),
metavar='RESOURCE_NAMES',
)
def _Run(self, args):
scope_data = {}
update_mask = []
parameter_names = ['--description', '--resource-names']
if args.IsSpecified('description'):
scope_data['description'] = args.description
update_mask.append('description')
if args.IsSpecified('resource_names'):
scope_data['resourceNames'] = args.resource_names
update_mask.append('resource_names')
if not update_mask:
raise calliope_exceptions.MinimumArgumentException(
parameter_names, 'Please specify at least one property to update'
)
return util.GetClient().projects_locations_logScopes.Patch(
util.GetMessages().LoggingProjectsLocationsLogScopesPatchRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetProjectResource(args.project).RelativeName(),
'locations',
'global',
),
'logScopes',
args.LOG_SCOPE_ID,
),
logScope=util.GetMessages().LogScope(**scope_data),
updateMask=','.join(update_mask),
)
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated log scope.
"""
return self._Run(args)
Update.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""Cloud Logging settings group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class Settings(base.Group):
"""Manages the org settings for the Cloud Logging Logs Router."""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""'logging settings describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Describe(base.DescribeCommand):
# pylint: disable=line-too-long
"""Display the settings for the Cloud Logging Logs Router.
If *kmsKeyName* is present in the output, then CMEK is enabled for your
project, folder, organization or billing-account. You can also find the Logs
Router service account using this command.
## EXAMPLES
To describe the Logs Router settings for a project, run:
$ {command} --project=[PROJECT_ID]
To describe the Logs Router settings for an organization, run:
$ {command} --organization=[ORGANIZATION_ID]
kmsKeyName:
'projects/my-project/locations/my-location/keyRings/my-keyring/cryptoKeys/key'
name: 'organizations/[ORGANIZATION_ID]/settings'
serviceAccountId:
'[SERVICE_ACCOUNT_ID]@gcp-sa-logging.iam.gserviceaccount.com'
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
util.AddParentArgs(parser, 'settings to describe')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The settings for the specified project, folder, organizations or
billing-account.
"""
parent_name = util.GetParentFromArgs(args)
return util.GetClient().projects.GetSettings(
util.GetMessages().LoggingProjectsGetSettingsRequest(name=parent_name))

View File

@@ -0,0 +1,206 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""'logging settings update' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as calliope_exceptions
from googlecloudsdk.command_lib.kms import resource_args as kms_resource_args
from googlecloudsdk.command_lib.resource_manager import completers
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Update(base.Command):
# pylint: disable=line-too-long
"""Update the settings for the Cloud Logging Logs Router.
Use this command to update the *--kms-key-name, --storage-location,
--disable-default-sink* and --analytics-mode associated with the Cloud Logging
Logs Router.
The Cloud KMS key must already exist and Cloud Logging must have
permission to access it.
The storage location must be allowed by Org Policy.
Customer-managed encryption keys (CMEK) for the Logs Router can currently
only be configured at the organization-level and will apply to all projects
in the organization.
## EXAMPLES
To enable CMEK for the Logs Router for an organization, run:
$ {command} --organization=[ORGANIZATION_ID]
--kms-key-name='projects/my-project/locations/my-location/keyRings/my-keyring/cryptoKeys/key'
To disable CMEK for the Logs Router for an organization, run:
$ {command} --organization=[ORGANIZATION_ID] --clear-kms-key
To update storage location for the Logs Router for an organization, run:
$ {command} --organization=[ORGANIZATION_ID]
--storage-location=[LOCATION_ID]
To update storage location for the Logs Router for a folder, run:
$ {command} --folder=[FOLDER_ID] --storage-location=[LOCATION_ID]
To disable default sink for the Logs Router for an organization, run:
$ {command} --organization=[ORGANIZATION_ID] --disable-default-sink=true
To enable default sink for the Logs Router for an organization, run:
$ {command} --organization=[ORGANIZATION_ID] --disable-default-sink=false
To enable analytics for the log buckets under an organization, run:
$ {command} --organization=[ORGANIZATION_ID] --disable-default-sink=false
--analytics-mode=required
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parent_group = parser.add_mutually_exclusive_group(required=True)
parent_group.add_argument(
'--organization',
required=False,
metavar='ORGANIZATION_ID',
completer=completers.OrganizationCompleter,
help='Organization to update Logs Router settings for.')
parent_group.add_argument(
'--folder',
required=False,
metavar='FOLDER_ID',
help='Folder to update Logs Router settings for.')
parser.add_argument(
'--storage-location',
required=False,
help='Update the storage location for ```_Default``` bucket and '
'```_Required``` bucket. Note: It only applies to the newly created '
'projects and will not affect the projects created before.')
parser.add_argument(
'--disable-default-sink',
action='store_true',
help='Enable or disable ```_Default``` sink for the ```_Default``` '
'bucket. Specify --no-disable-default-sink to enable a disabled '
'```_Default``` sink. Note: It only applies to the newly created '
'projects and will not affect the projects created before.')
parser.add_argument(
'--analytics-mode',
required=False,
hidden=True,
choices=['required', 'optional', 'unspecified'],
help=arg_parsers.UniverseHelpText(
default=(
'Update the analytics mode for newly-created project buckets. '
'Changing this setting does not modify any existing buckets.'
),
universe_help='This is not available.\n',
),
)
group = parser.add_mutually_exclusive_group(required=False)
kms_resource_args.AddKmsKeyResourceArg(
group,
resource='logs being processed by the Cloud Logging Logs Router',
permission_info=('The Cloud KMS CryptoKey Encrypter/Decryper role must '
'be assigned to the Cloud Logging Logs Router service '
'account'),
name='--kms-key-name')
group.add_argument(
'--clear-kms-key',
action='store_true',
help=('Disable CMEK for the Logs Router by clearing out Cloud KMS '
'cryptokey in the organization\'s CMEK settings.'))
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated settings.
"""
settings = {}
update_mask = []
parameter_names = [
'--kms-key-name | --clear-kms-key', '--storage-location',
'--disable-default-sink'
]
if args.IsSpecified('kms_key_name'):
settings['kmsKeyName'] = (
args.CONCEPTS.kms_key_name.Parse().RelativeName())
update_mask.append('kms_key_name')
if args.IsSpecified('clear_kms_key'):
settings['kmsKeyName'] = ''
update_mask.append('kms_key_name')
if args.IsSpecified('storage_location'):
settings['storageLocation'] = args.storage_location
update_mask.append('storage_location')
if args.IsSpecified('disable_default_sink'):
settings['disableDefaultSink'] = args.disable_default_sink
update_mask.append('disable_default_sink')
if args.IsSpecified('analytics_mode'):
update_mask.append('analytics_mode')
if args.analytics_mode == 'required':
settings['analyticsMode'] = (
util.GetMessages().Settings.AnalyticsModeValueValuesEnum.ANALYTICS_REQUIRED
)
elif args.analytics_mode == 'optional':
settings['analyticsMode'] = (
util.GetMessages().Settings.AnalyticsModeValueValuesEnum.ANALYTICS_OPTIONAL
)
else:
settings['analyticsMode'] = (
util.GetMessages().Settings.AnalyticsModeValueValuesEnum.ANALYTICS_MODE_UNSPECIFIED
)
if not update_mask:
raise calliope_exceptions.MinimumArgumentException(
parameter_names, 'Please specify at least one property to update.')
parent_name = util.GetParentFromArgs(args)
return util.GetClient().v2.UpdateSettings(
util.GetMessages().LoggingUpdateSettingsRequest(
name=parent_name,
settings=util.GetMessages().Settings(**settings),
updateMask=','.join(update_mask)))

View File

@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""Cloud Logging sinks group."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class Sinks(base.Group):
"""Manages sinks used to route logs to storage or export destinations."""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,256 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""'logging sinks create' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA
)
class Create(base.CreateCommand):
# pylint: disable=line-too-long
"""Create a log sink.
Create a log sink used to route log entries to a destination. The sink routes
all log entries that match its *--log-filter* flag.
An empty filter matches all logs.
Detailed information about filters can be found at:
[](https://cloud.google.com/logging/docs/view/logging-query-language)
The sink's destination can be a Cloud Logging log bucket, a Cloud Storage
bucket, a BigQuery dataset, a Cloud Pub/Sub topic, or a Google Cloud project.
The destination must already exist.
If creating a log sink to route logs to a destination outside of Cloud Logging
or to a Cloud Logging log bucket in another project, the log sink's service
account must be granted permission to write to the destination.
For more information about destination permissions, see:
https://cloud.google.com/logging/docs/export/configure_export_v2#dest-auth
Matching log entries are routed to the destination after the sink is created.
## EXAMPLES
To route all Google Compute Engine logs to BigQuery, run:
$ {command} my-bq-sink
bigquery.googleapis.com/projects/my-project/datasets/my_dataset --log-filter='resource.type="gce_instance"'
To route "syslog" from App Engine Flexible to a Cloud Storage bucket, run:
$ {command} my-gcs-sink storage.googleapis.com/my-bucket --log-filter='logName="projects/my-project/appengine.googleapis.com%2Fsyslog"'
To route Google App Engine logs with ERROR severity, run:
$ {command} my-error-logs
bigquery.googleapis.com/projects/my-project/datasets/my_dataset --log-filter='resource.type="gae_app" AND severity=ERROR'
To route all logs to a log bucket in a different project, run:
$ {command} my-sink
logging.googleapis.com/projects/my-central-project/locations/global/buckets/my-central-bucket
To route all logs to another project, run:
$ {command} my-sink
logging.googleapis.com/projects/my-destination-project
"""
# pylint: enable=line-too-long
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('sink_name', help='The name for the sink.')
parser.add_argument(
'destination',
help=arg_parsers.UniverseHelpText(
default='The destination for the sink.',
universe_help='Some destination types are not supported\n.',
),
)
parser.add_argument(
'--log-filter',
required=False,
help=('A filter expression for the sink. If present, the filter '
'specifies which log entries to export.'))
parser.add_argument(
'--include-children',
required=False,
action='store_true',
help=('Whether to export logs from all child projects and folders. '
'Only applies to sinks for organizations and folders.'))
parser.add_argument(
'--intercept-children',
required=False,
action='store_true',
help=(
'Whether to intercept logs from all child projects and folders. '
'Only applies to sinks for organizations and folders.'
),
)
parser.add_argument(
'--custom-writer-identity',
metavar='SERVICE_ACCOUNT_EMAIL',
help=(
'Writer identity for the sink. This flag can only be used if the '
'destination is a log bucket in a different project. The writer '
'identity is automatically generated when it is not provided for '
'a sink.'
),
)
bigquery_group = parser.add_argument_group(
help='Settings for sink exporting data to BigQuery.')
bigquery_group.add_argument(
'--use-partitioned-tables',
required=False,
action='store_true',
help=('If specified, use BigQuery\'s partitioned tables. By default, '
'Logging creates dated tables based on the log entries\' '
'timestamps, e.g. \'syslog_20170523\'. Partitioned tables remove '
'the suffix and special query syntax '
'(https://cloud.google.com/bigquery/docs/'
'querying-partitioned-tables) must be used.'))
parser.add_argument(
'--exclusion',
action='append',
type=arg_parsers.ArgDict(
spec={
'name': str,
'description': str,
'filter': str,
'disabled': bool
},
required_keys=['name', 'filter']),
help=('Specify an exclusion filter for a log entry that is not to be '
'exported. This flag can be repeated.\n\n'
'The ``name\'\' and ``filter\'\' attributes are required. The '
'following keys are accepted:\n\n'
'*name*::: An identifier, such as ``load-balancer-exclusion\'\'. '
'Identifiers are limited to 100 characters and can include only '
'letters, digits, underscores, hyphens, and periods.\n\n'
'*description*::: A description of this exclusion.\n\n'
'*filter*::: An advanced log filter that matches the log entries '
'to be excluded.\n\n'
'*disabled*::: If this exclusion should be disabled and not '
'exclude the log entries.'))
parser.add_argument('--description', help='Description of the sink.')
parser.add_argument(
'--disabled',
action='store_true',
help=('Sink will be disabled. Disabled sinks do not export logs.'))
util.AddParentArgs(parser, 'sink to create')
parser.display_info.AddCacheUpdater(None)
def CreateSink(self, parent, sink_data, custom_writer_identity):
"""Creates a v2 sink specified by the arguments."""
messages = util.GetMessages()
return util.GetClient().projects_sinks.Create(
messages.LoggingProjectsSinksCreateRequest(
parent=parent,
logSink=messages.LogSink(**sink_data),
uniqueWriterIdentity=True,
customWriterIdentity=custom_writer_identity))
def _Run(self, args):
if not args.log_filter:
# Attempt to create a sink with an empty filter.
console_io.PromptContinue(
'Sink with empty filter matches all entries.', cancel_on_no=True)
if not (args.organization or args.folder):
if args.include_children:
log.warning(
'include-children only has an effect for sinks at the folder '
'or organization level'
)
if args.intercept_children:
log.warning(
'intercept-children only has an effect for sinks at the folder '
'or organization level'
)
sink_ref = util.GetSinkReference(args.sink_name, args)
sink_data = {
'name': sink_ref.sinksId,
'destination': args.destination,
}
if args.IsSpecified('include_children'):
sink_data['includeChildren'] = args.include_children
if args.IsSpecified('intercept_children'):
sink_data['interceptChildren'] = args.intercept_children
if args.IsSpecified('log_filter'):
sink_data['filter'] = args.log_filter
if args.IsSpecified('use_partitioned_tables'):
bigquery_options = {}
bigquery_options['usePartitionedTables'] = args.use_partitioned_tables
sink_data['bigqueryOptions'] = bigquery_options
if args.IsSpecified('exclusion'):
sink_data['exclusions'] = args.exclusion
if args.IsSpecified('description'):
sink_data['description'] = args.description
if args.IsSpecified('disabled'):
sink_data['disabled'] = args.disabled
custom_writer_identity = None
if args.IsSpecified('custom_writer_identity'):
custom_writer_identity = args.custom_writer_identity
result = self.CreateSink(
util.GetParentFromArgs(args), sink_data, custom_writer_identity)
log.CreatedResource(sink_ref)
self._epilog_result_destination = result.destination
self._epilog_writer_identity = result.writerIdentity
return result
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The created sink with its destination.
"""
return self._Run(args)
def Epilog(self, unused_resources_were_displayed):
util.PrintPermissionInstructions(self._epilog_result_destination,
self._epilog_writer_identity)

View File

@@ -0,0 +1,68 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""'logging sinks delete' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.UniverseCompatible
class Delete(base.DeleteCommand):
"""Delete a sink.
Delete a sink and halt the export of log entries associated with that sink.
Deleting a sink does not affect log entries already exported through
the deleted sink, and will not affect other sinks that are exporting
the same log(s).
## EXAMPLES
To delete a sync 'my-bq-sync':
$ {command} my-bq-sink
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('sink_name', help='The name of the sink to delete.')
util.AddParentArgs(parser, 'sink to delete')
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
"""
sink_ref = util.GetSinkReference(args.sink_name, args)
sink_resource = util.CreateResourceName(util.GetParentFromArgs(args),
'sinks', sink_ref.sinksId)
console_io.PromptContinue('Really delete sink [%s]?' % sink_ref.sinksId,
cancel_on_no=True)
util.GetClient().projects_sinks.Delete(
util.GetMessages().LoggingProjectsSinksDeleteRequest(
sinkName=sink_resource))
log.DeletedResource(sink_ref)

View File

@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""'logging sinks describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class Describe(base.DescribeCommand):
"""Display information about a sink.
Display information about a sink.
## EXAMPLES
To describe a sync 'my-bq-sync':
$ {command} my-bq-sink
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('sink_name', help='The name of the sink to describe.')
util.AddParentArgs(parser, 'sink to describe')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The specified sink with its destination.
"""
sink_ref = util.GetSinkReference(args.sink_name, args)
sink_resource = util.CreateResourceName(util.GetParentFromArgs(args),
'sinks', sink_ref.sinksId)
return util.GetClient().projects_sinks.Get(
util.GetMessages().LoggingProjectsSinksGetRequest(
sinkName=sink_resource))

View File

@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""'logging sinks list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class List(base.ListCommand):
"""List the defined sinks.
List the defined sinks.
## EXAMPLES
To list all defined sinks:
$ {command} --limit=10
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
base.PAGE_SIZE_FLAG.RemoveFromParser(parser)
base.URI_FLAG.RemoveFromParser(parser)
util.AddParentArgs(parser, 'sinks to list')
parser.add_argument(
'--sink-filter',
help=(
'A filter expression passed to the Logging API to constrain the '
'sinks returned. For information on accepted values, see '
'https://cloud.google.com/logging/docs/reference/v2/rpc/google.logging.v2#listsinksrequest'
),
)
parser.display_info.AddFormat('table(name, destination, filter)')
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The list of sinks.
"""
result = util.GetClient().projects_sinks.List(
util.GetMessages().LoggingProjectsSinksListRequest(
parent=util.GetParentFromArgs(args), filter=args.sink_filter
)
)
for sink in result.sinks:
if not sink.filter:
sink.filter = '(empty filter)'
return result.sinks

View File

@@ -0,0 +1,342 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""'logging sinks update' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as calliope_exceptions
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA
)
class Update(base.UpdateCommand):
"""Update a sink.
Change the *[DESTINATION]* or *--log-filter* associated with a sink.
The new destination must already exist and Cloud Logging must have
permission to write to it.
Log entries are exported to the new destination immediately.
## EXAMPLES
To only update a sink filter, run:
$ {command} my-sink --log-filter='severity>=ERROR'
Detailed information about filters can be found at:
[](https://cloud.google.com/logging/docs/view/logging-query-language)
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('sink_name', help='The name of the sink to update.')
parser.add_argument(
'destination',
nargs='?',
help=arg_parsers.UniverseHelpText(
default=(
"A new destination for the sink. If omitted, the sink's"
' existing destination is unchanged.'
),
universe_help='Some destination types are not supported\n.',
),
)
parser.add_argument(
'--log-filter',
help=('A new filter expression for the sink. '
'If omitted, the sink\'s existing filter (if any) is unchanged.'))
parser.add_argument(
'--include-children',
required=False,
action='store_true',
help=(
'Whether to export logs from all child projects and folders. '
'Only applies to sinks for organizations and folders.'
),
)
parser.add_argument(
'--intercept-children',
required=False,
action='store_true',
help=(
'Whether to intercept logs from all child projects and folders. '
'Only applies to sinks for organizations and folders.'
),
)
parser.add_argument(
'--custom-writer-identity',
metavar='SERVICE_ACCOUNT_EMAIL',
help=(
'Writer identity for the sink. This flag can only be used if the '
'destination is a log bucket in a different project. The writer '
'identity is automatically generated when it is not provided for '
'a sink.'
),
)
util.AddParentArgs(parser, 'sink to update')
bigquery_group = parser.add_argument_group(
help='Settings for sink exporting data to BigQuery.')
bigquery_group.add_argument(
'--use-partitioned-tables',
action='store_true',
help=('If specified, use BigQuery\'s partitioned tables. By default, '
'Logging creates dated tables based on the log entries\' '
'timestamps, e.g. \'syslog_20170523\'. Partitioned tables remove '
'the suffix and special query syntax '
'(https://cloud.google.com/bigquery/docs/'
'querying-partitioned-tables) must be used.'))
parser.add_argument(
'--clear-exclusions',
action='store_true',
help=('Remove all logging exclusions from the sink.'))
parser.add_argument(
'--remove-exclusions',
type=arg_parsers.ArgList(),
metavar='EXCLUSION ID',
help=('Specify the name of the Logging exclusion(s) to delete.'))
parser.add_argument(
'--add-exclusion',
action='append',
type=arg_parsers.ArgDict(
spec={
'name': str,
'filter': str,
'description': str,
'disabled': bool
},
required_keys=['name', 'filter']),
help=('Add an exclusion filter for log entries that are not to be '
'routed to the sink\' destination. This flag can be repeated.\n\n'
'The ``name\'\' and ``filter\'\' attributes are required. The '
'following keys are accepted:\n\n'
'*name*::: Required. An identifier, such as '
'``load-balancer-exclusion\'\'. '
'Identifiers are limited to 100 characters and can include only '
'letters, digits, underscores, hyphens, and periods.\n\n'
'*description*::: Optional. A description of this exclusion.\n\n'
'*filter*::: Required. Entries that match this advanced log '
'filter will be excluded. Filter cannot be empty.\n\n'
'*disabled*::: Optional. By default, an exclusion is not '
'disabled. To disable an exclusion, include this key and specify '
'any value.\n\n'))
parser.add_argument(
'--update-exclusion',
action='append',
type=arg_parsers.ArgDict(
spec={
'name': str,
'filter': str,
'description': str,
'disabled': bool
},
required_keys=['name']),
help=('Update an exclusion filter for a log entry that is not to be '
'exported. This flag can be repeated.\n\n'
'The ``name\'\' attribute is required. The '
'following keys are accepted:\n\n'
'*name*::: Required. An identifier, such as '
'``load-balancer-exclusion\'\'. '
'Identifiers are limited to 100 characters and can include only '
'letters, digits, underscores, hyphens, and periods.\n\n'
'*description*::: Optional. A description of this exclusion.\n\n'
'*filter*::: Optional. Entries that match this advanced log '
'filter will be excluded. Filter cannot be empty.\n\n'
'*disabled*::: Optional. To disable an exclusion, include this '
'key and specify any value. To enable a disabled exclusion, '
'include this key, but do not specify any value. Do not include '
'this key unless you want to change its value.\n\n'))
parser.add_argument('--description', help='Description of the sink.')
parser.add_argument(
'--disabled',
action='store_true',
help=('Disable the sink. Disabled sinks do not route logs to the sink '
'destination. Specify --no-disabled to enable a disabled sink. '
'If this flag is not specified, the value will not be updated.'))
def GetSink(self, parent, sink_ref):
"""Returns a sink specified by the arguments."""
return util.GetClient().projects_sinks.Get(
util.GetMessages().LoggingProjectsSinksGetRequest(
sinkName=util.CreateResourceName(parent, 'sinks',
sink_ref.sinksId)))
def PatchSink(self, parent, sink_data, update_mask, custom_writer_identity):
"""Patches a sink specified by the arguments."""
messages = util.GetMessages()
return util.GetClient().projects_sinks.Patch(
messages.LoggingProjectsSinksPatchRequest(
sinkName=util.CreateResourceName(parent, 'sinks',
sink_data['name']),
logSink=messages.LogSink(**sink_data),
uniqueWriterIdentity=True,
updateMask=','.join(update_mask),
customWriterIdentity=custom_writer_identity))
def _Run(self, args):
sink_ref = util.GetSinkReference(args.sink_name, args)
sink = self.GetSink(util.GetParentFromArgs(args), sink_ref)
sink_data = {'name': sink_ref.sinksId}
update_mask = []
if args.IsSpecified('destination'):
sink_data['destination'] = args.destination
update_mask.append('destination')
if args.IsSpecified('include_children'):
sink_data['includeChildren'] = args.include_children
update_mask.append('include_children')
if args.include_children and not (args.organization or args.folder):
log.warning(
'include-children only has an effect for sinks at the folder '
'or organization level'
)
if args.IsSpecified('intercept_children'):
sink_data['interceptChildren'] = args.intercept_children
update_mask.append('intercept_children')
if args.intercept_children and not (args.organization or args.folder):
log.warning(
'intercept-children only has an effect for sinks at the folder '
'or organization level'
)
if args.IsSpecified('log_filter'):
sink_data['filter'] = args.log_filter
update_mask.append('filter')
parameter_names = ['[destination]', '--log-filter']
parameter_names.extend(['--use-partitioned-tables', '--clear-exclusions'])
if args.IsSpecified('use_partitioned_tables'):
bigquery_options = {}
bigquery_options['usePartitionedTables'] = args.use_partitioned_tables
sink_data['bigqueryOptions'] = bigquery_options
update_mask.append('bigquery_options.use_partitioned_tables')
if args.IsSpecified('description'):
sink_data['description'] = args.description
update_mask.append('description')
if args.IsSpecified('disabled'):
sink_data['disabled'] = args.disabled
update_mask.append('disabled')
if (args.IsSpecified('clear_exclusions') or
args.IsSpecified('remove_exclusions') or
args.IsSpecified('add_exclusion') or
args.IsSpecified('update_exclusion')):
sink_data['exclusions'] = []
update_mask.append('exclusions')
exclusions_to_remove = (
args.remove_exclusions
if args.IsSpecified('remove_exclusions') else [])
exclusions_to_update = (
args.update_exclusion if args.IsSpecified('update_exclusion') else [])
for exclusion in sink.exclusions:
if exclusion.name in exclusions_to_remove:
exclusions_to_remove.remove(exclusion.name)
else:
for i in range(len(exclusions_to_update)):
if exclusion.name == exclusions_to_update[i]['name']:
for key, value in exclusions_to_update[i].items():
if key == 'description':
exclusion.description = value
if key == 'filter':
exclusion.filter = value
if key == 'disabled':
exclusion.disabled = value
exclusions_to_update.pop(i)
break
sink_data['exclusions'].append(exclusion)
if exclusions_to_remove:
raise calliope_exceptions.InvalidArgumentException(
'--remove-exclusions', 'Exclusions {0} do not exist'.format(
','.join(exclusions_to_remove)))
if exclusions_to_update:
raise calliope_exceptions.InvalidArgumentException(
'--update-exclusion', 'Exclusions {0} do not exist'.format(','.join(
[exclusion['name'] for exclusion in exclusions_to_update])))
if args.IsSpecified('clear_exclusions'):
sink_data['exclusions'] = []
if args.IsSpecified('add_exclusion'):
sink_data['exclusions'] += args.add_exclusion
custom_writer_identity = None
if args.IsSpecified('custom_writer_identity'):
custom_writer_identity = args.custom_writer_identity
parameter_names.extend(['--custom_writer_identity'])
if not update_mask:
raise calliope_exceptions.MinimumArgumentException(
parameter_names, 'Please specify at least one property to update')
# Check for legacy configuration, and let users decide if they still want
# to update the sink with new settings.
if sink.writerIdentity and 'cloud-logs@' in sink.writerIdentity:
console_io.PromptContinue(
'This update will create a new writerIdentity (service account) for '
'the sink. In order for the sink to continue working, grant that '
'service account correct permission on the destination. The service '
'account will be displayed after a successful update operation.',
cancel_on_no=True,
default=False)
result = self.PatchSink(
util.GetParentFromArgs(args), sink_data, update_mask,
custom_writer_identity)
log.UpdatedResource(sink_ref)
if args.IsSpecified('destination'):
self._epilog_result_destination = result.destination
self._epilog_writer_identity = result.writerIdentity
return result
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated sink with its new destination.
"""
return self._Run(args)
def Epilog(self, unused_resources_were_displayed):
if hasattr(self, '_epilog_result_destination'):
util.PrintPermissionInstructions(self._epilog_result_destination,
self._epilog_writer_identity)

View File

@@ -0,0 +1,208 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""'logging 'tail' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import logging
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.core import log
from googlecloudsdk.core.util import platforms
_TAILING_INSTALL_LINK = 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging#install_live_tailing'
def _GrpcSetupHelpMessage():
"""Returns platform-specific guidance on setup for the tail command."""
current_os = platforms.OperatingSystem.Current()
if current_os == platforms.OperatingSystem.WINDOWS:
# This should never happen. gRPC is bundled with the Cloud SDK distribution
# for Windows, and should therefore never be inaccessible.
return ('The installation of the Cloud SDK is corrupted, and gRPC is '
'inaccessible.')
if current_os in (platforms.OperatingSystem.LINUX,
platforms.OperatingSystem.MACOSX):
return (
'Please ensure that the gRPC module is installed and the environment '
'is correctly configured. Run:\n sudo pip3 install grpcio\nand set:\n'
' export CLOUDSDK_PYTHON_SITEPACKAGES=1\nFor more information, see {}'
).format(_TAILING_INSTALL_LINK)
# By default, direct users to the docs.
return (
'Please ensure that the gRPC module is installed and the environment is '
'configured to allow gcloud to use the installation. For help, see {}'
).format(_TAILING_INSTALL_LINK)
class NoGRPCInstalledError(exceptions.ToolException):
"""Unable to import grpc-based modules."""
def __init__(self):
super(NoGRPCInstalledError, self).__init__(_GrpcSetupHelpMessage())
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Tail(base.Command):
"""Tail log entries."""
@staticmethod
def Args(parser):
"""Registers flags for this command."""
parser.add_argument(
'log_filter',
help=(
'Filter expression that specifies the log entries to return. A '
'detailed guide on the Logging query language can be found at: '
'https://cloud.google.com/logging/docs/view/logging-query-language.'
),
nargs='?')
parser.add_argument(
'--buffer-window',
required=False,
type=arg_parsers.Duration(),
help=(
'The duration of time for which entries should be buffered for '
'ordering before being returned. A longer buffer window helps to '
'return logs in chronological order, but it also increases the '
'latency from when entries are received by Cloud Logging to when '
'they are returned. If unset, Cloud Logging will use 2s by '
'default.'))
view_group = parser.add_argument_group(
help='These arguments are used in conjunction with the parent to '
'construct a view resource.')
view_group.add_argument(
'--location',
required=True,
metavar='LOCATION',
help='Location of the bucket. If this argument is provided, then '
'`--bucket` and `--view` must also be specified.')
view_group.add_argument(
'--bucket',
required=True,
help='Id of the bucket. If this argument is provided, then '
'`--location` and `--view` must also be specified.')
view_group.add_argument(
'--view',
required=True,
help='Id of the view. If this argument is provided, then '
'`--location` and `--bucket` must also be specified.')
util.AddParentArgs(parser, 'log entries to tail')
def _Run(self, args):
try:
# pylint: disable=g-import-not-at-top
from googlecloudsdk.api_lib.logging import tailing
# pylint: enable=g-import-not-at-top
except ImportError:
raise NoGRPCInstalledError()
log.err.Print('Initializing tail session.')
parent = util.GetParentFromArgs(args)
if args.IsSpecified('location'):
parent = util.CreateResourceName(
util.CreateResourceName(
util.CreateResourceName(parent, 'locations', args.location),
'buckets', args.bucket), 'views', args.view)
buffer_window_seconds = None
if args.buffer_window:
if args.buffer_window < 0 or args.buffer_window > 60:
log.error('The buffer window must be set between 0s and 1m.')
buffer_window_seconds = args.buffer_window
tailer = tailing.LogTailer()
# By default and up to the INFO verbosity, all console output is included in
# the log file. When tailing logs, coarse filters could cause very large
# files. So, we limit the log file to WARNING logs and above.
log.SetLogFileVerbosity(logging.WARNING)
return tailer.TailLogs(
[parent],
args.log_filter or '',
buffer_window_seconds=buffer_window_seconds)
def Run(self, args):
"""Gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
An iterator of log entries.
"""
return self._Run(args)
Tail.detailed_help = {
'DESCRIPTION':
"""
{command} streams newly received log entries. Log entries matching
`log-filter` are returned in the order that Cloud Logging received
them. If the log entries come from multiple logs, then entries from
different logs might be mixed in the results. To help return log
entries in order, use `--buffer-window`.
Before you can use {command}, you must complete the installation
instructions at
[Live tailing log entries](https://cloud.google.com/logging/docs/reference/tools/gcloud-logging#live-tailing).
For the quotas and limits associated with {command},
see [Logging API quotas and limits](https://cloud.google.com/logging/quotas#api-limits).
""",
'EXAMPLES':
"""\
To stream log entries from Google Compute Engine instances, run:
$ {command} "resource.type=gce_instance"
To stream log entries with severity ERROR or higher, run:
$ {command} "severity>=ERROR"
To stream log entries with severity ERROR but only output the timestamps
and instance IDs, run:
$ {command} "severity>=ERROR" --format="default(timestamp,resource[\"labels\"][\"instance_id\"])"
To stream with minimal latency but potentially incorrect ordering:
$ {command} "resource.type=gce_instance" --buffer-window=0s
To stream log entries in your project's syslog log from Compute Engine
instances containing payloads that include the word `SyncAddress` and
format the output in `JSON` format, run:
$ {command} "resource.type=gce_instance AND log_id(syslog) AND textPayload:SyncAddress" --format=json
To stream log entries from a folder, run:
$ {command} "resource.type=global" --folder=[FOLDER_ID]
Detailed information about filters can be found at:
https://cloud.google.com/logging/docs/view/logging-query-language
""",
}

View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""The views command group for the Cloud Logging CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Views(base.Group):
"""Manage log views.
Commands for managing views. A log view represents a subset of the log entries
in a Cloud Logging log bucket.
"""
category = base.MANAGEMENT_TOOLS_CATEGORY

View File

@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 Google Inc. 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.
"""'logging views add_iam_policy_binding' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.api_lib.util import exceptions as gcloud_exception
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.iam import iam_util
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class AddIamPolicyBinding(base.Command):
"""Add IAM policy binding to a log view."""
detailed_help = {
'EXAMPLES': """\
To add an IAM policy binding for the role 'roles/my-role'
for the user 'my-user@gmail.com' on my-view, run:
$ {command} my-view --member='user:my-user@gmail.com' --role='roles/my-role' --bucket=my-bucket --location=global
To add a binding with a condition, run:
$ {command} my-view --member='user:my-user@gmail.com' --role='roles/my-role' --bucket=my-bucket --location=global --condition=expression=[expression],title=[title],description=[description]
See https://cloud.google.com/iam/docs/managing-policies for details about IAM policies and member types.
""",
}
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'VIEW_ID', help='ID of the view that contains the IAM policy.'
)
util.AddParentArgs(parser, 'view that contains the IAM policy')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket that contains the view.'
)
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of the bucket that contains the view.',
)
iam_util.AddArgsForAddIamPolicyBinding(parser, add_condition=True)
@gcloud_exception.CatchHTTPErrorRaiseHTTPException(
'Status code: {status_code}. {status_message}.'
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated policy.
"""
view = util.CreateResourceName(
util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets', args.bucket
),
'views',
args.VIEW_ID,
)
messages = util.GetMessages()
policy = util.GetIamPolicy(view)
condition = iam_util.ValidateAndExtractCondition(args)
iam_util.AddBindingToIamPolicyWithCondition(
binding_message_type=messages.Binding,
condition_message_type=messages.Expr,
policy=policy,
member=args.member,
role=args.role,
condition=condition,
)
results = util.SetIamPolicy(view, policy)
iam_util.LogSetIamPolicy(view, 'logging view')
return results

View File

@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging views create' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
@base.UniverseCompatible
class Create(base.CreateCommand):
# pylint: disable=line-too-long
"""Create a log view on a log bucket.
## EXAMPLES
To create a view that matches all Google Compute Engine logs in a bucket, run:
$ {command} my-view --bucket=my-bucket --location=global
--log-filter='resource.type="gce_instance"'
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('VIEW_ID', help='ID of the view to create.')
parser.add_argument(
'--description', help='A textual description for the view.'
)
parser.add_argument('--log-filter', help='A filter for the view.')
util.AddParentArgs(parser, 'view to create')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket that will hold the view.'
)
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of the bucket that will hold the view',
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The created view.
"""
view_data = {}
if args.IsSpecified('description'):
view_data['description'] = args.description
if args.IsSpecified('log_filter'):
view_data['filter'] = args.log_filter
return util.GetClient().projects_locations_buckets_views.Create(
util.GetMessages().LoggingProjectsLocationsBucketsViewsCreateRequest(
viewId=args.VIEW_ID,
parent=util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets', args.bucket
),
logView=util.GetMessages().LogView(**view_data),
)
)

View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging views delete' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
DETAILED_HELP = {
'DESCRIPTION':
"""
Deletes a view on a bucket.
""",
'EXAMPLES':
"""
To delete a view on a bucket, run:
$ {command} my-view --bucket=my-bucket --location=global
""",
}
@base.UniverseCompatible
class Delete(base.DeleteCommand):
"""Delete a view.
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'VIEW_ID', help='ID of the view to delete.')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket.')
util.AddParentArgs(parser, 'view to delete')
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of bucket')
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
"""
util.GetClient().projects_locations_buckets_views.Delete(
util.GetMessages().LoggingProjectsLocationsBucketsViewsDeleteRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets',
args.bucket), 'views', args.VIEW_ID)))
log.DeletedResource(args.VIEW_ID)
Delete.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging buckets describe' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
Displays information about a log view.
""",
'EXAMPLES': """
To describe a view in a project, run:
$ {command} my-view --bucket=my-bucket --location=global
""",
}
@base.UniverseCompatible
class Describe(base.DescribeCommand):
"""Display information about a view."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('VIEW_ID', help='Id of the view to describe.')
util.AddParentArgs(parser, 'view to describe')
util.AddBucketLocationArg(parser, True, 'Location of the bucket.')
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of bucket')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The specified view
"""
return util.GetClient().projects_locations_buckets_views.Get(
util.GetMessages().LoggingProjectsLocationsBucketsViewsGetRequest(
name=util.CreateResourceName(
util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets',
args.bucket), 'views', args.VIEW_ID)))
Describe.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""'logging views get_iam_policy' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
Get the IAM policy for a view.
""",
'EXAMPLES': """
To describe a view in a project, run:
$ {command} my-view --bucket=my-bucket --location=global
""",
}
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class GetIamPolicy(base.Command):
"""Display the IAM policy for a view."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('VIEW_ID', help='ID of the view to fetch IAM policy')
util.AddParentArgs(parser, 'view to fetch IAM policy')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket that contains the view'
)
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of the bucket that holds the view.',
)
def Run(self, args):
"""This is what get-iam-policy called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The IAM policy for the specified view
"""
view = util.CreateResourceName(
util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets', args.bucket
),
'views',
args.VIEW_ID,
)
return util.GetIamPolicy(view)
GetIamPolicy.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging views list' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
DETAILED_HELP = {
'DESCRIPTION': """
Lists the views defined on a bucket.
""",
'EXAMPLES': """
To list the views defined on a bucket, run:
$ {command}
""",
}
@base.UniverseCompatible
class List(base.ListCommand):
"""List the defined views."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
util.AddParentArgs(parser, 'views to list')
util.AddBucketLocationArg(
parser, True, 'Location of the specified bucket')
parser.add_argument(
'--bucket', required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of bucket')
parser.display_info.AddFormat(
'table(name.segment(-1):label=VIEW_ID, filter, create_time, '
'update_time)')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Yields:
The list of views.
"""
result = util.GetClient().projects_locations_buckets_views.List(
util.GetMessages().LoggingProjectsLocationsBucketsViewsListRequest(
parent=util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets', args.bucket)))
for view in result.views:
yield view
List.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,97 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 Google Inc. 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.
"""'logging views remove_iam_policy_binding' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.api_lib.util import exceptions as gcloud_exception
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.iam import iam_util
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class RemoveIamPolicyBinding(base.Command):
"""Remove IAM policy binding to a log view."""
detailed_help = {
'EXAMPLES': """\
To remove an IAM policy binding for the role 'roles/my-role' for the user 'my-user@gmail.com' on my-view, run:
$ {command} my-view --member='user:my-user@gmail.com' --role='roles/my-role' --bucket=my-bucket --location=global
To remove a binding with a condition, run:
$ {command} my-view --member='user:my-user@gmail.com' --role='roles/my-role' --bucket=my-bucket --location=global --condition=expression=[expression],title=[title],description=[description]
See https://cloud.google.com/iam/docs/managing-policies for details about IAM policies and member types.
""",
}
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'VIEW_ID', help='ID of the view that contains the IAM policy.'
)
util.AddParentArgs(parser, 'view that contains the IAM policy')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket that contains the view.'
)
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of the bucket that contains the view.',
)
iam_util.AddArgsForRemoveIamPolicyBinding(parser, add_condition=True)
@gcloud_exception.CatchHTTPErrorRaiseHTTPException(
'Status code: {status_code}. {status_message}.'
)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated policy.
"""
view = util.CreateResourceName(
util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets', args.bucket
),
'views',
args.VIEW_ID,
)
policy = util.GetIamPolicy(view)
condition = iam_util.ValidateAndExtractCondition(args)
iam_util.RemoveBindingFromIamPolicyWithCondition(
policy=policy,
member=args.member,
role=args.role,
condition=condition,
)
results = util.SetIamPolicy(view, policy)
iam_util.LogSetIamPolicy(view, 'logging view')
return results

View File

@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""'logging views set_iam_policy' command.
Set the IAM policy for a logging view resource.
This command replaces the existing IAM policy for an logging view resource,
given a file encoded in JSON or YAML that contains the IAM policy.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.iam import iam_util
DETAILED_HELP = {
'DESCRIPTION': """
Set an IAM policy for a view.
""",
'EXAMPLES': """
To set the IAM policy using a json file 'my_policy.json' for the view `my-view` in `my-bucket` in the `global` location, run:
$ {command} my-view /path/to/my_policy.json --bucket=my-bucket --location=global
""",
}
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.GA)
class SetIamPolicy(base.Command):
"""Set IAM policy for a view."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument('VIEW_ID', help='ID of the view to set IAM policy.')
util.AddParentArgs(parser, 'view to set IAM policy')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket that contains the view.'
)
parser.add_argument(
'--bucket',
required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of the bucket that contains the view.',
)
iam_util.AddArgForPolicyFile(parser)
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The IAM policy.
"""
view = util.CreateResourceName(
util.CreateResourceName(
util.GetBucketLocationFromArgs(args), 'buckets', args.bucket
),
'views',
args.VIEW_ID,
)
messages = util.GetMessages()
policy, _ = iam_util.ParseYamlOrJsonPolicyFile(
args.policy_file, messages.Policy
)
results = util.SetIamPolicy(view, policy)
iam_util.LogSetIamPolicy(view, 'logging view')
return results
SetIamPolicy.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""'logging views update' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as calliope_exceptions
DETAILED_HELP = {
'DESCRIPTION': """
Updates the properties of a view.
""",
'EXAMPLES': """
To update a view in your project, run:
$ {command} my-view --bucket=my-bucket --location=global
--description=my-new-description
""",
}
@base.UniverseCompatible
class Update(base.UpdateCommand):
"""Update a view.
Changes one or more properties associated with a view.
"""
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'VIEW_ID', help='Id of the view to update.')
parser.add_argument(
'--description',
help='New description for the view.')
parser.add_argument(
'--log-filter',
help='New filter for the view.')
util.AddParentArgs(parser, 'view to update')
util.AddBucketLocationArg(
parser, True, 'Location of the bucket that contains the view.')
parser.add_argument(
'--bucket', required=True,
type=arg_parsers.RegexpValidator(r'.+', 'must be non-empty'),
help='ID of the bucket that holds the view')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The updated view.
"""
view_data = {}
update_mask = []
parameter_names = ['--log-filter', '--description']
if args.IsSpecified('log_filter'):
view_data['filter'] = args.log_filter
update_mask.append('filter')
if args.IsSpecified('description'):
view_data['description'] = args.description
update_mask.append('description')
if not update_mask:
raise calliope_exceptions.MinimumArgumentException(
parameter_names,
'Please specify at least one property to update')
return util.GetClient().projects_locations_buckets_views.Patch(
util.GetMessages().LoggingProjectsLocationsBucketsViewsPatchRequest(
name=util.CreateResourceName(util.CreateResourceName(
util.CreateResourceName(
util.GetProjectResource(args.project).RelativeName(),
'locations',
args.location),
'buckets', args.bucket), 'views', args.VIEW_ID),
logView=util.GetMessages().LogView(**view_data),
updateMask=','.join(update_mask)))
Update.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,146 @@
# -*- coding: utf-8 -*- #
# Copyright 2014 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.
"""'logging write' command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import encoding
from googlecloudsdk.api_lib.logging import util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.core import log
@base.UniverseCompatible
class Write(base.SilentCommand):
"""Write a log entry."""
SEVERITY_ENUM = ('DEFAULT', 'DEBUG', 'INFO', 'NOTICE', 'WARNING',
'ERROR', 'CRITICAL', 'ALERT', 'EMERGENCY')
PAYLOAD_TYPE = ('text', 'json')
@staticmethod
def Args(parser):
"""Register flags for this command."""
parser.add_argument(
'log_name', help=('Name of the log where the log entry will '
'be written.'))
parser.add_argument(
'message', help=('Message to put in the log entry. It can be '
'JSON if you include `--payload-type=json`.'))
parser.add_argument(
'--payload-type',
choices=Write.PAYLOAD_TYPE, default='text',
help=('Type of the log entry payload.'))
parser.add_argument(
'--severity', required=False,
choices=Write.SEVERITY_ENUM, default='DEFAULT',
help='Severity level of the log entry.')
parser.add_argument(
'--monitored-resource-type',
default='global',
help='Monitored Resource type to add to the payload',
)
parser.add_argument(
'--monitored-resource-labels',
type=arg_parsers.ArgDict(),
metavar='KEY=VALUE, ...',
default={},
help='Monitored Resource labels to add to the payload',
)
util.AddParentArgs(parser, 'log entries to write')
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
"""
messages = util.GetMessages()
severity_value = getattr(messages.LogEntry.SeverityValueValuesEnum,
args.severity.upper())
monitored_resource = messages.MonitoredResource(
type=args.monitored_resource_type
)
if args.monitored_resource_labels:
monitored_resource.labels = encoding.PyValueToMessage(
messages.MonitoredResource.LabelsValue, args.monitored_resource_labels
)
entry = messages.LogEntry(
logName=util.CreateLogResourceName(
util.GetParentFromArgs(args), args.log_name
),
resource=monitored_resource,
severity=severity_value,
)
if args.payload_type == 'json':
json_object = util.ConvertToJsonObject(args.message)
struct = messages.LogEntry.JsonPayloadValue()
# Protobufs in Python do strict type-checking. We have to change the
# type from JsonObject.Property to JsonPayloadValue.AdditionalProperty
# even though both types have the same fields (key, value).
struct.additionalProperties = [
messages.LogEntry.JsonPayloadValue.AdditionalProperty(
key=json_property.key,
value=json_property.value)
for json_property in json_object.properties
]
entry.jsonPayload = struct
else:
entry.textPayload = args.message
util.GetClient().entries.Write(
messages.WriteLogEntriesRequest(entries=[entry]))
log.status.write('Created log entry.\n')
Write.detailed_help = {
'DESCRIPTION': """\
{index}
If the destination log does not exist, it will be created.
By default, all log entries written with this command are written with
the "global" resource type.
{command} should be used for simple testing purposes.
Check Cloud Logging agent for a proper way to send log entries:
[](https://cloud.google.com/logging/docs/agent/)
""",
'EXAMPLES': """\
To create a log entry in a given log, run:
$ {command} LOG_NAME "A simple entry"
To create a high severity log entry, run:
$ {command} LOG_NAME "Urgent message" --severity=ALERT
To create a structured log, run:
$ {command} LOG_NAME '{"key": "value"}' --payload-type=json
To create a log entry with a custom resource type, run:
$ {command} LOG_NAME "A simple entry" --monitored-resource-type=gce_instance --monitored-resource-labels=zone=us-centra1-a,instance_id=1234
""",
}