674 lines
28 KiB
Python
674 lines
28 KiB
Python
# -*- 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 forwarding rules."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
import ipaddress
|
|
import re
|
|
|
|
from googlecloudsdk.api_lib.compute import base_classes
|
|
from googlecloudsdk.api_lib.compute import constants
|
|
from googlecloudsdk.api_lib.compute import forwarding_rules_utils as utils
|
|
from googlecloudsdk.calliope import arg_parsers
|
|
from googlecloudsdk.calliope import base
|
|
from googlecloudsdk.calliope import exceptions
|
|
from googlecloudsdk.command_lib.compute import flags as compute_flags
|
|
from googlecloudsdk.command_lib.compute.forwarding_rules import exceptions as fw_exceptions
|
|
from googlecloudsdk.command_lib.compute.forwarding_rules import flags
|
|
from googlecloudsdk.core import log
|
|
import six
|
|
from six.moves import range # pylint: disable=redefined-builtin
|
|
|
|
|
|
def _Args(parser, support_all_protocol):
|
|
"""Add the flags to create a forwarding rule."""
|
|
|
|
flags.AddCreateArgs(
|
|
parser,
|
|
include_psc_google_apis=True,
|
|
include_target_service_attachment=True,
|
|
)
|
|
flags.AddIPProtocols(parser, support_all_protocol)
|
|
flags.AddDescription(parser)
|
|
flags.AddPortsAndPortRange(parser)
|
|
flags.AddNetworkTier(parser, for_update=False)
|
|
flags.AddAllowGlobalAccess(parser)
|
|
flags.AddAllowPscGlobalAccess(parser)
|
|
flags.AddSourceIpRanges(parser)
|
|
flags.AddDisableAutomateDnsZone(parser)
|
|
flags.AddIsMirroringCollector(parser)
|
|
flags.AddServiceDirectoryRegistration(parser)
|
|
|
|
parser.add_argument(
|
|
'--service-label',
|
|
help='(Only for Internal Load Balancing): '
|
|
'https://cloud.google.com/load-balancing/docs/dns-names/\n'
|
|
'The DNS label to use as the prefix of the fully qualified domain '
|
|
'name for this forwarding rule. The full name will be internally '
|
|
'generated and output as dnsName. If this field is not specified, '
|
|
'no DNS record will be generated and no DNS name will be output. '
|
|
'You cannot use the `--service-label` flag if the forwarding rule '
|
|
'references an internal IP address that has the '
|
|
'`--purpose=SHARED_LOADBALANCER_VIP` flag set.')
|
|
flags.AddAddressesAndIPVersions(parser)
|
|
forwarding_rule_arg = flags.ForwardingRuleArgument()
|
|
forwarding_rule_arg.AddArgument(parser, operation_type='create')
|
|
parser.display_info.AddCacheUpdater(flags.ForwardingRulesCompleter)
|
|
return forwarding_rule_arg
|
|
|
|
|
|
class CreateHelper(object):
|
|
"""Helper class to create a forwarding rule."""
|
|
|
|
FORWARDING_RULE_ARG = None
|
|
|
|
def __init__(
|
|
self,
|
|
holder,
|
|
support_all_protocol,
|
|
support_sd_registration_for_regional,
|
|
):
|
|
self._holder = holder
|
|
self._support_all_protocol = support_all_protocol
|
|
self._support_sd_registration_for_regional = (
|
|
support_sd_registration_for_regional
|
|
)
|
|
|
|
@classmethod
|
|
def Args(cls, parser, support_all_protocol):
|
|
"""Inits the class args for supported features."""
|
|
cls.FORWARDING_RULE_ARG = _Args(parser, support_all_protocol)
|
|
|
|
def ConstructProtocol(self, messages, args):
|
|
if args.ip_protocol:
|
|
return messages.ForwardingRule.IPProtocolValueValuesEnum(args.ip_protocol)
|
|
else:
|
|
return
|
|
|
|
def Run(self, args):
|
|
"""Issues requests necessary to create Forwarding Rules."""
|
|
client = self._holder.client
|
|
|
|
forwarding_rule_ref = self.FORWARDING_RULE_ARG.ResolveAsResource(
|
|
args,
|
|
self._holder.resources,
|
|
scope_lister=compute_flags.GetDefaultScopeLister(client))
|
|
|
|
if forwarding_rule_ref.Collection() == 'compute.globalForwardingRules':
|
|
requests = self._CreateGlobalRequests(client, self._holder.resources,
|
|
args, forwarding_rule_ref)
|
|
elif forwarding_rule_ref.Collection() == 'compute.forwardingRules':
|
|
requests = self._CreateRegionalRequests(client, self._holder.resources,
|
|
args, forwarding_rule_ref)
|
|
|
|
return client.MakeRequests(requests)
|
|
|
|
def _CreateGlobalRequests(self, client, resources, args, forwarding_rule_ref):
|
|
"""Create a globally scoped request."""
|
|
|
|
is_psc_google_apis = (
|
|
hasattr(args, 'target_google_apis_bundle')
|
|
and args.target_google_apis_bundle
|
|
)
|
|
|
|
sd_registration = None
|
|
if hasattr(args, 'service_directory_registration'
|
|
) and args.service_directory_registration:
|
|
if not is_psc_google_apis:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--service-directory-registration',
|
|
'Can only be specified for regional forwarding rules or Private Service Connect forwarding rules targeting a Google APIs bundle.'
|
|
)
|
|
# Parse projects/../locations/..
|
|
match = re.match(
|
|
r'^projects/([^/]+)/locations/([^/]+)(?:/namespaces/([^/]+))?$',
|
|
args.service_directory_registration)
|
|
if not match:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--service-directory-registration',
|
|
'Must be of the form projects/PROJECT/locations/REGION or projects/PROJECT/locations/REGION/namespaces/NAMESPACE'
|
|
)
|
|
project = match.group(1)
|
|
region = match.group(2)
|
|
namespace = match.group(3)
|
|
|
|
if project != forwarding_rule_ref.project:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--service-directory-registration',
|
|
'Must be in the same project as the forwarding rule.')
|
|
|
|
sd_registration = client.messages.ForwardingRuleServiceDirectoryRegistration(
|
|
serviceDirectoryRegion=region, namespace=namespace)
|
|
|
|
ports_all_specified, range_list = _ExtractPortsAndAll(args.ports)
|
|
port_range = _MakeSingleUnifiedPortRange(args.port_range, range_list)
|
|
# All global forwarding rules must use EXTERNAL or INTERNAL_SELF_MANAGED
|
|
# schemes presently.
|
|
load_balancing_scheme = _GetLoadBalancingScheme(args, client.messages,
|
|
is_psc_google_apis)
|
|
if (load_balancing_scheme == client.messages.ForwardingRule
|
|
.LoadBalancingSchemeValueValuesEnum.INTERNAL):
|
|
raise fw_exceptions.ArgumentError(
|
|
'You cannot specify internal [--load-balancing-scheme] for a global '
|
|
'forwarding rule.')
|
|
|
|
if (load_balancing_scheme == client.messages.ForwardingRule
|
|
.LoadBalancingSchemeValueValuesEnum.INTERNAL_SELF_MANAGED):
|
|
if (not args.target_http_proxy and not args.target_https_proxy and
|
|
not args.target_grpc_proxy and not args.target_tcp_proxy):
|
|
target_error_message_with_tcp = (
|
|
'You must specify either [--target-http-proxy], '
|
|
'[--target-https-proxy], [--target-grpc-proxy] '
|
|
'or [--target-tcp-proxy] for an '
|
|
'INTERNAL_SELF_MANAGED [--load-balancing-scheme].')
|
|
raise fw_exceptions.ArgumentError(target_error_message_with_tcp)
|
|
|
|
if args.subnet:
|
|
raise fw_exceptions.ArgumentError(
|
|
'You cannot specify [--subnet] for an INTERNAL_SELF_MANAGED '
|
|
'[--load-balancing-scheme].')
|
|
|
|
if not args.address:
|
|
raise fw_exceptions.ArgumentError(
|
|
'You must specify [--address] for an INTERNAL_SELF_MANAGED '
|
|
'[--load-balancing-scheme]')
|
|
|
|
if is_psc_google_apis:
|
|
rule_name = forwarding_rule_ref.Name()
|
|
if len(rule_name) > 20 or rule_name[0].isdigit(
|
|
) or not rule_name.isalnum():
|
|
raise fw_exceptions.ArgumentError(
|
|
'A forwarding rule to Google APIs must have a name that is between '
|
|
' 1-20 characters long, alphanumeric, starting with a letter.')
|
|
|
|
if port_range:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--ports',
|
|
'[--ports] is not allowed for PSC-GoogleApis forwarding rules.')
|
|
if load_balancing_scheme:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--load-balancing-scheme',
|
|
'The --load-balancing-scheme flag is not allowed for PSC-GoogleApis'
|
|
' forwarding rules.')
|
|
|
|
if args.target_google_apis_bundle in flags.PSC_GOOGLE_APIS_BUNDLES:
|
|
target_as_str = args.target_google_apis_bundle
|
|
else:
|
|
bundles_list = ', '.join(flags.PSC_GOOGLE_APIS_BUNDLES)
|
|
raise exceptions.InvalidArgumentException(
|
|
'--target-google-apis-bundle',
|
|
'The valid values for target-google-apis-bundle are: ' +
|
|
bundles_list)
|
|
else:
|
|
# L7XLB in Premium Tier.
|
|
target_ref = utils.GetGlobalTarget(resources, args)
|
|
target_as_str = target_ref.SelfLink()
|
|
|
|
if ports_all_specified:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--ports',
|
|
'[--ports] cannot be set to ALL for global forwarding rules.')
|
|
if not port_range:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--ports', '[--ports] is required for global forwarding rules.')
|
|
|
|
protocol = self.ConstructProtocol(client.messages, args)
|
|
|
|
address = self._ResolveAddress(resources, args,
|
|
compute_flags.compute_scope.ScopeEnum.GLOBAL,
|
|
forwarding_rule_ref)
|
|
forwarding_rule = client.messages.ForwardingRule(
|
|
description=args.description,
|
|
name=forwarding_rule_ref.Name(),
|
|
IPAddress=address,
|
|
IPProtocol=protocol,
|
|
portRange=port_range,
|
|
target=target_as_str,
|
|
networkTier=_ConstructNetworkTier(client.messages, args),
|
|
loadBalancingScheme=load_balancing_scheme)
|
|
|
|
self._ProcessCommonArgs(client, resources, args, forwarding_rule_ref,
|
|
forwarding_rule)
|
|
if sd_registration:
|
|
forwarding_rule.serviceDirectoryRegistrations.append(sd_registration)
|
|
|
|
if args.IsSpecified('allow_global_access'):
|
|
forwarding_rule.allowGlobalAccess = args.allow_global_access
|
|
|
|
request = client.messages.ComputeGlobalForwardingRulesInsertRequest(
|
|
forwardingRule=forwarding_rule, project=forwarding_rule_ref.project)
|
|
|
|
return [(client.apitools_client.globalForwardingRules, 'Insert', request)]
|
|
|
|
def _CreateRegionalRequests(self, client, resources, args,
|
|
forwarding_rule_ref):
|
|
"""Create a regionally scoped request."""
|
|
is_psc_ilb = (
|
|
hasattr(args, 'target_service_attachment')
|
|
and args.target_service_attachment
|
|
)
|
|
|
|
target_ref, region_ref = utils.GetRegionalTarget(
|
|
client, resources, args, forwarding_rule_ref
|
|
)
|
|
|
|
if not args.region and region_ref:
|
|
args.region = region_ref
|
|
|
|
protocol = self.ConstructProtocol(client.messages, args)
|
|
|
|
address = self._ResolveAddress(resources, args,
|
|
compute_flags.compute_scope.ScopeEnum.REGION,
|
|
forwarding_rule_ref)
|
|
|
|
load_balancing_scheme = _GetLoadBalancingScheme(args, client.messages,
|
|
is_psc_ilb)
|
|
|
|
if is_psc_ilb and load_balancing_scheme:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--load-balancing-scheme',
|
|
'The --load-balancing-scheme flag is not allowed for PSC-ILB '
|
|
'forwarding rules.')
|
|
|
|
if (load_balancing_scheme == client.messages.ForwardingRule
|
|
.LoadBalancingSchemeValueValuesEnum.INTERNAL):
|
|
if args.port_range:
|
|
raise fw_exceptions.ArgumentError(
|
|
'You cannot specify [--port-range] for a forwarding rule '
|
|
'whose [--load-balancing-scheme] is internal, '
|
|
'please use [--ports] flag instead.')
|
|
|
|
if (load_balancing_scheme == client.messages.ForwardingRule
|
|
.LoadBalancingSchemeValueValuesEnum.INTERNAL_SELF_MANAGED):
|
|
raise fw_exceptions.ArgumentError(
|
|
'You cannot specify an INTERNAL_SELF_MANAGED '
|
|
'[--load-balancing-scheme] for a regional forwarding rule.')
|
|
|
|
forwarding_rule = client.messages.ForwardingRule(
|
|
description=args.description,
|
|
name=forwarding_rule_ref.Name(),
|
|
IPAddress=address,
|
|
IPProtocol=protocol,
|
|
networkTier=_ConstructNetworkTier(client.messages, args),
|
|
loadBalancingScheme=load_balancing_scheme)
|
|
if args.source_ip_ranges:
|
|
forwarding_rule.sourceIpRanges = args.source_ip_ranges
|
|
|
|
self._ProcessCommonArgs(client, resources, args, forwarding_rule_ref,
|
|
forwarding_rule)
|
|
|
|
ports_all_specified, range_list = _ExtractPortsAndAll(args.ports)
|
|
|
|
if target_ref.Collection() == 'compute.regionBackendServices':
|
|
# A FR pointing to a BES has no target attribute.
|
|
forwarding_rule.backendService = target_ref.SelfLink()
|
|
forwarding_rule.target = None
|
|
else:
|
|
# A FR pointing to anything not a BES has a target attribute.
|
|
forwarding_rule.backendService = None
|
|
forwarding_rule.target = target_ref.SelfLink()
|
|
|
|
if ((target_ref.Collection() == 'compute.regionBackendServices' or
|
|
target_ref.Collection() == 'compute.targetInstances') and
|
|
args.load_balancing_scheme == 'INTERNAL'):
|
|
# This is for L4ILB and internal protocol forwarding.
|
|
# API fields allPorts, ports, and portRange are mutually exclusive.
|
|
# API field portRange is not valid for this case.
|
|
# Use of L3_DEFAULT implies all ports even if allPorts is unset.
|
|
if ports_all_specified:
|
|
forwarding_rule.allPorts = True
|
|
elif range_list:
|
|
forwarding_rule.ports = [
|
|
six.text_type(p) for p in _GetPortList(range_list)
|
|
]
|
|
elif ((target_ref.Collection() == 'compute.regionTargetHttpProxies' or
|
|
target_ref.Collection() == 'compute.regionTargetHttpsProxies') and
|
|
args.load_balancing_scheme == 'INTERNAL'):
|
|
# This is a legacy configuration for L7ILB.
|
|
forwarding_rule.ports = [
|
|
six.text_type(p) for p in _GetPortList(range_list)
|
|
]
|
|
elif args.load_balancing_scheme == 'INTERNAL':
|
|
# There are currently no other valid combinations of targets with scheme
|
|
# internal. With scheme internal, targets must presently be a regional
|
|
# backend service (L4ILB) or a target instance (protocol forwarding).
|
|
raise exceptions.InvalidArgumentException(
|
|
'--load-balancing-scheme',
|
|
'Only target instances and backend services should be specified as '
|
|
'a target for internal load balancing.')
|
|
elif args.load_balancing_scheme == 'INTERNAL_MANAGED':
|
|
# This is L7ILB.
|
|
forwarding_rule.portRange = _MakeSingleUnifiedPortRange(
|
|
args.port_range, range_list)
|
|
elif args.load_balancing_scheme == 'EXTERNAL_MANAGED':
|
|
# This is regional L7XLB.
|
|
forwarding_rule.portRange = _MakeSingleUnifiedPortRange(
|
|
args.port_range, range_list)
|
|
elif ((target_ref.Collection() == 'compute.regionBackendServices') and
|
|
((args.load_balancing_scheme == 'EXTERNAL') or
|
|
(not args.load_balancing_scheme))):
|
|
# This is NetLB using a backend service. Scheme is either explicitly
|
|
# EXTERNAL or not supplied (EXTERNAL is the default scheme).
|
|
# API fields allPorts, ports, and portRange are mutually exclusive.
|
|
# All three API fields are valid for this case.
|
|
# Use of L3_DEFAULT implies all ports even if allPorts is unset.
|
|
if ports_all_specified:
|
|
forwarding_rule.allPorts = True
|
|
elif range_list:
|
|
if len(range_list) > 1:
|
|
# More than one port, potentially discontiguous, from --ports= flag.
|
|
forwarding_rule.ports = [
|
|
six.text_type(p) for p in _GetPortList(range_list)
|
|
]
|
|
else:
|
|
# Exactly one value from --ports= flag. Might be a single port (80);
|
|
# might be a range (80-90). Since it might be a range, the portRange
|
|
# API attribute is more appropriate.
|
|
forwarding_rule.portRange = six.text_type(range_list[0])
|
|
elif args.port_range:
|
|
forwarding_rule.portRange = _MakeSingleUnifiedPortRange(
|
|
args.port_range, range_list)
|
|
elif ((target_ref.Collection() == 'compute.targetPool' or
|
|
target_ref.Collection() == 'compute.targetInstances') and
|
|
((args.load_balancing_scheme == 'EXTERNAL') or
|
|
(not args.load_balancing_scheme))):
|
|
# This is NetLB using a target pool or external protocol forwarding.
|
|
# Scheme is either explicitly EXTERNAL or not supplied (EXTERNAL is the
|
|
# default scheme).
|
|
# API fields allPorts, ports, and portRange are mutually exclusive.
|
|
# API field ports is not valid for this case.
|
|
# Use of L3_DEFAULT implies all ports by definition.
|
|
if ports_all_specified:
|
|
forwarding_rule.allPorts = True
|
|
else:
|
|
forwarding_rule.portRange = _MakeSingleUnifiedPortRange(
|
|
args.port_range, range_list)
|
|
else:
|
|
# All other regional forwarding rules with load balancing scheme EXTERNAL.
|
|
forwarding_rule.portRange = _MakeSingleUnifiedPortRange(
|
|
args.port_range, range_list)
|
|
|
|
if hasattr(args, 'service_label'):
|
|
forwarding_rule.serviceLabel = args.service_label
|
|
|
|
if args.IsSpecified('allow_global_access'):
|
|
forwarding_rule.allowGlobalAccess = args.allow_global_access
|
|
|
|
if args.IsSpecified('allow_psc_global_access'):
|
|
forwarding_rule.allowPscGlobalAccess = args.allow_psc_global_access
|
|
|
|
if args.IsSpecified('ip_collection'):
|
|
forwarding_rule.ipCollection = flags.IP_COLLECTION_ARG.ResolveAsResource(
|
|
args, resources).SelfLink()
|
|
|
|
if args.IsSpecified('disable_automate_dns_zone'):
|
|
forwarding_rule.noAutomateDnsZone = args.disable_automate_dns_zone
|
|
|
|
if hasattr(args, 'is_mirroring_collector'):
|
|
forwarding_rule.isMirroringCollector = args.is_mirroring_collector
|
|
|
|
if hasattr(args, 'service_directory_registration'
|
|
) and args.service_directory_registration:
|
|
if is_psc_ilb:
|
|
# Parse projects/../locations/../namespaces/..
|
|
match = re.match(
|
|
r'^projects/([^/]+)/locations/([^/]+)/namespaces/([^/]+)$',
|
|
args.service_directory_registration)
|
|
if not match:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--service-directory-registration',
|
|
'If set, must be of the form projects/PROJECT/locations/REGION/namespaces/NAMESPACE'
|
|
)
|
|
project = match.group(1)
|
|
region = match.group(2)
|
|
|
|
if project != forwarding_rule_ref.project or region != forwarding_rule_ref.region:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--service-directory-registration',
|
|
'Service Directory registration must be in the same project and region as the forwarding rule.'
|
|
)
|
|
|
|
sd_registration = client.messages.ForwardingRuleServiceDirectoryRegistration(
|
|
namespace=match.group(3))
|
|
forwarding_rule.serviceDirectoryRegistrations.append(sd_registration)
|
|
else:
|
|
if not self._support_sd_registration_for_regional:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--service-directory-registration',
|
|
"""flag is available in one or more alternate release tracks. Try:
|
|
|
|
gcloud alpha compute forwarding-rules create --service-directory-registration
|
|
gcloud beta compute forwarding-rules create --service-directory-registration"""
|
|
)
|
|
# Parse projects/../locations/../namespaces/../services/..
|
|
match = re.match(
|
|
r'^projects/([^/]+)/locations/([^/]+)/namespaces/([^/]+)/services/([^/]+)$',
|
|
args.service_directory_registration)
|
|
if not match:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--service-directory-registration',
|
|
'Must be of the form projects/PROJECT/locations/REGION/namespaces/NAMESPACE/services/SERVICE'
|
|
)
|
|
project = match.group(1)
|
|
region = match.group(2)
|
|
|
|
if project != forwarding_rule_ref.project or region != forwarding_rule_ref.region:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--service-directory-registration',
|
|
'Service Directory registration must be in the same project and region as the forwarding rule.'
|
|
)
|
|
|
|
sd_registration = client.messages.ForwardingRuleServiceDirectoryRegistration(
|
|
namespace=match.group(3), service=match.group(4))
|
|
forwarding_rule.serviceDirectoryRegistrations.append(sd_registration)
|
|
|
|
request = client.messages.ComputeForwardingRulesInsertRequest(
|
|
forwardingRule=forwarding_rule,
|
|
project=forwarding_rule_ref.project,
|
|
region=forwarding_rule_ref.region)
|
|
|
|
return [(client.apitools_client.forwardingRules, 'Insert', request)]
|
|
|
|
def _ResolveAddress(self, resources, args, scope, forwarding_rule_ref):
|
|
"""Resolve address resource."""
|
|
|
|
# Address takes either an ip address or an address resource. If parsing as
|
|
# an IP address fails, then we resolve as a resource.
|
|
address = args.address
|
|
if address is not None:
|
|
try:
|
|
# ipaddress only allows unicode input
|
|
ipaddress.ip_network(six.text_type(args.address))
|
|
except ValueError:
|
|
# TODO(b/37086838): Make sure global/region settings are inherited by
|
|
# address resource.
|
|
if scope == compute_flags.compute_scope.ScopeEnum.REGION:
|
|
if not args.global_address and not args.address_region:
|
|
if forwarding_rule_ref.Collection() == 'compute.forwardingRules':
|
|
args.address_region = forwarding_rule_ref.region
|
|
address_ref = flags.AddressArg().ResolveAsResource(
|
|
args, resources, default_scope=scope)
|
|
address = address_ref.SelfLink()
|
|
|
|
return address
|
|
|
|
def _ProcessCommonArgs(self, client, resources, args, forwarding_rule_ref,
|
|
forwarding_rule):
|
|
"""Processes common arguments for global and regional commands.
|
|
|
|
Args:
|
|
client: The client used by gcloud.
|
|
resources: The resource parser.
|
|
args: The arguments passed to the gcloud command.
|
|
forwarding_rule_ref: The forwarding rule reference.
|
|
forwarding_rule: The forwarding rule to set properties on.
|
|
"""
|
|
|
|
if args.ip_version:
|
|
forwarding_rule.ipVersion = (
|
|
client.messages.ForwardingRule.IpVersionValueValuesEnum(
|
|
args.ip_version))
|
|
if args.network:
|
|
forwarding_rule.network = flags.NetworkArg().ResolveAsResource(
|
|
args, resources).SelfLink()
|
|
if args.subnet:
|
|
if (not args.subnet_region and
|
|
forwarding_rule_ref.Collection() == 'compute.forwardingRules'):
|
|
args.subnet_region = forwarding_rule_ref.region
|
|
forwarding_rule.subnetwork = flags.SUBNET_ARG.ResolveAsResource(
|
|
args, resources).SelfLink()
|
|
|
|
|
|
@base.ReleaseTracks(base.ReleaseTrack.GA)
|
|
@base.UniverseCompatible
|
|
class Create(base.CreateCommand):
|
|
"""Create a forwarding rule to direct network traffic to a load balancer."""
|
|
_support_all_protocol = False
|
|
_support_sd_registration_for_regional = False
|
|
|
|
@classmethod
|
|
def Args(cls, parser):
|
|
CreateHelper.Args(parser, cls._support_all_protocol)
|
|
|
|
def Run(self, args):
|
|
holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
|
|
return CreateHelper(
|
|
holder,
|
|
self._support_all_protocol,
|
|
self._support_sd_registration_for_regional,
|
|
).Run(args)
|
|
|
|
|
|
@base.ReleaseTracks(base.ReleaseTrack.BETA)
|
|
class CreateBeta(Create):
|
|
"""Create a forwarding rule to direct network traffic to a load balancer."""
|
|
_support_all_protocol = False
|
|
_support_sd_registration_for_regional = True
|
|
|
|
|
|
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
|
|
class CreateAlpha(CreateBeta):
|
|
"""Create a forwarding rule to direct network traffic to a load balancer."""
|
|
_support_all_protocol = True
|
|
_support_sd_registration_for_regional = True
|
|
|
|
|
|
Create.detailed_help = {
|
|
'DESCRIPTION': ("""
|
|
*{{command}}* is used to create a forwarding rule. {overview}
|
|
|
|
When creating a forwarding rule, exactly one of ``--target-instance'',
|
|
``--target-pool'', ``--target-http-proxy'', ``--target-https-proxy'',
|
|
``--target-grpc-proxy'', ``--target-ssl-proxy'', ``--target-tcp-proxy'',
|
|
``--target-vpn-gateway'', ``--backend-service'' or ``--target-google-apis-bundle''
|
|
must be specified.""".format(overview=flags.FORWARDING_RULES_OVERVIEW)),
|
|
'EXAMPLES':
|
|
"""
|
|
To create a global forwarding rule that will forward all traffic on port
|
|
8080 for IP address ADDRESS to a target http proxy PROXY, run:
|
|
|
|
$ {command} RULE_NAME --global --target-http-proxy=PROXY --ports=8080 --address=ADDRESS
|
|
|
|
To create a regional forwarding rule for the subnet SUBNET_NAME on the
|
|
default network that will forward all traffic on ports 80-82 to a
|
|
backend service SERVICE_NAME, run:
|
|
|
|
$ {command} RULE_NAME --load-balancing-scheme=INTERNAL --backend-service=SERVICE_NAME --subnet=SUBNET_NAME --network=default --region=REGION --ports=80-82
|
|
"""
|
|
}
|
|
|
|
CreateBeta.detailed_help = Create.detailed_help
|
|
CreateAlpha.detailed_help = CreateBeta.detailed_help
|
|
|
|
|
|
def _UnifyPortRangeFromListOfRanges(ports_range_list):
|
|
"""Return a single port range by combining a list of port ranges."""
|
|
if not ports_range_list:
|
|
return None, None
|
|
ports = sorted(ports_range_list)
|
|
combined_port_range = ports.pop(0)
|
|
for port_range in ports_range_list:
|
|
try:
|
|
combined_port_range = combined_port_range.Combine(port_range)
|
|
except arg_parsers.Error:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--ports', 'Must specify consecutive ports at this time.')
|
|
return combined_port_range
|
|
|
|
|
|
def _ExtractPortsAndAll(ports_with_all):
|
|
if ports_with_all:
|
|
return ports_with_all.all_specified, ports_with_all.ranges
|
|
else:
|
|
return False, []
|
|
|
|
|
|
def _MakeSingleUnifiedPortRange(arg_port_range, range_list_from_arg_ports):
|
|
"""Reconciles the deprecated --port-range arg with ranges from --ports arg."""
|
|
if arg_port_range:
|
|
log.warning(
|
|
'The --port-range flag is deprecated. Use equivalent --ports=%s'
|
|
' flag.', arg_port_range)
|
|
return six.text_type(arg_port_range)
|
|
elif range_list_from_arg_ports:
|
|
range_list = _UnifyPortRangeFromListOfRanges(range_list_from_arg_ports)
|
|
return six.text_type(range_list) if range_list else None
|
|
|
|
|
|
def _GetPortList(range_list):
|
|
"""Creates list of singleton port numbers from list of ports and ranges."""
|
|
ports = []
|
|
for port_range in range_list:
|
|
ports.extend(list(range(port_range.start, port_range.end + 1)))
|
|
return sorted(ports)
|
|
|
|
|
|
def _GetLoadBalancingScheme(args, messages, is_psc):
|
|
"""Get load balancing scheme."""
|
|
if not args.load_balancing_scheme:
|
|
# The default is EXTERNAL for non-PSC forwarding rules.
|
|
return None if is_psc else messages.ForwardingRule.LoadBalancingSchemeValueValuesEnum.EXTERNAL
|
|
if args.load_balancing_scheme == 'INTERNAL':
|
|
return messages.ForwardingRule.LoadBalancingSchemeValueValuesEnum.INTERNAL
|
|
elif args.load_balancing_scheme == 'EXTERNAL':
|
|
return messages.ForwardingRule.LoadBalancingSchemeValueValuesEnum.EXTERNAL
|
|
elif args.load_balancing_scheme == 'EXTERNAL_MANAGED':
|
|
return messages.ForwardingRule.LoadBalancingSchemeValueValuesEnum.EXTERNAL_MANAGED
|
|
elif args.load_balancing_scheme == 'INTERNAL_SELF_MANAGED':
|
|
return (messages.ForwardingRule.LoadBalancingSchemeValueValuesEnum
|
|
.INTERNAL_SELF_MANAGED)
|
|
elif args.load_balancing_scheme == 'INTERNAL_MANAGED':
|
|
return (messages.ForwardingRule.LoadBalancingSchemeValueValuesEnum
|
|
.INTERNAL_MANAGED)
|
|
return None
|
|
|
|
|
|
def _ConstructNetworkTier(messages, args):
|
|
"""Get network tier."""
|
|
if args.network_tier:
|
|
network_tier = args.network_tier.upper()
|
|
if network_tier in constants.NETWORK_TIER_CHOICES_FOR_INSTANCE:
|
|
return messages.ForwardingRule.NetworkTierValueValuesEnum(
|
|
args.network_tier)
|
|
else:
|
|
raise exceptions.InvalidArgumentException(
|
|
'--network-tier',
|
|
'Invalid network tier [{tier}]'.format(tier=network_tier))
|
|
else:
|
|
return
|