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/394/lib/googlecloudsdk/command_lib/scc/notifications/notification_util.py
# -*- 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 util methods common to Notification commands."""
import re
from googlecloudsdk.command_lib.scc import errors
from googlecloudsdk.command_lib.scc import util


def GetParentFromNotificationConfigName(notification_config_name):
  resource_pattern = re.compile("(organizations|projects|folders)/.*")
  if not resource_pattern.match(notification_config_name):
    raise errors.InvalidSCCInputError(
        "When providing a full resource path, it must also include the pattern "
        "the organization, project, or folder prefix."
    )
  return notification_config_name.split("/notificationConfigs/")[0]


def GetParentFromResourceName(resource_name):
  list_organization_components = resource_name.split("/")
  return list_organization_components[0] + "/" + list_organization_components[1]


def ValidateAndGetNotificationConfigV1Name(args):
  """Returns relative resource name for a v1 notification config.

  Validates on regexes for args containing full names or short names with
  resources. Localization is supported by the
  ValidateAndGetNotificationConfigV2Name method.

  Args:
    args: an argparse object that should contain .NOTIFICATIONCONFIGID,
      optionally 1 of .organization, .folder, .project

  Examples:

  args with NOTIFICATIONCONFIGID="organizations/123/notificationConfigs/config1"
  returns the NOTIFICATIONCONFIGID

  args with NOTIFICATIONCONFIGID="config1" and projects="projects/123" returns
  projects/123/notificationConfigs/config1
  """
  resource_pattern = re.compile(
      "(organizations|projects|folders)/.+/notificationConfigs/[a-zA-Z0-9-_]{1,128}$"
  )
  id_pattern = re.compile("[a-zA-Z0-9-_]{1,128}$")
  notification_config_id = args.NOTIFICATIONCONFIGID
  if not resource_pattern.match(
      notification_config_id
  ) and not id_pattern.match(notification_config_id):
    raise errors.InvalidNotificationConfigError(
        "NotificationConfig must match either (organizations|projects|folders)/"
        ".+/notificationConfigs/[a-zA-Z0-9-_]{1,128})$ or "
        "[a-zA-Z0-9-_]{1,128}$."
    )

  if resource_pattern.match(notification_config_id):
    # Handle config id as full resource name
    return notification_config_id

  return (
      util.GetParentFromNamedArguments(args)
      + "/notificationConfigs/"
      + notification_config_id
  )


def ValidateAndGetLocationFromV2Arg(args):
  """Returns the location from the location arg, or throws an error."""
  if args.IsKnownAndSpecified("location"):
    # arg format: locations/<location>
    if "/" in args.location:
      long_pattern = re.compile("^locations/.*$")
      if long_pattern.match(args.location):
        return args.location.split("/")[-1]
      else:
        raise errors.InvalidSCCInputError(
            "When providing a full resource path, it must include the pattern "
            "'^locations/.*$'."
        )
    # arg format: <location>
    else:
      return args.location
  else:
    return "global"


def ValidateAndGetNotificationConfigV2Name(args):
  """Returns relative resource name for a v2 notification config.

  Validates on regexes for args containing full names with locations or short
  names with resources.

  Args:
    args: an argparse object that should contain .NOTIFICATIONCONFIGID,
      optionally 1 of .organization, .folder, .project; and optionally .location

  Examples:

  args with NOTIFICATIONCONFIGID="organizations/123/notificationConfigs/config1"
  and location="locations/us" returns
  organizations/123/locations/us/notificationConfigs/config1

  args with
  NOTIFICATIONCONFIGID="folders/123/locations/us/notificationConfigs/config1"
  and returns folders/123/locations/us/notificationConfigs/config1

  args with NOTIFICATIONCONFIGID="config1", projects="projects/123", and
  locations="us" returns projects/123/notificationConfigs/config1
  """
  id_pattern = re.compile("[a-zA-Z0-9-_]{1,128}$")
  nonregionalized_resource_pattern = re.compile(
      "(organizations|projects|folders)/.+/notificationConfigs/[a-zA-Z0-9-_]{1,128}$"
  )
  regionalized_resource_pattern = re.compile(
      "(organizations|projects|folders)/.+/locations/.+/notificationConfigs/[a-zA-Z0-9-_]{1,128}$"
  )
  notification_config_id = args.NOTIFICATIONCONFIGID
  location = util.ValidateAndGetLocation(args, "v2")

  # id-only pattern (short name): compose the full name
  if id_pattern.match(notification_config_id):
    return f"{util.GetParentFromNamedArguments(args)}/locations/{location}/notificationConfigs/{notification_config_id}"

  # v2=style regionalized patterns
  if regionalized_resource_pattern.match(notification_config_id):
    return notification_config_id

  # v1-style nonregionalized patterns are acceptable
  if nonregionalized_resource_pattern.match(notification_config_id):
    # Handle config id as full resource name
    [parent_segment, id_segment] = notification_config_id.split(
        "/notificationConfigs/"
    )
    return f"{parent_segment}/locations/{location}/notificationConfigs/{id_segment}"

  raise errors.InvalidNotificationConfigError(
      "NotificationConfig must match"
      " (organizations|projects|folders)/.+/notificationConfigs/[a-zA-Z0-9-_]{1,128})$,"
      " (organizations|projects|folders)/.+/locations/.+/notificationConfigs/[a-zA-Z0-9-_]{1,128})$,"
      " or [a-zA-Z0-9-_]{1,128}$."
  )


def ValidateMutexOnConfigIdAndParent(args, parent):
  """Validates that only a full resource or resouce args are provided."""
  notification_config_id = args.NOTIFICATIONCONFIGID
  if "/" in notification_config_id:
    if parent is not None:
      raise errors.InvalidNotificationConfigError(
          "Only provide a full resource name "
          "(organizations/123/notificationConfigs/test-config) "
          "or an --(organization|folder|project) flag, not both."
      )
  elif parent is None:
    raise errors.InvalidNotificationConfigError(
        "A corresponding parent by a --(organization|folder|project) flag must "
        "be provided if it is not included in notification ID."
    )