File: //snap/google-cloud-cli/current/lib/surface/compute/routes/create.py
# -*- 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.
"""Command for creating routes."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import ipaddress
from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.calliope import actions
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.compute import completers
from googlecloudsdk.command_lib.compute import exceptions as compute_exceptions
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute import resource_manager_tags_utils
from googlecloudsdk.command_lib.compute.forwarding_rules import flags as ilb_flags
from googlecloudsdk.command_lib.compute.instances import flags as instance_flags
from googlecloudsdk.command_lib.compute.networks import flags as network_flags
from googlecloudsdk.command_lib.compute.routes import flags
from googlecloudsdk.command_lib.compute.vpn_tunnels import flags as vpn_flags
from googlecloudsdk.core import properties
import six
def _AddGaHops(next_hop_group):
"""Attach arguments for GA next-hops to the a parser group."""
next_hop_group.add_argument(
'--next-hop-instance',
help="""\
Specifies the name of an instance that should handle traffic
matching this route. When this flag is specified, the zone of
the instance must be specified using
``--next-hop-instance-zone''.
""")
next_hop_group.add_argument(
'--next-hop-address',
help="""\
Specifies the IP address of an instance that should handle
matching packets. The instance must have IP forwarding enabled
(i.e., include ``--can-ip-forward'' when creating the instance
using `gcloud compute instances create`)
""")
flags.NEXT_HOP_GATEWAY_ARG.AddArgument(next_hop_group)
next_hop_group.add_argument(
'--next-hop-vpn-tunnel',
help=('The target VPN tunnel that will receive forwarded traffic.'))
def _Args(parser):
"""Add arguments for route creation."""
parser.add_argument(
'--description', help='An optional, textual description for the route.')
parser.add_argument(
'--network',
default='default',
help='Specifies the network to which the route will be applied.')
parser.add_argument(
'--tags',
type=arg_parsers.ArgList(min_length=1),
default=[],
metavar='TAG',
help="""\
Identifies the set of instances that this route will apply to. If no
tags are provided, the route will apply to all instances in the network.
""")
parser.add_argument(
'--destination-range',
required=True,
help="""\
The destination range of outgoing packets that the route will
apply to. To match all traffic, use ``0.0.0.0/0''.
""")
parser.add_argument(
'--priority',
default=1000,
type=int,
help="""\
Specifies the priority of this route relative to other routes
with the same specificity. The lower the value, the higher the
priority.
""")
next_hop = parser.add_mutually_exclusive_group(required=True)
_AddGaHops(next_hop)
parser.add_argument(
'--next-hop-instance-zone',
action=actions.StoreProperty(properties.VALUES.compute.zone),
help=('The zone of the next hop instance. ' +
instance_flags.ZONE_PROPERTY_EXPLANATION))
parser.add_argument(
'--next-hop-vpn-tunnel-region',
help=('The region of the next hop vpn tunnel. ' +
compute_flags.REGION_PROPERTY_EXPLANATION))
next_hop.add_argument(
'--next-hop-ilb',
help="""\
Specifies the name or IP address of a forwarding rule for an internal TCP/UDP
load balancer. The forwarding rule's `--load-balancing-scheme` must be
`INTERNAL`. You can use any `--destination-range` that doesn't exactly
match the destination of a subnet route and isn't more specific (has a
longer subnet mask) than the destination of a subnet route. For
more information, see
https://cloud.google.com/load-balancing/docs/internal/ilb-next-hop-overview#destination_range.
""")
parser.add_argument(
'--next-hop-ilb-region',
help=('The region of the next hop forwarding rule. ' +
compute_flags.REGION_PROPERTY_EXPLANATION))
parser.add_argument(
'--resource-manager-tags',
type=arg_parsers.ArgDict(),
metavar='KEY=VALUE',
help="""\
A comma-separated list of Resource Manager tags to apply to the route.
""",
)
parser.display_info.AddCacheUpdater(completers.RoutesCompleter)
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.UniverseCompatible
class Create(base.CreateCommand):
r"""Create a new route.
*{command}* is used to create routes. A route is a rule that
specifies how certain packets should be handled by the virtual
network. Routes are associated with virtual machine instances
by tag, and the set of routes for a particular VM is called
its routing table. For each packet leaving a virtual machine,
the system searches that machine's routing table for a single
best matching route.
Routes match packets by destination IP address, preferring
smaller or more specific ranges over larger ones (see
`--destination-range`). If there is a tie, the system selects
the route with the smallest priority value. The packet
is then forwarded as specified by `--next-hop-address`,
`--next-hop-instance`, `--next-hop-vpn-tunnel`, or
`--next-hop-gateway` of the winning route. Packets that do
not match any route in the sending virtual machine routing
table will be dropped.
Exactly one of `--next-hop-address`, `--next-hop-gateway`,
`--next-hop-vpn-tunnel`, or `--next-hop-instance` must be
provided with this command.
## EXAMPLES
To create a route with the name 'route-name' with destination range
'0.0.0.0/0' and with next hop gateway 'default-internet-gateway', run:
$ {command} route-name \
--destination-range=0.0.0.0/0 \
--next-hop-gateway=default-internet-gateway
"""
NETWORK_ARG = None
INSTANCE_ARG = None
VPN_TUNNEL_ARG = None
ILB_ARG = None
ROUTE_ARG = None
@classmethod
def Args(cls, parser):
parser.display_info.AddFormat(flags.DEFAULT_LIST_FORMAT)
cls.NETWORK_ARG = network_flags.NetworkArgumentForOtherResource(
'Specifies the network to which the route will be applied.',
required=False)
cls.INSTANCE_ARG = instance_flags.InstanceArgumentForRoute(required=False)
cls.VPN_TUNNEL_ARG = vpn_flags.VpnTunnelArgumentForRoute(required=False)
cls.ILB_ARG = ilb_flags.ForwardingRuleArgumentForRoute(required=False)
cls.ROUTE_ARG = flags.RouteArgument()
cls.ROUTE_ARG.AddArgument(parser, operation_type='create')
_Args(parser)
def Run(self, args):
"""Issue API requests for route creation, callable from multiple tracks."""
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
client = holder.client
network_uri = self.NETWORK_ARG.ResolveAsResource(
args, holder.resources).SelfLink()
route_ref = self.ROUTE_ARG.ResolveAsResource(args, holder.resources)
if args.next_hop_instance:
next_hop_instance_uri = self.INSTANCE_ARG.ResolveAsResource(
args,
holder.resources,
scope_lister=instance_flags.GetInstanceZoneScopeLister(
client)).SelfLink()
else:
if args.next_hop_instance_zone:
raise compute_exceptions.ArgumentError(
'[--next-hop-instance-zone] can only be specified in conjunction '
'with [--next-hop-instance].')
next_hop_instance_uri = None
if args.next_hop_gateway:
next_hop_gateway_ref = flags.NEXT_HOP_GATEWAY_ARG.ResolveAsResource(
args, holder.resources)
next_hop_gateway_uri = next_hop_gateway_ref.SelfLink()
else:
next_hop_gateway_uri = None
next_hop_vpn_tunnel_uri = None
if args.next_hop_vpn_tunnel:
next_hop_vpn_tunnel_uri = self.VPN_TUNNEL_ARG.ResolveAsResource(
args,
holder.resources,
scope_lister=compute_flags.GetDefaultScopeLister(client)).SelfLink()
elif args.next_hop_vpn_tunnel_region:
raise compute_exceptions.ArgumentError(
'[--next-hop-vpn-tunnel-region] can only be specified in '
'conjunction with [--next-hop-vpn-tunnel].')
next_hop_ilb_uri = None
if args.next_hop_ilb:
try:
ipaddress.ip_address(args.next_hop_ilb)
if args.next_hop_ilb_region:
raise exceptions.InvalidArgumentException(
'--next-hop-ilb-region', 'This should not be specified if '
'an IP address is used for [--next-hop-ilb].')
next_hop_ilb_uri = args.next_hop_ilb
except ValueError:
next_hop_ilb_uri = self.ILB_ARG.ResolveAsResource(
args,
holder.resources,
scope_lister=compute_flags.GetDefaultScopeLister(
client)).SelfLink()
elif args.next_hop_ilb_region:
raise exceptions.InvalidArgumentException(
'--next-hop-ilb-region', 'This can only be specified in '
'conjunction with [--next-hop-ilb].')
request = client.messages.ComputeRoutesInsertRequest(
project=route_ref.project,
route=client.messages.Route(
description=args.description,
destRange=args.destination_range,
name=route_ref.Name(),
network=network_uri,
nextHopInstance=next_hop_instance_uri,
nextHopIp=args.next_hop_address,
nextHopGateway=next_hop_gateway_uri,
nextHopVpnTunnel=next_hop_vpn_tunnel_uri,
priority=args.priority,
tags=args.tags,
),
)
request.route.nextHopIlb = next_hop_ilb_uri
if args.resource_manager_tags is not None:
request.route.params = _CreateRouteParams(
client.messages, args.resource_manager_tags
)
return client.MakeRequests(
[(client.apitools_client.routes, 'Insert', request)]
)
def _CreateRouteParams(messages, resource_manager_tags):
resource_manager_tags_map = (
resource_manager_tags_utils.GetResourceManagerTags(resource_manager_tags)
)
params = messages.RouteParams
additional_properties = [
params.ResourceManagerTagsValue.AdditionalProperty(key=key, value=value)
for key, value in sorted(six.iteritems(resource_manager_tags_map))
]
return params(
resourceManagerTags=params.ResourceManagerTagsValue(
additionalProperties=additional_properties
)
)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
@base.UniverseCompatible
class CreateAlphaBeta(Create):
r"""Create a new route.
*{command}* is used to create routes. A route is a rule that
specifies how certain packets should be handled by the virtual
network. Routes are associated with virtual machine instances
by tag, and the set of routes for a particular VM is called
its routing table. For each packet leaving a virtual machine,
the system searches that machine's routing table for a single
best matching route.
Routes match packets by destination IP address, preferring
smaller or more specific ranges over larger ones (see
``--destination-range''). If there is a tie, the system selects
the route with the smallest priority value. If there is still
a tie, it uses the layer 3 and 4 packet headers to
select just one of the remaining matching routes. The packet
is then forwarded as specified by ``--next-hop-address'',
``--next-hop-instance'', ``--next-hop-vpn-tunnel'', ``--next-hop-gateway'',
or ``--next-hop-ilb'' of the winning route. Packets that do
not match any route in the sending virtual machine routing
table will be dropped.
Exactly one of ``--next-hop-address'', ``--next-hop-gateway'',
``--next-hop-vpn-tunnel'', ``--next-hop-instance'', or ``--next-hop-ilb''
must be provided with this command.
## EXAMPLES
To create a route with the name 'route-name' with destination range
'0.0.0.0/0' and with next hop gateway 'default-internet-gateway', run:
$ {command} route-name \
--destination-range=0.0.0.0/0 \
--next-hop-gateway=default-internet-gateway
"""