HEX
Server: Apache/2.4.65 (Ubuntu)
System: Linux ielts-store-v2 6.8.0-1036-gcp #38~22.04.1-Ubuntu SMP Thu Aug 14 01:19:18 UTC 2025 x86_64
User: root (0)
PHP: 7.2.34-54+ubuntu20.04.1+deb.sury.org+1
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,
Upload Files
File: //snap/google-cloud-cli/current/lib/googlecloudsdk/api_lib/compute/health_checks_utils.py
# -*- 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.
"""Code that's shared between multiple health-checks subcommands."""

from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

import copy
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import exceptions as calliope_exceptions
from googlecloudsdk.command_lib.compute.health_checks import exceptions as hc_exceptions


THRESHOLD_UPPER_BOUND = 10
THRESHOLD_LOWER_BOUND = 1
TIMEOUT_UPPER_BOUND_SEC = 300
TIMEOUT_LOWER_BOUND_SEC = 1
CHECK_INTERVAL_UPPER_BOUND_SEC = 300
CHECK_INTERVAL_LOWER_BOUND_SEC = 1


def AddProtocolAgnosticCreationArgs(parser, protocol_string):
  """Adds parser arguments common to creation for all protocols."""

  parser.add_argument(
      '--check-interval',
      type=arg_parsers.Duration(),
      default='5s',
      help="""\
      How often to perform a health check for an instance. For example,
      specifying ``10s'' will run the check every 10 seconds. The default
      value is ``5s''.
      See $ gcloud topic datetimes for information on duration formats.
       """)

  parser.add_argument(
      '--timeout',
      type=arg_parsers.Duration(),
      default='5s',
      help="""\
      If Google Compute Engine doesn't receive a healthy response from the
      instance by the time specified by the value of this flag, the health
      check request is considered a failure. For example, specifying ``10s''
      will cause the check to wait for 10 seconds before considering the
      request a failure. The default value is ``5s''.
      See $ gcloud topic datetimes for information on duration formats.
      """)

  parser.add_argument(
      '--unhealthy-threshold',
      type=int,
      default=2,
      help="""\
      The number of consecutive health check failures before a healthy
      instance is marked as unhealthy. The default is 2.
      """)

  parser.add_argument(
      '--healthy-threshold',
      type=int,
      default=2,
      help="""\
      The number of consecutive successful health checks before an
      unhealthy instance is marked as healthy. The default is 2.
      """)

  parser.add_argument(
      '--description',
      help="""\
      An optional string description for the """ + protocol_string + """ health
      check.
      """)


def AddProtocolAgnosticUpdateArgs(parser, protocol_string):
  """Adds parser arguments common to update subcommand for all protocols."""

  parser.add_argument(
      '--check-interval',
      type=arg_parsers.Duration(),
      help="""\
      How often to perform a health check for an instance. For example,
      specifying ``10s'' will run the check every 10 seconds.
      See $ gcloud topic datetimes for information on duration formats.
      """)

  parser.add_argument(
      '--timeout',
      type=arg_parsers.Duration(),
      help="""\
      If Google Compute Engine doesn't receive a healthy response from the
      instance by the time specified by the value of this flag, the health
      check request is considered a failure. For example, specifying ``10s''
      will cause the check to wait for 10 seconds before considering the
      request a failure.
      See $ gcloud topic datetimes for information on duration formats.
      """)

  parser.add_argument(
      '--unhealthy-threshold',
      type=int,
      help="""\
      The number of consecutive health check failures before a healthy
      instance is marked as unhealthy.
      """)

  parser.add_argument(
      '--healthy-threshold',
      type=int,
      help="""\
      The number of consecutive successful health checks before an
      unhealthy instance is marked as healthy.
      """)

  parser.add_argument(
      '--description',
      help=('A textual description for the ' + protocol_string +
            ' health check. Pass in an empty string to unset.'))


def AddHttpRelatedCreationArgs(parser, include_weighted_load_balancing=False):
  """Adds parser arguments for creation related to HTTP."""

  _AddPortRelatedCreationArgs(parser)
  AddProxyHeaderRelatedCreateArgs(parser)

  parser.add_argument(
      '--host',
      help="""\
      The value of the host header used for the health check. If unspecified,
      Google Cloud sets the host header to the IP address of the load balancer's
      forwarding rule.
      """)

  parser.add_argument(
      '--request-path',
      default='/',
      help="""\
      The request path that this health check monitors. For example,
      ``/healthcheck''. The default value is ``/''.
      """)

  if include_weighted_load_balancing:
    parser.add_argument(
        '--weight-report-mode',
        choices=['ENABLE', 'DISABLE', 'DRY_RUN'],
        help="""\
        Defines whether Weighted Load Balancing is enabled.
        """)


def AddHttpRelatedResponseArg(parser):
  """Adds parser argument for HTTP response field."""

  parser.add_argument(
      '--response',
      help="""\
      When empty, status code of the response determines health. When not empty,
      presence of specified string in first 1024 characters of response body
      determines health. Only ASCII characters allowed.
      """)


def AddHttpRelatedUpdateArgs(parser, include_weighted_load_balancing=False):
  """Adds parser arguments for update subcommands related to HTTP."""

  _AddPortRelatedUpdateArgs(parser)
  AddProxyHeaderRelatedUpdateArgs(parser)

  parser.add_argument(
      '--host',
      help="""\
      The value of the host header used in this HTTP health check request.
      The host header is empty by default. When empty, the health check will set
      the host header to the IP address of the backend VM or endpoint. You can
      set the host header to an empty value to return to this default behavior.
      """)

  parser.add_argument(
      '--request-path',
      help="""\
      The request path that this health check monitors. For example,
      ``/healthcheck''.
      """)

  if include_weighted_load_balancing:
    parser.add_argument(
        '--weight-report-mode',
        choices=['ENABLE', 'DISABLE', 'DRY_RUN'],
        help="""\
        Defines whether Weighted Load Balancing is enabled.
        """)


def AddTcpRelatedCreationArgs(parser):
  """Adds parser arguments for creation related to TCP."""

  _AddPortRelatedCreationArgs(parser)
  AddProxyHeaderRelatedCreateArgs(parser)
  _AddTcpRelatedArgsImpl(add_info_about_clearing=False, parser=parser)


def AddTcpRelatedUpdateArgs(parser):
  """Adds parser arguments for update subcommands related to TCP."""

  _AddPortRelatedUpdateArgs(parser)
  AddProxyHeaderRelatedUpdateArgs(parser)
  _AddTcpRelatedArgsImpl(add_info_about_clearing=True, parser=parser)


def AddGrpcRelatedCreationArgs(parser):
  """Adds parser arguments for creation related to gRPC."""

  _AddPortRelatedCreationArgs(
      parser,
      use_port_name=False,
      use_serving_port=True,
      port_type='TCP',
      default_port=None)

  parser.add_argument(
      '--grpc-service-name',
      help="""\
      An optional gRPC service name string of up to 1024 characters to include
      in the gRPC health check request. Only ASCII characters are allowed.""")


def AddGrpcRelatedUpdateArgs(parser):
  """Adds parser arguments for update subcommands related to gRPC."""

  _AddPortRelatedUpdateArgs(parser, use_port_name=False)

  parser.add_argument(
      '--grpc-service-name',
      help="""\
      An optional gRPC service name string of up to 1024 characters to include
      in the gRPC health check request. Pass in an empty string to unset.
      Only ASCII characters are allowed.""")


def AddUdpRelatedArgs(parser, request_and_response_required=True):
  """Adds parser arguments related to UDP."""

  _AddPortRelatedCreationArgs(
      parser, use_serving_port=False, port_type='UDP', default_port=None)

  parser.add_argument(
      '--request',
      required=request_and_response_required,
      help="""\
      Application data to send in payload of an UDP packet. It is an error if
      this is empty.
      """)

  parser.add_argument(
      '--response',
      required=request_and_response_required,
      help="""\
      The bytes to match against the beginning of the response data.
      It is an error if this is empty.
      """)


def _AddPortRelatedCreationArgs(parser,
                                use_port_name=True,
                                use_serving_port=True,
                                port_type='TCP',
                                default_port=80):
  """Adds parser create subcommand arguments --port and --port-name."""

  port_group_help = [
      'These flags configure the port that the health check monitors.'
  ]
  if default_port:
    port_group_help.append(
        'If none is specified, the default port of 80 is used.'
    )

  if use_port_name:
    port_group_help.append(
        'If both `--port` and `--port-name` are specified, `--port` takes '
        'precedence.')
  port_group = parser.add_group(help=' '.join(port_group_help))
  port_group.add_argument(
      '--port',
      type=int,
      default=default_port,
      help="""\
      The {} port number that this health check monitors.
      """.format(port_type))

  if use_port_name:
    port_group.add_argument(
        '--port-name',
        help="""\
        The port name that this health check monitors. By default, this is
        empty.
        """)

  if use_serving_port:
    _AddUseServingPortFlag(port_group, use_port_name)


def _AddPortRelatedUpdateArgs(parser, use_port_name=True):
  """Adds parser update subcommand arguments --port and --port-name."""

  port_group = parser.add_group(
      help=('These flags configure the port that the health check monitors.%s' %
            (' If both `--port` and `--port-name` are specified, `--port` takes'
             ' precedence.' if use_port_name else '')))

  port_group.add_argument(
      '--port',
      type=int,
      help='The TCP port number that this health check monitors.')

  if use_port_name:
    port_group.add_argument(
        '--port-name',
        help="""\
        The port name that this health check monitors. By default, this is
        empty. Setting this to an empty string will clear any existing
        port-name value.
        """)

  _AddUseServingPortFlag(port_group, use_port_name)


def _AddTcpRelatedArgsImpl(add_info_about_clearing, parser):
  """Adds TCP-related subcommand parser arguments."""

  request_help = """\
      An optional string of up to 1024 characters to send once the health check
      TCP connection has been established. The health checker then looks for a
      reply of the string provided in the `--response` field.

      If `--response` is not configured, the health checker does not wait for a
      response and regards the probe as successful if the TCP or SSL handshake
      was successful.
      """
  response_help = """\
      An optional string of up to 1024 characters that the health checker
      expects to receive from the instance. If the response is not received
      exactly, the health check probe fails. If `--response` is configured, but
      not `--request`, the health checker will wait for a response anyway.
      Unless your system automatically sends out a message in response to a
      successful handshake, only configure `--response` to match an explicit
      `--request`.
      """

  if add_info_about_clearing:
    request_help += """
      Setting this to an empty string will clear any existing request value.
      """
    response_help += """\
      Setting this to an empty string will clear any existing
      response value.
      """

  parser.add_argument(
      '--request',
      help=request_help)

  parser.add_argument(
      '--response',
      help=response_help)


def AddProxyHeaderRelatedCreateArgs(parser, default='NONE'):
  """Adds parser arguments for creation related to ProxyHeader."""

  parser.add_argument(
      '--proxy-header',
      choices={
          'NONE': 'No proxy header is added.',
          'PROXY_V1': r'Adds the header "PROXY UNKNOWN\r\n".',
      },
      default=default,
      help='The type of proxy protocol header to be sent to the backend.')


def AddProxyHeaderRelatedUpdateArgs(parser):
  """Adds parser arguments for update related to ProxyHeader."""

  AddProxyHeaderRelatedCreateArgs(parser, default=None)


def CheckProtocolAgnosticArgs(args):
  """Raises exception if any protocol-agnostic args are invalid."""

  if (args.check_interval is not None
      and (args.check_interval < CHECK_INTERVAL_LOWER_BOUND_SEC
           or args.check_interval > CHECK_INTERVAL_UPPER_BOUND_SEC)):
    raise hc_exceptions.ArgumentError(
        '[--check-interval] must not be less than {0} second or greater '
        'than {1} seconds; received [{2}] seconds.'.format(
            CHECK_INTERVAL_LOWER_BOUND_SEC, CHECK_INTERVAL_UPPER_BOUND_SEC,
            args.check_interval))

  if (args.timeout is not None
      and (args.timeout < TIMEOUT_LOWER_BOUND_SEC
           or args.timeout > TIMEOUT_UPPER_BOUND_SEC)):
    raise hc_exceptions.ArgumentError(
        '[--timeout] must not be less than {0} second or greater than {1} '
        'seconds; received: [{2}] seconds.'.format(
            TIMEOUT_LOWER_BOUND_SEC, TIMEOUT_UPPER_BOUND_SEC, args.timeout))

  if (args.healthy_threshold is not None
      and (args.healthy_threshold < THRESHOLD_LOWER_BOUND
           or args.healthy_threshold > THRESHOLD_UPPER_BOUND)):
    raise hc_exceptions.ArgumentError(
        '[--healthy-threshold] must be an integer between {0} and {1}, '
        'inclusive; received: [{2}].'.format(THRESHOLD_LOWER_BOUND,
                                             THRESHOLD_UPPER_BOUND,
                                             args.healthy_threshold))

  if (args.unhealthy_threshold is not None
      and (args.unhealthy_threshold < THRESHOLD_LOWER_BOUND
           or args.unhealthy_threshold > THRESHOLD_UPPER_BOUND)):
    raise hc_exceptions.ArgumentError(
        '[--unhealthy-threshold] must be an integer between {0} and {1}, '
        'inclusive; received [{2}].'.format(THRESHOLD_LOWER_BOUND,
                                            THRESHOLD_UPPER_BOUND,
                                            args.unhealthy_threshold))


def _RaiseBadPortSpecificationError(invalid_flag, port_spec_flag,
                                    invalid_value):
  raise calliope_exceptions.InvalidArgumentException(
      port_spec_flag, '{0} cannot be specified when using: {1}.'.format(
          invalid_flag, invalid_value))


def ValidateAndAddPortSpecificationToHealthCheck(args, x_health_check):
  """Modifies the health check as needed and adds port spec to the check."""
  if args.IsSpecified('port_name') and not args.IsSpecified('port'):
    # When only portName is specified (port is unspecified), we should remove
    # port so that its default value doesn't cause port to take precedence.
    x_health_check.port = None
  enum_class = type(x_health_check).PortSpecificationValueValuesEnum
  if args.use_serving_port:
    if args.IsSpecified('port_name'):
      _RaiseBadPortSpecificationError('--port-name', '--use-serving-port',
                                      '--use-serving-port')
    if args.IsSpecified('port'):
      _RaiseBadPortSpecificationError('--port', '--use-serving-port',
                                      '--use-serving-port')
    x_health_check.portSpecification = enum_class.USE_SERVING_PORT
    x_health_check.port = None
  else:
    if args.IsSpecified('port') and args.IsSpecified('port_name'):
      # Fixed port takes precedence over port name.
      x_health_check.portSpecification = enum_class.USE_FIXED_PORT
      x_health_check.portName = None
    elif args.IsSpecified('port_name'):
      x_health_check.portSpecification = enum_class.USE_NAMED_PORT
    else:
      x_health_check.portSpecification = enum_class.USE_FIXED_PORT


def ValidateAndAddPortSpecificationToGRPCHealthCheck(args, x_health_check):
  """Modifies the gRPC health check as needed and adds port specification."""

  enum_class = type(x_health_check).PortSpecificationValueValuesEnum
  if args.use_serving_port:
    if args.IsSpecified('port'):
      _RaiseBadPortSpecificationError('--port', '--use-serving-port',
                                      '--use-serving-port')
    x_health_check.portSpecification = enum_class.USE_SERVING_PORT
    x_health_check.port = None
  else:
    x_health_check.portSpecification = enum_class.USE_FIXED_PORT


def HandlePortRelatedFlagsForUpdate(args, x_health_check):
  """Calculate port, port_name and port_specification for HC update."""
  port = x_health_check.port
  port_name = x_health_check.portName
  port_specification = x_health_check.portSpecification
  enum_class = type(x_health_check).PortSpecificationValueValuesEnum

  if args.use_serving_port:
    if args.IsSpecified('port_name'):
      _RaiseBadPortSpecificationError('--port-name', '--use-serving-port',
                                      '--use-serving-port')
    if args.IsSpecified('port'):
      _RaiseBadPortSpecificationError('--port', '--use-serving-port',
                                      '--use-serving-port')
    port = None
    port_name = None
    port_specification = enum_class.USE_SERVING_PORT

  if args.IsSpecified('port'):
    # Fixed port takes precedence over port name.
    port = args.port
    port_name = None
    port_specification = enum_class.USE_FIXED_PORT
  elif args.IsSpecified('port_name'):
    if args.port_name:
      port = None
      port_name = args.port_name
      port_specification = enum_class.USE_NAMED_PORT
    else:
      # Empty port_name value is used to clear out the field.
      port_name = None
      port_specification = enum_class.USE_FIXED_PORT
  else:
    # Inherited values from existing health check should remain.
    pass

  return port, port_name, port_specification


def HandlePortRelatedFlagsForGRPCUpdate(args, x_health_check):
  """Calculate port and port_specification for gRPC HC update."""
  port = x_health_check.port
  port_specification = x_health_check.portSpecification
  enum_class = type(x_health_check).PortSpecificationValueValuesEnum

  if args.use_serving_port:
    if args.IsSpecified('port'):
      _RaiseBadPortSpecificationError('--port', '--use-serving-port',
                                      '--use-serving-port')
    port = None
    port_specification = enum_class.USE_SERVING_PORT

  if args.IsSpecified('port'):
    port = args.port
    port_specification = enum_class.USE_FIXED_PORT
  else:
    # Inherited values from existing health check should remain.
    pass

  return port, port_specification


def _AddUseServingPortFlag(parser, use_port_name=True):
  """Adds parser argument for using serving port option."""
  parser.add_argument(
      '--use-serving-port',
      action='store_true',
      help="""\
      If given, use the "serving port" for health checks:

        - When health checking network endpoints in a Network Endpoint
          Group, use the port specified with each endpoint.
          `--use-serving-port` must be used when using a Network Endpoint Group
          as a backend as this flag specifies the `portSpecification` option for
          a Health Check object.
        - When health checking other backends, use the port%s of
          the backend service.""" % (' or named port' if use_port_name else ''))


def IsRegionalHealthCheckRef(health_check_ref):
  """Returns True if the health check reference is regional."""

  return health_check_ref.Collection() == 'compute.regionHealthChecks'


def IsGlobalHealthCheckRef(health_check_ref):
  """Returns True if the health check reference is global."""

  return health_check_ref.Collection() == 'compute.healthChecks'


def AddHealthCheckLoggingRelatedArgs(parser):
  """Adds parser arguments for health check log config."""

  # The parser automatically adds support for --no-enable-logging. Argument
  # value is set to false internally, if --no-enable-logging is specified.
  parser.add_argument(
      '--enable-logging',
      action='store_true',
      default=None,
      help="""\
      Enable logging of health check probe results to Stackdriver. Logging is
      disabled by default.

      Use --no-enable-logging to disable logging.""")


def AddHealthCheckSourceRegionsRelatedArgs(parser):
  """Adds parser arguments for health check source regions."""

  parser.add_argument(
      '--source-regions',
      metavar='REGION',
      help="""\
        Define the list of Google Cloud regions from which health checks are
        performed. This option is supported only for global health checks that
        will be referenced by DNS routing policies. If specified, the
        --check-interval field should be at least 30 seconds. The
        --proxy-header and --request fields (for TCP health checks) are not
        supported with this option.

        If --source-regions is specified for a health check, then that health
        check cannot be used by a backend service or by a managed instance
        group (for autohealing).
        """,
      type=arg_parsers.ArgList(min_length=3),
      default=[],
  )


def CreateLogConfig(client, args):
  """Returns a HealthCheckLogconfig message if args are valid."""

  messages = client.messages
  log_config = None
  if args.enable_logging is not None:
    log_config = messages.HealthCheckLogConfig(enable=args.enable_logging)
  return log_config


def ModifyLogConfig(client, args, existing_log_config):
  """Returns a modified HealthCheckLogconfig message."""

  messages = client.messages
  log_config = None
  if not existing_log_config:
    # If log config has not changed then return early.
    if args.enable_logging is None:
      return log_config
    log_config = messages.HealthCheckLogConfig()
  else:
    log_config = copy.deepcopy(existing_log_config)

  if args.enable_logging is not None:
    log_config.enable = args.enable_logging

  return log_config