# -*- 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. """Shared resource flags for Cloud Monitoring commands.""" from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals from googlecloudsdk.calliope import arg_parsers from googlecloudsdk.calliope import base from googlecloudsdk.calliope import exceptions from googlecloudsdk.command_lib.monitoring import completers from googlecloudsdk.command_lib.util.args import labels_util from googlecloudsdk.command_lib.util.args import repeated from googlecloudsdk.core.util import times COMPARISON_TO_ENUM = { '>': 'COMPARISON_GT', '<': 'COMPARISON_LT', '>=': 'COMPARISON_GE', '<=': 'COMPARISON_LE', '==': 'COMPARISON_EQ', '=': 'COMPARISON_EQ', '!=': 'COMPARISON_NE', } UPTIME_MONITORED_RESOURCES = { 'uptime-url': 'Uptime check against a URL.', 'gce-instance': 'Uptime check against a Compute Engine instance.', 'gae-app': 'Uptime check against an App Engine module.', 'aws-ec2-instance': 'Uptime check against an AWS EC2 instance.', 'aws-elb-load-balancer': 'Uptime check against an ElasticLoadBalancer.', 'servicedirectory-service': ( 'Uptime check against a Service Directory service.' ), 'cloud-run-revision': 'Uptime check against a Cloud Run revision.', } UPTIME_GROUP_RESOURCES = { 'gce-instance': ( 'Uptime check against a group of instances from Google Cloud' ' or Amazon Web Services.' ), 'aws-elb-load-balancer': ( 'Uptime check against a group of Amazon ELB load balancers.' ), } UPTIME_PROTOCOLS = { 'http': 'An HTTP check.', 'https': 'An HTTPS check.', 'tcp': 'A TCP check.', } UPTIME_REQUEST_METHODS = { 'get': 'HTTP GET method', 'post': 'HTTP POST method', } UPTIME_CONTENT_TYPES = { 'unspecified': 'Not specified', 'url-encoded': 'URL encoded', 'user-provided': 'User provided', } UPTIME_STATUS_CLASSES = { '1xx': 'Any response code from 100-199 inclusive', '2xx': 'Any response code from 200-299 inclusive', '3xx': 'Any response code from 300-399 inclusive', '4xx': 'Any response code from 400-499 inclusive', '5xx': 'Any response code from 500-599 inclusive', 'any': 'Any response code', } UPTIME_PERIODS = { '1': 'One minute', '5': 'Five minutes', '10': 'Ten minutes', '15': 'Fifteen minutes', } UPTIME_REGIONS = { 'usa-oregon': 'us-west1', 'usa-virginia': 'us-east4', 'usa-iowa': 'us-central1', 'europe': 'europe-west1', 'south-america': 'southamerica-east1', 'asia-pacific': 'asia-southeast1', } UPTIME_MATCHER_TYPES = { 'contains-string': 'Response contains string', 'not-contains-string': 'Response does not contain string', 'matches-regex': 'Response matches regex', 'not-matches-regex': 'Response does not match regex', 'matches-json-path': 'Response matches at JSONPath', 'not-matches-json-path': 'Response does not match at JSONPath', } UPTIME_JSON_MATCHER_TYPES = { 'exact-match': 'Response matches exact string at JSONPath', 'regex-match': 'Response matches regex at JSONPath', } UPTIME_SERVICE_AGENT_TYPES = { 'oidc-token': 'OIDC Token authentication', } def AddFileMessageFlag(parser, resource, flag=None): """Adds flags for specifying a message as a file to the parser.""" parser.add_argument( '--{}-from-file'.format(flag or resource), type=arg_parsers.FileContents(), help='The path to a JSON or YAML file containing the {}.'.format( resource)) def AddMessageFlags(parser, resource, flag=None): """Adds flags for specifying a message as a string/file to the parser.""" message_group = parser.add_group(mutex=True) message_group.add_argument( '--{}'.format(flag or resource), help='The {} as a string. In either JSON or YAML format.'.format( resource)) message_group.add_argument( '--{}-from-file'.format(flag or resource), type=arg_parsers.FileContents(), help='The path to a JSON or YAML file containing the {}.'.format( resource)) def AddDisplayNameFlag(parser, resource, positional=False): if positional: base.Argument( 'display_name', metavar='DISPLAY_NAME', help='Display name for the uptime check or synthetic monitor.', ).AddToParser(parser) else: parser.add_argument( '--display-name', help='The display name for the {}.'.format(resource) ) def AddCombinerFlag(parser, resource): """Adds flags for specifying a combiner, which defines how to combine the results of multiple conditions.""" parser.add_argument( '--combiner', choices={ 'COMBINE_UNSPECIFIED': 'An unspecified combiner', 'AND': 'An incident is created only if ' 'all conditions are met simultaneously. ' 'This combiner is satisfied if all conditions are met, ' 'even if they are met on completely different resources.', 'OR': 'An incident is created if ' 'any of the listed conditions is met.', 'AND_WITH_MATCHING_RESOURCE': 'Combine conditions using ' 'logical AND operator, ' 'but unlike the regular AND option, ' 'an incident is created ' 'only if all conditions ' 'are met simultaneously ' 'on at least one resource.', }, help='The combiner for the {}.'.format(resource)) def AddPolicySettingsFlags(parser, update=False): """Adds policy settings flags to the parser.""" policy_settings_group = parser.add_group(help="""\ Policy Settings. If any of these are specified, they will overwrite fields in the `--policy` or `--policy-from-file` flags if specified.""") AddDisplayNameFlag(policy_settings_group, resource='Alert Policy') AddCombinerFlag(policy_settings_group, resource='Alert Policy') enabled_kwargs = { 'action': arg_parsers.StoreTrueFalseAction if update else 'store_true' } if not update: # Can't specify default if using StoreTrueFalseAction. enabled_kwargs['default'] = True policy_settings_group.add_argument( '--enabled', help='If the policy is enabled.', **enabled_kwargs) documentation_group = policy_settings_group.add_group(help='Documentation') documentation_group.add_argument( '--documentation-format', default='text/markdown' if not update else None, help='The MIME type that should be used with `--documentation` or ' '`--documentation-from-file`. Currently, only "text/markdown" is ' 'supported.') documentation_string_group = documentation_group.add_group(mutex=True) documentation_string_group.add_argument( '--documentation', help='The documentation to be included with the policy.') documentation_string_group.add_argument( '--documentation-from-file', type=arg_parsers.FileContents(), help='The path to a file containing the documentation to be included ' 'with the policy.') if update: repeated.AddPrimitiveArgs( policy_settings_group, 'Alert Policy', 'notification-channels', 'Notification Channels') AddUpdateLabelsFlags( 'user-labels', policy_settings_group, group_text='User Labels') else: AddCreateLabelsFlag(policy_settings_group, 'user-labels', 'policy') def AddFieldsFlagsWithMutuallyExclusiveSettings(parser, fields_help, add_settings_func, fields_choices=None, **kwargs): """Adds fields flags with mutually excludisve settings.""" update_group = parser.add_group(mutex=True) update_group.add_argument( '--fields', metavar='field', type=arg_parsers.ArgList(choices=fields_choices), help=fields_help) add_settings_func(update_group, **kwargs) def ValidateAlertPolicyUpdateArgs(args): """Validate alert policy update args.""" if args.fields and not (args.policy or args.policy_from_file): raise exceptions.OneOfArgumentsRequiredException( ['--policy', '--policy-from-file'], 'If --fields is specified.') def ComparisonValidator(if_value): """Validates and returns the comparator and value.""" if if_value.lower() == 'absent': return (None, None) if len(if_value) < 2: raise exceptions.BadArgumentException('--if', 'Invalid value for flag.') comparator_part = if_value[0] threshold_part = if_value[1:] try: comparator = COMPARISON_TO_ENUM[comparator_part] threshold_value = float(threshold_part) # currently only < and > are supported if comparator not in ['COMPARISON_LT', 'COMPARISON_GT']: raise exceptions.BadArgumentException('--if', 'Comparator must be < or >.') return comparator, threshold_value except KeyError: raise exceptions.BadArgumentException('--if', 'Comparator must be < or >.') except ValueError: raise exceptions.BadArgumentException('--if', 'Threshold not a value float.') def AddConditionSettingsFlags(parser): """Adds policy condition flags to the parser.""" condition_group = parser.add_group(help="""\ Condition Settings. This will add a condition to the created policy. If any conditions are already specified, this condition will be appended.""") condition_group.add_argument( '--condition-display-name', help='The display name for the condition.') condition_group.add_argument( '--condition-filter', help='Specifies the "filter" in a metric absence or metric threshold ' 'condition.') condition_group.add_argument( '--aggregation', help='Specifies an Aggregation message as a JSON/YAML value to be ' 'applied to the condition. For more information about the format: ' 'https://cloud.google.com/monitoring/api/ref_v3/rest/v3/' 'projects.alertPolicies') condition_group.add_argument( '--duration', type=arg_parsers.Duration(), help='The duration (e.g. "60s", "2min", etc.) that the condition ' 'must hold in order to trigger as true.') AddUpdateableConditionFlags(condition_group) def AddUpdateableConditionFlags(parser): """Adds flags for condition settings that are updateable to the parser.""" parser.add_argument( '--if', dest='if_value', # To avoid specifying args.if. type=ComparisonValidator, help='One of "absent", "< THRESHOLD", "> THRESHOLD" where "THRESHOLD" is ' 'an integer or float.') trigger_group = parser.add_group(mutex=True) trigger_group.add_argument( '--trigger-count', type=int, help='The absolute number of time series that must fail the predicate ' 'for the condition to be triggered.') trigger_group.add_argument( '--trigger-percent', type=float, help='The percentage of time series that must fail the predicate for ' 'the condition to be triggered.') def ValidateNotificationChannelUpdateArgs(args): """Validate notification channel update args.""" if (args.fields and not (args.channel_content or args.channel_content_from_file)): raise exceptions.OneOfArgumentsRequiredException( ['--channel-content', '--channel-content-from-file'], 'If --fields is specified.') def AddNotificationChannelSettingFlags(parser, update=False): """Adds flags for channel settings to the parser.""" channel_group = parser.add_group(help='Notification channel settings') AddDisplayNameFlag(channel_group, 'channel') channel_group.add_argument( '--description', help='An optional description for the channel.') channel_group.add_argument( '--type', help='The type of the notification channel. This field matches the ' 'value of the NotificationChannelDescriptor type field.') enabled_kwargs = { 'action': arg_parsers.StoreTrueFalseAction if update else 'store_true' } if not update: # Can't specify default if using StoreTrueFalseAction. enabled_kwargs['default'] = True channel_group.add_argument( '--enabled', help='Whether notifications are forwarded to the described channel.', **enabled_kwargs) if update: AddUpdateLabelsFlags( 'user-labels', channel_group, group_text='User Labels') AddUpdateLabelsFlags( 'channel-labels', channel_group, validate_values=False, group_text='Configuration Fields: Key-Value pairs that define the ' 'channel and its behavior.') else: AddCreateLabelsFlag(channel_group, 'user-labels', 'channel') AddCreateLabelsFlag( channel_group, 'channel-labels', 'channel', validate_values=False, extra_message='These are configuration fields that define the channel ' 'and its behavior.') def AddCreateLabelsFlag(parser, labels_name, resource_name, extra_message='', validate_values=True, skip_extra_message=False): """Add create labels flags.""" if not skip_extra_message: extra_message += ('If the {0} was given as a JSON/YAML object from a ' 'string or file, this flag will replace the labels value ' 'in the given {0}.'.format(resource_name)) labels_util.GetCreateLabelsFlag( extra_message=extra_message, labels_name=labels_name, validate_values=validate_values).AddToParser(parser) def AddUpdateLabelsFlags(labels_name, parser, group_text='', validate_values=True): """Add update labels flags.""" labels_group = parser.add_group(group_text) labels_util.GetUpdateLabelsFlag( '', labels_name=labels_name, validate_values=validate_values).AddToParser(labels_group) remove_group = labels_group.add_group(mutex=True) labels_util.GetRemoveLabelsFlag( '', labels_name=labels_name).AddToParser(remove_group) labels_util.GetClearLabelsFlag( labels_name=labels_name).AddToParser(remove_group) def GetMonitoredResourceContainerNameFlag(verb): """Flag for managing a monitored resource container.""" return base.Argument( 'monitored_resource_container_name', metavar='MONITORED_RESOURCE_CONTAINER_NAME', completer=completers.MonitoredResourceContainerCompleter, help=( 'Monitored resource container (example - projects/PROJECT_ID) project' ' you want to {0}.'.format(verb) ), ) def AddCriteriaPoliciesFlag(parser, resource): parser.add_argument( '--criteria-policies', metavar='CRITERIA_POLICIES', type=arg_parsers.ArgList(min_length=1, max_length=16), help=( 'The policies that the {} applies to. Exactly 1 alert policy is' ' required if `criteria-filter` is specified at the same time.' .format(resource) ), ) def AddCriteriaFilterFlag(parser, resource): parser.add_argument( '--criteria-filter', metavar='CRITERIA_FILTER', type=str, help=( 'Optional. When you define a {}, you can also define a filter for' ' that snooze. The filter is a string containing one or more' ' key-value pairs. The string uses the standard' ' https://google.aip.dev/160 filter syntax. If you define a filter' ' for a snooze, then the snooze can only apply to one alert policy.' " When the snooze is active, incidents won't be created when the" ' incident would have key-value pairs (labels) that match those' ' specified by the filter in the snooze. Snooze filters support' ' resource, metric, and metadata labels. If multiple labels are used,' ' then they must be connected with an AND operator. For example:' ' resource.labels.instance_id="1234567890" AND' ' resource.labels.zone="us-central1-a" AND' ' metric.labels.instance_name="test_group" AND' ' metadata.user_labels.foo="bar" AND' ' metadata.system_labels.region="us-central1"'.format(resource) ), ) def AddStartTimeFlag(parser, resource): parser.add_argument( '--start-time', type=arg_parsers.Datetime.Parse, help='The start time for the {}.'.format(resource)) def AddEndTimeFlag(parser, resource): parser.add_argument( '--end-time', type=arg_parsers.Datetime.Parse, help='The end time for the {}.'.format(resource)) def AddSnoozeSettingsFlags(parser, update=False): """Adds snooze settings flags to the parser.""" snooze_settings_group = parser.add_group(help="""\ Snooze Settings. If any of these are specified, they will overwrite fields in the `--snooze-from-file` flags if specified.""") AddDisplayNameFlag(snooze_settings_group, resource='Snooze') if not update: AddCriteriaPoliciesFlag(snooze_settings_group, resource='Snooze') AddCriteriaFilterFlag(snooze_settings_group, resource='Snooze') AddStartTimeFlag(snooze_settings_group, resource='Snooze') AddEndTimeFlag(snooze_settings_group, resource='Snooze') def AddUptimeSettingsFlags(parser, update=False): """Adds uptime check settings flags to the parser.""" if not update: AddUptimeResourceFlags(parser) AddUptimeProtocolFlags(parser, update) AddUptimeRunFlags(parser, update) AddUptimeMatcherFlags(parser) def AddUptimeResourceFlags(parser): """Adds uptime check resource settings flags to the parser.""" uptime_resource_group = parser.add_group( help='Uptime check resource.', mutex=True, required=True, ) monitored_resource_group = uptime_resource_group.add_group( help='Monitored resource' ) monitored_resource_group.add_argument( '--resource-type', help='Type of monitored resource, defaults to `uptime-url`.', choices=UPTIME_MONITORED_RESOURCES, ) base.Argument( '--resource-labels', metavar='KEY=VALUE', type=arg_parsers.ArgDict(key_type=str, value_type=str), action=arg_parsers.UpdateAction, required=True, help=( """Values for all of the labels listed in the associated monitored resource descriptor. See https://cloud.google.com/monitoring/api/resources for more information and allowed keys.""" ), ).AddToParser(monitored_resource_group) group_resource_group = uptime_resource_group.add_group( help='Monitored resource group' ) group_resource_group.add_argument( '--group-type', help=( 'The resource type of the group members, defaults to `gce-instance`.' ), choices=UPTIME_GROUP_RESOURCES, ) group_resource_group.add_argument( '--group-id', help='The group of resources being monitored.', required=True, type=str, ) uptime_resource_group.add_argument( '--synthetic-target', help="""The target of the Synthetic Monitor. This is the fully qualified GCFv2 resource name. """, type=str, ) def AddUptimeProtocolFlags(parser, update=False): """Adds uptime check protocol settings flags to the parser.""" uptime_protocol_group = parser.add_group( help='Uptime check protocol settings.' ) if not update: uptime_protocol_group.add_argument( '--protocol', help='The protocol of the request, defaults to `http`.', choices=UPTIME_PROTOCOLS, ) uptime_protocol_group.add_argument( '--port', help="""The port on the server against which to run the check. Defaults to `80` when `--protocol` is `http`. Defaults to `443` when `--protocol` is `https`. Required if `--protocol` is `tcp`.""", type=arg_parsers.BoundedInt(lower_bound=1, upper_bound=65535), ) uptime_protocol_group.add_argument( '--pings-count', help='Number of ICMP pings to send alongside the request.', type=arg_parsers.BoundedInt(lower_bound=1, upper_bound=3), ) uptime_protocol_group.add_argument( '--request-method', help="""The HTTP request method to use, defaults to `get`. Can only be set if `--protocol` is `http` or `https`.""", choices=UPTIME_REQUEST_METHODS, ) uptime_protocol_group.add_argument( '--path', help="""The path to the page against which to run the check, defaults to `/`. Can only be set if `--protocol` is `http` or `https`.""", type=str, ) uptime_protocol_group.add_argument( '--username', help="""The username to use when authenticating with the HTTP server. Can only be set if `--protocol` is `http` or `https`.""", type=str, ) uptime_protocol_group.add_argument( '--password', help="""The password to use when authenticating with the HTTP server. Can only be set if `--protocol` is `http` or `https`.""", type=str, ) uptime_protocol_group.add_argument( '--mask-headers', help="""Whether to encrypt the header information, defaults to `false`. Can only be set if `--protocol` is `http` or `https`.""", type=bool, ) uptime_service_agent_auth_group = uptime_protocol_group.add_group( help='Uptime check service agent authorization.' ) uptime_service_agent_auth_group.add_argument( '--service-agent-auth', help="""The type of authentication to use for the HTTP request. Can only be set if `--protocol` is `https`.""", choices=UPTIME_SERVICE_AGENT_TYPES) if update: uptime_headers_group = uptime_protocol_group.add_group( help='Uptime check headers.' ) base.Argument( '--update-headers', metavar='KEY=VALUE', type=arg_parsers.ArgDict(key_type=str, value_type=str), action=arg_parsers.UpdateAction, help=("""The list of headers to add to the uptime check. Any existing headers with matching "key" are overridden by the provided values."""), ).AddToParser(uptime_headers_group) uptime_remove_header_group = uptime_headers_group.add_group( help='Uptime check remove headers.', mutex=True, ) uptime_remove_header_group.add_argument( '--remove-headers', metavar='KEY', help="""The list of header keys to remove from the uptime check.""", type=arg_parsers.ArgList(str), ) uptime_remove_header_group.add_argument( '--clear-headers', help="""Clear all headers on the uptime check.""", type=bool, ) else: base.Argument( '--headers', metavar='KEY=VALUE', type=arg_parsers.ArgDict(key_type=str, value_type=str), action=arg_parsers.UpdateAction, help=( """The list of headers to send as part of the uptime check request. Can only be set if `--protocol` is `http` or `https`.""" ), ).AddToParser(uptime_protocol_group) uptime_protocol_group.add_argument( '--content-type', help="""The content type header to use for the check, defaults to `unspecified`. Can only be set if `--protocol` is `http` or `https`.""", choices=UPTIME_CONTENT_TYPES, ) uptime_protocol_group.add_argument( '--custom-content-type', help="""A user-provided content type header to use for the check. Can only be set if `--protocol` is `http` or `https`.""", type=str, ) uptime_protocol_group.add_argument( '--validate-ssl', help="""Whether to include SSL certificate validation as a part of the uptime check, defaults to `false`. Can only be set if `--protocol` is `http` or `https`.""", type=bool, ) uptime_protocol_group.add_argument( '--body', help="""The request body associated with the HTTP POST request. Can only be set if `--protocol` is `http` or `https`.""", type=str, ) uptime_status_group = uptime_protocol_group.add_group( help='Uptime check status.', mutex=True, ) if update: uptime_status_classes_group = uptime_status_group.add_group( help='Uptime check status classes.', mutex=True, ) uptime_status_classes_group.add_argument( '--set-status-classes', metavar='status-class', help="""List of HTTP status classes. The uptime check will only pass if the response code is contained in this list.""", type=arg_parsers.ArgList(choices=UPTIME_STATUS_CLASSES), ) uptime_status_classes_group.add_argument( '--add-status-classes', metavar='status-class', help="""The list of HTTP status classes to add to the uptime check.""", type=arg_parsers.ArgList(choices=UPTIME_STATUS_CLASSES), ) uptime_status_classes_group.add_argument( '--remove-status-classes', metavar='status-class', help="""The list of HTTP status classes to remove from the uptime check.""", type=arg_parsers.ArgList(choices=UPTIME_STATUS_CLASSES), ) uptime_status_classes_group.add_argument( '--clear-status-classes', help="""Clear all HTTP status classes on the uptime check. Setting this flag is the same as selecting only the `2xx` status class.""", type=bool, ) uptime_status_codes_group = uptime_status_group.add_group( help='Uptime check status codes.', mutex=True, ) uptime_status_codes_group.add_argument( '--set-status-codes', metavar='status-code', help="""List of HTTP status codes. The uptime check will only pass if the response code is present in this list.""", type=arg_parsers.ArgList(int), ) uptime_status_codes_group.add_argument( '--add-status-codes', metavar='status-code', help="""The list of HTTP status codes to add to the uptime check.""", type=arg_parsers.ArgList(int), ) uptime_status_codes_group.add_argument( '--remove-status-codes', metavar='status-code', help="""The list of HTTP status codes to remove from the uptime check.""", type=arg_parsers.ArgList(int), ) uptime_status_codes_group.add_argument( '--clear-status-codes', help="""Clear all HTTP status codes on the uptime check. Setting this flag is the same as selecting only the `2xx` status class.""", type=bool, ) else: uptime_status_group.add_argument( '--status-classes', metavar='status-class', help="""List of HTTP status classes. The uptime check only passes when the response code is contained in this list. Defaults to `2xx`. Can only be set if `--protocol` is `http` or `https`.""", type=arg_parsers.ArgList(choices=UPTIME_STATUS_CLASSES), ) uptime_status_group.add_argument( '--status-codes', metavar='status-code', help="""List of HTTP Status Codes. The uptime check will only pass if the response code is present in this list. Can only be set if `--protocol` is `http` or `https`.""", type=arg_parsers.ArgList(int), ) def AddUptimeRunFlags(parser, update=False): """Adds uptime check run flags to the parser.""" uptime_settings_group = parser.add_group(help='Settings.') uptime_settings_group.add_argument( '--period', help='''The time between uptime check or synthetic monitor executions in minutes, defaults to `1`. Can be set for synthetic monitors.''', choices=UPTIME_PERIODS, ) uptime_settings_group.add_argument( '--timeout', help=( 'The maximum amount of time in seconds to wait for the request to' ' complete, defaults to `60`. Can be set for synthetic monitors.' ), type=arg_parsers.BoundedInt(lower_bound=1, upper_bound=60), ) if update: AddDisplayNameFlag( uptime_settings_group, resource='uptime check or synthetic monitor', positional=False, ) uptime_regions_group = uptime_settings_group.add_group( help="""Uptime check selected regions.""", mutex=True, ) uptime_regions_group.add_argument( '--set-regions', metavar='region', help="""The list of regions from which the check is run. At least 3 regions must be selected.""", type=arg_parsers.ArgList(choices=UPTIME_REGIONS), ) uptime_regions_group.add_argument( '--add-regions', metavar='region', help="""The list of regions to add to the uptime check.""", type=arg_parsers.ArgList(choices=UPTIME_REGIONS), ) uptime_regions_group.add_argument( '--remove-regions', metavar='region', help="""The list of regions to remove from the uptime check.""", type=arg_parsers.ArgList(choices=UPTIME_REGIONS), ) uptime_regions_group.add_argument( '--clear-regions', help="""Clear all regions on the uptime check. This setting acts the same as if all available regions were selected.""", type=bool, ) else: uptime_settings_group.add_argument( '--regions', metavar='field', help="""The list of regions from which the check is run. At least 3 regions must be selected. Defaults to all available regions.""", type=arg_parsers.ArgList(choices=UPTIME_REGIONS), ) if update: AddUpdateLabelsFlags( 'user-labels', uptime_settings_group, 'User labels. Can be set for synthetic monitors.', ) else: AddCreateLabelsFlag( uptime_settings_group, 'user-labels', 'User labels. Can be set for synthetic monitors.', skip_extra_message=True, ) def AddUptimeMatcherFlags(parser): """Adds uptime check matcher flags to the parser.""" uptime_matcher_group = parser.add_group(help='Uptime check matcher settings.') uptime_matcher_group.add_argument( '--matcher-content', required=True, type=str, help='String, regex or JSON content to match.', ) uptime_matcher_group.add_argument( '--matcher-type', choices=UPTIME_MATCHER_TYPES, help="""The type of content matcher that is applied to the server output, defaults to `contains-string`.""", ) uptime_json_matcher_group = uptime_matcher_group.add_group( help='Uptime check matcher settings for JSON responses.' ) uptime_json_matcher_group.add_argument( '--json-path', type=str, required=True, help="""JSONPath within the response output pointing to the expected content to match. Only used if `--matcher-type` is `matches-json-path` or `not-matches-json-path`.""", ) uptime_json_matcher_group.add_argument( '--json-path-matcher-type', choices=UPTIME_JSON_MATCHER_TYPES, help="""The type of JSONPath match that is applied to the JSON output, defaults to `exact-match`. Only used if `--matcher-type` is `matches-json-path` or `not-matches-json-path`.""", ) def ValidateSnoozeUpdateArgs(args): """Validate snooze update args.""" if args.fields and not args.snooze_from_file: raise exceptions.OneOfArgumentsRequiredException( ['--snooze-from-file'], 'If --fields is specified.' ) def ValidateSnoozeInterval( snooze, display_name=None, start_time=None, end_time=None, ): """Validate snooze reference interval.""" snooze_past = False end_time_ref = times.ParseDateTime(snooze.interval.endTime) if end_time_ref < times.Now(): snooze_past = True if snooze_past: if display_name is not None: raise exceptions.InvalidArgumentException( '--display-name', 'Expired snoozes can no longer be updated.', ) elif start_time is not None: raise exceptions.InvalidArgumentException( '--start-time', 'Expired snoozes can no longer be updated.', ) elif end_time is not None: raise exceptions.InvalidArgumentException( '--end-time', 'Expired snoozes can no longer be updated.', ) def AddMigrateFlags(parser): """Adds migrate flags to the parser.""" migrate_group = parser.add_group() migrate_group.add_argument( '--policies-from-prometheus-alert-rules-yaml', metavar='PROMETHEUS_ALERT_RULE_FILE_PATHS', type=arg_parsers.ArgList(arg_parsers.FileContents()), help=( 'One or more Prometheus alert rule YAML files (separated by commas if' ' multiple) to be converted to Cloud Alerting Policies. Example: ' '--policies-from-prometheus-alert-rules-yaml=rules_1.yaml,rules_2.yaml' ), ) migrate_group.add_argument( '--channels-from-prometheus-alertmanager-yaml', metavar='PROMETHEUS_ALERT_MANAGER_FILE_PATH', type=arg_parsers.FileContents(), help=( 'Prometheus alert manager YAML file to be converted to Cloud' ' Monitoring notification channels. Specifying this flag with the' ' --policies-from-prometheus-alert-rules-yaml flag puts the newly' " created notification channels into the translated Alert Policies'" ' definition.' ), )