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/396/lib/googlecloudsdk/api_lib/edge_cloud/networking/routers/routers.py
# -*- 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.
"""Distributed Cloud Edge Network router API."""

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

import ipaddress

from apitools.base.py import encoding
from googlecloudsdk.api_lib.edge_cloud.networking import utils
from googlecloudsdk.calliope import parser_errors
from googlecloudsdk.core import exceptions as core_exceptions

import six


class RoutersClient(object):
  """Client for private connections service in the API."""
  # REST API Field Names for the updateMask
  FIELD_PATH_INTERFACE = 'interface'
  FIELD_PATH_BGP_PEER = 'bgp_peer'
  FIELD_PATH_ROUTE_ADVERTISEMENTS = 'route_advertisements'

  def __init__(self, release_track, client=None, messages=None):
    self._client = client or utils.GetClientInstance(release_track)
    self._messages = messages or utils.GetMessagesModule(release_track)
    self._service = self._client.projects_locations_zones_routers
    self._resource_parser = utils.GetResourceParser(release_track)

  def WaitForOperation(self, operation):
    """Waits for the given google.longrunning.Operation to complete."""
    return utils.WaitForOperation(self._client, operation, self._service)

  def ModifyToAddInterface(self, router_ref, args, existing):
    """Mutate the router to add an interface."""
    replacement = encoding.CopyProtoMessage(existing)
    new_interface = self._messages.Interface(name=args.interface_name)

    if args.interconnect_attachment is not None:
      attachment_ref = self._resource_parser.Create(
          'edgenetwork.projects.locations.zones.interconnectAttachments',
          interconnectAttachmentsId=args.interconnect_attachment,
          projectsId=router_ref.projectsId,
          locationsId=router_ref.locationsId,
          zonesId=router_ref.zonesId)

      if args.ip_mask_length is None or args.ip_address is None:
        raise parser_errors.ArgumentException(
            '--ip-address and --ip-mask-length must be set'
        )

      try:
        ip_address = ipaddress.ip_address(args.ip_address)
      except ValueError as err:
        raise parser_errors.ArgumentException(str(err))

      if args.ip_mask_length > ip_address.max_prefixlen:
        raise parser_errors.ArgumentException(
            '--ip-mask-length should be less than %s' % ip_address.max_prefixlen
        )

      cidr = '{0}/{1}'.format(args.ip_address, args.ip_mask_length)
      if ip_address.version == 4:  # Is an ipv4 cidr
        new_interface.ipv4Cidr = cidr
      else:
        new_interface.ipv6Cidr = cidr

      new_interface.linkedInterconnectAttachment = attachment_ref.RelativeName()

    if args.subnetwork is not None:
      subnet_ref = self._resource_parser.Create(
          'edgenetwork.projects.locations.zones.subnets',
          subnetsId=args.subnetwork,
          projectsId=router_ref.projectsId,
          locationsId=router_ref.locationsId,
          zonesId=router_ref.zonesId)
      new_interface.subnetwork = subnet_ref.RelativeName()

    if args.loopback_ip_addresses is not None:
      new_interface.loopbackIpAddresses = args.loopback_ip_addresses

    replacement.interface.append(new_interface)
    return replacement

  def ModifyToRemoveInterface(self, args, existing):
    """Mutate the router to delete a list of interfaces."""
    # Get the list of interfaces that are to be removed from args.
    input_remove_list = args.interface_names if args.interface_names else []
    input_remove_list = input_remove_list + ([args.interface_name]
                                             if args.interface_name else [])
    # Remove interface if exists
    actual_remove_list = []
    replacement = encoding.CopyProtoMessage(existing)
    existing_router = encoding.CopyProtoMessage(existing)

    for iface in existing_router.interface:
      if iface.name in input_remove_list:
        replacement.interface.remove(iface)
        actual_remove_list.append(iface.name)

    # If there still are interfaces that we didn't find, the input is invalid.
    not_found_interface = sorted(
        set(input_remove_list) - set(actual_remove_list))
    if not_found_interface:
      error_msg = 'interface [{}] not found'.format(
          ', '.join(not_found_interface))
      raise core_exceptions.Error(error_msg)

    return replacement

  def ModifyToAddBgpPeer(self, args, existing):
    """Mutate the router to add a BGP peer."""

    replacement = encoding.CopyProtoMessage(existing)
    bgp_peer_args = {
        'name': args.peer_name,
        'interface': args.interface,
        'peerAsn': args.peer_asn,
    }

    if args.peer_ipv4_range is not None:
      bgp_peer_args['peerIpv4Cidr'] = args.peer_ipv4_range

    # Only present in ALPHA release
    if 'peer_ipv6_range' in args and args.peer_ipv6_range is not None:
      bgp_peer_args['peerIpv6Cidr'] = args.peer_ipv6_range

    new_bgp_peer = self._messages.BgpPeer(**bgp_peer_args)
    replacement.bgpPeer.append(new_bgp_peer)
    return replacement

  def ModifyToRemoveBgpPeer(self, args, existing):
    """Mutate the router to delete BGP peers."""
    input_remove_list = args.peer_names if args.peer_names else []
    input_remove_list = input_remove_list + ([args.peer_name]
                                             if args.peer_name else [])
    actual_remove_list = []
    replacement = encoding.CopyProtoMessage(existing)
    existing_router = encoding.CopyProtoMessage(existing)

    for peer in existing_router.bgpPeer:
      if peer.name in input_remove_list:
        replacement.bgpPeer.remove(peer)
        actual_remove_list.append(peer.name)

    # If there still are bgp peers that we didn't find, the input is invalid.
    not_found_peer = sorted(set(input_remove_list) - set(actual_remove_list))
    if not_found_peer:
      error_msg = 'peer [{}] not found'.format(', '.join(not_found_peer))
      raise core_exceptions.Error(error_msg)

    return replacement

  def AddInterface(self, router_ref, args):
    """Create an interface on a router."""
    # Get current interfaces of router
    get_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersGetRequest(
        name=router_ref.RelativeName())
    router_object = self._service.Get(get_router_req)

    # Update interfaces to add the new interface
    new_router_object = self.ModifyToAddInterface(router_ref, args,
                                                  router_object)

    update_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersPatchRequest(
        name=router_ref.RelativeName(),
        router=new_router_object,
        updateMask=self.FIELD_PATH_INTERFACE)
    return self._service.Patch(update_router_req)

  def RemoveInterface(self, router_ref, args):
    """Remove a list of interfaces on a router."""
    # Get current interfaces of router
    get_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersGetRequest(
        name=router_ref.RelativeName())
    router_object = self._service.Get(get_router_req)
    # Update interfaces to add the new interface
    new_router_object = self.ModifyToRemoveInterface(args, router_object)

    update_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersPatchRequest(
        name=router_ref.RelativeName(),
        router=new_router_object,
        updateMask=self.FIELD_PATH_INTERFACE)

    return self._service.Patch(update_router_req)

  def ModifyToApplyAdvertisementChanges(self, args, existing):
    """Create a router based on `existing` with the routes change."""

    def cidrset(cidr_strs):
      return set(ipaddress.ip_network(cidrstr) for cidrstr in cidr_strs)

    def sorted_strings(cidrs):
      return [six.text_type(cidr) for cidr in sorted(cidrs)]

    advertisements = cidrset(existing.routeAdvertisements)
    replacement = encoding.CopyProtoMessage(existing)

    if args.add_advertisement_ranges:
      to_add = set(args.add_advertisement_ranges)
      already_present = sorted_strings(advertisements & to_add)
      if already_present:
        raise core_exceptions.Error(
            'attempting to add routes that are already present: {}'.format(
                ', '.join(already_present)))
      advertisements |= to_add
    elif args.remove_advertisement_ranges:
      to_rm = cidrset(args.remove_advertisement_ranges)
      already_missing = sorted_strings(to_rm - advertisements)
      if already_missing:
        raise core_exceptions.Error(
            'attempting to remove routes that are not present: {}'.format(
                ', '.join(already_missing)))
      advertisements -= to_rm
    elif args.set_advertisement_ranges:
      advertisements = cidrset(args.set_advertisement_ranges)
    else:
      raise parser_errors.ArgumentException(
          'Missing --add-advertisement-ranges, '
          '--remove-advertisement-ranges, or --set-advertisement-ranges')

    replacement.routeAdvertisements = list(map(str, sorted(advertisements)))
    return replacement

  def ChangeAdvertisements(self, router_ref, args):
    """Create a patch request that updates the Route advertisements of a router.
    """
    get_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersGetRequest(
        name=router_ref.RelativeName())
    router_object = self._service.Get(get_router_req)

    new_router_object = self.ModifyToApplyAdvertisementChanges(
        args, router_object)

    update_router_request = (
        self._messages.EdgenetworkProjectsLocationsZonesRoutersPatchRequest(
            name=router_ref.RelativeName(),
            router=new_router_object,
            updateMask=self.FIELD_PATH_ROUTE_ADVERTISEMENTS))

    return self._service.Patch(update_router_request)

  def AddBgpPeer(self, router_ref, args):
    """Mutate the router so to add a BGP peer."""
    # Get current router
    get_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersGetRequest(
        name=router_ref.RelativeName())
    router_object = self._service.Get(get_router_req)

    # Update router object to add the new bgp peer
    new_router_object = self.ModifyToAddBgpPeer(args, router_object)

    update_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersPatchRequest(
        name=router_ref.RelativeName(),
        router=new_router_object,
        updateMask=self.FIELD_PATH_BGP_PEER)
    return self._service.Patch(update_router_req)

  def RemoveBgpPeer(self, router_ref, args):
    """Mutate the router so to remove a BGP peer."""
    # Get current router
    get_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersGetRequest(
        name=router_ref.RelativeName())
    router_object = self._service.Get(get_router_req)

    # Update router object to remove specified bgp peers
    new_router_object = self.ModifyToRemoveBgpPeer(args, router_object)

    update_router_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersPatchRequest(
        name=router_ref.RelativeName(),
        router=new_router_object,
        updateMask=self.FIELD_PATH_BGP_PEER)
    return self._service.Patch(update_router_req)

  def GetStatus(self, router_ref):
    """Get the status of a specified router."""
    get_router_status_req = self._messages.EdgenetworkProjectsLocationsZonesRoutersDiagnoseRequest(
        name=router_ref.RelativeName())
    return self._service.Diagnose(get_router_status_req)